From ee9612e263cf9df8c39214dcd1e52a31b298de6f Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 20 Nov 2020 08:34:53 -0600 Subject: [PATCH 1/8] dsound: fix stream class to match hardware with latest sampling log --- .../DirectSound/DSStream_PacketManager.cpp | 29 ++++----- .../hle/DSOUND/DirectSound/DirectSound.hpp | 7 ++- .../DSOUND/DirectSound/DirectSoundInline.hpp | 15 +++-- .../DSOUND/DirectSound/DirectSoundStream.cpp | 61 +++++++++---------- 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp index 187760c7d..cd49593c6 100644 --- a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp +++ b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp @@ -75,13 +75,6 @@ void DSStream_Packet_Clear( free(buffer->pBuffer_data); - // Peform release only, don't trigger any events below. - if (status == XMP_STATUS_RELEASE_CXBXR) { - DSoundSGEMemDealloc(buffer->xmp_data.dwMaxSize); - buffer = pThis->Host_BufferPacketArray.erase(buffer); - return; - } - if (buffer->xmp_data.pdwStatus != xbox::zeroptr) { (*buffer->xmp_data.pdwStatus) = status; } @@ -218,6 +211,16 @@ bool DSStream_Packet_Process( return 0; } + // Do not allow to process when the voice is not activated. + if ((pThis->EmuFlags & DSE_FLAG_PAUSENOACTIVATE) != 0 && + (pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) == 0) { + return 0; + } + + if (!(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) { + pThis->EmuFlags |= DSE_FLAG_IS_ACTIVATED; + } + // If title want to pause, then don't process the packets. // If media object is being used as playback synch, then don't process the packets. if ((pThis->EmuFlags & DSE_FLAG_PAUSE) > 0 || @@ -228,16 +231,6 @@ bool DSStream_Packet_Process( return 0; } - if ((pThis->Xb_Status & X_DSSSTATUS_PAUSED) > 0) { - pThis->Xb_Status &= ~X_DSSSTATUS_PAUSED; - } - - if (pThis->Host_isProcessing == false) { - if (!(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) { - pThis->EmuFlags |= DSE_FLAG_IS_ACTIVATED; - } - } - DWORD dwAudioBytes; HRESULT hRet = pThis->EmuDirectSoundBuffer8->GetStatus(&dwAudioBytes); if (hRet == DS_OK) { @@ -372,7 +365,7 @@ bool DSStream_Packet_Flush( } // Clear flags and set status to zero. DSStream_Packet_FlushEx_Reset(pThis); - pThis->EmuFlags &= ~DSE_FLAG_PAUSE; + pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED); pThis->Xb_Status = 0; return false; } diff --git a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp index f65a65d49..207e166ad 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp @@ -133,9 +133,10 @@ struct SharedDSBuffer : DSBUFFER_S { #define DSE_FLAG_PCM_UNKNOWN (1 << 2) #define DSE_FLAG_SYNCHPLAYBACK_CONTROL (1 << 10) #define DSE_FLAG_PAUSE (1 << 11) -#define DSE_FLAG_FLUSH_ASYNC (1 << 12) -#define DSE_FLAG_ENVELOPE (1 << 13) -#define DSE_FLAG_ENVELOPE2 (1 << 14) // NOTE: This flag is a requirement for GetStatus to return X_DSSSTATUS_ENVELOPECOMPLETE value. +#define DSE_FLAG_PAUSENOACTIVATE (1 << 12) +#define DSE_FLAG_FLUSH_ASYNC (1 << 13) +#define DSE_FLAG_ENVELOPE (1 << 14) +#define DSE_FLAG_ENVELOPE2 (1 << 15) // NOTE: This flag is a requirement for GetStatus to return X_DSSSTATUS_ENVELOPECOMPLETE value. #define DSE_FLAG_RECIEVEDATA (1 << 20) #define DSE_FLAG_IS_ACTIVATED (1 << 21) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag. #define DSE_FLAG_DEBUG_MUTE (1 << 30) // Cxbx-R debugging usage only diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp index c8cd34af9..bd215786f 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp @@ -849,14 +849,16 @@ static inline HRESULT HybridDirectSoundBuffer_Pause( pDSBuffer->Play(0, 0, dwEmuPlayFlags); } DSoundBufferSynchPlaybackFlagRemove(dwEmuFlags); - dwEmuFlags &= ~DSE_FLAG_PAUSE; + dwEmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE); Xb_rtTimeStamp = 0; break; case X_DSSPAUSE_PAUSE: pDSBuffer->Stop(); DSoundBufferSynchPlaybackFlagRemove(dwEmuFlags); - dwEmuFlags |= DSE_FLAG_PAUSE; - Xb_rtTimeStamp = rtTimeStamp; + if ((dwEmuFlags & DSE_FLAG_PAUSENOACTIVATE) == 0) { + dwEmuFlags |= DSE_FLAG_PAUSE; + Xb_rtTimeStamp = rtTimeStamp; + } break; case X_DSSPAUSE_SYNCHPLAYBACK: //TODO: Test case Rayman 3 - Hoodlum Havoc, Battlestar Galactica, Miami Vice, Star Wars: KotOR, and... ? @@ -867,8 +869,13 @@ static inline HRESULT HybridDirectSoundBuffer_Pause( pDSBuffer->Stop(); } break; - // TODO: NOTE: If stream is playing, it perform same behavior as pause flag. If it is not played, it act as a queue until trigger to play it. + // NOTE: If stream is paused with packets, it will trigger to play. If it is not played, it act as a queue until trigger to play it. case X_DSSPAUSE_PAUSENOACTIVATE: + dwEmuFlags &= ~DSE_FLAG_PAUSE; + if ((dwEmuFlags & DSE_FLAG_IS_ACTIVATED) == 0) { + dwEmuFlags |= DSE_FLAG_PAUSENOACTIVATE; + Xb_rtTimeStamp = rtTimeStamp; + } break; } diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index 2c725e955..7f1faf076 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -133,7 +133,7 @@ void DirectSoundDoWork_Stream(xbox::LARGE_INTEGER& time) // TODO: Do we need this in async thread loop? if (pThis->Xb_rtPauseEx != 0LL && pThis->Xb_rtPauseEx <= time.QuadPart) { pThis->Xb_rtPauseEx = 0LL; - pThis->EmuFlags &= ~DSE_FLAG_PAUSE; + pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE); // Don't call play here, let DSStream_Packet_Process deal with it. } // If has flush async requested then verify time has expired to perform flush process. @@ -191,7 +191,7 @@ xbox::ulong_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Release) } for (auto buffer = pThis->Host_BufferPacketArray.begin(); buffer != pThis->Host_BufferPacketArray.end();) { - DSStream_Packet_Clear(buffer, XMP_STATUS_RELEASE_CXBXR, nullptr, nullptr, pThis); + DSStream_Packet_Clear(buffer, XMP_STATUS_FLUSHED, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis); } if (pThis->EmuBufferDesc.lpwfxFormat != nullptr) { @@ -549,14 +549,16 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_GetStatus__r2) // Convert host to xbox status flag. if (hRet == DS_OK) { - if (pThis->Host_isProcessing && !(dwStatusXbox & X_DSSSTATUS_PAUSED)) { + if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & (DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE)) == 0) { dwStatusXbox |= X_DSSSTATUS_PLAYING; } if (pThis->Host_BufferPacketArray.size() != pThis->X_MaxAttachedPackets) { dwStatusXbox |= X_DSSSTATUS_READY; } - + if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) { + dwStatusXbox |= X_DSSSTATUS_PAUSED; + } } else { dwStatusXbox = 0; hRet = DSERR_GENERIC; @@ -601,13 +603,32 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_GetVoiceProperties) return hRet; } + +xbox::hresult_xt CxbxrImpl_CDirectSoundStream_PauseEx( + xbox::X_CDirectSoundStream* pThis, + xbox::REFERENCE_TIME rtTimestamp, + xbox::dword_xt dwPause) +{ + xbox::hresult_xt hRet = HybridDirectSoundBuffer_Pause(pThis->EmuDirectSoundBuffer8, dwPause, pThis->EmuFlags, pThis->EmuPlayFlags, + pThis->Host_isProcessing, rtTimestamp, pThis->Xb_rtPauseEx); + + if ((pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) { + pThis->Host_isProcessing = false; + } + else if (!pThis->Host_isProcessing) { + DSStream_Packet_Process(pThis); + } + + return hRet; +} + // ****************************************************************** // * patch: CDirectSoundStream_Pause // ****************************************************************** xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Pause) ( X_CDirectSoundStream* pThis, - dword_xt dwPause) + dword_xt dwPause) { DSoundMutexGuardLock; @@ -621,26 +642,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Pause) return xbox::status_success; } - HRESULT hRet = HybridDirectSoundBuffer_Pause(pThis->EmuDirectSoundBuffer8, dwPause, pThis->EmuFlags, pThis->EmuPlayFlags, - pThis->Host_isProcessing, 0LL, pThis->Xb_rtPauseEx); - - if (dwPause == X_DSSPAUSE_PAUSENOACTIVATE) { - if (pThis->Host_BufferPacketArray.size() == 0 && !(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) { - pThis->EmuFlags |= DSE_FLAG_PAUSE; - } - } - - if ((pThis->EmuFlags & DSE_FLAG_PAUSE) > 0) { - pThis->Host_isProcessing = false; - if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) > 0) { - if (pThis->Host_BufferPacketArray.size() != 0) { - pThis->Xb_Status |= X_DSSSTATUS_PAUSED; - } - } - } - else if (!pThis->Host_isProcessing) { - DSStream_Packet_Process(pThis); - } + HRESULT hRet = CxbxrImpl_CDirectSoundStream_PauseEx(pThis, 0LL, dwPause); return hRet; } @@ -652,7 +654,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_PauseEx) ( X_CDirectSoundStream *pThis, REFERENCE_TIME rtTimestamp, - dword_xt dwPause) + dword_xt dwPause) { DSoundMutexGuardLock; @@ -663,10 +665,8 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_PauseEx) LOG_FUNC_END; // This function wasn't part of the XDK until 4721. (Same as IDirectSoundBuffer_PauseEx?) - // TODO: Implement time stamp feature (a thread maybe?) - HRESULT hRet = HybridDirectSoundBuffer_Pause(pThis->EmuDirectSoundBuffer8, dwPause, pThis->EmuFlags, pThis->EmuPlayFlags, - pThis->Host_isProcessing, rtTimestamp, pThis->Xb_rtPauseEx); + HRESULT hRet = CxbxrImpl_CDirectSoundStream_PauseEx(pThis, rtTimestamp, dwPause); return hRet; } @@ -735,9 +735,6 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Process) if ((pThis->Xb_Status & X_DSSSTATUS_STARVED) > 0) { pThis->Xb_Status &= ~X_DSSSTATUS_STARVED; } - if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) > 0 && (pThis->EmuFlags & DSE_FLAG_PAUSE) > 0) { - pThis->Xb_Status |= X_DSSSTATUS_PAUSED; - } DSStream_Packet_Process(pThis); // Once full it needs to change status to flushed when cannot hold any more packets. } else { From 3209bf7be5e25bd80cf95485ca95364c1dd52024 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Mon, 23 Nov 2020 06:33:10 -0600 Subject: [PATCH 2/8] dsound: fix pause flags as enums instead --- .../hle/DSOUND/DirectSound/DirectSoundStream.cpp | 4 ++-- src/core/hle/DSOUND/XbDSoundLogging.cpp | 12 ++++++------ src/core/hle/DSOUND/XbDSoundLogging.hpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index 7f1faf076..e29213467 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -634,7 +634,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Pause) LOG_FUNC_BEGIN LOG_FUNC_ARG(pThis) - LOG_FUNC_ARG(dwPause) + LOG_FUNC_ARG_TYPE(DSSPAUSE_FLAG, dwPause) LOG_FUNC_END; if (!pThis) { @@ -661,7 +661,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_PauseEx) LOG_FUNC_BEGIN LOG_FUNC_ARG(pThis) LOG_FUNC_ARG(rtTimestamp) - LOG_FUNC_ARG(dwPause) + LOG_FUNC_ARG_TYPE(DSSPAUSE_FLAG, dwPause) LOG_FUNC_END; // This function wasn't part of the XDK until 4721. (Same as IDirectSoundBuffer_PauseEx?) diff --git a/src/core/hle/DSOUND/XbDSoundLogging.cpp b/src/core/hle/DSOUND/XbDSoundLogging.cpp index 437049a72..578f62e30 100644 --- a/src/core/hle/DSOUND/XbDSoundLogging.cpp +++ b/src/core/hle/DSOUND/XbDSoundLogging.cpp @@ -118,12 +118,12 @@ FLAGS2STR_START(DSSFLUSHEX_FLAG) FLAG2STR(X_DSSFLUSHEX_ENVELOPE2) FLAGS2STR_END_and_LOGRENDER(DSSFLUSHEX_FLAG) -FLAGS2STR_START(DSSPAUSE_FLAG) - FLAG2STR(X_DSSPAUSE_RESUME) - FLAG2STR(X_DSSPAUSE_PAUSE) - FLAG2STR(X_DSSPAUSE_SYNCHPLAYBACK) - FLAG2STR(X_DSSPAUSE_PAUSENOACTIVATE) -FLAGS2STR_END_and_LOGRENDER(DSSPAUSE_FLAG) +ENUM2STR_START(DSSPAUSE_FLAG) + ENUM2STR_CASE(X_DSSPAUSE_RESUME) + ENUM2STR_CASE(X_DSSPAUSE_PAUSE) + ENUM2STR_CASE(X_DSSPAUSE_SYNCHPLAYBACK) + ENUM2STR_CASE(X_DSSPAUSE_PAUSENOACTIVATE) +ENUM2STR_END_and_LOGRENDER(DSSPAUSE_FLAG) FLAGS2STR_START(DSSSTATUS_FLAG) FLAG2STR(X_DSSSTATUS_READY) diff --git a/src/core/hle/DSOUND/XbDSoundLogging.hpp b/src/core/hle/DSOUND/XbDSoundLogging.hpp index 6b2f7e779..9d99b21ba 100644 --- a/src/core/hle/DSOUND/XbDSoundLogging.hpp +++ b/src/core/hle/DSOUND/XbDSoundLogging.hpp @@ -67,7 +67,7 @@ FLAGS2STR_HEADER(DSBSTOPEX_FLAG) // DSound Stream flag/enum FLAGS2STR_HEADER(DSSCAPS_FLAG) FLAGS2STR_HEADER(DSSFLUSHEX_FLAG) -FLAGS2STR_HEADER(DSSPAUSE_FLAG) +ENUM2STR_HEADER(DSSPAUSE_FLAG) FLAGS2STR_HEADER(DSSSTATUS_FLAG) // DSound class usage From 5031f1aa65d481593523d347a305554e4d2d67b3 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Tue, 24 Nov 2020 16:34:53 -0600 Subject: [PATCH 3/8] dsound: remove unused cxbxr flag from log --- src/core/hle/DSOUND/XbDSoundLogging.cpp | 1 - src/core/hle/DSOUND/XbDSoundTypes.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/core/hle/DSOUND/XbDSoundLogging.cpp b/src/core/hle/DSOUND/XbDSoundLogging.cpp index 578f62e30..916c22afb 100644 --- a/src/core/hle/DSOUND/XbDSoundLogging.cpp +++ b/src/core/hle/DSOUND/XbDSoundLogging.cpp @@ -139,7 +139,6 @@ ENUM2STR_START(XMP_STATUS) ENUM2STR_CASE(XMP_STATUS_PENDING) ENUM2STR_CASE(XMP_STATUS_FLUSHED) ENUM2STR_CASE(XMP_STATUS_FAILURE) - ENUM2STR_CASE((int)XMP_STATUS_RELEASE_CXBXR) // NOTE: Custom status for Cxbx-Reloaded. ENUM2STR_END_and_LOGRENDER(XMP_STATUS) FLAGS2STR_START(XMO_STREAMF) diff --git a/src/core/hle/DSOUND/XbDSoundTypes.h b/src/core/hle/DSOUND/XbDSoundTypes.h index fb6ca44c2..25cb4d7f5 100644 --- a/src/core/hle/DSOUND/XbDSoundTypes.h +++ b/src/core/hle/DSOUND/XbDSoundTypes.h @@ -225,7 +225,6 @@ XMEDIAPACKET, *PXMEDIAPACKET, *LPXMEDIAPACKET; #define XMP_STATUS_PENDING E_PENDING #define XMP_STATUS_FLUSHED E_ABORT #define XMP_STATUS_FAILURE E_FAIL -#define XMP_STATUS_RELEASE_CXBXR 0xFFFFFFFF // ****************************************************************** // * XMEDIAINFO From 3a506df75421e96037773ef5c6ada80615cb64e5 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Tue, 24 Nov 2020 16:37:20 -0600 Subject: [PATCH 4/8] dsound: Add stream's flushex flag type to extend verbose output --- src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index e29213467..4c0b67764 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -412,7 +412,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_FlushEx) LOG_FUNC_BEGIN LOG_FUNC_ARG(pThis) LOG_FUNC_ARG(rtTimeStamp) - LOG_FUNC_ARG(dwFlags) + LOG_FUNC_ARG_TYPE(DSSFLUSHEX_FLAG, dwFlags) LOG_FUNC_END; HRESULT hRet = DSERR_INVALIDPARAM; From 50d21d812770610c76de7fa6d24afd073fd6fdbf Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Mon, 23 Nov 2020 06:55:36 -0600 Subject: [PATCH 5/8] dsound: don't process flush if there's no packets --- .../hle/DSOUND/DirectSound/DSStream_PacketManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp index cd49593c6..61b77f67b 100644 --- a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp +++ b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp @@ -347,6 +347,7 @@ bool DSStream_Packet_Flush( xbox::X_CDirectSoundStream* pThis ) { + // If host's audio is still playing then return busy-state until buffer has stop playing. DWORD dwStatus; pThis->EmuDirectSoundBuffer8->GetStatus(&dwStatus); @@ -365,7 +366,12 @@ bool DSStream_Packet_Flush( } // Clear flags and set status to zero. DSStream_Packet_FlushEx_Reset(pThis); - pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED); pThis->Xb_Status = 0; + + // TESTCASE: Burnout 3 sets stream to pause state then calling SetFormat without processing any packets. + // Which then doesn't need to clear pause flag. + if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) != 0) { + pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED); + } return false; } From f872bb5f8ac3c13e3246c0d1b32d7d0f2e0fb4c2 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Mon, 23 Nov 2020 07:59:23 -0600 Subject: [PATCH 6/8] dsound: replace size to empty function --- .../hle/DSOUND/DirectSound/DSStream_PacketManager.cpp | 8 ++++---- src/core/hle/DSOUND/DirectSound/DirectSound.cpp | 2 +- src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp index 61b77f67b..3cb06070f 100644 --- a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp +++ b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp @@ -156,7 +156,7 @@ static inline void DSStream_Packet_Stop( { DSStream_Packet_Stop_Internal(pThis); - if (pThis->Host_BufferPacketArray.size() == 0) { + if (pThis->Host_BufferPacketArray.empty()) { if ((pThis->EmuFlags & DSE_FLAG_ENVELOPE2) > 0) { pThis->Xb_Status |= X_DSSSTATUS_ENVELOPECOMPLETE; } @@ -207,7 +207,7 @@ bool DSStream_Packet_Process( { // Do not allow to process if there is no packets. - if (pThis->Host_BufferPacketArray.size() == 0) { + if (pThis->Host_BufferPacketArray.empty()) { return 0; } @@ -282,7 +282,7 @@ bool DSStream_Packet_Process( bool isStreamEnd = packetCurrent->isStreamEnd; DSStream_Packet_Clear(packetCurrent, XMP_STATUS_SUCCESS, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis); - if (pThis->Host_BufferPacketArray.size() == 0) { + if (pThis->Host_BufferPacketArray.empty()) { if (isStreamEnd) { DSStream_Packet_Stop(pThis); } @@ -318,7 +318,7 @@ bool DSStream_Packet_Process( DSStream_Packet_Prefill(pThis, packetCurrent); } // Out of packets, let's stop stream's buffer. - if (pThis->Host_BufferPacketArray.size() == 0) { + if (pThis->Host_BufferPacketArray.empty()) { DSStream_Packet_Starved(pThis); return 0; } diff --git a/src/core/hle/DSOUND/DirectSound/DirectSound.cpp b/src/core/hle/DSOUND/DirectSound/DirectSound.cpp index 25de7da9b..7adba12a8 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSound.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSound.cpp @@ -899,7 +899,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSound_SynchPlayback) vector_ds_stream::iterator ppDSStream = g_pDSoundStreamCache.begin(); for (; ppDSStream != g_pDSoundStreamCache.end(); ppDSStream++) { - if ((*ppDSStream)->Host_BufferPacketArray.size() == 0) { + if ((*ppDSStream)->Host_BufferPacketArray.empty()) { continue; } if (((*ppDSStream)->EmuFlags & DSE_FLAG_SYNCHPLAYBACK_CONTROL) > 0) { diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index 4c0b67764..fcf13a303 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -126,7 +126,7 @@ void DirectSoundDoWork_Stream(xbox::LARGE_INTEGER& time) // Actually, DirectSoundStream need to process buffer packets here. vector_ds_stream::iterator ppDSStream = g_pDSoundStreamCache.begin(); for (; ppDSStream != g_pDSoundStreamCache.end(); ppDSStream++) { - if ((*ppDSStream)->Host_BufferPacketArray.size() == 0) { + if ((*ppDSStream)->Host_BufferPacketArray.empty()) { continue; } xbox::X_CDirectSoundStream* pThis = (*ppDSStream); From 07c3f3b0fa5a630c5f3e9108ff9949ad801c6525 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sun, 29 Nov 2020 05:04:48 -0600 Subject: [PATCH 7/8] dsound: fix async flush --- .../DirectSound/DSStream_PacketManager.cpp | 9 +++- .../hle/DSOUND/DirectSound/DirectSound.hpp | 1 + .../DSOUND/DirectSound/DirectSoundStream.cpp | 46 +++++++++++-------- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp index 3cb06070f..a2165dcdd 100644 --- a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp +++ b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp @@ -217,6 +217,10 @@ bool DSStream_Packet_Process( return 0; } + if (pThis->EmuFlags & DSE_FLAG_IS_FLUSHING) { + return 0; + } + if (!(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) { pThis->EmuFlags |= DSE_FLAG_IS_ACTIVATED; } @@ -347,7 +351,9 @@ bool DSStream_Packet_Flush( xbox::X_CDirectSoundStream* pThis ) { - + if ((pThis->EmuFlags & DSE_FLAG_IS_FLUSHING) == 0) { + pThis->EmuFlags |= DSE_FLAG_IS_FLUSHING; + } // If host's audio is still playing then return busy-state until buffer has stop playing. DWORD dwStatus; pThis->EmuDirectSoundBuffer8->GetStatus(&dwStatus); @@ -373,5 +379,6 @@ bool DSStream_Packet_Flush( if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) != 0) { pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED); } + pThis->EmuFlags &= ~DSE_FLAG_IS_FLUSHING; return false; } diff --git a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp index 207e166ad..e87167707 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSound.hpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSound.hpp @@ -139,6 +139,7 @@ struct SharedDSBuffer : DSBUFFER_S { #define DSE_FLAG_ENVELOPE2 (1 << 15) // NOTE: This flag is a requirement for GetStatus to return X_DSSSTATUS_ENVELOPECOMPLETE value. #define DSE_FLAG_RECIEVEDATA (1 << 20) #define DSE_FLAG_IS_ACTIVATED (1 << 21) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag. +#define DSE_FLAG_IS_FLUSHING (1 << 22) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag. #define DSE_FLAG_DEBUG_MUTE (1 << 30) // Cxbx-R debugging usage only #define DSE_FLAG_BUFFER_EXTERNAL (1 << 31) #define DSE_FLAG_AUDIO_CODECS (DSE_FLAG_PCM | DSE_FLAG_XADPCM | DSE_FLAG_PCM_UNKNOWN) diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp index fcf13a303..c6cc99711 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp @@ -380,6 +380,18 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Discontinuity) return DS_OK; } +xbox::hresult_xt CxbxrImpl_CDirectSoundStream_Flush +( + xbox::X_CDirectSoundStream* pThis) +{ + + DSoundBufferSynchPlaybackFlagRemove(pThis->EmuFlags); + + while (DSStream_Packet_Flush(pThis)); + + return DS_OK; +} + // ****************************************************************** // * patch: CDirectSoundStream_Flush // ****************************************************************** @@ -391,11 +403,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Flush) LOG_FUNC_ONE_ARG(pThis); - DSoundBufferSynchPlaybackFlagRemove(pThis->EmuFlags); - - while (DSStream_Packet_Flush(pThis)); - - return DS_OK; + return CxbxrImpl_CDirectSoundStream_Flush(pThis); } // ****************************************************************** @@ -422,22 +430,20 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_FlushEx) // Cannot use rtTimeStamp here, it must be flush. if (dwFlags == X_DSSFLUSHEX_IMMEDIATE) { - hRet = xbox::EMUPATCH(CDirectSoundStream_Flush)(pThis); + hRet = CxbxrImpl_CDirectSoundStream_Flush(pThis); } // Remaining flags require X_DSSFLUSHEX_ASYNC to be include. - else if ((dwFlags & X_DSSFLUSHEX_ASYNC) > 0) { + else if ((dwFlags & X_DSSFLUSHEX_ASYNC) > 0 && !pThis->Host_BufferPacketArray.empty()) { // If rtTimeStamp is zero'd, then call flush once and allow process flush in worker thread. if (rtTimeStamp == 0LL) { - bool isBusy = DSStream_Packet_Flush(pThis); - if (!isBusy) { - // testcase: Obscure will crash after new game's video if not call DSStream_Packet_Flush in same thread. - // If flush is not busy, then we don't need worker thread to continue flushing. - return hRet; - } xbox::LARGE_INTEGER getTime; xbox::KeQuerySystemTime(&getTime); pThis->Xb_rtFlushEx = getTime.QuadPart; + pThis->EmuFlags |= DSE_FLAG_IS_FLUSHING; + // HACK: Need to find a way to remove Flush call without break Obscure. + // Otherwise, it will behave like on hardware. + DSStream_Packet_Flush(pThis); } else { pThis->Xb_rtFlushEx = rtTimeStamp; @@ -549,15 +555,16 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_GetStatus__r2) // Convert host to xbox status flag. if (hRet == DS_OK) { - if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & (DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE)) == 0) { - dwStatusXbox |= X_DSSSTATUS_PLAYING; - - } if (pThis->Host_BufferPacketArray.size() != pThis->X_MaxAttachedPackets) { dwStatusXbox |= X_DSSSTATUS_READY; } - if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) { - dwStatusXbox |= X_DSSSTATUS_PAUSED; + if (!pThis->Host_BufferPacketArray.empty()) { + if ((pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) { + dwStatusXbox |= X_DSSSTATUS_PAUSED; + } + else if ((pThis->EmuFlags & (DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE | DSE_FLAG_IS_FLUSHING)) == 0) { + dwStatusXbox |= X_DSSSTATUS_PLAYING; + } } } else { dwStatusXbox = 0; @@ -735,6 +742,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Process) if ((pThis->Xb_Status & X_DSSSTATUS_STARVED) > 0) { pThis->Xb_Status &= ~X_DSSSTATUS_STARVED; } + pThis->EmuFlags &= ~DSE_FLAG_IS_FLUSHING; DSStream_Packet_Process(pThis); // Once full it needs to change status to flushed when cannot hold any more packets. } else { From e2fcedd1b7515d09eba70061cf8ab7230aada27c Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Tue, 1 Dec 2020 04:59:37 -0600 Subject: [PATCH 8/8] dsound: fix status return when envelope is complete --- .../DirectSound/DSStream_PacketManager.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp index a2165dcdd..f8cc13daf 100644 --- a/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp +++ b/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp @@ -179,6 +179,18 @@ static inline void DSStream_Packet_Starved( ); } +static inline void DSStream_Packet_Complete( + xbox::X_CDirectSoundStream* pThis + ) +{ + if ((pThis->EmuFlags & DSE_FLAG_ENVELOPE2) != 0) { + pThis->Xb_Status = X_DSSSTATUS_ENVELOPECOMPLETE; + } + else { + pThis->Xb_Status = 0; + } +} + // Prefill buffer with at least 1 second worth of buffer. See "nAvgBytesPerSec" below for inspection. static void DSStream_Packet_Prefill( xbox::X_CDirectSoundStream* pThis, @@ -289,6 +301,7 @@ bool DSStream_Packet_Process( if (pThis->Host_BufferPacketArray.empty()) { if (isStreamEnd) { DSStream_Packet_Stop(pThis); + DSStream_Packet_Complete(pThis); } else { DSStream_Packet_Starved(pThis); @@ -342,7 +355,7 @@ void DSStream_Packet_FlushEx_Reset( xbox::X_CDirectSoundStream* pThis ) { - // Remove flags only (This is the only place it will remove other than FlushEx perform set/remove the flags.) + // Remove flags only (This is the only place it will remove beside FlushEx perform re-set the flags.) pThis->EmuFlags &= ~(DSE_FLAG_FLUSH_ASYNC | DSE_FLAG_ENVELOPE | DSE_FLAG_ENVELOPE2); pThis->Xb_rtFlushEx = 0LL; } @@ -371,8 +384,8 @@ bool DSStream_Packet_Flush( DSStream_Packet_Clear(buffer, XMP_STATUS_FLUSHED, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis); } // Clear flags and set status to zero. + DSStream_Packet_Complete(pThis); DSStream_Packet_FlushEx_Reset(pThis); - pThis->Xb_Status = 0; // TESTCASE: Burnout 3 sets stream to pause state then calling SetFormat without processing any packets. // Which then doesn't need to clear pause flag.