379 lines
10 KiB
C
379 lines
10 KiB
C
/*==========================================================================
|
|
*
|
|
* 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;
|
|
}
|