C++编程:XAudio2_API应用示例.docx_第1页
C++编程:XAudio2_API应用示例.docx_第2页
C++编程:XAudio2_API应用示例.docx_第3页
C++编程:XAudio2_API应用示例.docx_第4页
C++编程:XAudio2_API应用示例.docx_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C+编程:XAudio2 API应用示例作者:LuoJun 声明:此文档未引用任何书籍期刊,无版权问题,可随意转载更新日期:2012/8/31XAudio2是一个跨平台的API,在Xbox 360及Windows中得到支持。在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中。在Windows上,XAudio2提供一个动态链接库(DLL)。以下例子只使用了其中的一部分功能,并不全面。详情请看微软技术页的XAudio2编程相关(英文)。使用XAudio2来播放未压缩的PCM音频数据的过程并不复杂,主要有以下几个步骤:1. 建立XAudio2 引擎使用XAudio2Create函数,该函数的功能是创建一个XAudio2对象(IXAudio2接口)。原型:HRESULT XAudio2Create(IXAudio2 *ppXAudio2,/这里返回XAudio2对象的指针UINT32 Flags,/此处必须为0 XAUDIO2_PROCESSOR XAudio2Processor/指定所用CPU,默认:XAUDIO2_DEFAULT_PROCESSOR);示例:XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR );2. 使用第1步建立的引擎建立MasteringVoice使用IXAudio2成员函数CreateMasteringVoice,该函数功能是创建并设置一个MasteringVoice原型:HRESULT CreateMasteringVoice(IXAudio2MasteringVoice *ppMasteringVoice,/这里返回MasteringVoice对象指针UINT32 InputChannels = XAUDIO2_DEFAULT_CHANNELS,/设置声道数,可选UINT32 InputSampleRate = XAUDIO2_DEFAULT_SAMPLERATE, /设置采样率,可选UINT32 Flags = 0,/必须是0,可选LPCWSTR szDeviceId = NULL, /设备,可选,NULL代表全局默认输出设备const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL, /音效,可选AUDIO_STREAM_CATEGORY StreamCategory = AudioCategory_GameEffects/流类型,可选);示例:pXAudio2-CreateMasteringVoice(&pMasterVoice);3. 使用第一步建立的引擎建立SourceVoice(或SubmixVoice,以下按SourceVoice举例)使用IXAudio2成员函数CreateSourceVoice,该函数功能是创建并设置一个SourceVoice原型:HRESULT CreateSourceVoice(IXAudio2SourceVoice *ppSourceVoice, /这里返回IXAudio2SourceVoice对象指针const WAVEFORMATEX *pSourceFormat, /PCM音频格式(下面讲到)UINT32 Flags = 0,/SourceVoide工作方式,可选float MaxFrequencyRatio = XAUDIO2_DEFAULT_FREQ_RATIO,/声调,可选,默认为1IXAudio2VoiceCallback *pCallback = NULL,/回调类指针,可选const XAUDIO2_VOICE_SENDS *pSendList = NULL,/目标格式设置,可选const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL/音效设置,可选);示例:pXAudio2-CreateSourceVoice(&pSourceVoice,&format,0,XAUDIO2_DEFAULT_FREQ_RATIO,NULL,NULL,NULL);其中format这样设置:(位数为bits,声道数为channels,采样率为hz)WAVEFORMATEX format;format.wFormatTag = WAVE_FORMAT_PCM;/PCM格式format.wBitsPerSample = bits;/位数format.nChannels = channels;/声道数format.nSamplesPerSec = hz;/采样率format.nBlockAlign = bits*channels/8;/数据块调整format.nAvgBytesPerSec = format.nBlockAlign*hz;/平均传输速率format.cbSize = 0;/附加信息4. 呈交音频数据使用IXAudio2SourceVoice的成员函数SubmitSourceBuffer,该函数功能是呈交一个XAUDIO2_BUFFER原型:HRESULT SubmitSourceBuffer(const XAUDIO2_BUFFER *pBuffer,/ 结构体XAUDIO2_BUFFER的指针(下面讲到)const XAUDIO2_BUFFER_WMA *pBufferWMA = NULL/wma格式Buffer的指针,可选,默认NULL);示例:pSourceVoice-SubmitSourceBuffer(&XAudio2Buffer,NULL);其中XAudio2Buffer这样设置:XAUDIO2_BUFFER XAudio2Buffer;XAudio2Buffer.Flags = 0;/可以设为0或XAUDIO2_END_OF_STREAM,当设为后者时,将使XAudio2播放完该数据块后自动停止,不再播放下一个数据块XAudio2Buffer.AudioBytes = BufferSize;/ 音频数据的长度,按字节算XAudio2Buffer.pAudioData = pBuffer;/具体音频数据的地址,unsigned char pBufferXAudio2Buffer.PlayBegin = 0;/起始播放地址XAudio2Buffer.PlayLength = 0;/播放长度,0为整数据块XAudio2Buffer.LoopBegin = 0;/循环起始位置XAudio2Buffer.LoopLength = 0;/循环长度,按字节算XAudio2Buffer.LoopCount = 0;/循环次数,0为不循环,255为无限循环XAudio2Buffer.pContext = NULL;/这里的pContext用来标识该数据块,供回调用,可以是NULL5. 继续呈交数据和播放数据:播放呈交的数据使用IXAudio2SourceVoice的成员函数Start,该函数功能是开始播放。原型:HRESULT Start(UINT32 Flags,/必须是0UINT32 OperationSet = XAUDIO2_COMMIT_NOW/使用XAUDIO2_COMMIT_NOW将立即生效,使用XAUDIO2_COMMIT_ALL将挂起,等待其它的数值的OperationSet的处理完);示例:pSourceVoice-Start(0, XAUDIO2_COMMIT_NOW);第5步做完之后,XAudio2将一块接一块地播放呈交的数据块。我们只需不断重复第四步,就能不断地播放音频数据了。需要注意的是,在XAudio2播放完某个XAudio2Buffer之前,该XAudio2Buffer以及XAudio2Buffer.pAudioData所指向的内存不能被修改或删除,否则将发生错误。但是某个XAudio2Buffer一旦被播放完,就能被修改了。为此,我们可以创建一个数组XAUDIO2_BUFFER 来循环呈交和更新数据。那怎么知道XAudio2到底播放了几个XAudio2Buffer呢,可以使用IXAudio2SourceVoice的成员函数GetState原型:GetState(XAUDIO2_VOICE_STATE *pVoiceState,/ 这里返回XAUDIO2_VOICE_STATE结构体指针optional UINT32 Flags/获取方式,可选,默认0.设为XAUDIO2_VOICE_NOSAMPLESPLAYED将只获取挂起(包括正在播放)的XAudio2Buffer数量,速度较快。注意:DirectX SDK版本没有此参数);XAUDIO2_VOICE_STATE包含三个成员:void * pCurrentBufferContext/对应XAUDIO2_BUFFER中的pContextUINT32 BuffersQueued/挂起(包括正在播放)的XAudio2Buffer数量UINT64 SamplesPlayed/已播放的样本数示例: pSourceVoice-GetState(&state);6. 暂停和停止播放暂停播放使用IXAudio2SourceVoice的成员函数:Stop原型:HRESULT Stop(UINT32 Flags,/ 设为0或XAUDIO2_PLAY_TAILS,后者代表等待音效放完UINT32 OperationSet = XAUDIO2_COMMIT_NOW/ XAUDIO2_COMMIT_NOW立即生效);如果设定XAUDIO2_PLAY_TAILS,应在音效输出完成后设定0,再Stop一次。暂停后再次调用Start将在暂停的位置开始播放。如果要完全停止,还需要使用IXAudio2SourceVoice的成员函数FlushSourceBuffers,该函数功能是清除挂起的XAudio2Buffer队列。原型:HRESULT FlushSourceBuffers();说明:该函数使用后要到XAudio2播放完一个XAudio2Buffer才生效,建议在回调中使用。使用该函数后,XAudio2Buffer队列计数将置07. IXAudio2SourceVoice的其他功能:设置声调使用SetFrequencyRatio函数原型:HRESULT SetFrequencyRatio(float Ratio,/1.0为正常声调,1.0为高声调快放,1.0为低声调慢放UINT32 OperationSet = XAUDIO2_COMMIT_NOW);IXAudio2SourceVoice继承自IXAudio2Voice,所以还有许多IXAudio2Voice的功能,比如设置音量用SetVolume等。注意:以上IXAudio2SourceVoice的成员函数中, Stop、GetState、 FlushSourceBuffers可以在回调中使用释放相关实例的顺序与创建他们的顺序相反。需要包含头文件Xaudio2.h和Objbase.h以及链接ole32.lib(而不是Microsoft网站上的Xaudio2.lib)下面给出我写的一个Speaker类供大家参考,该类使用XAudio2来播放PCM数据,在Win7x64系统中使用VS2010、DirectX SDK按x64、/clr(Speaker中没有使用托管类)编译测试通过其公开成员函数ReadData采用阻塞的方法来读取音频数据,一旦塞满缓冲区将自动开始播放,播放多少就读取多少,SetFormat设置PCM音频格式(不设置的话,默认是16位、2声道、44100采样率)。SetBufferSize设置缓冲块数和每块大小(不设置的话,默认是4块,每块40KB)#include #include #include Objbase.h#pragma comment(lib,Ole32.lib)#define DEF_MaxBufferCount4#define DEF_StreamingBufferSize40960class VoiceCallBack;class Speaker;class VoiceCallBack:public IXAudio2VoiceCallback/回调类public:HANDLE hBufferEndEvent; VoiceCallBack():hBufferEndEvent(CreateEvent(NULL,FALSE,FALSE,NULL)count =lastcontext = currentcontext= 0; VoiceCallBack()CloseHandle(hBufferEndEvent); Speaker *speaker; XAUDIO2_VOICE_STATE state;public:int count; int lastcontext; int currentcontext; /播放一个数据块前后触发事件 void OnBufferEnd(void *pBufferContext); /不需要的方法只保留声明 void OnBufferStart(void *pBufferContext) void OnVoiceProcessingPassEnd() void OnVoiceProcessingPassStart(UINT32 SamplesRequired) void OnStreamEnd() void OnLoopEnd(void *pBufferContext) void OnVoiceError(void *pBufferContext,HRESULT Error);class Speakerpublic:/XAudio2数据IXAudio2* pXAudio2;/XAudio2引擎IXAudio2MasteringVoice* pMasterVoice;/MsterVoiceVoiceCallBack voiceCallBack;/回调处理XAUDIO2_BUFFER *pXAudio2Buffer;/封装的用来呈交的音频缓冲数据块WAVEFORMATEX WaveFormat;/音频格式IXAudio2SourceVoice *pSourceVoice;/源音处理接口int MaxBufferCount;/最大缓冲数据块数int StreamingBufferSize;/缓冲数据块大小unsigned char *ppAudioData;/音频缓冲数据bool IsPlaying;/是否在播放HRESULT State;/状态,0为正常,0为信息或警告const wchar_t *pState;/状态内容详细描述/跟外部读取交换数据int ReadingBufferNumber;/正在读取的Bufferint WritingBufferNumber;/正在写入的Bufferint UnReadBufferCount;/未呈交Buffer数量int UnProcessedBufferCount;/呈交但未处理的Buffer数量int WritingPosition;/当前块准备写入位置/控制函数部分public:Speaker();/默认构造函数public:Speaker();/析构函数private:void reset();/重置交换数据参数private:HRESULT SetState(HRESULT state);/设置简单的状态信息public:void StopPlaying();/停止播放public:void Pause();/暂停public:void StartPlaying();/开始播放public:void SetFormat(short bits,short channels,int hz);/更改PCM格式public:void SetBufferSize(int MaxBufferCount,int StreamingBufferSize);/分配音频数据缓冲区public:static XAUDIO2_BUFFER MakeXAudio2Buffer(const BYTE *pBuffer,int BufferSize);/生成XAudio2缓冲区public:static WAVEFORMATEX MakePCMSourceFormat(short bits,short channels,int hz);/生成PCM格式信息public:void ReadData(unsigned char *pBuffer,int length);/从pBuffer指向的内存复制length字节的数据到缓冲区,不复制完不返回public:int ReadDataFrom(unsigned char *pBuffer,int length);/从pBuffer指向的内存复制length字节的数据,立即返回实际复制的数据字节数;void VoiceCallBack:OnBufferEnd(void *pBufferContext)if(pBufferContext = NULL)speaker-pSourceVoice-GetState(&state);speaker-UnProcessedBufferCount=state.BuffersQueued;elsecurrentcontext = *(int *) pBufferContext)+1;if(currentcontext lastcontext)count += currentcontext - lastcontext;else if(currentcontext MaxBufferCount + currentcontext - lastcontext;lastcontext = currentcontext;speaker-UnProcessedBufferCount -= count;count = 0;while(speaker-UnReadBufferCount & ( speaker-UnReadBufferCount1 | speaker-UnProcessedBufferCount+speaker-UnReadBufferCount+1 MaxBufferCount)/提交,但保留一块缓冲区,以免冲突speaker-pSourceVoice-SubmitSourceBuffer(&speaker-pXAudio2Bufferspeaker-ReadingBufferNumber,NULL);speaker-ReadingBufferNumber = (1 + speaker-ReadingBufferNumber) % speaker-MaxBufferCount;speaker-UnProcessedBufferCount+;speaker-UnReadBufferCount -;SetEvent(hBufferEndEvent); Speaker:Speaker()/初始化IsPlaying = false;MaxBufferCount = 0;StreamingBufferSize = 0;voiceCallBack.speaker = this;reset();/建立引擎if(FAILED(SetState(XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR )goto END;/建立MasteringVoiceif(FAILED(SetState(pXAudio2-CreateMasteringVoice(&pMasterVoice)goto END;/分配缓冲内存并设置XAudio2BufferSetBufferSize(DEF_MaxBufferCount,DEF_StreamingBufferSize);/设置默认缓冲/设置pcm格式WaveFormat = Speaker:MakePCMSourceFormat(16,2,44100);/建立SourceVoiceSetState(pXAudio2-CreateSourceVoice(&this-pSourceVoice,&this-WaveFormat,0,XAUDIO2_DEFAULT_FREQ_RATIO,&this-voiceCallBack,NULL,NULL);END:;Speaker:Speaker()SetBufferSize(0,0);/停止播放并释放缓冲区if(pSourceVoice != NULL)pSourceVoice-DestroyVoice();if(pMasterVoice != NULL)pMasterVoice-DestroyVoice();if(pXAudio2 != NULL)pXAudio2-StopEngine();void Speaker:reset()SetState(0);ReadingBufferNumber = 0;UnReadBufferCount = 0;UnProcessedBufferCount = 0;WritingBufferNumber = 0;WritingPosition = 0;voiceCallBack.count = 0;voiceCallBack.lastcontext = 0;void Speaker:StopPlaying()if(pSourceVoice = NULL)return;XAUDIO2_VOICE_STATE state;if(IsPlaying)IsPlaying = false;pSourceVoice-GetState(&state);while(state.BuffersQueued)if(FAILED(SetState(pSourceVoice-Stop(0,XAUDIO2_COMMIT_NOW)return;if(FAILED(SetState(pSourceVoice-FlushSourceBuffers()return;Sleep(1);pSourceVoice-GetState(&state);reset();void Speaker:Pause()if(pSourceVoice = NULL)return;if(IsPlaying)SetState(pSourceVoice-Stop(0,XAUDIO2_COMMIT_NOW);if(FAILED(State)return;IsPlaying = false;void Speaker:StartPlaying()SetState(pSourceVoice-Start(0,XAUDIO2_COMMIT_NOW);if(FAILED(State)return;this-IsPlaying = true;void Speaker:SetFormat(short bits,short channels,int hz)if(WaveFormat.wBitsPerSample = bits & WaveFormat.nChannels = channels & WaveFormat.nSamplesPerSec = hz)return;StopPlaying();if(pSourceVoice)pSourceVoice-DestroyVoice();pSourceVoice = NULL;WaveFormat = MakePCMSourceFormat(bits,channels,hz);if(FAILED(SetState(pXAudio2-CreateSourceVoice(&pSourceVoice,&WaveFormat,0,XAUDIO2_DEFAULT_FREQ_RATIO,&this-voiceCallBack,NULL,NULL)pSourceVoice = NULL;void Speaker:SetBufferSize(int MaxBufferCount,int StreamingBufferSize)if (this-MaxBufferCount!=MaxBufferCount | this-StreamingBufferSize!=StreamingBufferSize)this-StopPlaying();for(int i=0;iMaxBufferCount;+i)if(this-StreamingBufferSize)/删除块delete this-ppAudioDatai;if(this-pXAudio2Bufferi.pContext)delete this-pXAudio2Bufferi.pContext;if(this-MaxBufferCount)/删除所有delete this-ppAudioData;delete this-pXAudio2Buffer;this-MaxBufferCount=MaxBufferCount;/赋值this-StreamingBufferSize=StreamingBufferSize;voiceCallBack.lastcontext = 0;if(MaxBufferCount)/创建reset();this-ppAudioData = new unsigned char *MaxBufferCount;this-pXAudio2Buffer = new XAUDIO2_BUFFERMaxBufferCount;if (StreamingBufferSize)this-pXAudio2Buffer = new XAUDIO2_BUFFERMaxBufferCount;for(int i=0;ippAudioDatai = new unsigned charStreamingBufferSize;this-pXAudio2Bufferi = Speaker:MakeXAudio2Buffer(ppAudioDatai,StreamingBufferSize);*(int*)this-pXAudio2Bufferi.pContext) = i;XAUDIO2_BUFFER Speaker:MakeXAudio2Buffer(const BYTE *pBuffer,int BufferSize)XAUDIO2_BUFFER XAudio2Buffer;XAudio2Buffer.AudioBytes = BufferSize;XAudio2Buffer.Flags = 0;XAudio2Buffer.LoopBegin = 0;XAudio2Buffer.LoopCount = 0;XAudio2Buffer.LoopLength = 0;XAudio2Buffer.pAudioData = pBuffer;XAudio2Buffer.pContext = (void*)new int1;XAudio2Buffer.PlayBegin = 0;XAudio2Buffer.PlayLength = 0;return XAudio2Buffer;WAVEFORMATEX Speaker:MakePCMSourceFormat(short bits,short channels,int hz)WAVEFORMATEX format;format.wFormatTag = WAVE_FORMAT_PCM;/PCM格式format.wBitsPerSample = bits;/位数format.nChannels = channels;/声道数format.nSamplesPerSec = hz;/采样率format.nBlockAlign = bits*channels/8;/数据块调整format.nAvgBytesPerSec = format.nBlockAlign*hz;/平均传输速率format.cbSize = 0;/附加信息return format;void Speaker:ReadData(unsigned char *pBuffer,int length)int i=0;while(lengthi)/不读完不退出循环while(UnProcessedBufferCount + UnReadBufferCount = MaxBufferCount)if(!IsPlaying)StartPlaying();Sleep(0);continue;voiceCallBack.OnBufferEnd(NULL);Sleep(10);if(StreamingBufferSize length-i+WritingPosition)while(ippAudioDataWritingBufferNumberWritingPosition = pBufferi;+Wri

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论