diff --git a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp index 71d1f6e43..fec4d8c00 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp @@ -493,7 +493,7 @@ xbox::hresult_xt WINAPI EMUPATCH(IDirectSound_SetMixBinHeadroom) xbox::hresult_xt WINAPI EMUPATCH(IDirectSoundBuffer_SetMixBins) ( XbHybridDSBuffer* pHybridThis, - dword_xt dwMixBinMask + X_DSMIXBINBUNION mixBins ); // ****************************************************************** @@ -974,7 +974,7 @@ xbox::hresult_xt WINAPI EMUPATCH(CDirectSoundStream_SetI3DL2Source) xbox::hresult_xt WINAPI EMUPATCH(CDirectSoundStream_SetMixBins) ( X_CDirectSoundStream* pThis, - dword_xt dwMixBinMask + X_DSMIXBINBUNION mixBins ); // s+ @@ -1681,7 +1681,7 @@ xbox::hresult_xt WINAPI EMUPATCH(IDirectSoundStream_SetFrequency) xbox::hresult_xt WINAPI EMUPATCH(IDirectSoundStream_SetMixBins) ( X_CDirectSoundStream* pThis, - dword_xt dwMixBinMask); + X_DSMIXBINBUNION mixBins); // ****************************************************************** // * patch: CDirectSound3DCalculator_Calculate3D diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp index 2bad568d3..2c4ed4f71 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundBuffer.cpp @@ -224,7 +224,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateBuffer) // We have to set DSBufferDesc last due to EmuFlags must be either 0 or previously written value to preserve other flags. GeneratePCMFormat(DSBufferDesc, pdsbd->lpwfxFormat, (DWORD &)pdsbd->dwFlags, pEmuBuffer->EmuFlags, pdsbd->dwBufferBytes, - &pEmuBuffer->X_BufferCache, pEmuBuffer->X_BufferCacheSize, pEmuBuffer->Xb_VoiceProperties, pdsbd->lpMixBinsOutput, + &pEmuBuffer->X_BufferCache, pEmuBuffer->X_BufferCacheSize, pEmuBuffer->Xb_VoiceProperties, pdsbd->mixBinsOutput, pHybridBuffer->p_CDSVoice); pEmuBuffer->EmuBufferDesc = DSBufferDesc; @@ -1182,31 +1182,25 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundBuffer_SetMinDistance) xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundBuffer_SetMixBins) ( XbHybridDSBuffer* pHybridThis, - dword_xt dwMixBinMask) + X_DSMIXBINBUNION mixBins) { DSoundMutexGuardLock; - HRESULT hRet = DS_OK; - X_LPDSMIXBINS pMixBins = reinterpret_cast(dwMixBinMask); if (g_LibVersion_DSOUND < 4039) { LOG_FUNC_BEGIN LOG_FUNC_ARG(pHybridThis) - LOG_FUNC_ARG(dwMixBinMask) + LOG_FUNC_ARG(mixBins.dwMixBinMask) LOG_FUNC_END; - - LOG_UNIMPLEMENTED(); } else { LOG_FUNC_BEGIN LOG_FUNC_ARG(pHybridThis) - LOG_FUNC_ARG(pMixBins) + LOG_FUNC_ARG(mixBins.pMixBins) LOG_FUNC_END; - - EmuDirectSoundBuffer* pThis = pHybridThis->emuDSBuffer; - hRet = HybridDirectSoundBuffer_SetMixBins(pThis->Xb_VoiceProperties, pMixBins, pThis->EmuBufferDesc); } - return hRet; + EmuDirectSoundBuffer* pThis = pHybridThis->emuDSBuffer; + return HybridDirectSoundBuffer_SetMixBins(pThis->Xb_VoiceProperties, mixBins, pThis->EmuBufferDesc); } // ****************************************************************** @@ -1227,12 +1221,11 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundBuffer_SetMixBinVolumes_12) LOG_FUNC_ARG(alVolumes) LOG_FUNC_END; - // NOTE: Use this function for XDK 3911 only because the implementation was changed - // somewhere around the December 2001 (4134) update (or earlier, maybe). + EmuDirectSoundBuffer* pThis = pHybridThis->emuDSBuffer; + HRESULT hRet = HybridDirectSoundBuffer_SetMixBinVolumes_12(pThis->EmuDirectSoundBuffer8, dwMixBinMask, alVolumes, pThis->Xb_VoiceProperties, + pThis->EmuFlags, pThis->Xb_VolumeMixbin, pHybridThis->p_CDSVoice); - LOG_UNIMPLEMENTED(); - - return DS_OK; + return hRet; } // ****************************************************************** diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp index 00428662a..ad8e2be47 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp @@ -134,22 +134,25 @@ static inline void InitVoiceProperties(xbox::X_DSVOICEPROPS& Xb_VoiceProperties) static inline void GenerateMixBinDefault( xbox::X_DSVOICEPROPS &Xb_VoiceProperties, ::LPCWAVEFORMATEX lpwfxFormat, - xbox::X_LPDSMIXBINS mixbins_output, + xbox::X_DSMIXBINBUNION mixbins_output, bool is3D) { + std::unique_ptr convertedMixBins; + if (g_LibVersion_DSOUND < 4039) { - // Do not apply any update since below 4039 doesn't provide access to get properties. - return; + // Convert old style mixbin to a new style mixbin + convertedMixBins = std::make_unique(mixbins_output.dwMixBinMask, nullptr); + mixbins_output.pMixBins = convertedMixBins->GetMixBins(); } auto& xb_mixbinArray = Xb_VoiceProperties.MixBinVolumePairs; unsigned int i; // Use custom mixbin if provided. - if (mixbins_output != xbox::zeroptr) { + if (mixbins_output.pMixBins != xbox::zeroptr) { - Xb_VoiceProperties.dwMixBinCount = mixbins_output->dwCount; - auto& mixbinArray_output = mixbins_output->lpMixBinVolumePairs; + Xb_VoiceProperties.dwMixBinCount = mixbins_output.pMixBins->dwCount; + auto& mixbinArray_output = mixbins_output.pMixBins->lpMixBinVolumePairs; for (i = 0; i < Xb_VoiceProperties.dwMixBinCount; i++) { xb_mixbinArray[i].dwMixBin = mixbinArray_output[i].dwMixBin; @@ -254,7 +257,7 @@ static inline void GeneratePCMFormat( LPVOID* X_BufferCache, DWORD &X_BufferCacheSize, xbox::X_DSVOICEPROPS& Xb_VoiceProperties, - xbox::X_LPDSMIXBINS mixbins_output, + xbox::X_DSMIXBINBUNION mixbins_output, xbox::CDirectSoundVoice* Xb_Voice) { bool bIsSpecial = false; @@ -1124,13 +1127,16 @@ static inline HRESULT HybridDirectSoundBuffer_SetFormat( { pDSBuffer->Stop(); + xbox::X_DSMIXBINBUNION mixBins; + mixBins.pMixBins = mixbins_output; + if (X_BufferAllocate) { GeneratePCMFormat(BufferDesc, Xb_pwfxFormat, Xb_flags, dwEmuFlags, X_BufferCacheSize, - xbox::zeroptr, X_BufferCacheSize, Xb_VoiceProperties, mixbins_output, Xb_Voice); + xbox::zeroptr, X_BufferCacheSize, Xb_VoiceProperties, mixBins, Xb_Voice); // Don't allocate for DS Stream class, it is using straight from the source. } else { GeneratePCMFormat(BufferDesc, Xb_pwfxFormat, Xb_flags, dwEmuFlags, 0, - xbox::zeroptr, X_BufferCacheSize, Xb_VoiceProperties, mixbins_output, Xb_Voice); + xbox::zeroptr, X_BufferCacheSize, Xb_VoiceProperties, mixBins, Xb_Voice); } HRESULT hRet = DS_OK; if ((void*)g_pDSoundPrimaryBuffer == (void*)pDSBuffer) { @@ -1260,13 +1266,13 @@ static inline HRESULT HybridDirectSound3DBuffer_SetMinDistance( //IDirectSoundBuffer static inline HRESULT HybridDirectSoundBuffer_SetMixBins( xbox::X_DSVOICEPROPS& Xb_VoiceProperties, - xbox::X_LPDSMIXBINS in_MixBins, + xbox::X_DSMIXBINBUNION mixBins, DSBUFFERDESC& BufferDesc ) { HRESULT ret = DS_OK; - GenerateMixBinDefault(Xb_VoiceProperties, BufferDesc.lpwfxFormat, in_MixBins, ((BufferDesc.dwFlags & DSBCAPS_CTRL3D) > 0)); + GenerateMixBinDefault(Xb_VoiceProperties, BufferDesc.lpwfxFormat, mixBins, ((BufferDesc.dwFlags & DSBCAPS_CTRL3D) > 0)); return ret; } @@ -1275,7 +1281,7 @@ static inline HRESULT HybridDirectSoundBuffer_SetMixBins( //IDirectSoundBuffer x2 static inline HRESULT HybridDirectSoundBuffer_SetMixBinVolumes_8( LPDIRECTSOUNDBUFFER8 pDSBuffer, - xbox::X_LPDSMIXBINS pMixBins, + xbox::X_LPDSMIXBINS pMixBins, xbox::X_DSVOICEPROPS& Xb_VoiceProperties, DWORD EmuFlags, LONG &Xb_volumeMixBin, @@ -1291,7 +1297,7 @@ static inline HRESULT HybridDirectSoundBuffer_SetMixBinVolumes_8( for (DWORD i = 0; i < count; i++) { // Update the mixbin volume only, do not reassign volume pair array. for (DWORD i = 0; i < count; i++) { - auto& it_in = pMixBins->lpMixBinVolumePairs[i]; + const auto& it_in = pMixBins->lpMixBinVolumePairs[i]; for (DWORD ii = 0; ii < Xb_VoiceProperties.dwMixBinCount; ii++) { auto& it_internal = Xb_VoiceProperties.MixBinVolumePairs[ii]; @@ -1319,7 +1325,7 @@ static inline HRESULT HybridDirectSoundBuffer_SetMixBinVolumes_8( } if (counter > 0) { Xb_volumeMixBin = volume / (LONG)counter; - int32_t Xb_volume = Xb_Voice->GetVolume(); + int32_t Xb_volume = Xb_Voice->GetVolume() + Xb_Voice->GetHeadroom(); hRet = HybridDirectSoundBuffer_SetVolume(pDSBuffer, Xb_volume, EmuFlags, Xb_volumeMixBin, Xb_Voice); } else { @@ -1331,6 +1337,23 @@ static inline HRESULT HybridDirectSoundBuffer_SetMixBinVolumes_8( return hRet; } + +//IDirectSoundStream x2 +//IDirectSoundBuffer x2 +static inline HRESULT HybridDirectSoundBuffer_SetMixBinVolumes_12( + LPDIRECTSOUNDBUFFER8 pDSBuffer, + xbox::dword_xt dwMixBinMask, + const xbox::long_xt* alVolumes, + xbox::X_DSVOICEPROPS& Xb_VoiceProperties, + DWORD EmuFlags, + LONG &Xb_volumeMixBin, + xbox::CDirectSoundVoice* Xb_Voice) +{ + // Convert volumes/mask to xbox::X_DSMIXBINS and call the newer version of the function to keep implementations consistent + xbox::DSOUND::CMixBinConverter convertedMixBins(dwMixBinMask, alVolumes); + return HybridDirectSoundBuffer_SetMixBinVolumes_8(pDSBuffer, convertedMixBins.GetMixBins(), Xb_VoiceProperties, EmuFlags, Xb_volumeMixBin, Xb_Voice); +} + //IDirectSoundStream //IDirectSoundBuffer static inline HRESULT HybridDirectSound3DBuffer_SetMode( diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index 4734e0793..497904bef 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -233,7 +233,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(DirectSoundCreateStream) // We have to set DSBufferDesc last due to EmuFlags must be either 0 or previously written value to preserve other flags. GeneratePCMFormat(DSBufferDesc, pdssd->lpwfxFormat, (DWORD &)pdssd->dwFlags, (*ppStream)->EmuFlags, 0, - xbox::zeroptr, (*ppStream)->X_BufferCacheSize, (*ppStream)->Xb_VoiceProperties, pdssd->lpMixBinsOutput, + xbox::zeroptr, (*ppStream)->X_BufferCacheSize, (*ppStream)->Xb_VoiceProperties, pdssd->mixBinsOutput, &(*ppStream)->Xb_Voice); // Test case: Star Wars: KotOR has one packet greater than 5 seconds worth. Increasing to 10 seconds allow stream to work until @@ -1105,31 +1105,24 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_SetMinDistance) xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_SetMixBins) ( X_CDirectSoundStream* pThis, - dword_xt dwMixBinMask) // Also can be X_LPDSMIXBINS (4039+) + X_DSMIXBINBUNION mixBins) // Can be dword_xt (up to 4039) or X_LPDSMIXBINS (4039+) { DSoundMutexGuardLock; - HRESULT hRet = DS_OK; - X_LPDSMIXBINS pMixBins = reinterpret_cast(dwMixBinMask); if (g_LibVersion_DSOUND < 4039) { LOG_FUNC_BEGIN LOG_FUNC_ARG(pThis) - LOG_FUNC_ARG(dwMixBinMask) + LOG_FUNC_ARG(mixBins.dwMixBinMask) LOG_FUNC_END; - - LOG_UNIMPLEMENTED(); } else { LOG_FUNC_BEGIN LOG_FUNC_ARG(pThis) - LOG_FUNC_ARG(pMixBins) + LOG_FUNC_ARG(mixBins.pMixBins) LOG_FUNC_END; - - hRet = HybridDirectSoundBuffer_SetMixBins(pThis->Xb_VoiceProperties, pMixBins, pThis->EmuBufferDesc); } - - return hRet; + return HybridDirectSoundBuffer_SetMixBins(pThis->Xb_VoiceProperties, mixBins, pThis->EmuBufferDesc); } // ****************************************************************** @@ -1138,13 +1131,13 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_SetMixBins) xbox::hresult_xt WINAPI xbox::EMUPATCH(IDirectSoundStream_SetMixBins) ( X_CDirectSoundStream* pThis, - dword_xt dwMixBinMask) // Also can be X_LPDSMIXBINS (4039+) + X_DSMIXBINBUNION mixBins) // Can be dword_xt (up to 4039) or X_LPDSMIXBINS (4039+) { DSoundMutexGuardLock; LOG_FORWARD("CDirectSoundStream_SetMixBins"); - return xbox::EMUPATCH(CDirectSoundStream_SetMixBins)(pThis, dwMixBinMask); + return xbox::EMUPATCH(CDirectSoundStream_SetMixBins)(pThis, mixBins); } // ****************************************************************** @@ -1187,12 +1180,10 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_SetMixBinVolumes_12) LOG_FUNC_ARG(alVolumes) LOG_FUNC_END; - // NOTE: Use this function for XDK 3911 only because the implementation was changed - // somewhere around the March 2002 (4361) update (or earlier, maybe). + HRESULT hRet = HybridDirectSoundBuffer_SetMixBinVolumes_12(pThis->EmuDirectSoundBuffer8, dwMixBinMask, alVolumes, pThis->Xb_VoiceProperties, + pThis->EmuFlags, pThis->Xb_VolumeMixbin, &pThis->Xb_Voice); - LOG_UNIMPLEMENTED(); - - return S_OK; + return hRet; } // ****************************************************************** diff --git a/src/core/hle/DSOUND/XbDSoundFuncs.hpp b/src/core/hle/DSOUND/XbDSoundFuncs.hpp index 0a07427e7..c74e6313b 100644 --- a/src/core/hle/DSOUND/XbDSoundFuncs.hpp +++ b/src/core/hle/DSOUND/XbDSoundFuncs.hpp @@ -38,5 +38,35 @@ namespace xbox { return 2; // Default to stereo channel } + // A helper class, converting old (pre-XDK 4039) mixbin format to the new (XDK 4039 and newer) format + class CMixBinConverter + { + public: + CMixBinConverter(xbox::dword_xt dwMixBinMask, const xbox::long_xt* alVolumes) { + + if (dwMixBinMask != 0) { + for (unsigned int i = 0; i < 32; i++) { + if ((dwMixBinMask & (1 << i)) != 0) { + xbox::X_DSMIXBINVOLUMEPAIR pair { i, alVolumes != nullptr ? *alVolumes++ : 0 }; + m_volumePairs.emplace_back(pair); + } + } + + m_mixBins.dwCount = static_cast(m_volumePairs.size()); + m_mixBins.lpMixBinVolumePairs = m_volumePairs.data(); + } + else { + m_mixBins.dwCount = 0; + m_mixBins.lpMixBinVolumePairs = nullptr; + } + } + + xbox::X_LPDSMIXBINS GetMixBins() { return m_mixBins.dwCount != 0 ? &m_mixBins : nullptr; } + + private: + std::vector m_volumePairs; + xbox::X_DSMIXBINS m_mixBins; + }; + } } diff --git a/src/core/hle/DSOUND/XbDSoundLogging.cpp b/src/core/hle/DSOUND/XbDSoundLogging.cpp index ce0e5818f..437049a72 100644 --- a/src/core/hle/DSOUND/XbDSoundLogging.cpp +++ b/src/core/hle/DSOUND/XbDSoundLogging.cpp @@ -358,7 +358,7 @@ LOGRENDER(X_DSBUFFERDESC) LOGRENDER_MEMBER_TYPE(DSBCAPS_FLAG, dwFlags) LOGRENDER_MEMBER(dwBufferBytes) LOGRENDER_MEMBER_TYPE(LPWAVEFORMATEX, lpwfxFormat) - LOGRENDER_MEMBER_TYPE(DWORD, lpMixBinsOutput) + LOGRENDER_MEMBER(mixBinsOutput.dwMixBinMask) LOGRENDER_MEMBER(dwInputMixBin) ; } @@ -368,7 +368,7 @@ LOGRENDER(X_DSBUFFERDESC) LOGRENDER_MEMBER_TYPE(DSBCAPS_FLAG, dwFlags) LOGRENDER_MEMBER(dwBufferBytes) LOGRENDER_MEMBER_TYPE(LPWAVEFORMATEX, lpwfxFormat) - LOGRENDER_MEMBER(lpMixBinsOutput) + LOGRENDER_MEMBER(mixBinsOutput.pMixBins) LOGRENDER_MEMBER(dwInputMixBin) ; } @@ -384,7 +384,7 @@ LOGRENDER(X_DSSTREAMDESC) LOGRENDER_MEMBER_TYPE(LPWAVEFORMATEX, lpwfxFormat) LOGRENDER_MEMBER_TYPE(void*, lpfnCallback) LOGRENDER_MEMBER(lpvContext) - LOGRENDER_MEMBER_TYPE(DWORD, lpMixBinsOutput) + LOGRENDER_MEMBER(mixBinsOutput.dwMixBinMask) ; } else { @@ -394,7 +394,7 @@ LOGRENDER(X_DSSTREAMDESC) LOGRENDER_MEMBER_TYPE(LPWAVEFORMATEX, lpwfxFormat) LOGRENDER_MEMBER_TYPE(void*, lpfnCallback) LOGRENDER_MEMBER(lpvContext) - LOGRENDER_MEMBER(lpMixBinsOutput) + LOGRENDER_MEMBER(mixBinsOutput.pMixBins) ; } } diff --git a/src/core/hle/DSOUND/XbDSoundTypes.h b/src/core/hle/DSOUND/XbDSoundTypes.h index 4760e451b..fb6ca44c2 100644 --- a/src/core/hle/DSOUND/XbDSoundTypes.h +++ b/src/core/hle/DSOUND/XbDSoundTypes.h @@ -85,6 +85,12 @@ typedef struct _XDSMIXBINS { X_LPDSMIXBINVOLUMEPAIR lpMixBinVolumePairs; } X_DSMIXBINS, *X_LPDSMIXBINS; +// A convenience union combining Revision 1 (3911-4034) and Revision 2 (4039+) mixbin function parameters +union X_DSMIXBINBUNION { + dword_xt dwMixBinMask; + X_LPDSMIXBINS pMixBins; +}; + // EmuIDirectSoundBuffer_Play flags #define X_DSBPLAY_LOOPING 0x00000001 #define X_DSBPLAY_FROMSTART 0x00000002 @@ -149,7 +155,7 @@ struct X_DSBUFFERDESC dword_xt dwFlags; dword_xt dwBufferBytes; LPWAVEFORMATEX lpwfxFormat; - X_LPDSMIXBINS lpMixBinsOutput; + X_DSMIXBINBUNION mixBinsOutput; dword_xt dwInputMixBin; }; @@ -190,7 +196,7 @@ struct X_DSSTREAMDESC LPWAVEFORMATEX lpwfxFormat; LPFNXMOCALLBACK lpfnCallback; LPVOID lpvContext; - X_LPDSMIXBINS lpMixBinsOutput; + X_DSMIXBINBUNION mixBinsOutput; }; // ****************************************************************** diff --git a/src/core/hle/DSOUND/common/XbInternalDSVoice.cpp b/src/core/hle/DSOUND/common/XbInternalDSVoice.cpp index 7acccc814..0515f3aa0 100644 --- a/src/core/hle/DSOUND/common/XbInternalDSVoice.cpp +++ b/src/core/hle/DSOUND/common/XbInternalDSVoice.cpp @@ -117,7 +117,7 @@ uint32_t GetVolume(T& settings) // Interface for set volume template -void SetVolume(T& settings, uint32_t volume) +void SetVolume(T& settings, int32_t volume) { settings.volume = volume - settings.headroom; } @@ -133,7 +133,7 @@ uint32_t GetHeadroom(T& settings) template void SetHeadroom(T& settings, uint32_t set_headroom) { - settings.volume = settings.volume - set_headroom - settings.headroom; + settings.volume = settings.volume + settings.headroom - set_headroom; settings.headroom = set_headroom; }