OpenAL_AudioInterface.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /// @file
  2. /// @version 2.0
  3. ///
  4. /// @section LICENSE
  5. ///
  6. /// This program is free software; you can redistribute it and/or modify it under
  7. /// the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "OpenAL_AudioInterface.h"
  11. ALCdevice* gDevice = 0;
  12. ALCcontext* gContext = 0;
  13. short float2short(float f)
  14. {
  15. if (f > 1.0f)
  16. {
  17. f = 1.0f;
  18. }
  19. else if (f < -1.0f)
  20. {
  21. f = -1.0f;
  22. }
  23. return (short)(f * 32767);
  24. }
  25. OpenAL_AudioInterface::OpenAL_AudioInterface(theoraplayer::VideoClip* clip, int channelsCount, int frequency) :
  26. theoraplayer::AudioInterface(clip, channelsCount, frequency), theoraplayer::Timer()
  27. {
  28. this->sourceNumChannels = this->channelsCount;
  29. if (this->channelsCount > 2)
  30. {
  31. // ignore audio with more than 2 channels, use only the stereo channels
  32. this->channelsCount = 2;
  33. }
  34. this->maxBuffSize = frequency * this->channelsCount * 2;
  35. this->buffSize = 0;
  36. this->numProcessedSamples = 0;
  37. this->currentTimer = 0;
  38. this->tempBuffer = new short[this->maxBuffSize];
  39. alGenSources(1, &this->source);
  40. clip->setTimer(this);
  41. this->numPlayedSamples = 0;
  42. }
  43. OpenAL_AudioInterface::~OpenAL_AudioInterface()
  44. {
  45. if (this->tempBuffer != NULL)
  46. {
  47. delete[] this->tempBuffer;
  48. }
  49. if (this->source != 0)
  50. {
  51. alSourcei(this->source, AL_BUFFER, 0);
  52. alDeleteSources(1, &this->source);
  53. }
  54. while (this->bufferQueue.size() > 0)
  55. {
  56. alDeleteBuffers(1, &this->bufferQueue.front().id);
  57. this->bufferQueue.pop();
  58. }
  59. }
  60. float OpenAL_AudioInterface::getQueuedAudioSize()
  61. {
  62. return ((float)(this->numProcessedSamples - this->numPlayedSamples)) / this->frequency;
  63. }
  64. void OpenAL_AudioInterface::insertData(float* data, int samplesCount)
  65. {
  66. float* tempData = NULL;
  67. if (this->sourceNumChannels > 2)
  68. {
  69. tempData = new float[samplesCount * 2 / this->sourceNumChannels + 16]; // 16 padding just in case
  70. int i = 0;
  71. int n = 0;
  72. for (n = 0, i = 0; i < samplesCount; i += this->sourceNumChannels, n += 2)
  73. {
  74. tempData[n] = data[i];
  75. tempData[n + 1] = data[i + 1];
  76. }
  77. data = tempData;
  78. samplesCount = n;
  79. }
  80. //printf("got %d bytes, %d buffers queued\n",samplesCount,(int)this->bufferQueue.size());
  81. int state = 0;
  82. OpenAL_Buffer buff;
  83. ALuint format;
  84. for (int i = 0; i < samplesCount; ++i)
  85. {
  86. if (this->buffSize < this->maxBuffSize)
  87. {
  88. this->tempBuffer[this->buffSize] = float2short(data[i]);
  89. ++this->buffSize;
  90. }
  91. if (this->buffSize == this->frequency * this->channelsCount / 10)
  92. {
  93. memset(&buff, 0, sizeof(OpenAL_Buffer));
  94. alGenBuffers(1, &buff.id);
  95. format = (this->channelsCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
  96. alBufferData(buff.id, format, this->tempBuffer, this->buffSize * 2, this->frequency);
  97. alSourceQueueBuffers(this->source, 1, &buff.id);
  98. buff.samplesCount = this->buffSize / this->channelsCount;
  99. this->numProcessedSamples += this->buffSize / this->channelsCount;
  100. this->bufferQueue.push(buff);
  101. this->buffSize = 0;
  102. state = 0;
  103. alGetSourcei(this->source, AL_SOURCE_STATE, &state);
  104. if (state != AL_PLAYING)
  105. {
  106. //alSourcef(this->source,AL_PITCH,0.5); // debug
  107. //alSourcef(this->source,AL_SAMPLE_OFFSET,(float) this->numProcessedSamples-mFreq/4);
  108. alSourcePlay(this->source);
  109. }
  110. }
  111. }
  112. if (tempData != NULL)
  113. {
  114. delete[] tempData;
  115. }
  116. }
  117. void OpenAL_AudioInterface::update(float timeDelta)
  118. {
  119. int i = 0;
  120. int nProcessed = 0;
  121. OpenAL_Buffer buff;
  122. // process played buffers
  123. alGetSourcei(this->source, AL_BUFFERS_PROCESSED, &nProcessed);
  124. for (i = 0; i < nProcessed; ++i)
  125. {
  126. buff = this->bufferQueue.front();
  127. this->bufferQueue.pop();
  128. this->numPlayedSamples += buff.samplesCount;
  129. alSourceUnqueueBuffers(this->source, 1, &buff.id);
  130. alDeleteBuffers(1, &buff.id);
  131. }
  132. if (nProcessed != 0)
  133. {
  134. // update offset
  135. alGetSourcef(this->source, AL_SEC_OFFSET, &this->currentTimer);
  136. }
  137. // control playback and return time position
  138. //alGetSourcei(this->source,AL_SOURCE_STATE,&state);
  139. //if (state == AL_PLAYING)
  140. this->currentTimer += timeDelta;
  141. this->time = this->currentTimer + (float) this->numPlayedSamples / this->frequency;
  142. float duration = this->clip->getDuration();
  143. if (this->time > duration)
  144. {
  145. this->time = duration;
  146. }
  147. }
  148. void OpenAL_AudioInterface::pause()
  149. {
  150. alSourcePause(this->source);
  151. Timer::pause();
  152. }
  153. void OpenAL_AudioInterface::play()
  154. {
  155. alSourcePlay(this->source);
  156. Timer::play();
  157. }
  158. void OpenAL_AudioInterface::seek(float time)
  159. {
  160. OpenAL_Buffer buff;
  161. alSourceStop(this->source);
  162. while (!this->bufferQueue.empty())
  163. {
  164. buff = this->bufferQueue.front();
  165. this->bufferQueue.pop();
  166. alSourceUnqueueBuffers(this->source, 1, &buff.id);
  167. alDeleteBuffers(1, &buff.id);
  168. }
  169. // int nProcessed;
  170. // alGetSourcei(this->source,AL_BUFFERS_PROCESSED,&nProcessed);
  171. // if (nProcessed != 0)
  172. // nProcessed=nProcessed;
  173. this->buffSize = 0;
  174. this->currentTimer = 0;
  175. this->numPlayedSamples = this->numProcessedSamples = (int)(time * this->frequency);
  176. this->time = time;
  177. }
  178. OpenAL_AudioInterfaceFactory::OpenAL_AudioInterfaceFactory()
  179. {
  180. return;
  181. // openal init is here used only to simplify samples for this plugin
  182. // if you want to use this interface in your own program, you'll
  183. // probably want to remove the openal init/destory lines
  184. gDevice = alcOpenDevice(NULL);
  185. if (alcGetError(gDevice) != ALC_NO_ERROR)
  186. {
  187. return;
  188. }
  189. gContext = alcCreateContext(gDevice, NULL);
  190. if (alcGetError(gDevice) != ALC_NO_ERROR)
  191. {
  192. alcCloseDevice(gDevice);
  193. gDevice = NULL;
  194. return;
  195. }
  196. alcMakeContextCurrent(gContext);
  197. if (alcGetError(gDevice) != ALC_NO_ERROR)
  198. {
  199. alcDestroyContext(gContext);
  200. gContext = NULL;
  201. alcCloseDevice(gDevice);
  202. gDevice = NULL;
  203. }
  204. }
  205. OpenAL_AudioInterfaceFactory::~OpenAL_AudioInterfaceFactory()
  206. {
  207. return;
  208. if (gDevice != NULL)
  209. {
  210. alcMakeContextCurrent(NULL);
  211. alcDestroyContext(gContext);
  212. alcCloseDevice(gDevice);
  213. }
  214. }
  215. OpenAL_AudioInterface* OpenAL_AudioInterfaceFactory::createInstance(theoraplayer::VideoClip* clip, int channelsCount, int frequency)
  216. {
  217. return new OpenAL_AudioInterface(clip, channelsCount, frequency);
  218. }