wavStreamSource.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //--------------------------------------
  23. // audioStreamSource.cc
  24. // implementation of streaming audio source
  25. //
  26. // Kurtis Seebaldt
  27. //--------------------------------------
  28. #include "audio/wavStreamSource.h"
  29. #define BUFFERSIZE 32768
  30. typedef struct
  31. {
  32. ALubyte riff[4]; // 'RIFF'
  33. ALsizei riffSize;
  34. ALubyte wave[4]; // 'WAVE'
  35. ALubyte fmt[4]; // 'fmt '
  36. ALuint fmtSize;
  37. ALushort Format;
  38. ALushort Channels;
  39. ALuint SamplesPerSec;
  40. ALuint BytesPerSec;
  41. ALushort BlockAlign;
  42. ALushort BitsPerSample;
  43. ALubyte data[4]; // 'data'
  44. ALuint dataSize;
  45. } WAVE_Struct;
  46. /// WAV File-header
  47. struct WAVFileHdr
  48. {
  49. ALubyte id[4];
  50. ALsizei size;
  51. ALubyte type[4];
  52. };
  53. //// WAV Fmt-header
  54. struct WAVFmtHdr
  55. {
  56. ALushort format;
  57. ALushort channels;
  58. ALuint samplesPerSec;
  59. ALuint bytesPerSec;
  60. ALushort blockAlign;
  61. ALushort bitsPerSample;
  62. };
  63. /// WAV FmtEx-header
  64. struct WAVFmtExHdr
  65. {
  66. ALushort size;
  67. ALushort samplesPerBlock;
  68. };
  69. /// WAV Smpl-header
  70. struct WAVSmplHdr
  71. {
  72. ALuint manufacturer;
  73. ALuint product;
  74. ALuint samplePeriod;
  75. ALuint note;
  76. ALuint fineTune;
  77. ALuint SMPTEFormat;
  78. ALuint SMPTEOffest;
  79. ALuint loops;
  80. ALuint samplerData;
  81. struct
  82. {
  83. ALuint identifier;
  84. ALuint type;
  85. ALuint start;
  86. ALuint end;
  87. ALuint fraction;
  88. ALuint count;
  89. } loop[1];
  90. };
  91. /// WAV Chunk-header
  92. struct WAVChunkHdr
  93. {
  94. ALubyte id[4];
  95. ALuint size;
  96. };
  97. WavStreamSource::WavStreamSource(const char *filename) {
  98. stream = NULL;
  99. bIsValid = false;
  100. bBuffersAllocated = false;
  101. mBufferList[0] = 0;
  102. clear();
  103. mFilename = filename;
  104. mPosition = Point3F(0.f,0.f,0.f);
  105. }
  106. WavStreamSource::~WavStreamSource() {
  107. if(bReady && bIsValid)
  108. freeStream();
  109. }
  110. void WavStreamSource::clear()
  111. {
  112. if(stream)
  113. freeStream();
  114. mHandle = NULL_AUDIOHANDLE;
  115. mSource = 0;
  116. if(mBufferList[0] != 0)
  117. alDeleteBuffers(NUMBUFFERS, mBufferList);
  118. for(int i = 0; i < NUMBUFFERS; i++)
  119. mBufferList[i] = 0;
  120. dMemset(&mDescription, 0, sizeof(Audio::Description));
  121. mEnvironment = 0;
  122. mPosition.set(0.f,0.f,0.f);
  123. mDirection.set(0.f,1.f,0.f);
  124. mPitch = 1.f;
  125. mScore = 0.f;
  126. mCullTime = 0;
  127. bReady = false;
  128. bFinishedPlaying = false;
  129. bIsValid = false;
  130. bBuffersAllocated = false;
  131. }
  132. bool WavStreamSource::initStream() {
  133. WAVChunkHdr chunkHdr;
  134. WAVFileHdr fileHdr;
  135. WAVFmtHdr fmtHdr;
  136. ALint error;
  137. bFinished = false;
  138. char data[BUFFERSIZE];
  139. alSourceStop(mSource);
  140. alSourcei(mSource, AL_BUFFER, 0);
  141. stream = ResourceManager->openStream(mFilename);
  142. if(stream != NULL) {
  143. stream->read(4, &fileHdr.id[0]);
  144. stream->read(&fileHdr.size);
  145. stream->read(4, &fileHdr.type[0]);
  146. stream->read(4, &chunkHdr.id[0]);
  147. stream->read(&chunkHdr.size);
  148. // WAV Format header
  149. stream->read(&fmtHdr.format);
  150. stream->read(&fmtHdr.channels);
  151. stream->read(&fmtHdr.samplesPerSec);
  152. stream->read(&fmtHdr.bytesPerSec);
  153. stream->read(&fmtHdr.blockAlign);
  154. stream->read(&fmtHdr.bitsPerSample);
  155. format=(fmtHdr.channels==1?
  156. (fmtHdr.bitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
  157. (fmtHdr.bitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
  158. freq=fmtHdr.samplesPerSec;
  159. stream->read(4, &chunkHdr.id[0]);
  160. stream->read(&chunkHdr.size);
  161. DataSize = chunkHdr.size;
  162. DataLeft = DataSize;
  163. dataStart = stream->getPosition();
  164. // Clear Error Code
  165. alGetError();
  166. alGenBuffers(NUMBUFFERS, mBufferList);
  167. if ((error = alGetError()) != AL_NO_ERROR) {
  168. return false;
  169. }
  170. bBuffersAllocated = true;
  171. int numBuffers = 0;
  172. for(int loop = 0; loop < NUMBUFFERS; loop++)
  173. {
  174. ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
  175. if (DataToRead == DataLeft)
  176. bFinished = AL_TRUE;
  177. stream->read(DataToRead, data);
  178. DataLeft -= DataToRead;
  179. alBufferData(mBufferList[loop], format, data, DataToRead, freq);
  180. if ((error = alGetError()) != AL_NO_ERROR) {
  181. return false;
  182. }
  183. ++numBuffers;
  184. if(bFinished)
  185. break;
  186. }
  187. // Queue the buffers on the source
  188. alSourceQueueBuffers(mSource, numBuffers, mBufferList);
  189. if ((error = alGetError()) != AL_NO_ERROR) {
  190. return false;
  191. }
  192. buffersinqueue = numBuffers;
  193. alSourcei(mSource, AL_LOOPING, AL_FALSE);
  194. bReady = true;
  195. }
  196. else {
  197. return false;
  198. }
  199. bIsValid = true;
  200. return true;
  201. }
  202. bool WavStreamSource::updateBuffers() {
  203. ALint processed;
  204. ALuint BufferID;
  205. ALint error;
  206. char data[BUFFERSIZE];
  207. // don't do anything if buffer isn't initialized
  208. if(!bIsValid)
  209. return false;
  210. if(bFinished && mDescription.mIsLooping) {
  211. resetStream();
  212. }
  213. // reset AL error code
  214. alGetError();
  215. // Get status
  216. alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
  217. // If some buffers have been played, unqueue them and load new audio into them, then add them to the queue
  218. if (processed > 0)
  219. {
  220. while (processed)
  221. {
  222. alSourceUnqueueBuffers(mSource, 1, &BufferID);
  223. if ((error = alGetError()) != AL_NO_ERROR)
  224. return false;
  225. if (!bFinished)
  226. {
  227. ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
  228. if (DataToRead == DataLeft) {
  229. bFinished = AL_TRUE;
  230. }
  231. stream->read(DataToRead, data);
  232. DataLeft -= DataToRead;
  233. alBufferData(BufferID, format, data, DataToRead, freq);
  234. if ((error = alGetError()) != AL_NO_ERROR)
  235. return false;
  236. // Queue buffer
  237. alSourceQueueBuffers(mSource, 1, &BufferID);
  238. if ((error = alGetError()) != AL_NO_ERROR)
  239. return false;
  240. processed--;
  241. if(bFinished && mDescription.mIsLooping) {
  242. resetStream();
  243. }
  244. }
  245. else
  246. {
  247. buffersinqueue--;
  248. processed--;
  249. if (buffersinqueue == 0)
  250. {
  251. bFinishedPlaying = AL_TRUE;
  252. return AL_FALSE;
  253. }
  254. }
  255. }
  256. }
  257. return AL_TRUE;
  258. }
  259. void WavStreamSource::freeStream() {
  260. bReady = false;
  261. if(stream != NULL)
  262. ResourceManager->closeStream(stream);
  263. stream = NULL;
  264. if(bBuffersAllocated) {
  265. if(mBufferList[0] != 0)
  266. alDeleteBuffers(NUMBUFFERS, mBufferList);
  267. for(int i = 0; i < NUMBUFFERS; i++)
  268. mBufferList[i] = 0;
  269. bBuffersAllocated = false;
  270. }
  271. }
  272. void WavStreamSource::resetStream() {
  273. stream->setPosition(dataStart);
  274. DataLeft = DataSize;
  275. bFinished = AL_FALSE;
  276. }
  277. #include "console/console.h"
  278. F32 WavStreamSource::getElapsedTime()
  279. {
  280. Con::warnf( "GetElapsedTime not implemented in WaveStreams yet" );
  281. return -1.f;
  282. }
  283. F32 WavStreamSource::getTotalTime()
  284. {
  285. Con::warnf( "GetTotalTime not implemented in WaveStreams yet" );
  286. return -1.f;
  287. }