PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/soloud/src/backend/xaudio2/soloud_xaudio2.cpp

https://gitlab.com/humangamer/Blitz3D-Modernized
C++ | 247 lines | 190 code | 21 blank | 36 comment | 32 complexity | 05b8debefc5afcd42b04037450416aa8 MD5 | raw file
  1. /*
  2. SoLoud audio engine
  3. Copyright (c) 2013-2014 Jari Komppa
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. */
  19. #include "soloud.h"
  20. #include "soloud_thread.h"
  21. #if !defined(WITH_XAUDIO2)
  22. namespace SoLoud
  23. {
  24. result xaudio2_init(Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer)
  25. {
  26. return NOT_IMPLEMENTED;
  27. }
  28. };
  29. #else
  30. #include <windows.h>
  31. #ifdef _MSC_VER
  32. #include <xaudio2.h>
  33. #pragma comment(lib, "xaudio2.lib")
  34. #else
  35. #include "backend/xaudio2/xaudio2.h"
  36. #endif
  37. namespace SoLoud
  38. {
  39. static const int BUFFER_COUNT = 2;
  40. struct XAudio2Data
  41. {
  42. float *buffer[BUFFER_COUNT];
  43. IXAudio2 *xaudio2;
  44. IXAudio2MasteringVoice *masteringVoice;
  45. IXAudio2SourceVoice *sourceVoice;
  46. HANDLE bufferEndEvent;
  47. HANDLE audioProcessingDoneEvent;
  48. class VoiceCallback *voiceCb;
  49. Thread::ThreadHandle thread;
  50. Soloud *soloud;
  51. int samples;
  52. UINT32 bufferLengthBytes;
  53. };
  54. class VoiceCallback : public IXAudio2VoiceCallback
  55. {
  56. public:
  57. VoiceCallback(HANDLE aBufferEndEvent)
  58. : IXAudio2VoiceCallback(), mBufferEndEvent(aBufferEndEvent) {}
  59. virtual ~VoiceCallback() {}
  60. private:
  61. // Called just before this voice's processing pass begins.
  62. void __stdcall OnVoiceProcessingPassStart(UINT32 aBytesRequired) {}
  63. // Called just after this voice's processing pass ends.
  64. void __stdcall OnVoiceProcessingPassEnd() {}
  65. // Called when this voice has just finished playing a buffer stream
  66. // (as marked with the XAUDIO2_END_OF_STREAM flag on the last buffer).
  67. void __stdcall OnStreamEnd() {}
  68. // Called when this voice is about to start processing a new buffer.
  69. void __stdcall OnBufferStart(void *aBufferContext) {}
  70. // Called when this voice has just finished processing a buffer.
  71. // The buffer can now be reused or destroyed.
  72. void __stdcall OnBufferEnd(void *aBufferContext)
  73. {
  74. SetEvent(mBufferEndEvent);
  75. }
  76. // Called when this voice has just reached the end position of a loop.
  77. void __stdcall OnLoopEnd(void *aBufferContext) {}
  78. // Called in the event of a critical error during voice processing,
  79. // such as a failing xAPO or an error from the hardware XMA decoder.
  80. // The voice may have to be destroyed and re-created to recover from
  81. // the error. The callback arguments report which buffer was being
  82. // processed when the error occurred, and its HRESULT code.
  83. void __stdcall OnVoiceError(void *aBufferContext, HRESULT aError) {}
  84. HANDLE mBufferEndEvent;
  85. };
  86. static void xaudio2Thread(LPVOID aParam)
  87. {
  88. XAudio2Data *data = static_cast<XAudio2Data*>(aParam);
  89. int bufferIndex = 0;
  90. while (WAIT_OBJECT_0 != WaitForSingleObject(data->audioProcessingDoneEvent, 0))
  91. {
  92. XAUDIO2_VOICE_STATE state;
  93. data->sourceVoice->GetState(&state);
  94. while (state.BuffersQueued < BUFFER_COUNT)
  95. {
  96. data->soloud->mix(data->buffer[bufferIndex], data->samples);
  97. XAUDIO2_BUFFER info = {0};
  98. info.AudioBytes = data->bufferLengthBytes;
  99. info.pAudioData = reinterpret_cast<const BYTE*>(data->buffer[bufferIndex]);
  100. data->sourceVoice->SubmitSourceBuffer(&info);
  101. ++bufferIndex;
  102. if (bufferIndex >= BUFFER_COUNT)
  103. {
  104. bufferIndex = 0;
  105. }
  106. data->sourceVoice->GetState(&state);
  107. }
  108. WaitForSingleObject(data->bufferEndEvent, INFINITE);
  109. }
  110. }
  111. static void xaudio2Cleanup(Soloud *aSoloud)
  112. {
  113. if (0 == aSoloud->mBackendData)
  114. {
  115. return;
  116. }
  117. XAudio2Data *data = static_cast<XAudio2Data*>(aSoloud->mBackendData);
  118. SetEvent(data->audioProcessingDoneEvent);
  119. SetEvent(data->bufferEndEvent);
  120. Thread::wait(data->thread);
  121. Thread::release(data->thread);
  122. if (0 != data->sourceVoice)
  123. {
  124. data->sourceVoice->Stop();
  125. data->sourceVoice->FlushSourceBuffers();
  126. }
  127. if (0 != data->xaudio2)
  128. {
  129. data->xaudio2->StopEngine();
  130. }
  131. if (0 != data->sourceVoice)
  132. {
  133. data->sourceVoice->DestroyVoice();
  134. }
  135. if (0 != data->voiceCb)
  136. {
  137. delete data->voiceCb;
  138. }
  139. if (0 != data->masteringVoice)
  140. {
  141. data->masteringVoice->DestroyVoice();
  142. }
  143. if (0 != data->xaudio2)
  144. {
  145. data->xaudio2->Release();
  146. }
  147. for (int i=0;i<BUFFER_COUNT;++i)
  148. {
  149. if (0 != data->buffer[i])
  150. {
  151. delete[] data->buffer[i];
  152. }
  153. }
  154. CloseHandle(data->bufferEndEvent);
  155. CloseHandle(data->audioProcessingDoneEvent);
  156. delete data;
  157. aSoloud->mBackendData = 0;
  158. CoUninitialize();
  159. }
  160. result xaudio2_init(Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, unsigned int aChannels)
  161. {
  162. if (FAILED(CoInitializeEx(0, COINIT_MULTITHREADED)))
  163. {
  164. return UNKNOWN_ERROR;
  165. }
  166. XAudio2Data *data = new XAudio2Data;
  167. ZeroMemory(data, sizeof(XAudio2Data));
  168. aSoloud->mBackendData = data;
  169. aSoloud->mBackendCleanupFunc = xaudio2Cleanup;
  170. data->bufferEndEvent = CreateEvent(0, FALSE, FALSE, 0);
  171. if (0 == data->bufferEndEvent)
  172. {
  173. return UNKNOWN_ERROR;
  174. }
  175. data->audioProcessingDoneEvent = CreateEvent(0, FALSE, FALSE, 0);
  176. if (0 == data->audioProcessingDoneEvent)
  177. {
  178. return UNKNOWN_ERROR;
  179. }
  180. WAVEFORMATEX format;
  181. ZeroMemory(&format, sizeof(WAVEFORMATEX));
  182. format.nChannels = 2;
  183. format.nSamplesPerSec = aSamplerate;
  184. format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  185. format.nAvgBytesPerSec = aSamplerate*sizeof(float)*format.nChannels;
  186. format.nBlockAlign = sizeof(float)*format.nChannels;
  187. format.wBitsPerSample = sizeof(float)*8;
  188. if (FAILED(XAudio2Create(&data->xaudio2)))
  189. {
  190. return UNKNOWN_ERROR;
  191. }
  192. if (FAILED(data->xaudio2->CreateMasteringVoice(&data->masteringVoice,
  193. format.nChannels, aSamplerate)))
  194. {
  195. return UNKNOWN_ERROR;
  196. }
  197. data->voiceCb = new VoiceCallback(data->bufferEndEvent);
  198. if (FAILED(data->xaudio2->CreateSourceVoice(&data->sourceVoice,
  199. &format, XAUDIO2_VOICE_NOSRC|XAUDIO2_VOICE_NOPITCH, 2.f, data->voiceCb)))
  200. {
  201. return UNKNOWN_ERROR;
  202. }
  203. data->bufferLengthBytes = aBuffer * format.nChannels * sizeof(float);
  204. for (int i=0;i<BUFFER_COUNT;++i)
  205. {
  206. data->buffer[i] = new float[aBuffer * format.nChannels];
  207. }
  208. data->samples = aBuffer;
  209. data->soloud = aSoloud;
  210. aSoloud->postinit_internal(aSamplerate, aBuffer * format.nChannels, aFlags, 2);
  211. data->thread = Thread::createThread(xaudio2Thread, data);
  212. if (0 == data->thread)
  213. {
  214. return UNKNOWN_ERROR;
  215. }
  216. data->sourceVoice->Start();
  217. aSoloud->mBackendString = "XAudio2";
  218. return 0;
  219. }
  220. };
  221. #endif