mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-08-10 00:25:09 +00:00
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:
@@ -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" />
|
||||
|
@@ -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">
|
||||
|
@@ -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
|
||||
|
@@ -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");
|
||||
|
@@ -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
25
source/SoundBuffer.h
Normal 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;
|
||||
};
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
252
source/Windows/DXSoundBuffer.cpp
Normal file
252
source/Windows/DXSoundBuffer.cpp
Normal 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();
|
||||
}
|
30
source/Windows/DXSoundBuffer.h
Normal file
30
source/Windows/DXSoundBuffer.h
Normal 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;
|
||||
};
|
@@ -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>();
|
||||
}
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user