📄 dsapi.cpp
字号:
/*==========================================================================
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
* Source : DSstream.cpp
* File : DsApi.cpp
* Edited by : Liu Gang
* Version : V0023
* V0010 : Oct.8.1996
* V0011 : Nov.25.1996
* V0012 : Apr.1.1997, add IfPlaying() function to classes
* V0020 : Apr.2.1997, fixed a bug when playing static sound,
* do not use Mutex with static wave objects
* V0021 : May.2.1997, add function DS_IfSoundEnable()
* V0022 : May.10.1997, fixed a bug in IfPlaying(), close the sound if the sound is end
* V0023 : May.15.1997, fixed bugs when quit and init sound frequently
* V0024 : Aug.13.1997, fixed a bug when playing
* Content: streams data from a disk WAVE file to a
* DirectSound secondary buffer for playback.
*
***************************************************************************/
#include "stdafx.h"
#include "dsApi.h"
#include "dsWave.h" // wave file functions
#include "Assert.h"
//-----debug
//#define _DS_LOG_
#ifdef _DS_LOG_
#include <stdio.h>
#endif
//-----debug
#define _TEST_SOUND_
// globals for controling sounds
/////////////
// global sound device
LPDIRECTSOUND lpDS = NULL;
// global dynamic waveinfo objects
int nWaveCounter=0; // counter for them
LPWAVEDYNAMIC lpwdWaves[WAVE_OBJECT_MAX];
// global static waveinfo objects
int nSWaveCounter=0; // counter for them
LPWAVESTATIC lpwsWaves[WAVE_OBJECT_MAXS];
// handle of window to receive error messages
HWND DS_hwndGame;
/////////////
// globals for wave sound
/////////////
// true for enable sound
BOOL DS_bSoundEnable = FALSE;
// true for sound is usable
BOOL DS_bInitialized = FALSE;
// fade mode varible
int DS_nFadeMode = DS_FADE_NONE;
// sound volume varible
int DS_nVolume = 0;
// sound pan varible
int DS_nPan = 0;
/////////////
// multi threads
/////////////
// used by TimeFunc() and Stop() in WAVEDYNAMIC
// not used in WAVESTATIC
// WaitforSingleObject() to get mutex
// ReleaseMutex() to release mutex
BOOL bCreateMutex = FALSE;
HANDLE hMutex=0;
CRITICAL_SECTION csPlayKey; // Guards one variable, gbPlay
/////////////
// initialize sound
/////////////
// error handle
// hwnd : error window
// err : error number
// return value : Always false
BOOL SoundFail( HWND hWnd, int err );
// for static wave only
// called if the static sound buffer got the end
// clear all the sounds played prviously, and now they are stoped.
void DS_CloseStopedSoundS();
/////////////
/*****************************************************************************/
/* DS_InitSound() */
/* */
/* Performs sound initialization. */
/* */
/*****************************************************************************/
LPDIRECTSOUNDBUFFER lpDSBPrimary = NULL;
WAVEFORMATEX wfx;
// initialize direct sound object
// hwnd : handle of window to receive error messages
// nType : wave format,
// default if do not want to change params of waves
// return value : TRUE if succeeded
BOOL DS_InitSound( HWND hwnd, int nType/* = DS_WAVE_FORMAT_AUTO*/ )
{
HRESULT hr;
DSCAPS dscaps;
DSBUFFERDESC dsbd;
if( DS_bInitialized == TRUE )
{
OutputDebugString( "DS_InitSound Warning: sound has been initialized!\n" );
return FALSE; // sound has been initialized
}
DS_hwndGame = hwnd;
hr = DirectSoundCreate( NULL, &lpDS, NULL );
if( hr != DS_OK )
{
return SoundFail( DS_hwndGame, 0 );
}
if( nType == DS_WAVE_FORMAT_AUTO )
{
// SetCooperativeLevel, we only need normal mode
if(( hr = lpDS->SetCooperativeLevel( DS_hwndGame, DSSCL_NORMAL )) != DS_OK )
{
return SoundFail( DS_hwndGame, 1 );
}
}
else
{
// SetCooperativeLevel, normal mode is not enough
if(( hr = lpDS->SetCooperativeLevel( DS_hwndGame, DSSCL_PRIORITY )) != DS_OK )
{
return SoundFail( DS_hwndGame, 4 );
}
}
// get sound card compatible configration
dscaps.dwSize = sizeof( dscaps );
lpDS->GetCaps( &dscaps );
char buf[255];
#ifdef _DEBUG
wsprintf( buf, "DS Caps: %d\n",dscaps.dwFlags );
//OutputDebugString( buf );
#endif
// Set up the primary direct sound buffer.
memset(&dsbd, 0, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
if ((hr = lpDS->CreateSoundBuffer( &dsbd,
&lpDSBPrimary,
NULL )) != 0)
{
return SoundFail( DS_hwndGame, 2 );
}
// set primary buffer format if necessary
if( nType != DS_WAVE_FORMAT_AUTO )
{
int nChannels;
int nSamplesPerSec;
int nwBitsPerSample;
switch( nType )
{
case DS_WAVE_FORMAT_2_22_8:
nChannels = 2;
nSamplesPerSec = 22050;
nwBitsPerSample = 8;
break;
case DS_WAVE_FORMAT_2_22_16:
nChannels = 2;
nSamplesPerSec = 11025;
nwBitsPerSample = 8;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 11025;
wfx.wBitsPerSample = 8;
wfx.nBlockAlign = wfx.wBitsPerSample*wfx.nChannels/8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec*wfx.nBlockAlign;
wfx.cbSize = 0;
if ((hr = lpDSBPrimary->SetFormat(&wfx)) != DS_OK)
{
switch( hr )
{
case DSERR_BADFORMAT:
strcpy( buf," Bad format " );
break;
case DSERR_INVALIDCALL:
strcpy( buf," Invalid call " );
break;
case DSERR_INVALIDPARAM:
strcpy( buf," Invalid Parem " );
break;
case DSERR_OUTOFMEMORY:
strcpy( buf," Out of memory " );
break;
case DSERR_PRIOLEVELNEEDED:
strcpy( buf," Priority level needed " );
break;
}
return SoundFail( DS_hwndGame, 3 );
}
}
// always play in primary buffer
lpDSBPrimary->Play( 0, 0, DSBPLAY_LOOPING );
// for multi threads
if( bCreateMutex == FALSE )
{
hMutex = CreateMutex( NULL, FALSE, NULL );
InitializeCriticalSection (&csPlayKey);
bCreateMutex = TRUE;
}
// initialize secondary sound buffers
for( int i=0; i< WAVE_OBJECT_MAX; i++ )
{
lpwdWaves[i] = NULL;
}
for( i=0; i< WAVE_OBJECT_MAXS; i++ )
{
lpwsWaves[i] = NULL;
}
// enable sound
DS_bInitialized = TRUE;
DS_EnableSound( TRUE );
return TRUE;
}
// release sound device
void DS_QuitSound( void )
{
if( DS_bInitialized == FALSE )
{
OutputDebugString( "DS_QuitSound Warning: No sound at all!\n" );
return;
}
else
{
// disable sound
DS_EnableSound( FALSE );
DS_bInitialized = FALSE;
// for multi threads
if( bCreateMutex == TRUE )
{
CloseHandle( hMutex );
DeleteCriticalSection (&csPlayKey);
bCreateMutex = FALSE;
}
}
if( lpDS )
{
if( lpDSBPrimary != NULL )
{
lpDSBPrimary->Stop();
lpDSBPrimary->Release();
lpDSBPrimary = NULL;
}
lpDS->Release( );
lpDS = NULL;
}
}
// init fail message
BOOL SoundFail( HWND hWnd, int err )
{
char buf[129];
wsprintf(buf, "DirectSound init FAILED (%d):\n", err+DS_ERROR_ID);
switch( err )
{
case 0:
strcat( buf, "Direct Sound Creation Failed" );
break;
case 1:
strcat( buf, "Direct Sound Set Cooperative Level Failed" );
break;
case 2:
strcat( buf, "Cannot create primary buffer" );
break;
}
DS_QuitSound();
OutputDebugString( buf );
return FALSE;
// if( MessageBox(hWnd, buf, "Direct Sound Error", MB_OK|MB_ICONSTOP) == IDOK )
// return TRUE;
// else return FALSE;
}
// enable or disable sound effects
// bEnable : TRUE for enable sound
// return value : old state of sound, enable or disable
BOOL DS_EnableSound( BOOL bEnable )
{
BOOL bEnableSave = DS_bSoundEnable;
if( DS_bInitialized == FALSE )
return FALSE;
if( bEnable )
{
DS_bSoundEnable = TRUE;
}
else
{
DS_bSoundEnable = FALSE;
// check and destroy sound buffers
for( int i=0; i< WAVE_OBJECT_MAX; i++ )
{
//OutputDebugString( "Wait0," );
EnterCriticalSection (&csPlayKey);
WaitForSingleObject( hMutex, INFINITE );
if( lpwdWaves[i] != NULL )
{
int nID = lpwdWaves[i]->nID;
ReleaseMutex( hMutex );
//OutputDebugString( "End Wait0\n" );
lpwdWaves[i]->Stop();
//OutputDebugString( "Wait1," );
WaitForSingleObject( hMutex, INFINITE );
PostMessage( DS_hwndGame, WM_DSSTREAM_DONE, (WPARAM)nID, (LPARAM)0 );
//OutputDebugString( "Warning: Destroy dynamic sound object before stop playing sound!\n" );
}
ReleaseMutex( hMutex );
LeaveCriticalSection (&csPlayKey);
//OutputDebugString( "End Wait1\n" );
}
//-----debug
#ifdef _DS_LOG_
FILE*fp=fopen( "DSTest.log","at" );
fprintf(fp,"G" );
fclose(fp);
#endif
//-----debug
for( i=0; i< WAVE_OBJECT_MAXS; i++ )
{
EnterCriticalSection (&csPlayKey);
// WaitForSingleObject( hMutex, INFINITE );
if( lpwsWaves[i] != NULL )
{
int nID = lpwsWaves[i]->nID;
// ReleaseMutex( hMutex );
lpwsWaves[i]->Stop();
// WaitForSingleObject( hMutex, INFINITE );
PostMessage( DS_hwndGame, WM_DSSTREAM_DONE, (WPARAM)nID, (LPARAM)0 );
}
// ReleaseMutex( hMutex );
LeaveCriticalSection (&csPlayKey);
}
}
return bEnableSave;
}
// test if sound is enable
BOOL DS_IfSoundEnable()
{
return DS_bSoundEnable;
}
// nFade : fade mode, see above
// return value : old fade mode
int DS_FadeSound( int nFadeMode )
{
int nFadeSave = DS_nFadeMode;
DS_nFadeMode = nFadeMode;
return nFadeSave;
}
// set volume
// real range is from 0 to -10000,
// this function is range from 0 to -5000
// under -3200 I cannot hear at all
// nVol : volume of the sound device
// return value : old volume of the sound device, -1 if error occurs
int DS_VolumeSound( int nVol )
{
int nVolume;
nVolume = DS_nVolume;
if( nVol >0 ) nVol = 0;
if( nVol < -5000 ) nVol = -5000;
DS_nVolume = nVol;
#ifdef _DEBUG
OutputDebugString( "DS Volume:" );
OutputString( DS_nVolume, "\n" );
#endif
return nVolume;
}
// set pan
// real range is from -10000 to 10000,
// but this function is range from -2000 to 2000
// larger than 1000, right cannot hear
// smaller than -1000 left cannot hear
// nPan : pan value for the sound device
// return value : old pan value for the sound device
int DS_PanSound( int nPan )
{
int nPanSave = DS_nPan;
if( nPan < - 2000) nPan = -2000;
if( nPan > 2000 ) nPan = 2000;
DS_nPan = nPan;
#ifdef _DEBUG
OutputDebugString( "DS Pan:" );
OutputString( DS_nPan, "\n" );
#endif
return nPan;
}
// get sound volume
inline int DS_GetVolume()
{
return DS_nVolume;
}
///////////////////
//==========================================================================
//
// class WAVEDYNAMIC
//
//==========================================================================
///////////////////
// global wave play
// used by class WAVEDYNAMIC
// get WAVEDYNAMIC pointer
// nIndex : ID in global wave array
// return value : WAVEDYNAMIC pointer
LPWAVEDYNAMIC SetToGlobal( int nIndex );
// nIndex : ID in global wave array
// return value : 0 if succeeded, otherwise error number,
int StreamBufferSetup( int nIndex );
// nIndex : ID in global wave array
void StreamBufferRelease( int nIndex );
// nIndex : ID in global wave array
void ResetWavePlayer( int nIndex );
// nIndex : ID in global wave array
void CALLBACK TimeFunc( UINT, UINT, DWORD nIndex, DWORD, DWORD );
// constructor
CDynamicWave::CDynamicWave()
{
pwfx = NULL; /* Wave Format data structure */
hmmio = 0; /* MM I/O handle for the WAVE */
mmck; /* Multimedia RIFF chunk */
memset( &mmckInRIFF,0, sizeof( mmckInRIFF ) ); /* Use in opening a WAVE file */
lpDSBStreamBuffer = NULL; /* Points to DirectSoundBuffer */
dwBufferSize = 0; /* Size of the entire buffer */
dwBufferSegSize = 0; /* Size of one buffer segment */
dwNextWriteOffset = 0; /* Offset to next buffer segment */
dwPlayLast = 0; /* Stores last play cursor */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -