From 5ea80b86dbe0c8e05886ab9c8835e4766239c907 Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Fri, 26 Feb 2016 03:57:53 +0000 Subject: [PATCH 1/5] spu2-x:windows: Remove VersionHelpers workaround We've moved to the non-XP toolkit - it can be removed. --- plugins/spu2-x/src/Windows/Config.cpp | 22 ++-------------------- plugins/spu2-x/src/Windows/WinConfig.h | 1 + 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/plugins/spu2-x/src/Windows/Config.cpp b/plugins/spu2-x/src/Windows/Config.cpp index 8434e11900..02f2b3e84b 100644 --- a/plugins/spu2-x/src/Windows/Config.cpp +++ b/plugins/spu2-x/src/Windows/Config.cpp @@ -82,20 +82,6 @@ int numSpeakers = 0; int dplLevel = 0; /*****************************************************************************/ -BOOL IsVistaOrGreater2() // workaround for XP toolset missing VersionHelpers.h -{ - OSVERSIONINFOEX osvi; - DWORDLONG dwlConditionMask = 0; - int op = VER_GREATER_EQUAL; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - osvi.dwMajorVersion = 6; - - VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op); - - return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask); -} void ReadSettings() { @@ -140,12 +126,8 @@ void ReadSettings() // portaudio occasionally has issues selecting the proper default audio device. // let's use xaudio2 until this is sorted (rama) -// if ( IsVistaOrGreater2() ) { // XA2 for WinXP, morder modern gets Portaudio -// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent()); -// } -// else { - CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent()); -// } +// CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent()); + CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent()); // find the driver index of this module: OutputModule = FindOutputModuleById( omodid ); diff --git a/plugins/spu2-x/src/Windows/WinConfig.h b/plugins/spu2-x/src/Windows/WinConfig.h index 269ff0c465..3169a9d4e2 100644 --- a/plugins/spu2-x/src/Windows/WinConfig.h +++ b/plugins/spu2-x/src/Windows/WinConfig.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "resource.h" From c8162df9363b50d3b7348b2279f2607e15014f65 Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sun, 28 Feb 2016 13:52:39 +0000 Subject: [PATCH 2/5] spu2-x: Only XAudio2 2.7 requires the DXSDK Use the newer Windows SDK for everything else. --- plugins/spu2-x/src/Windows/Spu2-X.vcxproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj index 900911bdac..27a150b2ef 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj @@ -107,8 +107,6 @@ $(ProjectName)-dev false - $(DXSDK_DIR)\include;$(IncludePath) - $(DXSDK_DIR)\Lib\x86;$(LibraryPath) @@ -121,7 +119,7 @@ - $(DXSDK_DIR)include;$(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) + $(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) FLOAT_SAMPLES;NDEBUG;_USRDLL;%(PreprocessorDefinitions) Async StreamingSIMDExtensions2 @@ -160,7 +158,7 @@ - $(DXSDK_DIR)include;$(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) + $(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) FLOAT_SAMPLES;_USRDLL;%(PreprocessorDefinitions) Async Use @@ -193,7 +191,7 @@ - $(DXSDK_DIR)include;$(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) + $(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) FLOAT_SAMPLES;NDEBUG;_USRDLL;%(PreprocessorDefinitions) Async StreamingSIMDExtensions2 @@ -234,7 +232,7 @@ - $(DXSDK_DIR)include;$(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) + $(SolutionDir)3rdparty\portaudio\include\;%(AdditionalIncludeDirectories) wxUSE_GUI=0;FLOAT_SAMPLES;DEBUG_FAST;_USRDLL;%(PreprocessorDefinitions) Async Use @@ -344,7 +342,9 @@ - + + $(DXSDK_DIR)include;%(AdditionalIncludeDirectories) + true true From de56e30bbabb79255c3b38de953338ececaf256e Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sun, 28 Feb 2016 15:10:28 +0000 Subject: [PATCH 3/5] spu2-x:windows:xaudio: Remove ifdefs and rename class/vars This reverts commit 8a61c7d3367e73c48674dc0f760d026201ef5a03. The plan is to support both XAudio2 2.7 and 2.8+. This file will only be used for 2.7, so let's remove the ifdefs and rename the class and vars. --- plugins/spu2-x/src/SndOut.cpp | 2 +- plugins/spu2-x/src/SndOut.h | 2 +- plugins/spu2-x/src/Windows/Config.cpp | 2 +- plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp | 38 +++++++------------ 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/plugins/spu2-x/src/SndOut.cpp b/plugins/spu2-x/src/SndOut.cpp index 34812fc90b..2359db0487 100644 --- a/plugins/spu2-x/src/SndOut.cpp +++ b/plugins/spu2-x/src/SndOut.cpp @@ -87,7 +87,7 @@ SndOutModule* mods[]= { &NullOut, #ifdef _MSC_VER - XAudio2Out, + XAudio2_27_Out, DSoundOut, WaveOut, #endif diff --git a/plugins/spu2-x/src/SndOut.h b/plugins/spu2-x/src/SndOut.h index 520e08572b..561f956dab 100644 --- a/plugins/spu2-x/src/SndOut.h +++ b/plugins/spu2-x/src/SndOut.h @@ -670,7 +670,7 @@ public: //internal extern SndOutModule* WaveOut; extern SndOutModule* DSoundOut; -extern SndOutModule* XAudio2Out; +extern SndOutModule* XAudio2_27_Out; #endif extern SndOutModule* PortaudioOut; #if defined(SPU2X_SDL) || defined(SPU2X_SDL2) diff --git a/plugins/spu2-x/src/Windows/Config.cpp b/plugins/spu2-x/src/Windows/Config.cpp index 02f2b3e84b..fdb2bcdffd 100644 --- a/plugins/spu2-x/src/Windows/Config.cpp +++ b/plugins/spu2-x/src/Windows/Config.cpp @@ -127,7 +127,7 @@ void ReadSettings() // let's use xaudio2 until this is sorted (rama) // CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent()); - CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent()); + CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2_27_Out->GetIdent()); // find the driver index of this module: OutputModule = FindOutputModuleById( omodid ); diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp index 58928eee28..ba39334128 100644 --- a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp +++ b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp @@ -17,7 +17,6 @@ #include "Global.h" -#define _WIN32_DCOM #include "Dialogs.h" #include @@ -25,7 +24,7 @@ namespace Exception { - class XAudio2Error : public std::runtime_error + class XAudio2_27Error : public std::runtime_error { protected: static const char* SomeKindaErrorString( HRESULT hr ) @@ -50,8 +49,8 @@ namespace Exception return m_Message.c_str(); } - virtual ~XAudio2Error() throw() {} - XAudio2Error( const HRESULT result, const std::string& msg ) : + virtual ~XAudio2_27Error() throw() {} + XAudio2_27Error( const HRESULT result, const std::string& msg ) : runtime_error( msg ), ErrorCode( result ), m_Message() @@ -65,7 +64,7 @@ namespace Exception static const double SndOutNormalizer = (double)(1UL<<(SndOutVolumeShift+16)); -class XAudio2Mod: public SndOutModule +class XAudio2_27_Mod: public SndOutModule { private: static const int PacketsPerBuffer = 8; @@ -132,7 +131,7 @@ private: if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC, 1.0f, this ) ) ) { - throw Exception::XAudio2Error( hr, "XAudio2 CreateSourceVoice failure." ); + throw Exception::XAudio2_27Error( hr, "XAudio2 CreateSourceVoice failure." ); } InitializeCriticalSection( &cs ); @@ -232,9 +231,8 @@ private: } }; -#if _WIN32_WINNT < 0x602 + HMODULE xAudio2DLL; -#endif CComPtr pXAudio2; IXAudio2MasteringVoice* pMasteringVoice; BaseStreamingVoice* voiceContext; @@ -246,7 +244,7 @@ public: HRESULT hr; jASSUME( pXAudio2 == NULL ); -#if _WIN32_WINNT < 0x602 + // On some systems XAudio2.7 can unload itself and cause PCSX2 to crash. // Maintain an extra library reference so it can't do so. Does not // affect XAudio 2.8+, but that's Win8+. See @@ -255,7 +253,6 @@ public: xAudio2DLL = LoadLibrary(L"XAudioD2_7.dll"); #else xAudio2DLL = LoadLibrary(L"XAudio2_7.dll"); -#endif #endif // @@ -264,29 +261,26 @@ public: CoInitializeEx( NULL, COINIT_MULTITHREADED ); UINT32 flags = 0; -#if _WIN32_WINNT < 0x602 if( IsDebugBuild ) flags |= XAUDIO2_DEBUG_ENGINE; -#endif try { if ( FAILED(hr = XAudio2Create( &pXAudio2, flags ) ) ) - throw Exception::XAudio2Error( hr, + throw Exception::XAudio2_27Error( hr, "Failed to init XAudio2 engine. XA2 may not be available on your system.\n" "Ensure that you have the latest DirectX runtimes installed, or use \n" "DirectX / WaveOut drivers instead. Error Details:" ); -#if _WIN32_WINNT < 0x602 + XAUDIO2_DEVICE_DETAILS deviceDetails; pXAudio2->GetDeviceDetails( 0, &deviceDetails ); -#endif // 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; + int speakers; switch(numSpeakers) // speakers = (numSpeakers + 1) *2; ? { case 0: speakers = 2; break; // Stereo @@ -296,10 +290,8 @@ public: default: speakers = 2; } -#if _WIN32_WINNT < 0x602 // Any windows driver should support stereo at the software level, I should think! jASSUME( deviceDetails.OutputFormat.Format.nChannels > 1 ); -#endif // // Create a mastering voice @@ -360,7 +352,7 @@ public: voiceContext->Init( pXAudio2 ); } - catch( Exception::XAudio2Error& ex ) + catch( Exception::XAudio2_27Error& ex ) { SysMessage( ex.CMessage() ); pXAudio2.Release(); @@ -394,18 +386,16 @@ public: pXAudio2.Release(); CoUninitialize(); -#if _WIN32_WINNT < 0x602 if (xAudio2DLL) { FreeLibrary(xAudio2DLL); xAudio2DLL = nullptr; } -#endif } virtual void Configure(uptr parent) { } - + s32 Test() const { return 0; @@ -424,7 +414,7 @@ public: const wchar_t* GetLongName() const { - return L"XAudio 2 (Recommended)"; + return L"XAudio 2.7 (Recommended)"; } void ReadSettings() @@ -441,4 +431,4 @@ public: } static XA2; -SndOutModule *XAudio2Out = &XA2; +SndOutModule *XAudio2_27_Out = &XA2; From 5344c3f121aeb694fbc29d032d9df5b579e2a10b Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sun, 28 Feb 2016 16:11:29 +0000 Subject: [PATCH 4/5] spu2-x: Rename SndOut_XAudio2.cpp to SndOut_XAudio2_7.cpp --- .../src/Windows/{SndOut_XAudio2.cpp => SndOut_XAudio2_27.cpp} | 0 plugins/spu2-x/src/Windows/Spu2-X.vcxproj | 2 +- plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename plugins/spu2-x/src/Windows/{SndOut_XAudio2.cpp => SndOut_XAudio2_27.cpp} (100%) diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp b/plugins/spu2-x/src/Windows/SndOut_XAudio2_27.cpp similarity index 100% rename from plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp rename to plugins/spu2-x/src/Windows/SndOut_XAudio2_27.cpp diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj index 27a150b2ef..831269c541 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj @@ -342,7 +342,7 @@ - + $(DXSDK_DIR)include;%(AdditionalIncludeDirectories) diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters index d456189de8..24b060b7a3 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters @@ -144,7 +144,7 @@ Source Files\Sound Output\Windows - + Source Files\Sound Output\Windows From e7745d13f4e9c2696f1b022b96c0d4089a991009 Mon Sep 17 00:00:00 2001 From: Jonathan Li Date: Sun, 28 Feb 2016 21:41:04 +0000 Subject: [PATCH 5/5] spu2-x:windows: Add XAudio2 2.8 backend On Windows Vista and 7, the XAudio2 2.7 backend will still be used. Windows 8, 8.1 and 10 users will use XAudio2 2.8/2.9 (depending on OS). --- plugins/spu2-x/src/PS2E-spu2.cpp | 14 + plugins/spu2-x/src/SndOut.h | 1 + plugins/spu2-x/src/Spu2replay.cpp | 12 + plugins/spu2-x/src/Windows/Config.cpp | 5 +- plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp | 402 ++++++++++++++++++ plugins/spu2-x/src/Windows/Spu2-X.vcxproj | 1 + .../spu2-x/src/Windows/Spu2-X.vcxproj.filters | 3 + 7 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp diff --git a/plugins/spu2-x/src/PS2E-spu2.cpp b/plugins/spu2-x/src/PS2E-spu2.cpp index 10b2006c1b..d7432b1f1e 100644 --- a/plugins/spu2-x/src/PS2E-spu2.cpp +++ b/plugins/spu2-x/src/PS2E-spu2.cpp @@ -160,6 +160,20 @@ EXPORT_C_(s32) SPU2test() { if( !CheckSSE() ) return -1; +#ifdef _WIN32 + if (IsWindows8OrGreater()) + { + for (int n = 0; mods[n] != nullptr; ++n) + { + if (mods[n] == XAudio2_27_Out) + { + mods[n] = XAudio2Out; + break; + } + } + } +#endif + ReadSettings(); if( SndBuffer::Test() != 0 ) { diff --git a/plugins/spu2-x/src/SndOut.h b/plugins/spu2-x/src/SndOut.h index 561f956dab..8cfab252b9 100644 --- a/plugins/spu2-x/src/SndOut.h +++ b/plugins/spu2-x/src/SndOut.h @@ -671,6 +671,7 @@ public: extern SndOutModule* WaveOut; extern SndOutModule* DSoundOut; extern SndOutModule* XAudio2_27_Out; +extern SndOutModule* XAudio2Out; #endif extern SndOutModule* PortaudioOut; #if defined(SPU2X_SDL) || defined(SPU2X_SDL2) diff --git a/plugins/spu2-x/src/Spu2replay.cpp b/plugins/spu2-x/src/Spu2replay.cpp index 5a059e7bcc..2558ab05c8 100644 --- a/plugins/spu2-x/src/Spu2replay.cpp +++ b/plugins/spu2-x/src/Spu2replay.cpp @@ -225,6 +225,18 @@ EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdS conprintf("Playing %s file on %x...",filename,hwnd); + if (IsWindows8OrGreater()) + { + for (int n = 0; mods[n] != nullptr; ++n) + { + if (mods[n] == XAudio2_27_Out) + { + mods[n] = XAudio2Out; + break; + } + } + } + #endif // load file diff --git a/plugins/spu2-x/src/Windows/Config.cpp b/plugins/spu2-x/src/Windows/Config.cpp index fdb2bcdffd..c7d4f2cbd8 100644 --- a/plugins/spu2-x/src/Windows/Config.cpp +++ b/plugins/spu2-x/src/Windows/Config.cpp @@ -127,7 +127,10 @@ void ReadSettings() // let's use xaudio2 until this is sorted (rama) // CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent()); - CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2_27_Out->GetIdent()); + if (IsWindows8OrGreater()) + CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent()); + else + CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2_27_Out->GetIdent()); // find the driver index of this module: OutputModule = FindOutputModuleById( omodid ); diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp new file mode 100644 index 0000000000..523cac20a7 --- /dev/null +++ b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp @@ -0,0 +1,402 @@ +/* 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 "Global.h" + +#include "Dialogs.h" +#include + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#include + +namespace Exception +{ + class XAudio2Error : public std::runtime_error + { + protected: + static const char* SomeKindaErrorString(HRESULT hr) + { + switch (hr) { + case XAUDIO2_E_INVALID_CALL: + return "Invalid call for the XA2 object state."; + + case XAUDIO2_E_DEVICE_INVALIDATED: + return "Device is unavailable, unplugged, unsupported, or has been consumed by The Nothing."; + } + return "Unknown error code!"; + } + + public: + const HRESULT ErrorCode; + std::string m_Message; + + const char* CMessage() const + { + return m_Message.c_str(); + } + + virtual ~XAudio2Error() throw() {} + XAudio2Error(const HRESULT result, const std::string& msg) : + runtime_error(msg), + ErrorCode(result), + m_Message() + { + char omg[1024]; + sprintf_s(omg, "%s (code 0x%x)\n\n%s", what(), ErrorCode, SomeKindaErrorString(ErrorCode)); + m_Message = omg; + } + }; +} + +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; + s16* qbuffer; + + 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() + { + } + + BaseStreamingVoice(uint numChannels) : + m_nBuffers(Config_XAudio2.NumBuffers), + m_nChannels(numChannels), + m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer), + m_BufferSizeBytes(m_BufferSize * sizeof(s16)) + { + } + + 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; + + // + // Create an XAudio2 voice to stream this wave + // + HRESULT hr; + if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, + XAUDIO2_VOICE_NOSRC, 1.0f, this))) { + throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure."); + } + + InitializeCriticalSection(&cs); + EnterCriticalSection(&cs); + + pSourceVoice->FlushSourceBuffers(); + pSourceVoice->Start(0, 0); + + qbuffer = new s16[m_nBuffers * m_BufferSize]; + ZeroMemory(qbuffer, m_BufferSizeBytes * m_nBuffers); + + // Start some buffers. + + for (uint i = 0; i < m_nBuffers; i++) { + XAUDIO2_BUFFER buf = { 0 }; + buf.AudioBytes = m_BufferSizeBytes; + buf.pContext = &qbuffer[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< typename T > + class StreamingVoice : public BaseStreamingVoice + { + public: + StreamingVoice(IXAudio2* pXAudio2) : + BaseStreamingVoice(sizeof(T) / sizeof(s16)) + { + } + + virtual ~StreamingVoice() + { + IXAudio2SourceVoice* killMe = pSourceVoice; + pSourceVoice = NULL; + killMe->FlushSourceBuffers(); + killMe->DestroyVoice(); + + EnterCriticalSection(&cs); + safe_delete_array(qbuffer); + LeaveCriticalSection(&cs); + DeleteCriticalSection(&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. + if (pSourceVoice == NULL || context == NULL) { + 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; + decltype(&XAudio2Create) pXAudio2Create; + CComPtr pXAudio2; + IXAudio2MasteringVoice* pMasteringVoice; + BaseStreamingVoice* voiceContext; + +public: + + s32 Init() + { + HRESULT hr; + + jASSUME(pXAudio2 == NULL); + + 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())); + + // + // Initialize XAudio2 + // + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + try { + 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; + switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ? + { + case 0: speakers = 2; break; // Stereo + case 1: speakers = 4; break; // Quadrafonic + case 2: speakers = 6; break; // Surround 5.1 + case 3: speakers = 8; break; // Surround 7.1 + default: speakers = 2; + } + + // + // Create a mastering voice + // + if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) { + SysMessage("Failed creating mastering voice: %#X\n", hr); + CoUninitialize(); + return -1; + } + + switch (speakers) { + case 2: + ConLog("* SPU2 > Using normal 2 speaker stereo output.\n"); + voiceContext = new StreamingVoice(pXAudio2); + break; + + case 3: + ConLog("* SPU2 > 2.1 speaker expansion enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); + break; + + case 4: + ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n"); + voiceContext = new StreamingVoice(pXAudio2); + break; + + case 5: + ConLog("* SPU2 > 4.1 speaker expansion enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); + break; + + case 6: + case 7: + switch (dplLevel) { + case 0: + ConLog("* SPU2 > 5.1 speaker expansion enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); //"normal" stereo upmix + break; + case 1: + ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); // basic Dpl decoder without rear stereo balancing + break; + case 2: + ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); //gigas PLII + break; + } + break; + + default: // anything 8 or more gets the 7.1 treatment! + ConLog("* SPU2 > 7.1 speaker expansion enabled.\n"); + voiceContext = new StreamingVoice(pXAudio2); + break; + } + + voiceContext->Init(pXAudio2); + } catch (Exception::XAudio2Error& ex) { + SysMessage(ex.CMessage()); + pXAudio2.Release(); + CoUninitialize(); + return -1; + } + + return 0; + } + + void Close() + { + safe_delete(voiceContext); + + voiceContext = NULL; + + if (pMasteringVoice != NULL) + pMasteringVoice->DestroyVoice(); + + pMasteringVoice = NULL; + + pXAudio2.Release(); + CoUninitialize(); + + if (xAudio2DLL) { + FreeLibrary(xAudio2DLL); + xAudio2DLL = nullptr; + pXAudio2Create = nullptr; + } + } + + virtual void Configure(uptr parent) + { + } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() + { + if (voiceContext == NULL) return 0; + return 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 831269c541..3c3a7430b0 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj @@ -342,6 +342,7 @@ + $(DXSDK_DIR)include;%(AdditionalIncludeDirectories) diff --git a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters index 24b060b7a3..3f164873fd 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters +++ b/plugins/spu2-x/src/Windows/Spu2-X.vcxproj.filters @@ -213,6 +213,9 @@ Source Files\Sound Output + + Source Files\Sound Output\Windows +