alapp.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:14k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* ALApp
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <vorbis/vorbisfile.h>
  22. #include <mad.h>
  23. #include "alapp.h"
  24. #ifdef _WIN32
  25. #pragma comment (lib,"openal32.lib")
  26. #pragma comment (lib,"ogg.lib")
  27. #pragma comment (lib,"vorbis.lib")
  28. #pragma comment (lib,"vorbisfile.lib")
  29. #pragma comment (lib,"libmad.lib")
  30. #endif
  31. /*****************************************************************************/
  32. /*                                                                           */
  33. /*                                                                           */
  34. /*                                                                           */
  35. /*****************************************************************************/
  36. class SoundFileOgg : public SoundFile {
  37. public:
  38. SoundFileOgg(const char *name);
  39. virtual ~SoundFileOgg();
  40. virtual int size();
  41. virtual int read(char *buf,int size = -1);
  42. virtual void seek(double time);
  43. protected:
  44. FILE *file;
  45. OggVorbis_File vf;
  46. vorbis_info *vi;
  47. };
  48. SoundFileOgg::SoundFileOgg(const char *name) {
  49. file = fopen(name,"rb");
  50. if(!file) {
  51. fprintf(stderr,"SoundFileOgg::SoundFileOgg(): error open "%s" filen",name);
  52. return;
  53. }
  54. if(ov_open(file,&vf,NULL,0) < 0) {
  55. fprintf(stderr,"SoundFileOgg::SoundFileOgg(): "%s" is not ogg bitstreamn",name);
  56. fclose(file);
  57. file = NULL;
  58. return;
  59. }
  60. vi = ov_info(&vf,-1);
  61. channels = vi->channels;
  62. freq = vi->rate;
  63. }
  64. SoundFileOgg::~SoundFileOgg() {
  65. if(file) {
  66. ov_clear(&vf);
  67. fclose(file);
  68. }
  69. }
  70. /*
  71.  */
  72. int SoundFileOgg::size() {
  73. if(!file) return 0;
  74. return (int)(ov_time_total(&vf,-1) + 0.5) * channels * freq * 2;
  75. }
  76. int SoundFileOgg::read(char *buffer,int size) {
  77. if(!file) return 0;
  78. int current_section;
  79. if(size < 0) size = this->size();
  80. int read = 0;
  81. while(read < size) {
  82. int ret = ov_read(&vf,buffer + read,size - read,0,2,1,&current_section);
  83. if(ret <= 0) break;
  84. read += ret;
  85. }
  86. return read;
  87. }
  88. void SoundFileOgg::seek(double time) {
  89. if(!file) return;
  90. ov_time_seek(&vf,time);
  91. }
  92. /*****************************************************************************/
  93. /*                                                                           */
  94. /*                                                                           */
  95. /*                                                                           */
  96. /*****************************************************************************/
  97. class SoundFileMp3 : public SoundFile {
  98. public:
  99. SoundFileMp3(const char *name);
  100. virtual ~SoundFileMp3();
  101. virtual int size();
  102. virtual int read(char *buf,int size = -1);
  103. virtual void seek(double time);
  104. protected:
  105. int read_frame();
  106. inline int scale(mad_fixed_t sample);
  107. enum {
  108. BUFFER_SIZE = 4096,
  109. };
  110. FILE *file;
  111. int file_size;
  112. unsigned char buffer[BUFFER_SIZE];
  113. int buffer_length;
  114. struct mad_synth synth;
  115. struct mad_stream stream;
  116. struct mad_frame frame;
  117. int bitrate;
  118. };
  119. SoundFileMp3::SoundFileMp3(const char *name) {
  120. file = fopen(name,"rb");
  121. if(!file) {
  122. fprintf(stderr,"SoundFileMp3::SoundFileMp3(): error open "%s" filen",name);
  123. return;
  124. }
  125. fseek(file,0,SEEK_END);
  126. file_size = ftell(file);
  127. fseek(file,0,SEEK_SET);
  128. buffer_length = 0;
  129. mad_synth_init(&synth);
  130. mad_stream_init(&stream);
  131. mad_frame_init(&frame);
  132. if(read_frame() == 0) {
  133. fprintf(stderr,"SoundFileMp3::SoundFileMp3(): can`t find framen",name);
  134. fclose(file);
  135. file = NULL;
  136. mad_synth_finish(&synth);
  137. mad_stream_finish(&stream);
  138. mad_frame_finish(&frame);
  139. return;
  140. }
  141. channels = (frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2;
  142. freq = frame.header.samplerate;
  143. bitrate = frame.header.bitrate;
  144. }
  145. SoundFileMp3::~SoundFileMp3() {
  146. if(file) {
  147. fclose(file);
  148. mad_synth_finish(&synth);
  149. mad_stream_finish(&stream);
  150. mad_frame_finish(&frame);
  151. }
  152. }
  153. /*
  154.  */
  155. int SoundFileMp3::read_frame() {
  156. while(1) {
  157. int ret = fread(&buffer[buffer_length],1,BUFFER_SIZE - buffer_length,file);
  158. if(ret <= 0) break;
  159. buffer_length += ret;
  160. while(1) {
  161. mad_stream_buffer(&stream,buffer,buffer_length);
  162. ret = mad_frame_decode(&frame,&stream);
  163. if(stream.next_frame) {
  164. int length = buffer + buffer_length - (unsigned char*)stream.next_frame;
  165. memmove(buffer,stream.next_frame,length);
  166. buffer_length = length;
  167. }
  168. if(ret == 0) return 1;
  169. if(stream.error == MAD_ERROR_BUFLEN) break;
  170. }
  171. }
  172. return 0;
  173. }
  174. /*
  175.  */
  176. inline int SoundFileMp3::scale(mad_fixed_t sample) {
  177. sample += (1 << (MAD_F_FRACBITS - 16));
  178. if(sample >= MAD_F_ONE) sample = MAD_F_ONE - 1;
  179. else if(sample < -MAD_F_ONE) sample = -MAD_F_ONE;
  180. return sample >> (MAD_F_FRACBITS + 1 - 16);
  181. }
  182. /*
  183.  */
  184. int SoundFileMp3::size() {
  185. if(!file) return 0;
  186. return file_size * 8 / bitrate * channels * freq * 2;
  187. }
  188. int SoundFileMp3::read(char *buffer,int size) {
  189. if(!file) return 0;
  190. if(size < 0) size = this->size();
  191. int read = 0;
  192. while(read < size) {
  193. mad_synth_frame(&synth,&frame);
  194. struct mad_pcm *pcm = &synth.pcm;
  195. mad_fixed_t *left = pcm->samples[0];
  196. mad_fixed_t *right = pcm->samples[1];
  197. unsigned short *data = (unsigned short*)(buffer + read);
  198. for(unsigned int length = pcm->length; length > 0; length--) {
  199. *data++ = scale(*left++);
  200. if(channels == 2) *data++ = scale(*right++);
  201. }
  202. read += pcm->length * channels * 2;
  203. if(!read_frame()) return read;
  204. }
  205. return read;
  206. }
  207. void SoundFileMp3::seek(double time) {
  208. if(!file) return;
  209. fseek(file,(unsigned int)((double)bitrate / 8.0 * time),SEEK_SET);
  210. read_frame();
  211. }
  212. /*****************************************************************************/
  213. /*                                                                           */
  214. /*                                                                           */
  215. /*                                                                           */
  216. /*****************************************************************************/
  217. class SoundFileWav : public SoundFile {
  218. public:
  219. SoundFileWav(const char *name);
  220. virtual ~SoundFileWav();
  221. virtual int size();
  222. virtual int read(char *buf,int size = -1);
  223. virtual void seek(double time);
  224. protected:
  225. enum {
  226. RIFF = 0x46464952,
  227. WAVE = 0x45564157,
  228. FMT = 0x20746D66,
  229. DATA = 0x61746164,
  230. };
  231. struct Fmt {
  232. unsigned short encoding;
  233. unsigned short channels;
  234. unsigned int frequency;
  235. unsigned int byterate;
  236. unsigned short blockalign;
  237. unsigned short bitspersample;
  238. };
  239. FILE *file;
  240. Fmt fmt;
  241. unsigned int data_offset;
  242. unsigned int data_length;
  243. };
  244. SoundFileWav::SoundFileWav(const char *name) {
  245. memset(&fmt,0,sizeof(Fmt));
  246. file = fopen(name,"rb");
  247. if(!file) {
  248. fprintf(stderr,"SoundFileWav::SoundFileWav(): error open "%s" filen",name);
  249. return;
  250. }
  251. unsigned int magic;
  252. unsigned int length;
  253. fread(&magic,sizeof(unsigned int),1,file);
  254. fread(&length,sizeof(unsigned int),1,file);
  255. if(magic != RIFF) {
  256. fprintf(stderr,"SoundFileWav::SoundFileWav(): wrong main chunkn");
  257. fclose(file);
  258. file = NULL;
  259. return;
  260. }
  261. fread(&magic,sizeof(unsigned int),1,file);
  262. if(magic != WAVE) {
  263. fprintf(stderr,"SoundFileWav::SoundFileWav(): unknown file typen");
  264. fclose(file);
  265. file = NULL;
  266. return;
  267. }
  268. while(1) {
  269. if(fread(&magic,sizeof(unsigned int),1,file) != 1) break;
  270. if(fread(&length,sizeof(unsigned int),1,file) != 1) break;
  271. if(magic == FMT) {
  272. fread(&fmt,sizeof(Fmt),1,file);
  273. if(fmt.encoding != 1) {
  274. fprintf(stderr,"SoundFileWav::SoundFileWav(): can`t open compressed waveform datan");
  275. fclose(file);
  276. file = NULL;
  277. return;
  278. }
  279. if(fmt.bitspersample != 16) {
  280. fprintf(stderr,"SoundFileWav::SoundFileWav(): can`t open %d bit per sample formatn",fmt.bitspersample);
  281. fclose(file);
  282. file = NULL;
  283. return;
  284. }
  285. channels = fmt.channels;
  286. freq = fmt.frequency;
  287. } else if(magic == DATA) {
  288. data_offset = ftell(file);
  289. data_length = length;
  290. break;
  291. } else {
  292. fseek(file,length,SEEK_CUR);
  293. }
  294. }
  295. if(channels == 0 || freq == 0 || data_offset == 0 || data_length == 0) {
  296. fprintf(stderr,"SoundFileWav::SoundFileWav(): can`t find FMT or DATA blockn");
  297. fclose(file);
  298. file = NULL;
  299. }
  300. }
  301. SoundFileWav::~SoundFileWav() {
  302. if(file) fclose(file);
  303. }
  304. /*
  305.  */
  306. int SoundFileWav::size() {
  307. if(!file) return 0;
  308. return data_length;
  309. }
  310. int SoundFileWav::read(char *buffer,int size) {
  311. if(!file) return 0;
  312. int left = data_length - ftell(file) + data_offset;
  313. if(size < 0 || left < size) size = left;
  314. fread(buffer,sizeof(char),size,file);
  315. return size;
  316. }
  317. void SoundFileWav::seek(double time) {
  318. if(!file) return;
  319. fseek(file,data_offset + (int)(time * fmt.channels * fmt.frequency),SEEK_SET);
  320. }
  321. /*****************************************************************************/
  322. /*                                                                           */
  323. /*                                                                           */
  324. /*                                                                           */
  325. /*****************************************************************************/
  326. SoundFile *SoundFile::load(const char *name) {
  327. if(strstr(name,".ogg")) return new SoundFileOgg(name);
  328. if(strstr(name,".mp3")) return new SoundFileMp3(name);
  329. if(strstr(name,".wav")) return new SoundFileWav(name);
  330. fprintf(stderr,""%s" is not supportedn",name);
  331. return NULL;
  332. }
  333. /*****************************************************************************/
  334. /*                                                                           */
  335. /*                                                                           */
  336. /*                                                                           */
  337. /*****************************************************************************/
  338. Sound::Sound(const char *name,int flag) : flag(flag) {
  339. file = SoundFile::load(name);
  340. if(!file) return;
  341. format = file->channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
  342. if(file->size() < BUFFER_SIZE * 2) this->flag &= ~STREAM;
  343. if(this->flag & STREAM) {
  344. buffer = new char[BUFFER_SIZE * 2];
  345. alGenBuffers(2,buffers);
  346. alGenSources(1,&source);
  347. current_buffer = 0;
  348. } else {
  349. buffer = new char[file->size()];
  350. int size = file->read(buffer);
  351. alGenBuffers(1,buffers);
  352. alBufferData(buffers[0],format,buffer,size,file->freq);
  353. alGenSources(1,&source);
  354. alSourcei(source,AL_BUFFER,buffers[0]);
  355. alSourcei(source,AL_LOOPING,flag & LOOP ? AL_TRUE : AL_FALSE);
  356. delete buffer;
  357. }
  358. }
  359. Sound::~Sound() {
  360. if(!file) return;
  361. delete file;
  362. if(flag & STREAM) delete buffer;
  363. alDeleteSources(1,&source);
  364. if(flag & STREAM) alDeleteBuffers(2,buffers);
  365. else alDeleteBuffers(1,buffers);
  366. }
  367. /*
  368.  */
  369. void Sound::play() {
  370. if(!file) return;
  371. ALint state;
  372. alGetSourcei(source,AL_SOURCE_STATE,&state);
  373. if(state == AL_PLAYING) return;
  374. if(state != AL_PAUSED && flag & STREAM) {
  375. file->read(buffer,BUFFER_SIZE);
  376. alBufferData(buffers[0],format,buffer,BUFFER_SIZE,file->freq);
  377. file->read(buffer,BUFFER_SIZE);
  378. alBufferData(buffers[1],format,buffer,BUFFER_SIZE,file->freq);
  379. alSourceQueueBuffers(source,2,buffers);
  380. ALApp::addStream(this);
  381. }
  382. alSourcePlay(source);
  383. }
  384. /*
  385.  */
  386. void Sound::pause() {
  387. if(!file) return;
  388. alSourcePause(source);
  389. }
  390. /*
  391.  */
  392. void Sound::stop() {
  393. if(!file) return;
  394. alSourceStop(source);
  395. file->seek(0.0);
  396. if(flag & STREAM) {
  397. ALint queued;
  398. alGetSourcei(source,AL_BUFFERS_QUEUED,&queued);
  399. if(queued > 0) alSourceUnqueueBuffers(source,2,buffers);
  400. ALApp::removeStream(this);
  401. current_buffer = 0;
  402. }
  403. }
  404. /*
  405.  */
  406. void Sound::update() {
  407. if(!file) return;
  408. if(flag & STREAM) {
  409. ALint processed;
  410. alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);
  411. if(processed == 1) {
  412. alSourceUnqueueBuffers(source,1,&buffers[current_buffer]);
  413. int size = file->read(buffer,BUFFER_SIZE);
  414. if(size > 0 || (size == 0 && flag & LOOP)) {
  415. alBufferData(buffers[current_buffer],format,buffer,size,file->freq);
  416. alSourceQueueBuffers(source,1,&buffers[current_buffer]);
  417. if(size != BUFFER_SIZE && flag & LOOP) file->seek(0.0);
  418. } else {
  419. int queued;
  420. alGetSourcei(source,AL_BUFFERS_QUEUED,&queued);
  421. if(queued == 0) file->seek(0.0);
  422. }
  423. current_buffer = 1 - current_buffer;
  424. } else if(processed == 2) {
  425. alSourceUnqueueBuffers(source,2,buffers);
  426. current_buffer = 0;
  427. play();
  428. }
  429. }
  430. }
  431. /*****************************************************************************/
  432. /*                                                                           */
  433. /*                                                                           */
  434. /*                                                                           */
  435. /*****************************************************************************/
  436. std::vector<Sound*> ALApp::streams;
  437. ALApp::ALApp() {
  438. device = alcOpenDevice(NULL);
  439. if(!device) {
  440. fprintf(stderr,"ALApp::ALApp(): invalid devicen");
  441. return;
  442. }
  443. context = alcCreateContext(device,NULL);
  444. if(!context) {
  445. fprintf(stderr,"ALApp::ALApp(): invalid contextn");
  446. return;
  447. }
  448. alcMakeContextCurrent(context);
  449. }
  450. ALApp::~ALApp() {
  451. alcDestroyContext(context);
  452. alcCloseDevice(device);
  453. }
  454. /*
  455.  */
  456. void ALApp::error() {
  457. ALenum error;
  458. while((error = alGetError()) != AL_NO_ERROR) {
  459. fprintf(stderr,"ALApp::error(): 0x%04Xn",error);
  460. }
  461. }
  462. /*
  463.  */
  464. void ALApp::update() {
  465. for(int i = 0; i < (int)streams.size(); i++) streams[i]->update();
  466. }
  467. /*
  468.  */
  469. void ALApp::addStream(Sound *s) {
  470. int i = 0;
  471. for(i = 0; i < (int)streams.size(); i++) if(streams[i] == s) break;
  472. if(i == (int)streams.size()) streams.push_back(s);
  473. }
  474. /*
  475.  */
  476. void ALApp::removeStream(Sound *s) {
  477. if((int)streams.size() == 0) return;
  478. int i = 0;
  479. for(i = 0; i < (int)streams.size(); i++) if(streams[i] == s) break;
  480. if(i == (int)streams.size()) streams.erase(streams.begin() + i);
  481. }