422 lines
9.9 KiB
C++
422 lines
9.9 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
// File: dsutil.cpp
|
||
|
//
|
||
|
// Desc: Routines for dealing with sounds from resources
|
||
|
//
|
||
|
// Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
#define STRICT
|
||
|
#include <windows.h>
|
||
|
#include <mmsystem.h>
|
||
|
#include <dsound.h>
|
||
|
#include "dsutil.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_LoadSoundBuffer()
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
LPDIRECTSOUNDBUFFER DSUtil_LoadSoundBuffer( LPDIRECTSOUND pDS, LPCTSTR strName )
|
||
|
{
|
||
|
LPDIRECTSOUNDBUFFER pDSB = NULL;
|
||
|
DSBUFFERDESC dsbd;
|
||
|
BYTE* pbWaveData;
|
||
|
|
||
|
ZeroMemory( &dsbd, sizeof(dsbd) );
|
||
|
dsbd.dwSize = sizeof(dsbd);
|
||
|
dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME |
|
||
|
DSBCAPS_CTRLFREQUENCY | DSBCAPS_GETCURRENTPOSITION2;
|
||
|
|
||
|
if( SUCCEEDED( DSUtil_GetWaveResource( NULL, strName, &dsbd.lpwfxFormat,
|
||
|
&pbWaveData, &dsbd.dwBufferBytes ) ) )
|
||
|
{
|
||
|
|
||
|
if( SUCCEEDED( pDS->CreateSoundBuffer( &dsbd, &pDSB, NULL ) ) )
|
||
|
{
|
||
|
if( FAILED( DSUtil_FillSoundBuffer( pDSB, pbWaveData,
|
||
|
dsbd.dwBufferBytes ) ) )
|
||
|
{
|
||
|
pDSB->Release();
|
||
|
pDSB = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDSB = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pDSB;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_ReloadSoundBuffer()
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_ReloadSoundBuffer( LPDIRECTSOUNDBUFFER pDSB, LPCTSTR strName )
|
||
|
{
|
||
|
BYTE* pbWaveData;
|
||
|
DWORD cbWaveSize;
|
||
|
|
||
|
if( FAILED( DSUtil_GetWaveResource( NULL, strName, NULL, &pbWaveData,
|
||
|
&cbWaveSize ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( FAILED( pDSB->Restore() ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( FAILED( DSUtil_FillSoundBuffer( pDSB, pbWaveData, cbWaveSize ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name:
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_GetWaveResource( HMODULE hModule, LPCTSTR strName,
|
||
|
WAVEFORMATEX** ppWaveHeader, BYTE** ppbWaveData,
|
||
|
DWORD* pcbWaveSize )
|
||
|
{
|
||
|
HRSRC hResInfo;
|
||
|
HGLOBAL hResData;
|
||
|
VOID* pvRes;
|
||
|
|
||
|
if( NULL == ( hResInfo = FindResource( hModule, strName, TEXT("WAV") ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( NULL == ( hResData = LoadResource( hModule, hResInfo ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( NULL == ( pvRes = LockResource( hResData ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( FAILED( DSUtil_ParseWaveResource( pvRes, ppWaveHeader, ppbWaveData,
|
||
|
pcbWaveSize ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name:
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
SoundObject* DSUtil_CreateSound( LPDIRECTSOUND pDS, LPCTSTR strName,
|
||
|
DWORD dwNumConcurrentBuffers )
|
||
|
{
|
||
|
SoundObject* pSound = NULL;
|
||
|
LPWAVEFORMATEX pWaveHeader;
|
||
|
BYTE* pbData;
|
||
|
DWORD cbData;
|
||
|
|
||
|
if( NULL == pDS )
|
||
|
return NULL;
|
||
|
|
||
|
if( dwNumConcurrentBuffers < 1 )
|
||
|
dwNumConcurrentBuffers = 1;
|
||
|
|
||
|
if( SUCCEEDED( DSUtil_GetWaveResource( NULL, strName, &pWaveHeader,
|
||
|
&pbData, &cbData ) ) )
|
||
|
{
|
||
|
pSound = new SoundObject;
|
||
|
pSound->dwNumBuffers = dwNumConcurrentBuffers;
|
||
|
pSound->pbWaveData = pbData;
|
||
|
pSound->cbWaveSize = cbData;
|
||
|
pSound->dwCurrent = 0;
|
||
|
pSound->pdsbBuffers = new LPDIRECTSOUNDBUFFER[dwNumConcurrentBuffers+1];
|
||
|
|
||
|
pSound->pdsbBuffers[0] = DSUtil_LoadSoundBuffer( pDS, strName );
|
||
|
|
||
|
for( DWORD i=1; i<pSound->dwNumBuffers; i++ )
|
||
|
{
|
||
|
if( FAILED( pDS->DuplicateSoundBuffer( pSound->pdsbBuffers[0],
|
||
|
&pSound->pdsbBuffers[i] ) ) )
|
||
|
{
|
||
|
pSound->pdsbBuffers[i] = DSUtil_LoadSoundBuffer( pDS, strName );
|
||
|
if( NULL == pSound->pdsbBuffers[i] )
|
||
|
{
|
||
|
DSUtil_DestroySound( pSound );
|
||
|
pSound = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pSound;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_DestroySound()
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
VOID DSUtil_DestroySound( SoundObject* pSound )
|
||
|
{
|
||
|
if( pSound )
|
||
|
{
|
||
|
for( DWORD i=0; i<pSound->dwNumBuffers; i++ )
|
||
|
{
|
||
|
if( pSound->pdsbBuffers[i] )
|
||
|
pSound->pdsbBuffers[i]->Release();
|
||
|
}
|
||
|
|
||
|
delete pSound->pdsbBuffers;
|
||
|
delete pSound;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name:
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
LPDIRECTSOUNDBUFFER DSUtil_GetFreeSoundBuffer( SoundObject* pSound )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
if( NULL == pSound )
|
||
|
return NULL;
|
||
|
|
||
|
LPDIRECTSOUNDBUFFER pDSB = pSound->pdsbBuffers[pSound->dwCurrent];
|
||
|
if( NULL == pDSB )
|
||
|
return NULL;
|
||
|
|
||
|
hr = pDSB->GetStatus( &dwStatus );
|
||
|
if( FAILED(hr) )
|
||
|
dwStatus = 0;
|
||
|
|
||
|
if( dwStatus & DSBSTATUS_PLAYING )
|
||
|
{
|
||
|
if( pSound->dwNumBuffers <= 1 )
|
||
|
return NULL;
|
||
|
|
||
|
if( ++pSound->dwCurrent >= pSound->dwNumBuffers )
|
||
|
pSound->dwCurrent = 0;
|
||
|
|
||
|
pDSB = pSound->pdsbBuffers[pSound->dwCurrent];
|
||
|
|
||
|
hr = pDSB->GetStatus( &dwStatus);
|
||
|
if( FAILED(hr) )
|
||
|
dwStatus = 0;
|
||
|
|
||
|
if( dwStatus & DSBSTATUS_PLAYING )
|
||
|
{
|
||
|
pDSB->Stop();
|
||
|
pDSB->SetCurrentPosition( 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( dwStatus & DSBSTATUS_BUFFERLOST )
|
||
|
{
|
||
|
if( FAILED( pDSB->Restore() ) )
|
||
|
return NULL;
|
||
|
|
||
|
if( FAILED( DSUtil_FillSoundBuffer( pDSB, pSound->pbWaveData,
|
||
|
pSound->cbWaveSize ) ) )
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return pDSB;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_PlaySound()
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_PlaySound( SoundObject* pSound, DWORD dwPlayFlags )
|
||
|
{
|
||
|
if( NULL == pSound )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( !(dwPlayFlags & DSBPLAY_LOOPING) || (pSound->dwNumBuffers == 1) )
|
||
|
{
|
||
|
LPDIRECTSOUNDBUFFER pDSB = DSUtil_GetFreeSoundBuffer( pSound );
|
||
|
if( pDSB )
|
||
|
{
|
||
|
if( SUCCEEDED( pDSB->Play( 0, 0, dwPlayFlags ) ) )
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_StopSound()
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_StopSound( SoundObject* pSound )
|
||
|
{
|
||
|
if( NULL == pSound )
|
||
|
return E_FAIL;
|
||
|
|
||
|
for( DWORD i=0; i<pSound->dwNumBuffers; i++ )
|
||
|
{
|
||
|
pSound->pdsbBuffers[i]->Stop();
|
||
|
pSound->pdsbBuffers[i]->SetCurrentPosition( 0 );
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name:
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_FillSoundBuffer( LPDIRECTSOUNDBUFFER pDSB, BYTE* pbWaveData,
|
||
|
DWORD dwWaveSize )
|
||
|
{
|
||
|
VOID* pMem1;
|
||
|
VOID* pMem2;
|
||
|
DWORD dwSize1;
|
||
|
DWORD dwSize2;
|
||
|
|
||
|
if( NULL == pDSB || NULL == pbWaveData || 0 == dwWaveSize )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( FAILED( pDSB->Lock( 0, dwWaveSize, &pMem1, &dwSize1, &pMem2,
|
||
|
&dwSize2, 0 ) ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( 0 != dwSize1 ) CopyMemory( pMem1, pbWaveData, dwSize1 );
|
||
|
if( 0 != dwSize2 ) CopyMemory( pMem2, pbWaveData+dwSize1, dwSize2 );
|
||
|
|
||
|
pDSB->Unlock( pMem1, dwSize1, pMem2, dwSize2);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name:
|
||
|
// Desc:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT DSUtil_ParseWaveResource( 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') )
|
||
|
return E_FAIL;
|
||
|
|
||
|
if( dwType != mmioFOURCC('W', 'A', 'V', 'E') )
|
||
|
return E_FAIL;
|
||
|
|
||
|
pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
|
||
|
|
||
|
while( pdw < pdwEnd )
|
||
|
{
|
||
|
dwType = *pdw++;
|
||
|
dwLength = *pdw++;
|
||
|
|
||
|
if( dwType == mmioFOURCC('f', 'm', 't', ' ') )
|
||
|
{
|
||
|
if (ppWaveHeader && !*ppWaveHeader)
|
||
|
{
|
||
|
if( dwLength < sizeof(WAVEFORMAT) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
*ppWaveHeader = (WAVEFORMATEX*)pdw;
|
||
|
|
||
|
if( (!ppbWaveData || *ppbWaveData) &&
|
||
|
(!pcbWaveSize || *pcbWaveSize) )
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( dwType == mmioFOURCC('d', 'a', 't', 'a') )
|
||
|
{
|
||
|
if( (ppbWaveData && !*ppbWaveData) ||
|
||
|
(pcbWaveSize && !*pcbWaveSize) )
|
||
|
{
|
||
|
if( ppbWaveData )
|
||
|
*ppbWaveData = (BYTE*)pdw;
|
||
|
|
||
|
if( pcbWaveSize )
|
||
|
*pcbWaveSize = dwLength;
|
||
|
|
||
|
if( !ppWaveHeader || *ppWaveHeader )
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pdw = (DWORD*)( (BYTE*)pdw + ((dwLength+1)&~1) );
|
||
|
}
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DSUtil_PlayPannedSound()
|
||
|
// Desc: Play a sound, but first set the panning according to where the
|
||
|
// object is on the screen. fScreenXPos is between -1.0f (left) and
|
||
|
// 1.0f (right).
|
||
|
//-----------------------------------------------------------------------------
|
||
|
VOID DSUtil_PlayPannedSound( SoundObject* pSound, FLOAT fScreenXPos )
|
||
|
{
|
||
|
LPDIRECTSOUNDBUFFER pDSB = DSUtil_GetFreeSoundBuffer( pSound );
|
||
|
|
||
|
if( pDSB )
|
||
|
{
|
||
|
pDSB->SetPan( (LONG)( 10000.0f * fScreenXPos ) );
|
||
|
pDSB->Play( 0, 0, 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|