Seamless audio is !HERE! for DirectSoundStream only

It is still experimental, need to fix 2nd intros become not playable or
stuck. However Pause and PauseEx function will affect this seamless
audio as well. Still got more to do.
This commit is contained in:
RadWolfie 2018-03-16 17:53:47 -05:00
parent add65ca173
commit 3ed172988d
3 changed files with 56 additions and 77 deletions

View File

@ -457,7 +457,6 @@ VOID WINAPI XTL::EMUPATCH(DirectSoundDoWork)()
LOG_FUNC();
//TODO: This need a lock in each frame. I think it does not wait for each frame.
XTL::X_CDirectSoundBuffer* *pDSBuffer = g_pDSoundBufferCache;
for (int v = 0; v < SOUNDBUFFER_CACHE_SIZE; v++, pDSBuffer++) {
if ((*pDSBuffer) == nullptr || (*pDSBuffer)->X_BufferCache == xbnullptr || (*pDSBuffer)->EmuBufferToggle != X_DSB_TOGGLE_DEFAULT) {
@ -487,7 +486,6 @@ VOID WINAPI XTL::EMUPATCH(DirectSoundDoWork)()
(*pDSBuffer)->EmuLockFlags);
}
//TODO: Find a way to seamlessly play audio between two packets...
// Actually, DirectSoundStream need to process buffer packets here.
XTL::X_CDirectSoundStream* *pDSStream = g_pDSoundStreamCache;
for (int v = 0; v < SOUNDSTREAM_CACHE_SIZE; v++, pDSStream++) {
@ -499,46 +497,19 @@ VOID WINAPI XTL::EMUPATCH(DirectSoundDoWork)()
HRESULT hRet = pThis->EmuDirectSoundBuffer8->GetStatus(&dwAudioBytes);
if (hRet == DS_OK) {
std::vector<host_voice_packet>::iterator buffer = pThis->Host_BufferPacketArray.begin();
//if ((dwAudioBytes & DSBSTATUS_PLAYING) == 0) {
if (pThis->Host_PacketEventHandle == INVALID_HANDLE_VALUE) {
//printf("DEBUG: audio was stop.\n");
if ((dwAudioBytes & DSBSTATUS_PLAYING) == 0) {
useNextBufferPacket:
DSoundBufferWriteToBuffer(pThis->EmuDirectSoundBuffer8, pThis->Host_dwWriteOffsetNext, buffer->pBuffer_data, buffer->size);
LPDIRECTSOUNDBUFFER8 pDSBPacketOld = pThis->EmuDirectSoundBuffer8;
static LPDIRECTSOUND3DBUFFER8 pDS3DBufferDummy = nullptr;
if (pThis->EmuDirectSoundBuffer8Next == nullptr) {
DSoundBufferPrepare(pThis->EmuDirectSoundBuffer8, pThis->EmuBufferDesc, pThis->EmuPlayFlags,
buffer->pBuffer_data, buffer->size);
} else {
pThis->EmuDirectSoundBuffer8 = pThis->EmuDirectSoundBuffer8Next;
pThis->EmuDirectSoundBuffer8Next = nullptr;
pThis->Host_dwWriteOffsetNext += buffer->size;
if (pThis->EmuBufferDesc->dwBufferBytes < pThis->Host_dwWriteOffsetNext) {
pThis->Host_dwWriteOffsetNext -= pThis->EmuBufferDesc->dwBufferBytes;
}
DSoundBufferTransferSettings(pDSBPacketOld, pThis->EmuDirectSoundBuffer8, pDS3DBufferDummy, pDS3DBufferDummy);
if (pThis->Host_PacketEventHandle == INVALID_HANDLE_VALUE) {
pThis->Host_PacketEventHandle = CreateEvent(nullptr, false, false, nullptr);
pThis->Host_NotifyPosition.hEventNotify = pThis->Host_PacketEventHandle;
if ((dwAudioBytes & DSBSTATUS_PLAYING) == 0) {
pThis->EmuDirectSoundBuffer8->Play(0, 0, DSBPLAY_LOOPING);
}
float fSize = (float)buffer->size;
float fNAvgBytesPerSec = (float)pThis->EmuBufferDesc->lpwfxFormat->nAvgBytesPerSec;
float fNSamplesPerSec = (float)pThis->EmuBufferDesc->lpwfxFormat->nSamplesPerSec;
float fWBitsPerSample = (float)pThis->EmuBufferDesc->lpwfxFormat->wBitsPerSample;
// TODO: Find out if we can use Notification accurate enough to trigger (or is it both notification and get current position not accurate?).
//printf("decimal test = %d\n", DWORD(fSize - ((fSize / fNAvgBytesPerSec) * (fNSamplesPerSec / fWBitsPerSample))));
pThis->Host_NotifyPosition.dwOffset = DWORD(fSize - (((fSize / fNAvgBytesPerSec) * (fNSamplesPerSec / fWBitsPerSample)) * pThis->EmuBufferDesc->lpwfxFormat->nChannels));
pThis->Host_NotifyPosition.hEventNotify = pThis->Host_PacketEventHandle;
LPDIRECTSOUNDNOTIFY8 pDSBNotify8;
pThis->EmuDirectSoundBuffer8->QueryInterface(IID_IDirectSoundNotify8, (PVOID*)&pDSBNotify8);
pDSBNotify8->SetNotificationPositions(1, &pThis->Host_NotifyPosition);
pDSBNotify8->Release();
pThis->EmuDirectSoundBuffer8->SetCurrentPosition(0);
pThis->EmuDirectSoundBuffer8->Play(0, 0, 0);
pDSBPacketOld->Release();
free(buffer->pBuffer_data);
if (buffer->pdwStatus != xbnullptr) {
@ -547,21 +518,36 @@ VOID WINAPI XTL::EMUPATCH(DirectSoundDoWork)()
pThis->Host_BufferPacketArray.erase(buffer);
} else {
// Prepare next packet data to be played.
if (pThis->EmuDirectSoundBuffer8Next == nullptr) {
if (pThis->Host_BufferPacketArray.size() == 0) {
continue;
}
DSoundBufferPrepare(pThis->EmuDirectSoundBuffer8Next, pThis->EmuBufferDesc, pThis->EmuPlayFlags,
buffer->pBuffer_data, buffer->size);
if (pThis->Host_BufferPacketArray.size() == 0) {
continue;
}
hRet = WaitForSingleObject(pThis->Host_PacketEventHandle, 0);
if (hRet == 0) {
//printf("DEBUG: Notification found, playing next packet\n");
CloseHandle(pThis->Host_PacketEventHandle);
pThis->Host_PacketEventHandle = INVALID_HANDLE_VALUE;
goto useNextBufferPacket;
DWORD writePos, playPos;
hRet = pThis->EmuDirectSoundBuffer8->GetCurrentPosition(&playPos, &writePos);
if (hRet == DS_OK) {
static DWORD triggerRange = pThis->EmuBufferDesc->lpwfxFormat->nSamplesPerSec / pThis->EmuBufferDesc->lpwfxFormat->wBitsPerSample;
DWORD rangeStart = pThis->Host_dwWriteOffsetNext - triggerRange * 2;
DWORD rangeEnd = pThis->Host_dwWriteOffsetNext;
// Within range check
if (writePos <= pThis->Host_dwWriteOffsetNext) {
if (rangeStart > INT_MAX) {
rangeStart = 0;
}
if (writePos >= rangeStart && writePos <= rangeEnd) {
goto useNextBufferPacket;
}
// Outside range check
} else {
if (rangeStart > INT_MAX) {
rangeStart = pThis->EmuBufferDesc->dwBufferBytes - DWORD((int)rangeStart * -1);
}
if ((writePos >= rangeStart && writePos <= pThis->EmuBufferDesc->dwBufferBytes) || (writePos >= 0 && writePos <= rangeEnd)) {
goto useNextBufferPacket;
}
}
}
/* // For debug real time info.
DWORD playPos, writePos;
@ -1744,15 +1730,18 @@ HRESULT WINAPI XTL::EMUPATCH(DirectSoundCreateStream)
}
pDSBufferDesc->dwSize = sizeof(DSBUFFERDESC);
//pDSBufferDesc->dwFlags = (pdssd->dwFlags & dwAcceptableMask) | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2;
pDSBufferDesc->dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2; //aka DSBCAPS_DEFAULT
pDSBufferDesc->dwBufferBytes = DSBSIZE_MIN;
pDSBufferDesc->dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GETCURRENTPOSITION2; //aka DSBCAPS_DEFAULT + control position
pDSBufferDesc->lpwfxFormat = nullptr;
GeneratePCMFormat(pDSBufferDesc, pdssd->lpwfxFormat, dwEmuFlags);
// Allocate at least 1 second worth of bytes in PCM format.
pDSBufferDesc->dwBufferBytes = pDSBufferDesc->lpwfxFormat->nAvgBytesPerSec;
(*ppStream)->X_MaxAttachedPackets = pdssd->dwMaxAttachedPackets;
(*ppStream)->Host_BufferPacketArray.reserve(pdssd->dwMaxAttachedPackets);
(*ppStream)->EmuDirectSoundBuffer8Next = nullptr;
(*ppStream)->Host_PacketEventHandle = INVALID_HANDLE_VALUE;
(*ppStream)->EmuPlayFlags = DSBPLAY_LOOPING;
(*ppStream)->Host_dwWriteOffsetNext = 0;
DSoundBufferSetDefault((*ppStream), pDSBufferDesc, dwEmuFlags, 0);

View File

@ -463,9 +463,7 @@ class X_CDirectSoundStream
DWORD X_BufferCacheSize; // Not really needed...
DWORD X_MaxAttachedPackets;
std::vector<struct host_voice_packet> Host_BufferPacketArray;
LPDIRECTSOUNDBUFFER8 EmuDirectSoundBuffer8Next;
HANDLE Host_PacketEventHandle;
DSBPOSITIONNOTIFY Host_NotifyPosition;
DWORD Host_dwWriteOffsetNext;
};
// ******************************************************************

View File

@ -575,34 +575,26 @@ inline void ResizeIDirectSoundBuffer(
DSoundBufferReplace(pDSBuffer, pDSBufferDesc, PlayFlags, pDS3DBuffer);
}
inline void DSoundBufferPrepare(
inline void DSoundBufferWriteToBuffer(
LPDIRECTSOUNDBUFFER8 &pDSBuffer,
LPDSBUFFERDESC pDSBufferDesc,
DWORD dwPlayFlags,
DWORD dwOffset,
PVOID pBufferData,
DWORD dwBufferSize) {
LPVOID pAudioPtr, pAudioPtr2;
DWORD dwAudioBytes, dwAudioBytes2;
DWORD dwTempHolder = pDSBufferDesc->dwBufferBytes;
DSoundBufferCreate(pDSBufferDesc, pDSBuffer);
LPDIRECTSOUND3DBUFFER8 pDummy3DBuffer = nullptr;
ResizeIDirectSoundBuffer(pDSBuffer, pDSBufferDesc,
dwPlayFlags, dwBufferSize, pDummy3DBuffer);
PVOID pAudioPtr;
DWORD dwAudioBytes;
HRESULT hRet = pDSBuffer->Lock(0, 0, &pAudioPtr, &dwAudioBytes,
nullptr, nullptr, DSBLOCK_ENTIREBUFFER);
HRESULT hRet = pDSBuffer->Lock(dwOffset, dwBufferSize, &pAudioPtr, &dwAudioBytes,
&pAudioPtr2, &dwAudioBytes2, 0);
if (hRet == DS_OK) {
if (pAudioPtr != 0) {
memcpy_s(pAudioPtr, dwAudioBytes, pBufferData, dwBufferSize);
pDSBuffer->Unlock(pAudioPtr, dwAudioBytes, nullptr, 0);
if (pAudioPtr != nullptr) {
memcpy_s(pAudioPtr, dwAudioBytes, pBufferData, dwAudioBytes);
if (pAudioPtr2 != nullptr) {
memcpy_s(pAudioPtr2, dwAudioBytes2, (PUCHAR)pBufferData + dwAudioBytes, dwAudioBytes2);
}
pDSBuffer->Unlock(pAudioPtr, dwAudioBytes, pAudioPtr2, dwAudioBytes2);
}
}
}