|
|
/*==========================================================================
* * 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 <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <dsound.h>
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; i<pSO->iAlloc; 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; i<pSO->iAlloc; 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; i<pSO->iAlloc; 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; }
|