From 6ef3bfb943358ab42287c43d4d482da0de497a75 Mon Sep 17 00:00:00 2001 From: Filjo Abraham Date: Sun, 9 Feb 2020 17:19:09 -0600 Subject: [PATCH] Merge XAudio.inl to XAudio.cpp --- plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp | 400 ++++++++++++++++- plugins/spu2-x/src/Windows/SndOut_XAudio2.inl | 417 ------------------ plugins/spu2-x/src/Windows/Spu2-X.vcxproj | 1 - .../spu2-x/src/Windows/Spu2-X.vcxproj.filters | 3 - 4 files changed, 399 insertions(+), 422 deletions(-) delete mode 100644 plugins/spu2-x/src/Windows/SndOut_XAudio2.inl diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp index 0d395df308..1f45befc5e 100644 --- a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp +++ b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp @@ -21,5 +21,403 @@ #undef _WIN32_WINNT #define _WIN32_WINNT 0x0602 #include +#include +#include +#include +#include +#include -#include "SndOut_XAudio2.inl" +namespace Exception +{ +class XAudio2Error : public std::runtime_error +{ +private: + static std::string CreateErrorMessage(const HRESULT result, const std::string &msg) + { + std::stringstream ss; + ss << " (code 0x" << std::hex << result << ")\n\n"; + switch (result) { + case XAUDIO2_E_INVALID_CALL: + ss << "Invalid call for the XA2 object state."; + break; + case XAUDIO2_E_DEVICE_INVALIDATED: + ss << "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing."; + break; + default: + ss << "Unknown error code!"; + break; + } + return msg + ss.str(); + } + +public: + explicit XAudio2Error(const HRESULT result, const std::string &msg) + : std::runtime_error(CreateErrorMessage(result, msg)) + { + } +}; +} + +static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16)); + +class XAudio2Mod : public SndOutModule +{ +private: + static const int PacketsPerBuffer = 8; + static const int MAX_BUFFER_COUNT = 3; + + class BaseStreamingVoice : public IXAudio2VoiceCallback + { + protected: + IXAudio2SourceVoice *pSourceVoice; + std::unique_ptr m_buffer; + + const uint m_nBuffers; + const uint m_nChannels; + const uint m_BufferSize; + const uint m_BufferSizeBytes; + + CRITICAL_SECTION cs; + + public: + int GetEmptySampleCount() + { + XAUDIO2_VOICE_STATE state; + pSourceVoice->GetState(&state); + return state.SamplesPlayed & (m_BufferSize - 1); + } + + virtual ~BaseStreamingVoice() + { + DeleteCriticalSection(&cs); + } + + BaseStreamingVoice(uint numChannels) + : pSourceVoice(nullptr) + , m_nBuffers(Config_XAudio2.NumBuffers) + , m_nChannels(numChannels) + , m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer) + , m_BufferSizeBytes(m_BufferSize * sizeof(s16)) + { + InitializeCriticalSection(&cs); + } + + virtual void Init(IXAudio2 *pXAudio2) = 0; + + protected: + // Several things must be initialized separate of the constructor, due to the fact that + // virtual calls can't be made from the constructor's context. + void _init(IXAudio2 *pXAudio2, uint chanConfig) + { + WAVEFORMATEXTENSIBLE wfx; + + memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE)); + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.nSamplesPerSec = SampleRate; + wfx.Format.nChannels = m_nChannels; + wfx.Format.wBitsPerSample = 16; + wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8; + wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign; + wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfx.Samples.wValidBitsPerSample = 16; + wfx.dwChannelMask = chanConfig; + wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + HRESULT hr; + if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx, + XAUDIO2_VOICE_NOSRC, 1.0f, this))) { + throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: "); + } + + EnterCriticalSection(&cs); + + pSourceVoice->FlushSourceBuffers(); + pSourceVoice->Start(0, 0); + + m_buffer = std::make_unique(m_nBuffers * m_BufferSize); + + // Start some buffers. + for (uint i = 0; i < m_nBuffers; i++) { + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = m_BufferSizeBytes; + buf.pContext = &m_buffer[i * m_BufferSize]; + buf.pAudioData = (BYTE *)buf.pContext; + pSourceVoice->SubmitSourceBuffer(&buf); + } + + LeaveCriticalSection(&cs); + } + + STDMETHOD_(void, OnVoiceProcessingPassStart) + () {} + STDMETHOD_(void, OnVoiceProcessingPassStart) + (UINT32) {} + STDMETHOD_(void, OnVoiceProcessingPassEnd) + () {} + STDMETHOD_(void, OnStreamEnd) + () {} + STDMETHOD_(void, OnBufferStart) + (void *) {} + STDMETHOD_(void, OnLoopEnd) + (void *) {} + STDMETHOD_(void, OnVoiceError) + (THIS_ void *pBufferContext, HRESULT Error) {} + }; + + template + class StreamingVoice : public BaseStreamingVoice + { + public: + StreamingVoice() + : BaseStreamingVoice(sizeof(T) / sizeof(s16)) + { + } + + virtual ~StreamingVoice() + { + IXAudio2SourceVoice *killMe = pSourceVoice; + // XXX: Potentially leads to a race condition that causes a nullptr + // dereference when SubmitSourceBuffer is called in OnBufferEnd? + pSourceVoice = nullptr; + if (killMe != nullptr) { + killMe->FlushSourceBuffers(); + killMe->DestroyVoice(); + } + + // XXX: Not sure we even need a critical section - DestroyVoice is + // blocking, and the documentation states no callbacks are called + // or audio data is read after it returns, so it's safe to free up + // resources. + EnterCriticalSection(&cs); + m_buffer = nullptr; + LeaveCriticalSection(&cs); + } + + void Init(IXAudio2 *pXAudio2) + { + int chanMask = 0; + switch (m_nChannels) { + case 1: + chanMask |= SPEAKER_FRONT_CENTER; + break; + case 2: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + break; + case 3: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY; + break; + case 4: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + break; + case 5: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + break; + case 6: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY; + break; + case 8: + chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY; + break; + } + _init(pXAudio2, chanMask); + } + + protected: + STDMETHOD_(void, OnBufferEnd) + (void *context) + { + EnterCriticalSection(&cs); + + // All of these checks are necessary because XAudio2 is wonky shizat. + // XXX: The pSourceVoice nullptr check seems a bit self-inflicted + // due to the destructor logic. + if (pSourceVoice == nullptr || context == nullptr) { + LeaveCriticalSection(&cs); + return; + } + + T *qb = (T *)context; + + for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize) + SndBuffer::ReadSamples(qb); + + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = m_BufferSizeBytes; + buf.pAudioData = (BYTE *)context; + buf.pContext = context; + + pSourceVoice->SubmitSourceBuffer(&buf); + LeaveCriticalSection(&cs); + } + }; + + HMODULE xAudio2DLL = nullptr; + decltype(&XAudio2Create) pXAudio2Create = nullptr; + CComPtr pXAudio2; + IXAudio2MasteringVoice *pMasteringVoice = nullptr; + std::unique_ptr m_voiceContext; + +public: + s32 Init() + { + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + try { + HRESULT hr; + + xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (xAudio2DLL == nullptr) + throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError())); + + pXAudio2Create = reinterpret_cast(GetProcAddress(xAudio2DLL, "XAudio2Create")); + if (pXAudio2Create == nullptr) + throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError())); + + if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))) + throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:"); + + // Stereo Expansion was planned to grab the currently configured number of + // Speakers from Windows's audio config. + // This doesn't always work though, so let it be a user configurable option. + + int speakers; + // speakers = (numSpeakers + 1) *2; ? + switch (numSpeakers) { + case 0: // Stereo + speakers = 2; + break; + case 1: // Quadrafonic + speakers = 4; + break; + case 2: // Surround 5.1 + speakers = 6; + break; + case 3: // Surround 7.1 + speakers = 8; + break; + default: + speakers = 2; + } + + if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) + throw Exception::XAudio2Error(hr, "Failed creating mastering voice: "); + + switch (speakers) { + case 2: + ConLog("* SPU2 > Using normal 2 speaker stereo output.\n"); + m_voiceContext = std::make_unique>(); + break; + case 3: + ConLog("* SPU2 > 2.1 speaker expansion enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + case 4: + ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n"); + m_voiceContext = std::make_unique>(); + break; + case 5: + ConLog("* SPU2 > 4.1 speaker expansion enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + case 6: + case 7: + switch (dplLevel) { + case 0: // "normal" stereo upmix + ConLog("* SPU2 > 5.1 speaker expansion enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + case 1: // basic Dpl decoder without rear stereo balancing + ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + case 2: // gigas PLII + ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + } + break; + default: // anything 8 or more gets the 7.1 treatment! + ConLog("* SPU2 > 7.1 speaker expansion enabled.\n"); + m_voiceContext = std::make_unique>(); + break; + } + + m_voiceContext->Init(pXAudio2); + } catch (std::runtime_error &ex) { + SysMessage(ex.what()); + Close(); + return -1; + } + + return 0; + } + + void Close() + { + // Clean up? + // All XAudio2 interfaces are released when the engine is destroyed, + // but being tidy never hurt. + + // Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes + // XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft. + // But doing no cleanup at all causes XA2 under XP to crash. So after much trial + // and error we found a happy compromise as follows: + + m_voiceContext = nullptr; + + if (pMasteringVoice != nullptr) + pMasteringVoice->DestroyVoice(); + + pMasteringVoice = nullptr; + + pXAudio2.Release(); + CoUninitialize(); + + if (xAudio2DLL) { + FreeLibrary(xAudio2DLL); + xAudio2DLL = nullptr; + pXAudio2Create = nullptr; + } + } + + virtual void Configure(uptr parent) + { + } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() + { + if (m_voiceContext == nullptr) + return 0; + return m_voiceContext->GetEmptySampleCount(); + } + + const wchar_t *GetIdent() const + { + return L"xaudio2"; + } + + const wchar_t *GetLongName() const + { + return L"XAudio 2 (Recommended)"; + } + + void ReadSettings() + { + } + + void SetApiSettings(wxString api) + { + } + + void WriteSettings() const + { + } + +} static XA2; + +SndOutModule *XAudio2Out = &XA2; diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.inl b/plugins/spu2-x/src/Windows/SndOut_XAudio2.inl deleted file mode 100644 index 1567663a93..0000000000 --- a/plugins/spu2-x/src/Windows/SndOut_XAudio2.inl +++ /dev/null @@ -1,417 +0,0 @@ -/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2 - * Developed and maintained by the Pcsx2 Development Team. - * - * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz] - * - * SPU2-X is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with SPU2-X. If not, see . - */ - -#include -#include -#include -#include -#include - -namespace Exception -{ -class XAudio2Error : public std::runtime_error -{ -private: - static std::string CreateErrorMessage(const HRESULT result, const std::string &msg) - { - std::stringstream ss; - ss << " (code 0x" << std::hex << result << ")\n\n"; - switch (result) { - case XAUDIO2_E_INVALID_CALL: - ss << "Invalid call for the XA2 object state."; - break; - case XAUDIO2_E_DEVICE_INVALIDATED: - ss << "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing."; - break; - default: - ss << "Unknown error code!"; - break; - } - return msg + ss.str(); - } - -public: - explicit XAudio2Error(const HRESULT result, const std::string &msg) - : std::runtime_error(CreateErrorMessage(result, msg)) - { - } -}; -} - -static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16)); - -class XAudio2Mod : public SndOutModule -{ -private: - static const int PacketsPerBuffer = 8; - static const int MAX_BUFFER_COUNT = 3; - - class BaseStreamingVoice : public IXAudio2VoiceCallback - { - protected: - IXAudio2SourceVoice *pSourceVoice; - std::unique_ptr m_buffer; - - const uint m_nBuffers; - const uint m_nChannels; - const uint m_BufferSize; - const uint m_BufferSizeBytes; - - CRITICAL_SECTION cs; - - public: - int GetEmptySampleCount() - { - XAUDIO2_VOICE_STATE state; - pSourceVoice->GetState(&state); - return state.SamplesPlayed & (m_BufferSize - 1); - } - - virtual ~BaseStreamingVoice() - { - DeleteCriticalSection(&cs); - } - - BaseStreamingVoice(uint numChannels) - : pSourceVoice(nullptr) - , m_nBuffers(Config_XAudio2.NumBuffers) - , m_nChannels(numChannels) - , m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer) - , m_BufferSizeBytes(m_BufferSize * sizeof(s16)) - { - InitializeCriticalSection(&cs); - } - - virtual void Init(IXAudio2 *pXAudio2) = 0; - - protected: - // Several things must be initialized separate of the constructor, due to the fact that - // virtual calls can't be made from the constructor's context. - void _init(IXAudio2 *pXAudio2, uint chanConfig) - { - WAVEFORMATEXTENSIBLE wfx; - - memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE)); - wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfx.Format.nSamplesPerSec = SampleRate; - wfx.Format.nChannels = m_nChannels; - wfx.Format.wBitsPerSample = 16; - wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8; - wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign; - wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - wfx.Samples.wValidBitsPerSample = 16; - wfx.dwChannelMask = chanConfig; - wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - HRESULT hr; - if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX *)&wfx, - XAUDIO2_VOICE_NOSRC, 1.0f, this))) { - throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: "); - } - - EnterCriticalSection(&cs); - - pSourceVoice->FlushSourceBuffers(); - pSourceVoice->Start(0, 0); - - m_buffer = std::make_unique(m_nBuffers * m_BufferSize); - - // Start some buffers. - for (uint i = 0; i < m_nBuffers; i++) { - XAUDIO2_BUFFER buf = {0}; - buf.AudioBytes = m_BufferSizeBytes; - buf.pContext = &m_buffer[i * m_BufferSize]; - buf.pAudioData = (BYTE *)buf.pContext; - pSourceVoice->SubmitSourceBuffer(&buf); - } - - LeaveCriticalSection(&cs); - } - - STDMETHOD_(void, OnVoiceProcessingPassStart) - () {} - STDMETHOD_(void, OnVoiceProcessingPassStart) - (UINT32) {} - STDMETHOD_(void, OnVoiceProcessingPassEnd) - () {} - STDMETHOD_(void, OnStreamEnd) - () {} - STDMETHOD_(void, OnBufferStart) - (void *) {} - STDMETHOD_(void, OnLoopEnd) - (void *) {} - STDMETHOD_(void, OnVoiceError) - (THIS_ void *pBufferContext, HRESULT Error) {} - }; - - template - class StreamingVoice : public BaseStreamingVoice - { - public: - StreamingVoice() - : BaseStreamingVoice(sizeof(T) / sizeof(s16)) - { - } - - virtual ~StreamingVoice() - { - IXAudio2SourceVoice *killMe = pSourceVoice; - // XXX: Potentially leads to a race condition that causes a nullptr - // dereference when SubmitSourceBuffer is called in OnBufferEnd? - pSourceVoice = nullptr; - if (killMe != nullptr) { - killMe->FlushSourceBuffers(); - killMe->DestroyVoice(); - } - - // XXX: Not sure we even need a critical section - DestroyVoice is - // blocking, and the documentation states no callbacks are called - // or audio data is read after it returns, so it's safe to free up - // resources. - EnterCriticalSection(&cs); - m_buffer = nullptr; - LeaveCriticalSection(&cs); - } - - void Init(IXAudio2 *pXAudio2) - { - int chanMask = 0; - switch (m_nChannels) { - case 1: - chanMask |= SPEAKER_FRONT_CENTER; - break; - case 2: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - break; - case 3: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY; - break; - case 4: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; - break; - case 5: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; - break; - case 6: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY; - break; - case 8: - chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY; - break; - } - _init(pXAudio2, chanMask); - } - - protected: - STDMETHOD_(void, OnBufferEnd) - (void *context) - { - EnterCriticalSection(&cs); - - // All of these checks are necessary because XAudio2 is wonky shizat. - // XXX: The pSourceVoice nullptr check seems a bit self-inflicted - // due to the destructor logic. - if (pSourceVoice == nullptr || context == nullptr) { - LeaveCriticalSection(&cs); - return; - } - - T *qb = (T *)context; - - for (int p = 0; p < PacketsPerBuffer; p++, qb += SndOutPacketSize) - SndBuffer::ReadSamples(qb); - - XAUDIO2_BUFFER buf = {0}; - buf.AudioBytes = m_BufferSizeBytes; - buf.pAudioData = (BYTE *)context; - buf.pContext = context; - - pSourceVoice->SubmitSourceBuffer(&buf); - LeaveCriticalSection(&cs); - } - }; - - HMODULE xAudio2DLL = nullptr; - decltype(&XAudio2Create) pXAudio2Create = nullptr; - CComPtr pXAudio2; - IXAudio2MasteringVoice *pMasteringVoice = nullptr; - std::unique_ptr m_voiceContext; - -public: - s32 Init() - { - CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - try { - HRESULT hr; - - xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (xAudio2DLL == nullptr) - throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError())); - - pXAudio2Create = reinterpret_cast(GetProcAddress(xAudio2DLL, "XAudio2Create")); - if (pXAudio2Create == nullptr) - throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError())); - - if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))) - throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:"); - - // Stereo Expansion was planned to grab the currently configured number of - // Speakers from Windows's audio config. - // This doesn't always work though, so let it be a user configurable option. - - int speakers; - // speakers = (numSpeakers + 1) *2; ? - switch (numSpeakers) { - case 0: // Stereo - speakers = 2; - break; - case 1: // Quadrafonic - speakers = 4; - break; - case 2: // Surround 5.1 - speakers = 6; - break; - case 3: // Surround 7.1 - speakers = 8; - break; - default: - speakers = 2; - } - - if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) - throw Exception::XAudio2Error(hr, "Failed creating mastering voice: "); - - switch (speakers) { - case 2: - ConLog("* SPU2 > Using normal 2 speaker stereo output.\n"); - m_voiceContext = std::make_unique>(); - break; - case 3: - ConLog("* SPU2 > 2.1 speaker expansion enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - case 4: - ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n"); - m_voiceContext = std::make_unique>(); - break; - case 5: - ConLog("* SPU2 > 4.1 speaker expansion enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - case 6: - case 7: - switch (dplLevel) { - case 0: // "normal" stereo upmix - ConLog("* SPU2 > 5.1 speaker expansion enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - case 1: // basic Dpl decoder without rear stereo balancing - ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - case 2: // gigas PLII - ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - } - break; - default: // anything 8 or more gets the 7.1 treatment! - ConLog("* SPU2 > 7.1 speaker expansion enabled.\n"); - m_voiceContext = std::make_unique>(); - break; - } - - m_voiceContext->Init(pXAudio2); - } catch (std::runtime_error &ex) { - SysMessage(ex.what()); - Close(); - return -1; - } - - return 0; - } - - void Close() - { - // Clean up? - // All XAudio2 interfaces are released when the engine is destroyed, - // but being tidy never hurt. - - // Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes - // XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft. - // But doing no cleanup at all causes XA2 under XP to crash. So after much trial - // and error we found a happy compromise as follows: - - m_voiceContext = nullptr; - - if (pMasteringVoice != nullptr) - pMasteringVoice->DestroyVoice(); - - pMasteringVoice = nullptr; - - pXAudio2.Release(); - CoUninitialize(); - - if (xAudio2DLL) { - FreeLibrary(xAudio2DLL); - xAudio2DLL = nullptr; - pXAudio2Create = nullptr; - } - } - - virtual void Configure(uptr parent) - { - } - - s32 Test() const - { - return 0; - } - - int GetEmptySampleCount() - { - if (m_voiceContext == nullptr) - return 0; - return m_voiceContext->GetEmptySampleCount(); - } - - const wchar_t *GetIdent() const - { - return L"xaudio2"; - } - - const wchar_t *GetLongName() const - { - return L"XAudio 2 (Recommended)"; - } - - void ReadSettings() - { - } - - void SetApiSettings(wxString api) - { - } - - void WriteSettings() const - { - } - -} static XA2; - -SndOutModule *XAudio2Out = &XA2; diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj index 0a124578be..ac0155c629 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj @@ -145,7 +145,6 @@ - diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters index 4da5e58127..6d488786fe 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters @@ -224,9 +224,6 @@ Resources - - Source Files\Sound Output\Windows -