有时候一个音频特效需要多次播放,比如一个连击动作的声效。
1.当然你可以多次打开文件,读取内容然后播放;
2.也可以打开文件,读取一次到内存,创建多个XAUDIO2_BUFFER,提交多次进行播放;
3.最好的方法是使用XAUDIO2_BUFFER的Loop功能来进行播放,只需要读取一次文件,创建一个XAUDIO2_BUFFER,提交一次,就可以实现播放多次的需求。
对于多次打开文件这种方法,一般是不会采用的,读写操作,解析文件,申请内存等都耗时间,可能会导致声效不及时,出现错觉。
对于第二种方法,可以采用,但是要多次创建XAUDIO2_BUFFER,多次提交,多次等待,也有不少缺点,但是也算可行。需要注意的是,回调实现的方法是void OnBufferEnd(void * pBufferContext) { SetEvent(hBufferEndEvent); }
下面是实现方法:
#pragma once #include "WaveFile.h" #include "XAudio2.h" class VoiceCallback : public IXAudio2VoiceCallback { public: HANDLE hBufferEndEvent; VoiceCallback() : hBufferEndEvent(CreateEvent(NULL, FALSE, FALSE, NULL)){} ~VoiceCallback(){ CloseHandle(hBufferEndEvent); } //Called when the voice has just finished playing a contiguous audio stream. void OnStreamEnd() { /*SetEvent(hBufferEndEvent);*/ } //Unused methods are stubs void OnVoiceProcessingPassEnd() { } void OnVoiceProcessingPassStart(UINT32 SamplesRequired) { } void OnBufferEnd(void * pBufferContext) { SetEvent(hBufferEndEvent); } void OnBufferStart(void * pBufferContext) { } void OnLoopEnd(void * pBufferContext) { /*SetEvent(hBufferEndEvent);*/ } void OnVoiceError(void * pBufferContext, HRESULT Error) { } }; int main(int argc, char *argv[]) { HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);;//com初始化 if (FAILED(hr)) return 0; IXAudio2 *pEngine = NULL; hr = XAudio2Create(&pEngine);//创建引擎 if (FAILED(hr)) return 0; IXAudio2MasteringVoice *pMasterVoice = NULL; hr = pEngine->CreateMasteringVoice(&pMasterVoice);//创建主声音,默认是输出当前扬声器 if (FAILED(hr)) return 0; CWaveFile waveFile; hr = waveFile.Open(L"F:\\桌面\\TestSong.wav", NULL, WAVEFILE_READ);//加载文件 if (FAILED(hr)) return 0; WAVEFORMATEX *waveFormat = waveFile.GetFormat();//获取文件格式 VoiceCallback pCallBack; IXAudio2SourceVoice *pSourceVoice = NULL; hr = pEngine->CreateSourceVoice(&pSourceVoice, waveFormat, 0, 1.0f, &pCallBack);//创建源声音,用来提交数据 if (FAILED(hr)) return 0; DWORD size = waveFile.GetSize();//获取文件的大小 BYTE *pData = new BYTE[size];//申请内存空间,用于保存数据 hr = waveFile.Read(pData, size, &size);//读取文件内容 if (FAILED(hr)) return 0; XAUDIO2_BUFFER buffer = {0};//将读取的文件数据,赋值XAUDIO2_BUFFER buffer.AudioBytes = size; buffer.pAudioData = pData; hr = pSourceVoice->SubmitSourceBuffer(&buffer);//提交内存数据 if (FAILED(hr)) return 0; XAUDIO2_BUFFER buffer1 = { 0 };//将读取的文件数据,赋值XAUDIO2_BUFFER buffer1.AudioBytes = size; buffer1.pAudioData = pData; hr = pSourceVoice->SubmitSourceBuffer(&buffer1);//提交内存数据 if (FAILED(hr)) return 0; XAUDIO2_BUFFER buffer2 = { 0 };//将读取的文件数据,赋值XAUDIO2_BUFFER buffer2.AudioBytes = size; buffer2.pAudioData = pData; hr = pSourceVoice->SubmitSourceBuffer(&buffer2);//提交内存数据 if (FAILED(hr)) return 0; hr = pSourceVoice->Start(0);//启动源声音 if (FAILED(hr)) return 0; XAUDIO2_VOICE_STATE state; pSourceVoice->GetState(&state);//获取状态 while (state.BuffersQueued > /*XAUDIO2_MAX_QUEUED_BUFFERS - 1*/0) { WaitForSingleObject(pCallBack.hBufferEndEvent, INFINITE); pSourceVoice->GetState(&state); } pMasterVoice->DestroyVoice();//释放资源 pSourceVoice->DestroyVoice();//释放资源 pEngine->Release();//释放资源 CoUninitialize();//释放资源 delete []pData;//释放资源 pData = NULL; return 0; }源码下载:http://download.csdn.net/detail/u011417605/9481804
对于第三种方法,这是最好的方式了,使用XAUDIO2_BUFFER的Loop功能来进行播放,只需要读取一次文件,创建一个XAUDIO2_BUFFER,提交一次,就可以实现播放多次的需求。
// Used in IXAudio2SourceVoice::SubmitSourceBuffer typedef struct XAUDIO2_BUFFER { UINT32 Flags; // Either 0 or XAUDIO2_END_OF_STREAM. UINT32 AudioBytes; // Size of the audio data buffer in bytes. const BYTE* pAudioData; // Pointer to the audio data buffer. UINT32 PlayBegin; // First sample in this buffer to be played. UINT32 PlayLength; // Length of the region to be played in samples, // or 0 to play the whole buffer. UINT32 LoopBegin; // First sample of the region to be looped. UINT32 LoopLength; // Length of the desired loop region in samples, // or 0 to loop the entire buffer. UINT32 LoopCount; // Number of times to repeat the loop region, // or XAUDIO2_LOOP_INFINITE to loop forever. void* pContext; // Context value to be passed back in callbacks. } XAUDIO2_BUFFER;需要注意的是,回调实现的是:
void OnStreamEnd() { SetEvent(hBufferEndEvent); }
然后,XAUDIO2_BUFFER的标志位需要设置buffer.Flags = XAUDIO2_END_OF_STREAM;
下面是实现:
#pragma once #include "WaveFile.h" #include "XAudio2.h" class VoiceCallback : public IXAudio2VoiceCallback { public: HANDLE hBufferEndEvent; VoiceCallback() : hBufferEndEvent(CreateEvent(NULL, FALSE, FALSE, NULL)){} ~VoiceCallback(){ CloseHandle(hBufferEndEvent); } //Called when the voice has just finished playing a contiguous audio stream. void OnStreamEnd() { SetEvent(hBufferEndEvent); } //Unused methods are stubs void OnVoiceProcessingPassEnd() { } void OnVoiceProcessingPassStart(UINT32 SamplesRequired) { } void OnBufferEnd(void * pBufferContext) { /*SetEvent(hBufferEndEvent);*/ } void OnBufferStart(void * pBufferContext) { } void OnLoopEnd(void * pBufferContext) { /*SetEvent(hBufferEndEvent);*/ } void OnVoiceError(void * pBufferContext, HRESULT Error) { } }; int main(int argc, char *argv[]) { HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);;//com初始化 if (FAILED(hr)) return 0; IXAudio2 *pEngine = NULL; hr = XAudio2Create(&pEngine);//创建引擎 if (FAILED(hr)) return 0; IXAudio2MasteringVoice *pMasterVoice = NULL; hr = pEngine->CreateMasteringVoice(&pMasterVoice);//创建主声音,默认是输出当前扬声器 if (FAILED(hr)) return 0; CWaveFile waveFile; hr = waveFile.Open(L"F:\\桌面\\TestSong.wav", NULL, WAVEFILE_READ);//加载文件 if (FAILED(hr)) return 0; WAVEFORMATEX *waveFormat = waveFile.GetFormat();//获取文件格式 VoiceCallback pCallBack; IXAudio2SourceVoice *pSourceVoice = NULL; hr = pEngine->CreateSourceVoice(&pSourceVoice, waveFormat, 0, 1.0f, &pCallBack);//创建源声音,用来提交数据 if (FAILED(hr)) return 0; DWORD size = waveFile.GetSize();//获取文件的大小 BYTE *pData = new BYTE[size];//申请内存空间,用于保存数据 hr = waveFile.Read(pData, size, &size);//读取文件内容 if (FAILED(hr)) return 0; XAUDIO2_BUFFER buffer = {0};//将读取的文件数据,赋值XAUDIO2_BUFFER buffer.AudioBytes = size; buffer.pAudioData = pData; buffer.LoopBegin = 0; buffer.LoopCount = 3; buffer.LoopLength = (double)size / waveFormat->nBlockAlign;//块对齐,数据的最小原子单位 buffer.PlayBegin = 0; buffer.PlayLength = (double)size / waveFormat->nBlockAlign; buffer.pContext = &pCallBack; buffer.Flags = XAUDIO2_END_OF_STREAM; hr = pSourceVoice->SubmitSourceBuffer(&buffer);//提交内存数据 if (FAILED(hr)) return 0; hr = pSourceVoice->Start(0);//启动源声音 if (FAILED(hr)) return 0; XAUDIO2_VOICE_STATE state; pSourceVoice->GetState(&state);//获取状态 while (state.BuffersQueued > /*XAUDIO2_MAX_QUEUED_BUFFERS - 1*/0) { WaitForSingleObject(pCallBack.hBufferEndEvent, INFINITE); pSourceVoice->GetState(&state); } pMasterVoice->DestroyVoice();//释放资源 pSourceVoice->DestroyVoice();//释放资源 pEngine->Release();//释放资源 CoUninitialize();//释放资源 delete []pData;//释放资源 pData = NULL; return 0; }
交流QQ:1245178753
源码下载:http://download.csdn.net/detail/u011417605/9481822本文地址:http://blog.csdn.net/u011417605/article/details/51066693