| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-22 18:18:37 -07:00
										 |  |  | // Note that this file *and this file only* must include XAudio2.h from the old
 | 
					
						
							|  |  |  | // DXSDK instead of other possible places.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <XAudio2_7/XAudio2.h>
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "AudioCommon/AudioCommon.h"
 | 
					
						
							|  |  |  | #include "AudioCommon/XAudio2_7Stream.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | #include "Common/Event.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct StreamingVoiceContext2_7 : public IXAudio2VoiceCallback | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   CMixer* const m_mixer; | 
					
						
							|  |  |  |   Common::Event& m_sound_sync_event; | 
					
						
							|  |  |  |   IXAudio2SourceVoice* m_source_voice; | 
					
						
							|  |  |  |   std::unique_ptr<BYTE[]> xaudio_buffer; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   void SubmitBuffer(PBYTE buf_data); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   StreamingVoiceContext2_7(IXAudio2* pXAudio2, CMixer* pMixer, Common::Event& pSyncEvent); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ~StreamingVoiceContext2_7(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 20:37:04 -08:00
										 |  |  |   void Stop(); | 
					
						
							|  |  |  |   void Play(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   STDMETHOD_(void, OnVoiceError)(THIS_ void* pBufferContext, HRESULT Error) {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32) {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnVoiceProcessingPassEnd)() {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnBufferStart)(void*) {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnLoopEnd)(void*) {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnStreamEnd)() {} | 
					
						
							|  |  |  |   STDMETHOD_(void, OnBufferEnd)(void* context); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int NUM_BUFFERS = 3; | 
					
						
							|  |  |  | const int SAMPLES_PER_BUFFER = 96; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int NUM_CHANNELS = 2; | 
					
						
							|  |  |  | const int BUFFER_SIZE = SAMPLES_PER_BUFFER * NUM_CHANNELS; | 
					
						
							|  |  |  | const int BUFFER_SIZE_BYTES = BUFFER_SIZE * sizeof(s16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StreamingVoiceContext2_7::SubmitBuffer(PBYTE buf_data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XAUDIO2_BUFFER buf = {}; | 
					
						
							|  |  |  |   buf.AudioBytes = BUFFER_SIZE_BYTES; | 
					
						
							|  |  |  |   buf.pContext = buf_data; | 
					
						
							|  |  |  |   buf.pAudioData = buf_data; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_source_voice->SubmitSourceBuffer(&buf); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | StreamingVoiceContext2_7::StreamingVoiceContext2_7(IXAudio2* pXAudio2, CMixer* pMixer, | 
					
						
							|  |  |  |                                                    Common::Event& pSyncEvent) | 
					
						
							|  |  |  |     : m_mixer(pMixer), m_sound_sync_event(pSyncEvent), | 
					
						
							|  |  |  |       xaudio_buffer(new BYTE[NUM_BUFFERS * BUFFER_SIZE_BYTES]()) | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   WAVEFORMATEXTENSIBLE wfx = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | 
					
						
							|  |  |  |   wfx.Format.nSamplesPerSec = m_mixer->GetSampleRate(); | 
					
						
							|  |  |  |   wfx.Format.nChannels = 2; | 
					
						
							|  |  |  |   wfx.Format.wBitsPerSample = 16; | 
					
						
							|  |  |  |   wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8; | 
					
						
							|  |  |  |   wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; | 
					
						
							|  |  |  |   wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); | 
					
						
							|  |  |  |   wfx.Samples.wValidBitsPerSample = 16; | 
					
						
							|  |  |  |   wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; | 
					
						
							|  |  |  |   wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create source voice
 | 
					
						
							|  |  |  |   HRESULT hr; | 
					
						
							|  |  |  |   if (FAILED(hr = pXAudio2->CreateSourceVoice(&m_source_voice, &wfx.Format, XAUDIO2_VOICE_NOSRC, | 
					
						
							|  |  |  |                                               1.0f, this))) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("XAudio2_7 CreateSourceVoice failed: %#X", hr); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_source_voice->Start(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // start buffers with silence
 | 
					
						
							|  |  |  |   for (int i = 0; i != NUM_BUFFERS; ++i) | 
					
						
							|  |  |  |     SubmitBuffer(xaudio_buffer.get() + (i * BUFFER_SIZE_BYTES)); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StreamingVoiceContext2_7::~StreamingVoiceContext2_7() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_source_voice) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_source_voice->Stop(); | 
					
						
							|  |  |  |     m_source_voice->DestroyVoice(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StreamingVoiceContext2_7::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_source_voice) | 
					
						
							|  |  |  |     m_source_voice->Stop(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StreamingVoiceContext2_7::Play() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_source_voice) | 
					
						
							|  |  |  |     m_source_voice->Start(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StreamingVoiceContext2_7::OnBufferEnd(void* context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   //  buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!m_source_voice || !context) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // m_sound_sync_event->Wait(); // sync
 | 
					
						
							|  |  |  |   // m_sound_sync_event->Spin(); // or tight sync
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_mixer->Mix(static_cast<short*>(context), SAMPLES_PER_BUFFER); | 
					
						
							|  |  |  |   SubmitBuffer(static_cast<BYTE*>(context)); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HMODULE XAudio2_7::m_xaudio2_dll = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void XAudio2_7::ReleaseIXAudio2(IXAudio2* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ptr->Release(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool XAudio2_7::InitLibrary() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_xaudio2_dll) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_xaudio2_dll = ::LoadLibrary(TEXT("xaudio2_7.dll")); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return m_xaudio2_dll != nullptr; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-24 04:13:02 -04:00
										 |  |  | XAudio2_7::XAudio2_7() | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_mastering_voice(nullptr), m_volume(1.0f), | 
					
						
							|  |  |  |       m_cleanup_com(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | XAudio2_7::~XAudio2_7() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Stop(); | 
					
						
							|  |  |  |   if (m_cleanup_com) | 
					
						
							|  |  |  |     CoUninitialize(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool XAudio2_7::Start() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   HRESULT hr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // callback doesn't seem to run on a specific CPU anyways
 | 
					
						
							|  |  |  |   IXAudio2* xaudptr; | 
					
						
							|  |  |  |   if (FAILED(hr = XAudio2Create(&xaudptr, 0, XAUDIO2_DEFAULT_PROCESSOR))) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("XAudio2_7 init failed: %#X", hr); | 
					
						
							|  |  |  |     Stop(); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   m_xaudio2 = std::unique_ptr<IXAudio2, Releaser>(xaudptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // XAudio2 master voice
 | 
					
						
							|  |  |  |   // XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion?
 | 
					
						
							|  |  |  |   if (FAILED(hr = m_xaudio2->CreateMasteringVoice(&m_mastering_voice, 2, m_mixer->GetSampleRate()))) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("XAudio2_7 master voice creation failed: %#X", hr); | 
					
						
							|  |  |  |     Stop(); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Volume
 | 
					
						
							|  |  |  |   m_mastering_voice->SetVolume(m_volume); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_voice_context = std::unique_ptr<StreamingVoiceContext2_7>( | 
					
						
							|  |  |  |       new StreamingVoiceContext2_7(m_xaudio2.get(), m_mixer.get(), m_sound_sync_event)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void XAudio2_7::SetVolume(int volume) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // linear 1- .01
 | 
					
						
							|  |  |  |   m_volume = (float)volume / 100.f; | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_mastering_voice) | 
					
						
							|  |  |  |     m_mastering_voice->SetVolume(m_volume); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void XAudio2_7::Clear(bool mute) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_muted = mute; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (m_voice_context) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (m_muted) | 
					
						
							|  |  |  |       m_voice_context->Stop(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       m_voice_context->Play(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void XAudio2_7::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // m_sound_sync_event.Set();
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_voice_context.reset(); | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_mastering_voice) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_mastering_voice->DestroyVoice(); | 
					
						
							|  |  |  |     m_mastering_voice = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_xaudio2.reset();  // release interface
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_xaudio2_dll) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ::FreeLibrary(m_xaudio2_dll); | 
					
						
							|  |  |  |     m_xaudio2_dll = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | } |