zoukankan      html  css  js  c++  java
  • XAudio2播放PCM

    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格式音频数据文件。

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

     

  • 相关阅读:
    sublime开启vim模式
    git命令行界面
    搬进Github
    【POJ 2886】Who Gets the Most Candies?
    【UVA 1451】Average
    【CodeForces 625A】Guest From the Past
    【ZOJ 3480】Duck Typing
    【POJ 3320】Jessica's Reading Problemc(尺取法)
    【HDU 1445】Ride to School
    【HDU 5578】Friendship of Frog
  • 原文地址:https://www.cnblogs.com/lidabo/p/6834925.html
Copyright © 2011-2022 走看看