dsound: fix stream class to match hardware with latest sampling log

This commit is contained in:
RadWolfie 2020-11-20 08:34:53 -06:00
parent 471f3894cc
commit ee9612e263
4 changed files with 55 additions and 57 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 {