room101/WIN32/DSUTIL.C

320 lines
7.3 KiB
C

/*==========================================================================
*
* Copyright (C) 1995 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>
#include <stdio.h>
#include <assert.h>
#include "dsutil.h"
IDirectSoundBuffer*
DSLoadSoundBuffer(IDirectSound* pDS, SNDOBJ* wave)
{
IDirectSoundBuffer* pDSB = NULL;
DSBUFFERDESC dsBD = {0};
dsBD.lpwfxFormat = wave->header;
dsBD.dwBufferBytes = wave->size;
dsBD.dwSize = sizeof(dsBD);
dsBD.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
if (SUCCEEDED(IDirectSound_CreateSoundBuffer(pDS, &dsBD, &pDSB, NULL)))
{
if (!DSFillSoundBuffer(pDSB, wave))
{
IDirectSoundBuffer_Release(pDSB);
pDSB = NULL;
}
}
else
{
pDSB = NULL;
}
return pDSB;
}
BOOL
DSReloadSoundBuffer(IDirectSoundBuffer* pDSB, SNDOBJ* wave)
{
return SUCCEEDED(IDirectSoundBuffer_Restore(pDSB)) && DSFillSoundBuffer(pDSB, wave);
}
SNDOBJ*
SndObjCreate(IDirectSound* pDS, LPCTSTR lpName, int iConcurrent)
{
SNDOBJ* pSO = NULL;
LPWAVEFORMATEX header;
BYTE* pbData;
DWORD cbData;
FILE* file;
int size, i;
if (iConcurrent < 1) iConcurrent = 1;
file = fopen(lpName, "rb");
assert(file);
pSO = calloc(sizeof(SNDOBJ) + (iConcurrent-1) * sizeof(IDirectSoundBuffer*), 1);
assert(pSO);
fseek(file, 0, SEEK_END);
size = ftell(file);
rewind(file);
pSO->memory = malloc(size);
assert(pSO->memory);
fread(pSO->memory, 1, size, file);
DSParseWaveResource(pSO->memory, &header, &pbData, &cbData);
pSO->iAlloc = iConcurrent;
pSO->header = header;
pSO->data = pbData;
pSO->size = cbData;
pSO->Buffers[0] = DSLoadSoundBuffer(pDS, pSO);
for (i = 1; i < pSO->iAlloc; i++)
{
if (FAILED(IDirectSound_DuplicateSoundBuffer(pDS,
pSO->Buffers[0], &pSO->Buffers[i])))
{
pSO->Buffers[i] = DSLoadSoundBuffer(pDS, pSO);
if (!pSO->Buffers[i])
{
SndObjDestroy(pSO);
pSO = NULL;
break;
}
}
}
return pSO;
}
void
SndObjDestroy(SNDOBJ* pSO)
{
int i;
if (pSO)
{
for (i = 0; i < pSO->iAlloc; i++)
{
if (pSO->Buffers[i])
{
IDirectSoundBuffer_Release(pSO->Buffers[i]);
pSO->Buffers[i] = NULL;
}
}
free(pSO->memory);
free(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))
{
pDSB = NULL;
}
}
}
return pDSB;
}
BOOL
SndObjPlay(SNDOBJ* pSO, DWORD dwPlayFlags)
{
IDirectSoundBuffer* pDSB;
if (pSO)
{
if ((!(dwPlayFlags & DSBPLAY_LOOPING) || (pSO->iAlloc == 1)))
{
pDSB = SndObjGetFreeBuffer(pSO);
if (pDSB != NULL)
{
return SUCCEEDED(IDirectSoundBuffer_Play(pDSB, 0, 0, dwPlayFlags));
}
}
}
return FALSE;
}
BOOL
SndObjStop(SNDOBJ* pSO)
{
int i;
if (pSO)
{
for (i = 0; i < pSO->iAlloc; i++)
{
IDirectSoundBuffer_Stop(pSO->Buffers[i]);
IDirectSoundBuffer_SetCurrentPosition(pSO->Buffers[i], 0);
}
return TRUE;
}
return FALSE;
}
BOOL
DSFillSoundBuffer(IDirectSoundBuffer *pDSB, SNDOBJ* wave)
{
LPVOID pMem1, pMem2;
DWORD dwSize1, dwSize2;
if (pDSB && wave->data && wave->size)
{
if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, wave->size,
&pMem1, &dwSize1, &pMem2, &dwSize2, 0)))
{
CopyMemory(pMem1, wave->data, dwSize1);
if ( 0 != dwSize2 )
{
CopyMemory(pMem2, wave->data + 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;
}