/*========================================================================== * * Copyright (c) 1995 - 1999 Microsoft Corporation. All Rights Reserved. * * File: dsutil.cpp * Content: Routines for dealing with sounds from resources * * ***************************************************************************/ #define WIN32_LEAN_AND_MEAN #include #include #include #include typedef struct { BYTE *pbWaveData; // pointer into wave resource (for restore) DWORD cbWaveSize; // size of wave data (for restore) int iAlloc; // number of buffers. int iCurrent; // current buffer IDirectSoundBuffer* Buffers[1]; // list of buffers } SNDOBJ, *HSNDOBJ; #define _HSNDOBJ_DEFINED #include "dsutil.h" static const char c_szWAV[] = "WAV"; /////////////////////////////////////////////////////////////////////////////// // // DSLoadSoundBuffer // /////////////////////////////////////////////////////////////////////////////// IDirectSoundBuffer *DSLoadSoundBuffer(IDirectSound *pDS, LPCTSTR lpName) { IDirectSoundBuffer *pDSB = NULL; DSBUFFERDESC dsBD = {0}; BYTE *pbWaveData; if (DSGetWaveResource(NULL, lpName, &dsBD.lpwfxFormat, &pbWaveData, &dsBD.dwBufferBytes)) { dsBD.dwSize = sizeof(dsBD); dsBD.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GETCURRENTPOSITION2; if (SUCCEEDED(IDirectSound_CreateSoundBuffer(pDS, &dsBD, &pDSB, NULL))) { if (!DSFillSoundBuffer(pDSB, pbWaveData, dsBD.dwBufferBytes)) { IDirectSoundBuffer_Release(pDSB); pDSB = NULL; } } else { pDSB = NULL; } } return pDSB; } /////////////////////////////////////////////////////////////////////////////// // // DSReloadSoundBuffer // /////////////////////////////////////////////////////////////////////////////// BOOL DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName) { BOOL result=FALSE; BYTE *pbWaveData; DWORD cbWaveSize; if (DSGetWaveResource(NULL, lpName, NULL, &pbWaveData, &cbWaveSize)) { if (SUCCEEDED(IDirectSoundBuffer_Restore(pDSB)) && DSFillSoundBuffer(pDSB, pbWaveData, cbWaveSize)) { result = TRUE; } } return result; } /////////////////////////////////////////////////////////////////////////////// // // DSGetWaveResource // /////////////////////////////////////////////////////////////////////////////// BOOL DSGetWaveResource(HMODULE hModule, LPCTSTR lpName, WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData, DWORD *pcbWaveSize) { HRSRC hResInfo; HGLOBAL hResData; void *pvRes; if (((hResInfo = FindResource(hModule, lpName, c_szWAV)) != NULL) && ((hResData = LoadResource(hModule, hResInfo)) != NULL) && ((pvRes = LockResource(hResData)) != NULL) && DSParseWaveResource(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize)) { return TRUE; } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // SndObj fns /////////////////////////////////////////////////////////////////////////////// SNDOBJ *SndObjCreate(IDirectSound *pDS, LPCTSTR lpName, int iConcurrent) { SNDOBJ *pSO = NULL; LPWAVEFORMATEX pWaveHeader; BYTE *pbData; UINT cbData; if (DSGetWaveResource(NULL, lpName, &pWaveHeader, &pbData, &cbData)) { if (iConcurrent < 1) iConcurrent = 1; if ((pSO = (SNDOBJ *)LocalAlloc(LPTR, sizeof(SNDOBJ) + (iConcurrent-1) * sizeof(IDirectSoundBuffer *))) != NULL) { int i; pSO->iAlloc = iConcurrent; pSO->pbWaveData = pbData; pSO->cbWaveSize = cbData; pSO->Buffers[0] = DSLoadSoundBuffer(pDS, lpName); for (i=1; iiAlloc; i++) { if (FAILED(IDirectSound_DuplicateSoundBuffer(pDS, pSO->Buffers[0], &pSO->Buffers[i]))) { pSO->Buffers[i] = DSLoadSoundBuffer(pDS, lpName); if (!pSO->Buffers[i]) { SndObjDestroy(pSO); pSO = NULL; break; } } } } } return pSO; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void SndObjDestroy(SNDOBJ *pSO) { if (pSO) { int i; for (i=0; iiAlloc; i++) { if (pSO->Buffers[i]) { IDirectSoundBuffer_Release(pSO->Buffers[i]); pSO->Buffers[i] = NULL; } } LocalFree((HANDLE)pSO); } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// IDirectSoundBuffer *SndObjGetFreeBuffer(SNDOBJ *pSO) { IDirectSoundBuffer *pDSB; if (pSO == NULL) return NULL; if (pDSB = pSO->Buffers[pSO->iCurrent]) { HRESULT hres; DWORD dwStatus; hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus); if (FAILED(hres)) dwStatus = 0; if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING) { if (pSO->iAlloc > 1) { if (++pSO->iCurrent >= pSO->iAlloc) pSO->iCurrent = 0; pDSB = pSO->Buffers[pSO->iCurrent]; hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus); if (SUCCEEDED(hres) && (dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING) { IDirectSoundBuffer_Stop(pDSB); IDirectSoundBuffer_SetCurrentPosition(pDSB, 0); } } else { pDSB = NULL; } } if (pDSB && (dwStatus & DSBSTATUS_BUFFERLOST)) { if (FAILED(IDirectSoundBuffer_Restore(pDSB)) || !DSFillSoundBuffer(pDSB, pSO->pbWaveData, pSO->cbWaveSize)) { pDSB = NULL; } } } return pDSB; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// BOOL SndObjPlay(SNDOBJ *pSO, DWORD dwPlayFlags) { BOOL result = FALSE; if (pSO == NULL) return FALSE; if ((!(dwPlayFlags & DSBPLAY_LOOPING) || (pSO->iAlloc == 1))) { IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(pSO); if (pDSB != NULL) { result = SUCCEEDED(IDirectSoundBuffer_Play(pDSB, 0, 0, dwPlayFlags)); } } return result; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// BOOL SndObjStop(SNDOBJ *pSO) { int i; if (pSO == NULL) return FALSE; for (i=0; iiAlloc; i++) { IDirectSoundBuffer_Stop(pSO->Buffers[i]); IDirectSoundBuffer_SetCurrentPosition(pSO->Buffers[i], 0); } return TRUE; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize) { if (pDSB && pbWaveData && cbWaveSize) { LPVOID pMem1, pMem2; DWORD dwSize1, dwSize2; if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize, &pMem1, &dwSize1, &pMem2, &dwSize2, 0))) { CopyMemory(pMem1, pbWaveData, dwSize1); if ( 0 != dwSize2 ) CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2); IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2); return TRUE; } } return FALSE; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData,DWORD *pcbWaveSize) { DWORD *pdw; DWORD *pdwEnd; DWORD dwRiff; DWORD dwType; DWORD dwLength; if (ppWaveHeader) *ppWaveHeader = NULL; if (ppbWaveData) *ppbWaveData = NULL; if (pcbWaveSize) *pcbWaveSize = 0; pdw = (DWORD *)pvRes; dwRiff = *pdw++; dwLength = *pdw++; dwType = *pdw++; if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F')) goto exit; // not even RIFF if (dwType != mmioFOURCC('W', 'A', 'V', 'E')) goto exit; // not a WAV pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4); while (pdw < pdwEnd) { dwType = *pdw++; dwLength = *pdw++; switch (dwType) { case mmioFOURCC('f', 'm', 't', ' '): if (ppWaveHeader && !*ppWaveHeader) { if (dwLength < sizeof(WAVEFORMAT)) goto exit; // not a WAV *ppWaveHeader = (WAVEFORMATEX *)pdw; if ((!ppbWaveData || *ppbWaveData) && (!pcbWaveSize || *pcbWaveSize)) { return TRUE; } } break; case mmioFOURCC('d', 'a', 't', 'a'): if ((ppbWaveData && !*ppbWaveData) || (pcbWaveSize && !*pcbWaveSize)) { if (ppbWaveData) *ppbWaveData = (LPBYTE)pdw; if (pcbWaveSize) *pcbWaveSize = dwLength; if (!ppWaveHeader || *ppWaveHeader) return TRUE; } break; } pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1)); } exit: return FALSE; }