XAudio2

是一个跨平台的API,在Xbox 360及Windows中得到支持。在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中。在Windows上,XAudio2提供一个动态链接库(DLL)。以下例子只使用了其中的一部分功能,并不全面。详情请看微软技术页的XAudio2编程相关(英文)。 使用XAudio2来播放未压缩的PCM音频数据的过程并不复杂,主要有以下几个步骤:

1. 建立XAudio2 引擎

使用XAudio2Create函数,该函数的功能是创建一个XAudio2对象(IXAudio2接口)。

示例:XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR );

2. 使用第1步建立的引擎建立MasteringVoice

使用IXAudio2成员函数CreateMasteringVoice,该函数功能是创建并设置一个MasteringVoice 原型

示例:pXAudio2->CreateMasteringVoice(&pMasterVoice);

3. 使用第一步建立的引擎建立SourceVoice(或SubmixVoice,以下按SourceVoice举例) 使用IXAudio2成员函数CreateSourceVoice,该函数功能是创建并设置一个SourceVoice 原型

示例:

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 原型

示例: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 pBuffer[]

XAudio2Buffer.PlayBegin = 0;//起始播放地址

XAudio2Buffer.PlayLength = 0;//播放长度,0为整数据块

XAudio2Buffer.LoopBegin = 0;//循环起始位置

XAudio2Buffer.LoopLength = 0;//循环长度,按字节算

XAudio2Buffer.LoopCount = 0;//循环次数,0为不循环,255为无限循环

XAudio2Buffer.pContext = NULL;//这里的pContext用来标识该数据块,供回调用,可以是NULL

5. 继续呈交数据和播放数据:

播放呈交的数据使用IXAudio2SourceVoice的成员函数Start,该函数功能是开始播放。

原型:HRESULT Start(

UINT32 Flags,//必须是0

UINT32 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(

XAUDIO2_VOICE_STATE *pVoiceState,// 这里返回结构体指针

[optional] UINT32 Flags//获取方式,可选,默认0.设为XAUDIO2_VOICE_NOSAMPLESPLAYED将

只获取挂起(包括正在播放)的XAudio2Buffer数量,速度较快。注意:DirectX SDK版本没有此参数 );

XAUDIO2_VOICE_STATE包含三个成员:

void * pCurrentBufferContext//对应XAUDIO2_BUFFER中的pContext

UINT32 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队列计数将置0

7. IXAudio2SourceVoice的其他功能:设置声调使用SetFrequencyRatio函数

原型:HRESULT SetFrequencyRatio(

float Ratio,//1.0为正常声调,>1.0为高声调快放,<1.0为低声调慢放

UINT32 OperationSet = XAUDIO2_COMMIT_NOW

);

IXAudio2SourceVoice继承自,所以还有许多IXAudio2Voice的功能,比如设置音量用SetVolume等。

注意:以上IXAudio2SourceVoice的成员函数中, Stop、GetState、 FlushSourceBuffers可以在回调中使用 释放相关实例的顺序与创建他们的顺序相反。需要包含头文件Xaudio2.h和Objbase.h以及链接ole32.lib(而不是Microsoft网站上的Xaudio2.lib)

=============================================================================================================

以上摘抄

程序说明:

1、参考DirectX SDK 例程XAudio2BasicSound编写。

2、实现功能:验证XAduio2播放语音流程,实现播放二进制存储的PCM格式音频数据文件。

  1. // XAudio2_test.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <Windows.h>
  5. #include "XAudio2.h"
  6. //--------------------------------------------------------------------------------------
  7. // Helper macros
  8. //--------------------------------------------------------------------------------------
  9. #ifndef SAFE_DELETE_ARRAY
  10. #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
  11. #endif
  12. #ifndef SAFE_RELEASE
  13. #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
  14. #endif
  15. int main()
  16. {
  17. IXAudio2 *pXAudio2;//这里返回XAudio2对象的指针
  18. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  19. HRESULT hr;
  20. if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
  21. {
  22. wprintf(L"Failed to init XAudio2 engine: %#X\n", hr);
  23. CoUninitialize();
  24. return 0;
  25. }
  26. //
  27. // Create a mastering voice
  28. //
  29. IXAudio2MasteringVoice* pMasteringVoice = NULL;
  30. if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice)))
  31. {
  32. wprintf(L"Failed creating mastering voice: %#X\n", hr);
  33. SAFE_RELEASE(pXAudio2);
  34. CoUninitialize();
  35. return 0;
  36. }
  37. WAVEFORMATEX pwfx;
  38. pwfx.wFormatTag         = WAVE_FORMAT_PCM;  //PCM格式
  39. pwfx.wBitsPerSample     = 16;               //位数
  40. pwfx.nChannels          = 1;                //声道数
  41. pwfx.nSamplesPerSec     = 8000;             //采样率
  42. pwfx.nBlockAlign        = 16*1 / 8;         //数据块调整
  43. pwfx.nAvgBytesPerSec    = pwfx.nBlockAlign * 8000;      //平均传输速率
  44. pwfx.cbSize             = 0;                //附加信息
  45. //
  46. // Play the wave using a XAudio2SourceVoice
  47. //
  48. // Create the source voice
  49. IXAudio2SourceVoice* pSourceVoice;
  50. if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, &pwfx)))
  51. {
  52. wprintf(L"Error %#X creating source voice\n", hr);
  53. return hr;
  54. }
  55. FILE *fp;
  56. //SPEECHDECODE文件说明: 该文件为保存的二进制音频数据,格式:16位,采样率8K.
  57. int re = fopen_s(&fp, "SPEECHDECODE", "rb");
  58. XAUDIO2_BUFFER XBuffer[4];
  59. BYTE *pRBuffer[4];
  60. int i = 0;
  61. for (i = 0; i < 4; i++)
  62. {
  63. pRBuffer[i] = (BYTE *)malloc(640);
  64. fread(pRBuffer[i], 640, 1, fp);
  65. XBuffer[i].AudioBytes = 640;
  66. XBuffer[i].Flags = 0;
  67. XBuffer[i].LoopBegin = 0;
  68. XBuffer[i].LoopCount = 0;
  69. XBuffer[i].LoopLength = 0;
  70. XBuffer[i].pAudioData = pRBuffer[i];
  71. XBuffer[i].pContext = (void*)new int[1];
  72. XBuffer[i].PlayBegin = 0;
  73. XBuffer[i].PlayLength = 0;
  74. if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))
  75. {
  76. wprintf(L"Error %#X submitting source buffer\n", hr);
  77. pSourceVoice->DestroyVoice();
  78. return hr;
  79. }
  80. }
  81. hr = pSourceVoice->Start(0);
  82. BOOL isRunning = TRUE;
  83. i = 0;
  84. while (SUCCEEDED(hr) && isRunning)
  85. {
  86. XAUDIO2_VOICE_STATE state;
  87. //检查播放缓存区缓冲块数量,当缓存块数量不足时,则新加入
  88. pSourceVoice->GetState(&state);
  89. isRunning = (state.BuffersQueued > 0) != 0;
  90. // Wait till the escape key is pressed
  91. if (GetAsyncKeyState(VK_ESCAPE))    //Esc键退出
  92. break;
  93. printf("state.BuffersQueued = %d\n", state.BuffersQueued);
  94. if (state.BuffersQueued <= 2)
  95. {
  96. if (fread(pRBuffer[i], 640, 1, fp) <= 0) break;
  97. XBuffer[i].pAudioData = pRBuffer[i];
  98. if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))
  99. {
  100. wprintf(L"Error %#X submitting source buffer\n", hr);
  101. pSourceVoice->DestroyVoice();
  102. return hr;
  103. }
  104. i = (i + 1) % 4;
  105. }
  106. Sleep(10);
  107. }
  108. END:
  109. hr = pSourceVoice->Stop(0);
  110. pSourceVoice->DestroyVoice();
  111. for (i = 0; i < 4; i++)
  112. {
  113. if (pRBuffer[i]) free(pRBuffer[i]);
  114. }
  115. if (pXAudio2) {
  116. pXAudio2->Release();
  117. pXAudio2 = NULL;
  118. }
  119. CoUninitialize();
  120. return 0;
  121. }

XAudio2播放PCM的更多相关文章

  1. 最简单的视音频播放示例8:DirectSound播放PCM

    本文记录DirectSound播放音频的技术.DirectSound是Windows下最常见的音频播放技术.目前大部分的音频播放应用都是通过DirectSound来播放的.本文记录一个使用Direct ...

  2. 最简单的视音频播放演示样例8:DirectSound播放PCM

    ===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...

  3. 通过WinAPI播放PCM声音

    在Windows平台上,播放PCM声音使用的API通常有如下两种. waveOut and waveIn:传统的音频MMEAPI,也是使用的最多的 xAudio2:C++/COM API,主要针对游戏 ...

  4. ffplay代码播放pcm数据

    摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...

  5. DirectSound播放PCM(可播放实时采集的音频数据)

    前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...

  6. 最简单的视音频播放示例9:SDL2播放PCM

    本文记录SDL播放音频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...

  7. 使用AudioTrack播放PCM音频数据(android)

    众所周知,Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的.MediaPl ...

  8. Android 音视频深入 二 AudioTrack播放pcm(附源码下载)

    本篇项目地址,名字是录音和播放PCM,求starhttps://github.com/979451341/Audio-and-video-learning-materials 1.AudioTrack ...

  9. OpenAL播放pcm或wav数据流-windows/ios/android(一)

    OpenAL播放pcm或wav数据流-windows/iOS/Android(一)   最近在研究渲染问题,本文采用openal做pcm和wav数据流播放,并非本地文件,demo是windows的,i ...

随机推荐

  1. 笔记-python-standard library-17.7 queue

    笔记-python-standard library-17.7 queue 1.  queue source code:Lib/queue.py 该模块实现了多生产者,多消费者队列. 此模块实现了所有 ...

  2. contest0 from codechef

    A  CodeChef - KSPHERES 中文题意  Mandarin Chinese Eugene has a sequence of upper hemispheres and another ...

  3. 6,MongoDB 之 Array Object 的特殊操作

    相比关系型数据库, Array [1,2,3,4,5] 和 Object { 'name':'DragonFire' } 是MongoDB 比较特殊的类型了 特殊在哪里呢?在他们的操作上又有什么需要注 ...

  4. Java线程和多线程(五)——单例类中的线程安全

    单例模式是最广泛使用的创建模式之一.在现实世界之中,诸如Databae的连接或者是企业信息系统(EIS)等,通常其创建都是受到限制的,应该尽量复用已存在对象而不是频繁创建销毁.为了达到这个目的,开发者 ...

  5. centos使用--防火墙

    目录 1 切换到zsh 1.1 查看系统当前的shell 1.2 查看bin下是否有zsh包 1.3 安装zsh包 1.4 切换shell至zsh 2 安装oh-my-zsh 2.1 oh-my-zs ...

  6. Ajax异步与JavaScript的一些初浅认识

    向服务器请求数据的技术 有以下五种常用技术用于向服务器请求数据 XMLHttpRequest(XHR) Dynamic script tag insertion(动态脚本标签插入) iframes C ...

  7. 孤荷凌寒自学python第五十天第一次接触NoSql数据库_Firebase

    孤荷凌寒自学python第五十天第一次接触NoSql数据库_Firebase (完整学习过程屏幕记录视频地址在文末) 之前对关系型数据库的学习告一段落,虽然能力所限没有能够完全完成理想中的所有数据库操 ...

  8. Leetcode 661.图片平滑器

    图片平滑器 包含整数的二维矩阵 M 表示一个图片的灰度.你需要设计一个平滑器来让每一个单元的灰度成为平均灰度 (向下舍入) ,平均灰度的计算是周围的8个单元和它本身的值求平均,如果周围的单元格不足八个 ...

  9. Scrapy 学习笔记(一)数据提取

    Scrapy 中常用的数据提取方式有三种:Css 选择器.XPath.正则表达式. Css 选择器 Web 中的 Css 选择器,本来是用于实现在特定 DOM 元素上应用花括号内的样式这样一个功能的. ...

  10. C#程序怎么写,效率高

    文章:改善C#程序,提高程序运行效率的50种方法 文章:编写高效率的C#代码