/* 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; //----------------------------------------------------------------------------- std::shared_ptr DXSoundBuffer::create(uint32_t dwBufferSize, uint32_t nSampleRate, int nChannels) { if (!g_lpDS) return NULL; 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 = DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; LPDIRECTSOUNDBUFFER pBuffer; // 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..." HRESULT hr = g_lpDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL); if (FAILED(hr)) { LogFileOutput("DXSoundBuffer: CreateSoundBuffer(), hr=0x%08X\n", (uint32_t)hr); return NULL; } return std::make_shared(pBuffer); } DXSoundBuffer::DXSoundBuffer(LPDIRECTSOUNDBUFFER pBuffer) : m_pBuffer(pBuffer) { _ASSERT(m_pBuffer); } DXSoundBuffer::~DXSoundBuffer() { HRESULT hr = m_pBuffer->Release(); } 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(); }