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; }