Add SoundBuffer interface (PR #1352)

This replaces the LPDIRECTSOUNDBUFFER pointer with a pure virtual class and an implementation that wraps the LPDIRECTSOUNDBUFFER, allowing other sound implementations without having to simulate the exact alignment of a DIRECTSOUNDBUFFER object.

Additionally, moves the DSInit and DSUninit calls out of the SoundCore.cpp file (into a new DXSoundBuffer.cpp (for Windows)), allowing them to be appropriately reimplemented in a non-DirectSound environment.
This commit is contained in:
Jamiras
2024-12-30 05:42:26 -07:00
committed by GitHub
parent cb1366f485
commit a2b03483ee
13 changed files with 360 additions and 180 deletions

View File

@@ -107,6 +107,7 @@
<ClInclude Include="source\SaveState.h" />
<ClInclude Include="source\SerialComms.h" />
<ClInclude Include="source\SNESMAX.h" />
<ClInclude Include="source\SoundBuffer.h" />
<ClInclude Include="source\SoundCore.h" />
<ClInclude Include="source\Speaker.h" />
<ClInclude Include="source\Speech.h" />
@@ -134,6 +135,7 @@
<ClInclude Include="source\W5100.h" />
<ClInclude Include="source\Windows\AppleWin.h" />
<ClInclude Include="source\Windows\DirectInput.h" />
<ClInclude Include="source\Windows\DXSoundBuffer.h" />
<ClInclude Include="source\Windows\HookFilter.h" />
<ClInclude Include="source\Windows\Win32Frame.h" />
<ClInclude Include="source\YamlHelper.h" />
@@ -264,6 +266,7 @@
<ClCompile Include="Source\VidHD.cpp" />
<ClCompile Include="source\Windows\AppleWin.cpp" />
<ClCompile Include="source\Windows\DirectInput.cpp" />
<ClCompile Include="source\Windows\DXSoundBuffer.cpp" />
<ClCompile Include="source\Windows\HookFilter.cpp" />
<ClCompile Include="source\Windows\Win32Frame.cpp" />
<ClCompile Include="source\Windows\WinFrame.cpp" />

View File

@@ -274,6 +274,9 @@
<ClCompile Include="source\MockingboardCardManager.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\Windows\DXSoundBuffer.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h">
@@ -621,6 +624,12 @@
<ClInclude Include="source\MemoryDefs.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\SoundBuffer.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\Windows\DXSoundBuffer.h">
<Filter>Source Files\Windows</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resource\Applewin.bmp">

View File

@@ -3,6 +3,7 @@
#include "Video.h"
class NetworkBackend;
class SoundBuffer;
class FrameBase
{
@@ -48,6 +49,9 @@ public:
// useful to use libslirp in Linux
virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend(const std::string & interfaceName) = 0;
// create an object to write sound output to
virtual std::shared_ptr<SoundBuffer> CreateSoundBuffer() = 0;
// FindResource, MAKEINTRESOURCE, SizeofResource, LoadResource, LockResource
// Return pointer to resource if size is correct.
// NULL if resource is invalid or size check fails

View File

@@ -280,7 +280,7 @@ void MockingboardCardManager::UpdateSoundBuffer(void)
bool MockingboardCardManager::Init(void)
{
if (!g_bDSAvailable)
if (!DSAvailable())
return false;
HRESULT hr = DSGetSoundBuffer(&m_mockingboardVoice, DSBCAPS_CTRLVOLUME, SOUNDBUFFER_SIZE, MockingboardCard::SAMPLE_RATE, MockingboardCard::NUM_MB_CHANNELS, "MB");

View File

@@ -842,7 +842,7 @@ bool SSI263::DSInit(void)
// Create single SSI263 voice
//
if (!g_bDSAvailable)
if (!DSAvailable())
return false;
HRESULT hr = DSGetSoundBuffer(&SSI263SingleVoice, DSBCAPS_CTRLVOLUME, m_kDSBufferByteSize, SAMPLE_RATE_SSI263, m_kNumChannels, "SSI263");

25
source/SoundBuffer.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
class SoundBuffer
{
public:
virtual ~SoundBuffer() = default;
virtual HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) = 0;
virtual HRESULT Release() = 0;
virtual HRESULT SetCurrentPosition(DWORD dwNewPosition) = 0;
virtual HRESULT GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor) = 0;
virtual HRESULT Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags) = 0;
virtual HRESULT Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2) = 0;
virtual HRESULT Stop() = 0;
virtual HRESULT Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags) = 0;
virtual HRESULT SetVolume(LONG lVolume) = 0;
virtual HRESULT GetVolume(LONG* lplVolume) = 0;
virtual HRESULT GetStatus(LPDWORD lpdwStatus) = 0;
virtual HRESULT Restore() = 0;
};

View File

@@ -34,30 +34,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Log.h"
#include "Speaker.h"
//-----------------------------------------------------------------------------
#define MAX_SOUND_DEVICES 10
static std::string sound_devices[MAX_SOUND_DEVICES];
static GUID sound_device_guid[MAX_SOUND_DEVICES];
static int num_sound_devices = 0;
static LPDIRECTSOUND g_lpDS = NULL;
//-------------------------------------
// Used for muting & fading:
static const UINT uMAX_VOICES = NUM_SLOTS * 2 + 1 + 1; // 8x (2x SSI263) + spkr + MockingboardCardManager
static UINT g_uNumVoices = 0;
UINT g_uNumVoices = 0;
static VOICE* g_pVoices[uMAX_VOICES] = {NULL};
static VOICE* g_pSpeakerVoice = NULL;
//-------------------------------------
bool g_bDSAvailable = false;
//-----------------------------------------------------------------------------
// NB. Also similar is done by: MockingboardCardManager::Destroy()
@@ -72,26 +58,6 @@ VOICE::~VOICE(void)
}
}
//-----------------------------------------------------------------------------
static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
{
int i = num_sound_devices;
if(i == MAX_SOUND_DEVICES)
return TRUE;
if(lpGUID != NULL)
memcpy(&sound_device_guid[i], lpGUID, sizeof (GUID));
else
memset(&sound_device_guid[i], 0, sizeof(GUID));
sound_devices[i] = lpszDesc;
if(g_fh) fprintf(g_fh, "%d: %s - %s\n",i,lpszDesc,lpszDrvName);
num_sound_devices++;
return TRUE;
}
//-----------------------------------------------------------------------------
#ifdef _DEBUG
@@ -139,7 +105,7 @@ static const char *DirectSound_ErrorText (HRESULT error)
//-----------------------------------------------------------------------------
HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, uint32_t dwOffset, uint32_t dwBytes,
HRESULT DSGetLock(const std::shared_ptr<SoundBuffer>& pVoice, uint32_t dwOffset, uint32_t dwBytes,
SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0,
SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1)
{
@@ -184,36 +150,17 @@ HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, uint32_t dwOffset, uint32_t dwByte
HRESULT DSGetSoundBuffer(VOICE* pVoice, uint32_t dwFlags, uint32_t dwBufferSize, uint32_t nSampleRate, int nChannels, const char* pszDevName)
{
if (!g_lpDS)
return E_FAIL;
pVoice->name = pszDevName;
WAVEFORMATEX wavfmt;
DSBUFFERDESC dsbdesc;
std::shared_ptr<SoundBuffer> soundBuffer = GetFrame().CreateSoundBuffer();
if (!soundBuffer)
return E_FAIL;
wavfmt.wFormatTag = WAVE_FORMAT_PCM;
wavfmt.nChannels = nChannels;
wavfmt.nSamplesPerSec = nSampleRate;
wavfmt.wBitsPerSample = 16;
wavfmt.nBlockAlign = wavfmt.nChannels==1 ? 2 : 4;
wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
memset (&dsbdesc, 0, sizeof (dsbdesc));
dsbdesc.dwSize = sizeof (dsbdesc);
dsbdesc.dwBufferBytes = dwBufferSize;
dsbdesc.lpwfxFormat = &wavfmt;
dsbdesc.dwFlags = dwFlags | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
// Are buffers released when g_lpDS OR pVoice->lpDSBvoice is released?
// . From DirectX doc:
// "Buffer objects are owned by the device object that created them. When the
// device object is released, all buffers created by that object are also released..."
HRESULT hr = g_lpDS->CreateSoundBuffer(&dsbdesc, &pVoice->lpDSBvoice, NULL);
if(FAILED(hr))
HRESULT hr = soundBuffer->Init(dwFlags, dwBufferSize, nSampleRate, nChannels, pszDevName);
if (FAILED(hr))
return hr;
//
pVoice->lpDSBvoice = soundBuffer;
_ASSERT(g_uNumVoices < uMAX_VOICES);
if(g_uNumVoices < uMAX_VOICES)
@@ -255,7 +202,7 @@ bool DSVoiceStop(PVOICE Voice)
HRESULT hr = Voice->lpDSBvoice->Stop();
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSStop failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSStop failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
@@ -280,7 +227,7 @@ bool DSZeroVoiceBuffer(PVOICE Voice, uint32_t dwBufferSize)
HRESULT hr = DSGetLock(Voice->lpDSBvoice, 0, 0, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, 0);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
@@ -290,14 +237,14 @@ bool DSZeroVoiceBuffer(PVOICE Voice, uint32_t dwBufferSize)
hr = Voice->lpDSBvoice->Unlock((void*)pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
hr = Voice->lpDSBvoice->Play(0,0,DSBPLAY_LOOPING);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSPlay failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSPlay failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
@@ -320,7 +267,7 @@ bool DSZeroVoiceWritableBuffer(PVOICE Voice, uint32_t dwBufferSize)
&pDSLockedBuffer1, &dwDSLockedBufferSize1);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
@@ -332,7 +279,7 @@ bool DSZeroVoiceWritableBuffer(PVOICE Voice, uint32_t dwBufferSize)
(void*)pDSLockedBuffer1, dwDSLockedBufferSize1);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), hr);
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), (uint32_t)hr);
return false;
}
@@ -366,7 +313,7 @@ static bool SoundCore_StartTimer()
return true;
}
static void SoundCore_StopTimer()
void SoundCore_StopTimer()
{
if(!g_bTimerActive)
return;
@@ -516,103 +463,6 @@ void SoundCore_TweakVolumes()
//-----------------------------------------------------------------------------
static UINT g_uDSInitRefCount = 0;
bool DSInit()
{
if(g_bDSAvailable)
{
g_uDSInitRefCount++;
return true; // Already initialised successfully
}
num_sound_devices = 0;
HRESULT hr = DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, NULL);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "DSEnumerate failed (%08X)\n",hr);
return false;
}
if(g_fh)
{
fprintf(g_fh, "Number of sound devices = %d\n",num_sound_devices);
}
bool bCreatedOK = false;
for(int x=0; x<num_sound_devices; x++)
{
hr = DirectSoundCreate(&sound_device_guid[x], &g_lpDS, NULL);
if(SUCCEEDED(hr))
{
if(g_fh) fprintf(g_fh, "DSCreate succeeded for sound device #%d\n",x);
bCreatedOK = true;
break;
}
if(g_fh) fprintf(g_fh, "DSCreate failed for sound device #%d (%08X)\n",x,hr);
}
if(!bCreatedOK)
{
if(g_fh) fprintf(g_fh, "DSCreate failed for all sound devices\n");
return false;
}
HWND hwnd = GetFrame().g_hFrameWindow;
_ASSERT(hwnd);
hr = g_lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
if (FAILED(hr))
{
if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr);
return false;
}
DSCAPS DSCaps;
memset(&DSCaps, 0, sizeof(DSCAPS));
DSCaps.dwSize = sizeof(DSCAPS);
hr = g_lpDS->GetCaps(&DSCaps);
if(FAILED(hr))
{
if(g_fh) fprintf(g_fh, "GetCaps failed (%08X)\n",hr);
// Not fatal: so continue...
}
g_bDSAvailable = true;
g_uDSInitRefCount = 1;
return true;
}
//-----------------------------------------------------------------------------
void DSUninit()
{
if(!g_bDSAvailable)
return;
_ASSERT(g_uDSInitRefCount);
if(g_uDSInitRefCount == 0)
return;
g_uDSInitRefCount--;
if(g_uDSInitRefCount)
return;
//
_ASSERT(g_uNumVoices == 0);
SAFE_RELEASE(g_lpDS);
g_bDSAvailable = false;
SoundCore_StopTimer();
}
//-----------------------------------------------------------------------------
LONG NewVolume(uint32_t dwVolume, uint32_t dwVolumeMax)
{
float fVol = (float) dwVolume / (float) dwVolumeMax; // 0.0=Max, 1.0=Min

View File

@@ -4,10 +4,11 @@
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#include "SoundBuffer.h"
struct VOICE
{
LPDIRECTSOUNDBUFFER lpDSBvoice;
LPDIRECTSOUNDNOTIFY lpDSNotify;
std::shared_ptr<SoundBuffer> lpDSBvoice;
bool bActive; // Playback is active
bool bMute;
LONG nVolume; // Current volume (as used by DirectSound)
@@ -19,8 +20,6 @@ struct VOICE
VOICE(void)
{
lpDSBvoice = NULL;
lpDSNotify = NULL;
bActive = false;
bMute = false;
nVolume = 0;
@@ -36,7 +35,7 @@ struct VOICE
typedef VOICE* PVOICE;
HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, uint32_t dwOffset, uint32_t dwBytes,
HRESULT DSGetLock(const std::shared_ptr<SoundBuffer>& pVoice, uint32_t dwOffset, uint32_t dwBytes,
SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0,
SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1);
@@ -57,8 +56,11 @@ void SoundCore_SetErrorInc(const int nErrorInc);
int SoundCore_GetErrorMax();
void SoundCore_SetErrorMax(const int nErrorMax);
void SoundCore_StopTimer();
bool DSInit();
void DSUninit();
bool DSAvailable();
LONG NewVolume(uint32_t dwVolume, uint32_t dwVolumeMax);
@@ -68,6 +70,4 @@ void SysClk_UninitTimer();
void SysClk_StartTimerUsec(uint32_t dwUsecPeriod);
void SysClk_StopTimer();
//
extern bool g_bDSAvailable;
extern UINT g_uNumVoices;

View File

@@ -952,9 +952,9 @@ bool Spkr_DSInit()
// Create single Apple speaker voice
//
if (!g_bDSAvailable)
if (!DSAvailable())
{
LogFileOutput("Spkr_DSInit: g_bDSAvailable=0\n");
LogFileOutput("Spkr_DSInit: DSAvailable=0\n");
return false;
}
@@ -980,14 +980,14 @@ bool Spkr_DSInit()
SpeakerVoice.nVolume = DSBVOLUME_MAX;
hr = SpeakerVoice.lpDSBvoice->SetVolume(SpeakerVoice.nVolume);
LogFileOutput("Spkr_DSInit: SetVolume(%d) res = %08X\n", SpeakerVoice.nVolume, hr);
LogFileOutput("Spkr_DSInit: SetVolume(%d) res = %08X\n", SpeakerVoice.nVolume, (uint32_t)hr);
//
DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
hr = SpeakerVoice.lpDSBvoice->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor);
if (FAILED(hr))
LogFileOutput("Spkr_DSInit: GetCurrentPosition failed (%08X)\n", hr);
LogFileOutput("Spkr_DSInit: GetCurrentPosition failed (%08X)\n", (uint32_t)hr);
if (SUCCEEDED(hr) && (dwCurrentPlayCursor == dwCurrentWriteCursor))
{
// KLUDGE: For my WinXP PC with "VIA AC'97 Enhanced Audio Controller"
@@ -995,7 +995,7 @@ bool Spkr_DSInit()
Sleep(200);
hr = SpeakerVoice.lpDSBvoice->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor);
LogFileOutput("Spkr_DSInit: GetCurrentPosition kludge (%08X)\n", hr);
LogFileOutput("Spkr_DSInit: GetCurrentPosition kludge (%08X)\n", (uint32_t)hr);
LogOutput("[DSInit] PC=%08" DWORD_T_FMT ", WC=%08" DWORD_T_FMT ", Diff=%08" DWORD_T_FMT "\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor);
}

View File

@@ -0,0 +1,252 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
AppleWin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
AppleWin 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Description: DirectX implementation of SoundBuffer
*
* Author: Tom Charlesworth
*/
#include "StdAfx.h"
#include "DXSoundBuffer.h"
#include "Core.h" // for g_fh
#include "Interface.h"
#include "SoundCore.h"
//-----------------------------------------------------------------------------
#define MAX_SOUND_DEVICES 10
static std::string sound_devices[MAX_SOUND_DEVICES];
static GUID sound_device_guid[MAX_SOUND_DEVICES];
static int num_sound_devices = 0;
static LPDIRECTSOUND g_lpDS = NULL;
static bool g_bDSAvailable = false;
static UINT g_uDSInitRefCount = 0;
//-----------------------------------------------------------------------------
HRESULT DXSoundBuffer::Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName)
{
if (!g_lpDS)
return E_FAIL;
WAVEFORMATEX wavfmt;
DSBUFFERDESC dsbdesc;
wavfmt.wFormatTag = WAVE_FORMAT_PCM;
wavfmt.nChannels = nChannels;
wavfmt.nSamplesPerSec = nSampleRate;
wavfmt.wBitsPerSample = 16;
wavfmt.nBlockAlign = wavfmt.nChannels == 1 ? 2 : 4;
wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
memset(&dsbdesc, 0, sizeof(dsbdesc));
dsbdesc.dwSize = sizeof(dsbdesc);
dsbdesc.dwBufferBytes = dwBufferSize;
dsbdesc.lpwfxFormat = &wavfmt;
dsbdesc.dwFlags = dwFlags | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
// Are buffers released when g_lpDS OR m_pBuffer is released?
// . From DirectX doc:
// "Buffer objects are owned by the device object that created them. When the
// device object is released, all buffers created by that object are also released..."
return g_lpDS->CreateSoundBuffer(&dsbdesc, &m_pBuffer, NULL);
}
HRESULT DXSoundBuffer::Release()
{
if (!m_pBuffer)
return DS_OK;
HRESULT hr = m_pBuffer->Release();
m_pBuffer = NULL;
return hr;
}
HRESULT DXSoundBuffer::SetCurrentPosition(DWORD dwNewPosition)
{
return m_pBuffer->SetCurrentPosition(dwNewPosition);
}
HRESULT DXSoundBuffer::GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor)
{
return m_pBuffer->GetCurrentPosition(lpdwCurrentPlayCursor, lpdwCurrentWriteCursor);
}
HRESULT DXSoundBuffer::Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags)
{
return m_pBuffer->Lock(dwWriteCursor, dwWriteBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags);
}
HRESULT DXSoundBuffer::Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2)
{
return m_pBuffer->Unlock(lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
}
HRESULT DXSoundBuffer::Stop()
{
return m_pBuffer->Stop();
}
HRESULT DXSoundBuffer::Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags)
{
return m_pBuffer->Play(dwReserved1, dwReserved2, dwFlags);
}
HRESULT DXSoundBuffer::SetVolume(LONG lVolume)
{
return m_pBuffer->SetVolume(lVolume);
}
HRESULT DXSoundBuffer::GetVolume(LONG* lplVolume)
{
return m_pBuffer->GetVolume(lplVolume);
}
HRESULT DXSoundBuffer::GetStatus(LPDWORD lpdwStatus)
{
return m_pBuffer->GetStatus(lpdwStatus);
}
HRESULT DXSoundBuffer::Restore()
{
return m_pBuffer->Restore();
}
//-----------------------------------------------------------------------------
bool DSAvailable()
{
return g_bDSAvailable;
}
static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
{
int i = num_sound_devices;
if (i == MAX_SOUND_DEVICES)
return TRUE;
if (lpGUID != NULL)
memcpy(&sound_device_guid[i], lpGUID, sizeof(GUID));
else
memset(&sound_device_guid[i], 0, sizeof(GUID));
sound_devices[i] = lpszDesc;
if (g_fh) fprintf(g_fh, "%d: %s - %s\n", i, lpszDesc, lpszDrvName);
num_sound_devices++;
return TRUE;
}
bool DSInit()
{
if (g_bDSAvailable)
{
g_uDSInitRefCount++;
return true; // Already initialised successfully
}
num_sound_devices = 0;
HRESULT hr = DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, NULL);
if (FAILED(hr))
{
if (g_fh) fprintf(g_fh, "DSEnumerate failed (%08X)\n", (uint32_t)hr);
return false;
}
if (g_fh)
{
fprintf(g_fh, "Number of sound devices = %d\n", num_sound_devices);
}
bool bCreatedOK = false;
for (int x = 0; x < num_sound_devices; x++)
{
hr = DirectSoundCreate(&sound_device_guid[x], &g_lpDS, NULL);
if (SUCCEEDED(hr))
{
if (g_fh) fprintf(g_fh, "DSCreate succeeded for sound device #%d\n", x);
bCreatedOK = true;
break;
}
if (g_fh) fprintf(g_fh, "DSCreate failed for sound device #%d (%08X)\n", x, (uint32_t)hr);
}
if (!bCreatedOK)
{
if (g_fh) fprintf(g_fh, "DSCreate failed for all sound devices\n");
return false;
}
HWND hwnd = GetFrame().g_hFrameWindow;
_ASSERT(hwnd);
hr = g_lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
if (FAILED(hr))
{
if (g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n", (uint32_t)hr);
return false;
}
DSCAPS DSCaps;
memset(&DSCaps, 0, sizeof(DSCAPS));
DSCaps.dwSize = sizeof(DSCAPS);
hr = g_lpDS->GetCaps(&DSCaps);
if (FAILED(hr))
{
if (g_fh) fprintf(g_fh, "GetCaps failed (%08X)\n", (uint32_t)hr);
// Not fatal: so continue...
}
g_bDSAvailable = true;
g_uDSInitRefCount = 1;
return true;
}
void DSUninit()
{
if (!g_bDSAvailable)
return;
_ASSERT(g_uDSInitRefCount);
if (g_uDSInitRefCount == 0)
return;
g_uDSInitRefCount--;
if (g_uDSInitRefCount)
return;
//
_ASSERT(g_uNumVoices == 0);
SAFE_RELEASE(g_lpDS);
g_bDSAvailable = false;
SoundCore_StopTimer();
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "SoundBuffer.h"
class DXSoundBuffer : public SoundBuffer
{
public:
~DXSoundBuffer() { Release(); }
virtual HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName);
virtual HRESULT Release();
virtual HRESULT SetCurrentPosition(DWORD dwNewPosition);
virtual HRESULT GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor);
virtual HRESULT Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags);
virtual HRESULT Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2);
virtual HRESULT Stop();
virtual HRESULT Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags);
virtual HRESULT SetVolume(LONG lVolume);
virtual HRESULT GetVolume(LONG* lplVolume);
virtual HRESULT GetStatus(LPDWORD lpdwStatus);
virtual HRESULT Restore();
private:
LPDIRECTSOUNDBUFFER m_pBuffer = NULL;
};

View File

@@ -10,6 +10,7 @@
#include "CardManager.h"
#include "Debugger/Debug.h"
#include "Tfe/PCapBackend.h"
#include "DXSoundBuffer.h"
#include "../resource/resource.h"
// Win32Frame methods are implemented in AppleWin, WinFrame and WinVideo.
@@ -630,3 +631,8 @@ std::shared_ptr<NetworkBackend> Win32Frame::CreateNetworkBackend(const std::stri
std::shared_ptr<NetworkBackend> backend(new PCapBackend(interfaceName));
return backend;
}
std::shared_ptr<SoundBuffer> Win32Frame::CreateSoundBuffer()
{
return std::make_shared<DXSoundBuffer>();
}

View File

@@ -60,6 +60,7 @@ public:
virtual std::string Video_GetScreenShotFolder() const;
virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend(const std::string& interfaceName);
virtual std::shared_ptr<SoundBuffer> CreateSoundBuffer();
bool GetFullScreenShowSubunitStatus(void);
bool GetWindowedModeShowDiskiiStatus(void);