www.pudn.com > GameEngine_src.rar > CEasyAudio.cpp


// CEasyAudio.cpp: implementation of the CEasyAudio class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "CEasyAudio.h" 
#include "normal.h" 
#include "BaseUtil.h" 
#include  
#include  
#include  
 
 
#pragma comment(lib,"dsound.lib") 
#pragma comment(lib,"dxguid.lib") 
#pragma comment(lib,"strmiids.lib") 
 
 
//Wav文件的文件头结构 
struct WAV_FILE_HEADER 
{ 
	char  RiffID[4];				//'RIFF'块 
	long  WaveformChunkSize;		//4个字节 
	char  WaveID[4];				//.wav文件应为'WAVE'类型 
	char  FormatID[4];				//'fmt '块(末尾有一个空格) 
	long  FormatChunkSize;			//16个字节 
	short FormatTag;				//.wav文件应为WAVE_FORMAT_PCM 
	short Channels;					//声道数 
	long  SampleRate;				//采样频率 
	long  BytesPerSec;				//每秒采样的字节数 
	short BlockAlign;				//块对齐大小 
	short BitsPerSample;			//bit位数(8bit或16bit) 
	char  DataID[4];				//'data'块 
	long  DataSize;					//data块的大小(实际的声音数据) 
}; 
 
PEASYAUDIO pEasyAudio = NULL; 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
PEASYAUDIO InitEasyAudio( HWND hwnd ) 
{ 
	if ( pEasyAudio == NULL ) 
	{ 
		pEasyAudio = new CEasyAudio; 
		if ( pEasyAudio != NULL ) 
		{ 
			if ( pEasyAudio->Init( hwnd ) == false ) 
			{ 
				delete pEasyAudio; 
				pEasyAudio = NULL; 
			} 
		} 
	} 
 
	return pEasyAudio; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void FreeEasyAudio() 
{ 
	SafeDelete( pEasyAudio ); 
} 
 
//*************************************************CEasyAudio**************************************************** 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
CEasyAudio::CEasyAudio() 
{ 
	m_pDS = NULL; 
	m_SoundVolume = 0; 
 
	m_pGraph = NULL; 
	m_pControl = NULL; 
	m_pPosition = NULL; 
	m_MusicVolume = 0; 
	m_interval = 60000; 
} 
 
CEasyAudio::~CEasyAudio() 
{ 
 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasyAudio::Init( HWND hwnd ) 
{ 
    LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL; 
 
	//创建DS8对象 
	if( FAILED( DirectSoundCreate8( NULL, &m_pDS, NULL ) ) ) 
		return false; 
 
	//设置协调级别 
	if( FAILED( m_pDS->SetCooperativeLevel( hwnd, DSSCL_NORMAL ) ) ) 
		return false; 
 
	if ( FAILED( CoInitialize(NULL) ) ) 
		return false; 
 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasyAudio::Free() 
{ 
	m_SoundList.Clear(); 
	SafeRelease( m_pDS ); 
	SafeRelease( m_pPosition ); 
	SafeRelease( m_pControl ); 
	SafeRelease( m_pGraph ); 
	CoUninitialize(); 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
PEASYSOUND CEasyAudio::CreateSoundBuffer( char *file, bool isFromFile, int numBuffer ) 
{ 
	PEASYSOUND pES = m_SoundList.CreateOneNode(); 
	assert( pES != NULL ); 
	bool re; 
	if ( isFromFile ) 
	{ 
		re = pES->LoadWAV( file, numBuffer ); 
	} 
	else 
	{ 
		re = pES->LoadWAVFromMemory( file, numBuffer ); 
	} 
 
	if ( re == false ) 
	{ 
		m_SoundList.Delete( pES ); 
		pES = NULL; 
	} 
	return pES; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasyAudio::DeleteSoundBuffer( PEASYSOUND pES ) 
{ 
	m_SoundList.Delete( pES ); 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasyAudio::ChangeSoundVolume( int changeValue ) 
{ 
	m_SoundVolume += changeValue; 
	if ( m_SoundVolume >= DSBVOLUME_MIN && m_SoundVolume <= DSBVOLUME_MAX ) 
	{ 
		CList::Iterator it; 
		for ( it = m_SoundList.Begin(); it != m_SoundList.End(); ++it ) 
			(*it).SetVolume( m_SoundVolume ); 
	} 
	else 
		m_SoundVolume -= changeValue; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasyAudio::PlayMP3( char *filename ) 
{ 
	SafeRelease( m_pPosition ); 
	SafeRelease( m_pControl ); 
	SafeRelease( m_pGraph ); 
 
	HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph); 
	if ( FAILED( hr ) ) 
		return false; 
 
	hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl); 
	if ( FAILED( hr ) ) 
		return false; 
 
	hr = m_pGraph->QueryInterface(IID_IMediaPosition, (void **)&m_pPosition); 
	if ( FAILED( hr ) ) 
		return false; 
 
	WCHAR wName[MAX_PATH]; 
	MultiByteToWideChar( CP_ACP, 0, filename, -1, wName, MAX_PATH ); 
	if ( m_pGraph->RenderFile( wName, NULL ) != S_OK ) 
		return false; 
 
	IBasicAudio *pBA = NULL; 
	m_pGraph->QueryInterface( IID_IBasicAudio, (void **)&pBA );  
	 
	if ( pBA != NULL ) 
	{ 
		pBA->put_Volume( m_MusicVolume ); 
		pBA->Release(); 
	} 
	else 
		return false; 
 
	if ( m_pControl != NULL ) 
	{ 
		m_pControl->Run(); 
	} 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasyAudio::ChangeMusicVolume( int v ) 
{ 
	m_MusicVolume += v; 
	if ( m_MusicVolume >= DSBVOLUME_MIN && m_MusicVolume <= DSBVOLUME_MAX ) 
	{ 
		IBasicAudio *pBA = NULL; 
		if ( m_pGraph != NULL ) 
		{ 
			m_pGraph->QueryInterface( IID_IBasicAudio, (void **)&pBA );  
 
			if ( pBA != NULL ) 
			{ 
				pBA->put_Volume( m_MusicVolume ); 
				pBA->Release(); 
			} 
		} 
	} 
	else 
		m_MusicVolume -= v; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasyAudio::UpdateMP3() 
{ 
	DWORD thisTick = timeGetTime(); 
	if ( thisTick - m_LastTick > m_interval ) 
	{ 
		m_LastTick = thisTick; 
		//FILTER_STATE state; 
		if ( m_pPosition != NULL ) 
		{ 
			REFTIME endTime, curTime; 
			m_pPosition->get_Duration( &endTime ); 
			m_pPosition->get_CurrentPosition( &curTime ); 
 
			if ( curTime >= endTime ) 
				m_pPosition->put_CurrentPosition( 0 ); 
		} 
	} 
} 
 
//*******************************************CEasySound**************************************************************** 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
CEasySound::CEasySound() 
{ 
	m_pDSBuffer = NULL; 
	m_NumBuffer = 0; 
	m_pData = NULL; 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
CEasySound::~CEasySound() 
{ 
	Free(); 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasySound::Init() 
{ 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasySound::Free() 
{ 
	for ( int i = 0; i < m_NumBuffer; ++i ) 
	{ 
		SafeRelease( m_pDSBuffer[i] ); 
	} 
	m_NumBuffer = 0; 
	SafeDeleteArray( m_pDSBuffer ); 
	SafeDeleteArray( m_pData ); 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasySound::LoadWAV( char *filename, int numBuffer ) 
{ 
	Free(); 
 
	m_pDSBuffer = new LPDIRECTSOUNDBUFFER[numBuffer];	//分配数组 
	assert( m_pDSBuffer != NULL ); 
 
	FILE *fp = fopen( filename, "rb" );				// open file 
	if ( fp == NULL ) 
		return false; 
 
	WAV_FILE_HEADER wfh; 
	fread( &wfh, sizeof(wfh), 1, fp );				// read file header 
	 
	if ( memcmp( wfh.RiffID, "RIFF", 4 ) || 
		 memcmp( wfh.WaveID, "WAVE", 4 ) || 
		 memcmp( wfh.FormatID, "fmt ", 4 ) || 
		 memcmp( wfh.DataID, "data", 4 )	)		//检查是否为WAV文件 
	{ 
		fclose(fp); 
		debug_assert(false); 
		return false; 
	} 
 
	WAVEFORMATEX wf;								//填写声音格式结构 
	memset( &wf, 0, sizeof(wf) ); 
	wf.wFormatTag	= WAVE_FORMAT_PCM; 
	wf.nChannels	= wfh.Channels;					//声道 
	wf.nSamplesPerSec=wfh.SampleRate;				//播放频率 
	wf.wBitsPerSample=wfh.BitsPerSample;			//位数 
	wf.nBlockAlign	= ( wf.wBitsPerSample / 8 ) * wf.nChannels; 
	wf.nAvgBytesPerSec=wf.nSamplesPerSec * wf.nBlockAlign; 
 
	if ( wfh.DataSize > 4 * wf.nAvgBytesPerSec ) 
	{ 
		fclose(fp); 
		MessageBox( NULL, "file too large", NULL, MB_OK ); 
		Free(); 
		return false; 
	} 
 
	DSBUFFERDESC dsbd; 
	memset( &dsbd, 0, sizeof(dsbd) ); 
	dsbd.dwSize		= sizeof(dsbd); 
	dsbd.dwFlags	= DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_STATIC; 
	dsbd.dwBufferBytes = wfh.DataSize; 
	dsbd.lpwfxFormat= &wf; 
 
	if ( pEasyAudio->GetLPDS()->CreateSoundBuffer( &dsbd, &m_pDSBuffer[0], NULL ) != DS_OK ) 
	{ 
		fclose(fp); 
		assert(false); 
		return false; 
	} 
 
	m_pData = new unsigned char[wfh.DataSize]; 
	m_DataSize = wfh.DataSize; 
	assert( m_pData != NULL ); 
	fread( m_pData, wfh.DataSize, 1, fp ); 
	fclose(fp); 
 
	for ( int i = 1; i < numBuffer; ++i ) 
	{ 
		if ( pEasyAudio->GetLPDS()->DuplicateSoundBuffer( m_pDSBuffer[0], &m_pDSBuffer[i] ) != DS_OK ) 
			assert(false); 
	} 
	m_NumBuffer = numBuffer; 
 
	for ( i = 0; i < numBuffer; ++i ) 
	{ 
		if ( FillBuffer( m_pDSBuffer[i] ) == false ) 
			assert(false); 
	} 
 
	SetVolume( pEasyAudio->GetSoundVolume() ); 
 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasySound::LoadWAVFromMemory( char *filename, int numBuffer ) 
{ 
	Free(); 
 
	char *buf = filename; 
	m_pDSBuffer = new LPDIRECTSOUNDBUFFER[numBuffer];	//分配数组 
	assert( m_pDSBuffer != NULL ); 
	m_NumBuffer = numBuffer; 
 
	if ( buf == NULL ) 
		return false; 
 
	WAV_FILE_HEADER wfh; 
	wfh = READ_MEMORY( buf, WAV_FILE_HEADER );		// read file header 
	buf += sizeof(WAV_FILE_HEADER); 
	 
	if ( memcmp( wfh.RiffID, "RIFF", 4 ) || 
		 memcmp( wfh.WaveID, "WAVE", 4 ) || 
		 memcmp( wfh.FormatID, "fmt ", 4 ) || 
		 memcmp( wfh.DataID, "data", 4 )	)		//检查是否为WAV文件 
	{ 
		debug_assert(false); 
		return false; 
	} 
 
	WAVEFORMATEX wf;								//填写声音格式结构 
	memset( &wf, 0, sizeof(wf) ); 
	wf.wFormatTag	= WAVE_FORMAT_PCM; 
	wf.nChannels	= wfh.Channels;					//声道 
	wf.nSamplesPerSec=wfh.SampleRate;				//播放频率 
	wf.wBitsPerSample=wfh.BitsPerSample;			//位数 
	wf.nBlockAlign	= ( wf.wBitsPerSample / 8 ) * wf.nChannels; 
	wf.nAvgBytesPerSec=wf.nSamplesPerSec * wf.nBlockAlign; 
 
	DSBUFFERDESC dsbd; 
	memset( &dsbd, 0, sizeof(dsbd) ); 
	dsbd.dwSize		= sizeof(dsbd); 
	dsbd.dwFlags	= DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC; 
	dsbd.dwBufferBytes = wfh.DataSize; 
	dsbd.lpwfxFormat= &wf; 
 
	if ( pEasyAudio->GetLPDS()->CreateSoundBuffer( &dsbd, &m_pDSBuffer[0], NULL ) != DS_OK ) 
	{ 
		assert(false); 
		return false; 
	} 
 
	m_pData = new unsigned char[wfh.DataSize]; 
	m_DataSize = wfh.DataSize; 
	assert( m_pData != NULL ); 
	memcpy( m_pData, buf, wfh.DataSize ); 
 
	for ( int i = 1; i < numBuffer; ++i ) 
	{ 
		if ( pEasyAudio->GetLPDS()->DuplicateSoundBuffer( m_pDSBuffer[0], &m_pDSBuffer[i] ) != DS_OK ) 
			assert(false); 
	} 
 
	for ( i = 0; i < numBuffer; ++i ) 
	{ 
		if ( FillBuffer( m_pDSBuffer[i] ) == false ) 
			assert(false); 
	} 
 
	SetVolume( pEasyAudio->GetSoundVolume() ); 
 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
bool CEasySound::FillBuffer( LPDIRECTSOUNDBUFFER buf ) 
{ 
	void *ptr1 = NULL; 
	void *ptr2 = NULL; 
	unsigned long size1, size2; 
	if ( buf->Lock( 0, m_DataSize, &ptr1, &size1, &ptr2, &size2, 0 ) != DS_OK ) 
		return false; 
 
	memcpy( ptr1, m_pData, size1 ); 
	if ( ptr2 != NULL ) 
		memcpy( ptr2, &m_pData[size1], size2 ); 
 
	buf->Unlock( ptr1, size1, ptr2, size2 ); 
	return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasySound::Play() 
{ 
	unsigned long status; 
	LPDIRECTSOUNDBUFFER pDSB = NULL; 
 
	for ( int i = 0; i < m_NumBuffer; ++i ) 
	{ 
		status = 0; 
		m_pDSBuffer[i]->GetStatus( &status ); 
		if ( (status & DSBSTATUS_PLAYING) == 0 ) 
		{ 
			pDSB = m_pDSBuffer[i]; 
			break; 
		} 
	} 
 
	if ( pDSB != NULL ) 
	{ 
		if ( status & DSBSTATUS_BUFFERLOST ) 
		{ 
			if ( pDSB->Restore() == DS_OK ) 
			{ 
				FillBuffer( pDSB ); 
			} 
			else 
				return; 
		} 
 
		pDSB->SetCurrentPosition( 0 ); 
		pDSB->Play( 0, 0, 0 ); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasySound::Stop() 
{ 
	for ( int i = 0; i < m_NumBuffer; ++i ) 
	{ 
		m_pDSBuffer[i]->Stop(); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CEasySound::SetVolume( long v ) 
{ 
	for ( int i = 0; i < m_NumBuffer; ++i ) 
	{ 
		m_pDSBuffer[i]->SetVolume(v); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
int CEasySound::GetCurPos() 
{ 
	unsigned long curPos = 0; 
	if ( m_pDSBuffer ) 
	{ 
		m_pDSBuffer[0]->GetCurrentPosition( &curPos, 0 ); 
		debug_assert( curPos < m_DataSize ); 
	} 
	return curPos; 
}