📄 dsapi.cpp
字号:
dwProgress = 0; /* Used with above to show prog. */
bDonePlaying = TRUE; /* Signals early abort to timer */
bLoopFile = FALSE; /* Should we loop playback? */
bFoundEnd = TRUE; /* Timer found file end */
nRemainingSegments = 0;/* Segments 'til timer shutdown */
//char strFileName[65]; /* wave file name */
nID = WAVE_OBJECT_NONE; // ID, and if wave file has been opened
bPlaying = FALSE, bTimerInstalled = FALSE; // if is playing, timer has been installed
uTimerID = 0, uLastPercent = 0; // timer ID and percent has been played
// return 1;
}
// destructor
CDynamicWave::~CDynamicWave()
{
if( nID != WAVE_OBJECT_NONE )
{
PostMessage( DS_hwndGame, WM_DSSTREAM_DONE, (WPARAM)nID, (LPARAM)0 );
Stop();
OutputDebugString( "DS Warning: not stop playing sound before destroy sound buffer!\n" );
}
}
// load sound buffer
// filename : wave file name
// return value : TRUE if succeeded
BOOL WAVEDYNAMIC::Load( LPCTSTR filename )
{
// register this sound buffer to global array
BOOL bSuccess = FALSE;
for( int i=0; i< WAVE_OBJECT_MAX; i++ )
{
if( lpwdWaves[i] == NULL )
{
lpwdWaves[i] = this;
nID = i;
bSuccess = TRUE;
#ifdef __TEST_SOUND__
for( int x=0; x<WAVE_OBJECT_MAX; x++ )
{
if( nID == x ) continue;
if( !lpwdWaves[x] ) continue;
ASSERT( this != lpwdWaves[x] );
}
#endif
break;
}
}
if( !bSuccess )
{
return FALSE;
}
// load sound with a wave format file
strcpy( strFileName, filename );
if(StreamBufferSetup( nID ) != 0 )
{
// Error opening the WAVE file so abort
lpwdWaves[nID] = NULL;
nID = WAVE_OBJECT_NONE;
return FALSE;
}
nWaveCounter++;
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nID]->lpDSBStreamBuffer );
#endif
#ifdef _DEBUG
char tmp[33];
itoa( nWaveCounter, tmp, 10 );
// OutputDebugString( "DS Dynamic wave Load:" );
// OutputDebugString(tmp);
// OutputDebugString("\n");
#endif
return TRUE;
}
// release sound buffer
void WAVEDYNAMIC::Close()
{
if( nID == WAVE_OBJECT_NONE ) return;
//OutputDebugString( "Wait2," );
WaitForSingleObject( hMutex, INFINITE );
// release sound buffer, and unregister from global array
StreamBufferRelease( nID );
lpwdWaves[nID] = NULL;
nID = WAVE_OBJECT_NONE;
nWaveCounter--;
ReleaseMutex( hMutex );
//OutputDebugString( "End Wait2\n" );
#ifdef _DEBUG
char tmp[33];
itoa( nWaveCounter, tmp, 10 );
// OutputDebugString( "DS Dynamic wave Close:" );
// OutputDebugString(tmp);
// OutputDebugString("\n");
#endif
}
// play wave file
// dwFlags : TRUE if looping
// pos : position to play from
// return value : TRUE if played
// if this object is playing, stop and playing again
// Warning: a bug report here: the last sound in segment buffer
// cannot be played, so you need the file larger than
// normal at last, with a period of slience.
BOOL WAVEDYNAMIC::Play( DWORD dwFlags/*=DSBPLAY_LOOPING*/, DWORD pos/*=0*/ )
{
HRESULT dsrval;
if( !DS_bSoundEnable ) return TRUE;
if( bPlaying == TRUE )
{
PostMessage( DS_hwndGame, WM_DSSTREAM_DONE, (WPARAM)nID, (LPARAM)0 );
Stop();
}
if( !Load( strFileName ) )
return FALSE;
#ifdef __TEST_SOUND__
ASSERT( nID != WAVE_OBJECT_NONE );
ASSERT( lpDSBStreamBuffer );
#endif
#ifdef __TEST_SOUND__
ASSERT( bPlaying == FALSE );
#endif
// Ensure that position is at 0, ready to go
// set position
if( lpDSBStreamBuffer->SetCurrentPosition( pos ) != DS_OK )
return FALSE;
// set volume
if( lpDSBStreamBuffer->SetVolume( DS_nVolume ) != DS_OK )
return FALSE;
// set pan
if( lpDSBStreamBuffer->SetPan( DS_nPan ) != DS_OK )
return FALSE;
// play
if( lpDSBStreamBuffer->Play( 0, 0, DSBPLAY_LOOPING ) != DS_OK )
return FALSE;
bPlaying = TRUE;
if( timeBeginPeriod( PLAYBACK_TIMER_PERIOD
/ PLAYBACK_OVERSAMPLE ) != TIMERR_NOERROR )
{
/* Can't create timer! */
dsrval = lpDSBStreamBuffer->Stop();
bPlaying = bTimerInstalled = FALSE;
Close();
return FALSE;
}
else
{
if(( uTimerID = timeSetEvent( PLAYBACK_TIMER_PERIOD
/ PLAYBACK_OVERSAMPLE,
PLAYBACK_TIMER_ACCURACY,
TimeFunc, (DWORD)nID,
/*TIME_ONESHOT*/TIME_PERIODIC )) != 0 )
{
bTimerInstalled = TRUE;
#ifdef __TEST_SOUND__
for( int i=0; i< WAVE_OBJECT_MAX; i++ )
{
if( i == nID ) continue;
if( !lpwdWaves[i] ) continue;
ASSERT( uTimerID != lpwdWaves[i]->uTimerID );
}
#endif
}
else
{
timeEndPeriod( PLAYBACK_TIMER_PERIOD
/ PLAYBACK_OVERSAMPLE );
dsrval = lpDSBStreamBuffer->Stop();
bPlaying = bTimerInstalled = FALSE;
Close();
return FALSE;
}
}
bLoopFile = dwFlags;
return TRUE;
}
// reset wave player, avoid to use
void WAVEDYNAMIC::Reset()
{
ResetWavePlayer( nID );
}
// stop playing
// if has stoped, no effects
void WAVEDYNAMIC::Stop()
{
HRESULT dsrval;
if( nID == WAVE_OBJECT_NONE ) return;
WaitForSingleObject( hMutex, INFINITE );
#ifdef __TEST_SOUND__
ASSERT( !bDonePlaying );
#endif
bDonePlaying = TRUE;
#ifdef __TEST_SOUND__
ASSERT( bTimerInstalled );
#endif
if( bTimerInstalled )
{
bTimerInstalled = FALSE;
timeKillEvent( uTimerID );
timeEndPeriod( PLAYBACK_TIMER_PERIOD
/ PLAYBACK_OVERSAMPLE );
uTimerID = 0;
}
#ifdef __TEST_SOUND__
ASSERT( bPlaying );
#endif
if( bPlaying )
{
bPlaying = FALSE;
dsrval = lpDSBStreamBuffer->Stop();
ReleaseMutex( hMutex );
Close();
WaitForSingleObject( hMutex, INFINITE );
}
ReleaseMutex( hMutex );
}
// for fade out
// to make the sound lower and lower
// return value : TRUE if succeeded
BOOL WAVEDYNAMIC::FadeOut()
{
LONG lVolume;
int nStep;
BOOL retrn = FALSE;
if( lpDSBStreamBuffer->GetVolume( &lVolume ) == DS_OK )
{
nStep = 100;//0 - lVolume+50;
if( lVolume-nStep > -2000 )
lVolume = lVolume - nStep;
else
{
lVolume = -2000; retrn = TRUE;
}
if( lpDSBStreamBuffer->SetVolume( lVolume ) != DS_OK )
{
retrn = TRUE;
}
}
else retrn = TRUE;
return retrn;
}
// to make the sound louder and louder
// return value : TRUE if succeeded
BOOL WAVEDYNAMIC::FadeIn()
{
LONG lVolume;
int nStep;
BOOL retrn = FALSE;
if( lpDSBStreamBuffer->GetVolume( &lVolume ) == DS_OK )
{
nStep = 100;//0 - lVolume + 50;
if( lVolume+nStep > 0 )
{
lVolume = 0; retrn = TRUE;
}
else
{
lVolume = lVolume + nStep;
}
if( lpDSBStreamBuffer->SetVolume( lVolume ) != DS_OK )
{
retrn = TRUE;
}
}
else retrn = TRUE;
return retrn;
}
//////////////////
// functinos used by WAVEDYNAMIC
//////////////////
/*****************************************************************************/
/* SetToGlobal() */
/* */
/* this functions call is to get WAVEDYNAMIC object from global array */
/* */
/*****************************************************************************/
// nIndex : ID in global wave array
// return value : WAVEDYNAMIC pointer
inline LPWAVEDYNAMIC SetToGlobal( int nIndex )
{
return lpwdWaves[nIndex];
}
/*****************************************************************************/
/* StreamBufferSetup() */
/* */
/* This function uses the filename stored in the global character array to*/
/* open a WAVE file. Then it creates a secondary DirectSoundBuffer object */
/* which will later be used to stream that file from disk during playback. */
/* */
/*****************************************************************************/
// nIndex : ID in global wave array
// return value : 0 if succeeded, otherwise error number,
int StreamBufferSetup( int nIndex )
{
DSBUFFERDESC dsbd;
HRESULT dsRetVal;
LPBYTE lpWrite1, lpWrite2;
DWORD dwLen1, dwLen2;
UINT uChkErr;
int nChkErr;
LPWAVEDYNAMIC lpwiWave = NULL;
// set lpwdWaves[nIndex] to lpwiWave
// so that you can use lpwiWave directly
#ifdef __TEST_SOUND__
ASSERT( nIndex >= 0 );
#endif
lpwiWave = SetToGlobal( nIndex );
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
/* This portion of the WAVE I/O is patterned after what's in DSTRWAVE, which
* was in turn adopted from WAVE.C which is part of the DSSHOW sample.
*/
if(( nChkErr = WaveOpenFile( lpwiWave->strFileName, &lpwiWave->hmmio, &lpwiWave->pwfx, &lpwiWave->mmckInRIFF )) != 0 )
{
nChkErr = ERR_WAVE_OPEN_FAILED;
//SoundFail( DS_hwndGame, nChkErr );
goto END_SETUP;
}
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
if( lpwiWave->pwfx->wFormatTag != WAVE_FORMAT_PCM )
{
nChkErr = ERR_WAVE_INVALID_FORMAT;
//SoundFail( DS_hwndGame, nChkErr );
WaveCloseReadFile( &lpwiWave->hmmio, &lpwiWave->pwfx );
goto END_SETUP;
}
/* Seek to the data chunk */
if(( nChkErr = WaveStartDataRead( &lpwiWave->hmmio, &lpwiWave->mmck, &lpwiWave->mmckInRIFF )) != 0 )
{
nChkErr = ERR_WAVE_CORRUPTED_FILE;
//SoundFail( DS_hwndGame, nChkErr );
WaveCloseReadFile( &lpwiWave->hmmio, &lpwiWave->pwfx );
goto END_SETUP;
}
/* As a side note, mmck.ckSize will be the size of all the data in this file.
* That's something which might be handy when calculating the length... */
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
/* Calculate a buffer length, making sure it is an exact multiple of the
* buffer segment size.
*/
lpwiWave->dwBufferSize = ((DWORD)lpwiWave->pwfx->nAvgBytesPerSec
* (((NUM_BUFFER_SEGMENTS * PLAYBACK_TIMER_PERIOD)
/ 10)) / 100);
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
lpwiWave->dwBufferSegSize = lpwiWave->dwBufferSize / NUM_BUFFER_SEGMENTS;
lpwiWave->dwBufferSize = lpwiWave->dwBufferSegSize * NUM_BUFFER_SEGMENTS;
/*
* Create the secondary DirectSoundBuffer object to receive our sound data.
*/
memset( &dsbd, 0, sizeof( DSBUFFERDESC ));
dsbd.dwSize = sizeof( DSBUFFERDESC );
dsbd.dwFlags = DSBCAPS_CTRLDEFAULT;
dsbd.dwBufferBytes = lpwiWave->dwBufferSize;
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
/* Set Format properties according to the WAVE file we just opened */
//LPDIRECTSOUNDBUFFER lpDSB = NULL;
dsbd.lpwfxFormat = lpwiWave->pwfx;
dsRetVal = lpDS->CreateSoundBuffer( &dsbd,
&lpwiWave->lpDSBStreamBuffer,
NULL );
if( dsRetVal != DS_OK )
{
nChkErr = ERR_CREATEDSB_FAILED;
//SoundFail( DS_hwndGame, nChkErr );
WaveCloseReadFile( &lpwiWave->hmmio, &lpwiWave->pwfx );
goto END_SETUP;
}
/*
// set wave format
if ((dsRetVal = lpDSBPrimary->SetFormat(&wfx)) != DS_OK)
{
nChkErr = ERR_WAVE_FORMAT_INVALID;
SoundFail( DS_hwndGame, nChkErr );
WaveCloseReadFile( &lpwiWave->hmmio, &lpwiWave->pwfx );
goto END_SETUP;
}
*/
#ifdef __TEST_SOUND__
ASSERT( lpwiWave->lpDSBStreamBuffer );
#endif
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
//lpwiWave->lpDSBStreamBuffer = lpDSBStreamBuffer;
lpwiWave->bFoundEnd = FALSE;
lpwiWave->nRemainingSegments = 0;
dsRetVal = lpwiWave->lpDSBStreamBuffer->Lock( 0, lpwiWave->dwBufferSize,
(void**)&lpWrite1, &dwLen1,
(void**)&lpWrite2, &dwLen2,
0 );
if( dsRetVal != DS_OK )
{
nChkErr = ERR_CREATEDSB_LOST;
//SoundFail( DS_hwndGame, nChkErr );
WaveCloseReadFile( &lpwiWave->hmmio, &lpwiWave->pwfx );
lpwiWave->lpDSBStreamBuffer->Release();
lpwiWave->lpDSBStreamBuffer = NULL;
goto END_SETUP;
}
#ifdef __TEST_SOUND__
ASSERT( lpwiWave->lpDSBStreamBuffer );
#endif
#ifdef __TEST_SOUND__
ASSERT( lpwdWaves[nIndex] == lpwiWave );
#endif
if( dwLen1 )
{
nChkErr = WaveReadFile( lpwiWave->hmmio, (UINT)dwLen1, lpWrite1,
&lpwiWave->mmck, &uChkErr );
if( uChkErr < dwLen1 )
{
if( lpwiWave->bLoopFile )
{
/* If the file is shorter than the buffer and we're looping, we need to
* read the file in again so that we don't get a block of silence before
* the timer loops playback.
*/
LPBYTE lpTemp = lpWrite1;
do
{
/* Continue decrementing our count and moving our temp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -