• XAudio2学习之混音


    XAudio2不仅能够进行採样率转换。还能够进行混音。所谓混音就是将多路音频混合成一路进行输出。混音主要是IXAudio2SubmixVoice进行此项功能。

    数据由IXAudio2SourceVoice提交后。流向IXAudio2SubmixVoice进行採样率转换(假设须要的话),而且进行音频混合,最后形成一路採样率和IXAudio2MasteringVoice一致的音频流,由IXAudio2MasteringVoice输出到音频输出设备。

    混音主要步骤:

    1.初始化COM组件。

    2.指定特定格式创建Mastering Voice:2通道/48K。32位深。

    3.创建一个IXAudio2SubmixVoice对象,格式和mastering voice一致:作用是混合两路音频为一路,并输出到mastering voice。

    4.打开多个文件来提供多路音频数据:这里使用两个文件。

    5.针对每一个文件创建IXAudio2SourceVoice对象,格式为每一个文件的格式。

    6.针对每一个IXAudio2SourceVoice创建IXAudio2SubmixVoice对象,并分别设置输入格式为每一个文件相应的格式,分别设置为IXAudio2SourceVoice对象的输出voice,并分别指定IXAudio2SubmixVoice对象的输出voice为第三步创建的用来混音的IXAudio2SubmixVoice对象。

    主要用来採样率转换,将採样率由文件提供的採样率转为和Mastering Voice一致的採样率。

    7.分配内存,分别读取文件数据。并制定到XAUDIO2_BUFFER。

    8.分别调用SubmitSourceBuffer将数据提交。

    9.分别调用Start来启动Source Voice。

    10.等待播放完毕。

    11.释放对象和内存数据。

    主要实现代码例如以下:WaveFile.h/WaveFile.cpp请到前面文章中寻找地址自行下载。

    #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)    { }
    	void OnBufferStart(void * pBufferContext) {    }
    	void OnLoopEnd(void * pBufferContext) {    }
    	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;
     
    	WAVEFORMATEX waveFormatex;//设置主声音的格式
    	waveFormatex.nChannels = 2;
    	waveFormatex.nSamplesPerSec = 48000;
    	waveFormatex.wBitsPerSample = 32;
    	waveFormatex.nAvgBytesPerSec = 384000;
    	waveFormatex.nBlockAlign = 8;
    	waveFormatex.wFormatTag = WAVE_FORMAT_PCM;
    
     	IXAudio2MasteringVoice *pMasterVoice = NULL;
     	hr = pEngine->CreateMasteringVoice(&pMasterVoice,waveFormatex.nChannels,waveFormatex.nSamplesPerSec);//创建主声音。默认是输出当前扬声器
     	if (FAILED(hr))
     		return 0;
    
    	XAUDIO2_SEND_DESCRIPTOR pSend;
    	pSend.pOutputVoice = pMasterVoice;//指定输出为mastering voice
    	pSend.Flags = XAUDIO2_SEND_USEFILTER;
    
    	XAUDIO2_VOICE_SENDS pSendList;
    	pSendList.pSends = &pSend;
    	pSendList.SendCount = 1;
    
    	IXAudio2SubmixVoice *pSubmixVoice = NULL;
    	hr = pEngine->CreateSubmixVoice(&pSubmixVoice, waveFormatex.nChannels, waveFormatex.nSamplesPerSec, 0, 0, &pSendList);//指定输出为mastering voice,作用:混音,将两路音频数据混为一路并输出到mastering voice
    	if (FAILED(hr))
    		return 0;
    	
    	CWaveFile waveFile1;
    	hr = waveFile1.Open(L"C:\Users\xdd\Desktop\时间都去哪儿了.wav", NULL, WAVEFILE_READ);//载入文件1
    	if (FAILED(hr))
    		return 0;
    
    
    	CWaveFile waveFile2;
    	hr = waveFile2.Open(L"C:\Users\xdd\Desktop\1KHz-stero.wav", NULL, WAVEFILE_READ);//载入文件2
    	if (FAILED(hr))
    		return 0;
    
    	WAVEFORMATEX *waveFormat1 = waveFile1.GetFormat();//获取文件格式1
    	WAVEFORMATEX *waveFormat2 = waveFile2.GetFormat();//获取文件格式2
    
    	pSend.pOutputVoice = pSubmixVoice;//指定输出为SubmixVoice
    
    	IXAudio2SubmixVoice *pSubmixVoice1 = NULL;
    	hr = pEngine->CreateSubmixVoice(&pSubmixVoice1, waveFormat1->nChannels, waveFormat1->nSamplesPerSec, 0, 0, &pSendList);//指定输出为pSubmixVoice,作用:对文件1的音频数据进行重採样为mastering voice的採样率
    	if (FAILED(hr))
    		return 0;
    
    	IXAudio2SubmixVoice *pSubmixVoice2 = NULL;
    	hr = pEngine->CreateSubmixVoice(&pSubmixVoice2, waveFormat2->nChannels, waveFormat2->nSamplesPerSec, 0, 0, &pSendList);//指定输出为pSubmixVoice,作用:对文件2的音频数据进行重採样为mastering voice的採样率
    	if (FAILED(hr))
    		return 0;
    
    	pSend.pOutputVoice = pSubmixVoice1;//指定输出为pSubmixVoice1
    
    	VoiceCallback voiceCallBack1;
     	IXAudio2SourceVoice *pSourceVoice1 = NULL;
    	hr = pEngine->CreateSourceVoice(&pSourceVoice1, waveFormat1, 0, 1.0f, &voiceCallBack1,&pSendList);//创建源声音。用来提交数据.指定输出为SubmixVoice1
     	if (FAILED(hr))
     		return 0;
    
    	pSend.pOutputVoice = pSubmixVoice2;//指定输出为pSubmixVoice2
    
    	VoiceCallback voiceCallBack2;
    	IXAudio2SourceVoice *pSourceVoice2 = NULL;
    	hr = pEngine->CreateSourceVoice(&pSourceVoice2, waveFormat2, 0, 1.0f, &voiceCallBack2, &pSendList);//创建源声音,用来提交数据.指定输出为SubmixVoice2
    	if (FAILED(hr))
    		return 0;
     
     	DWORD size1 = waveFile1.GetSize();//获取文件的大小
     	BYTE *pData1 = new BYTE[size1];//申请内存空间,用于保存数据
     	hr = waveFile1.Read(pData1, size1, &size1);//读取文件内容
     	if (FAILED(hr))
     		return 0;
    
    	DWORD size2 = waveFile2.GetSize();//获取文件的大小
    	BYTE *pData2 = new BYTE[size2];//申请内存空间,用于保存数据
    	hr = waveFile2.Read(pData2, size2, &size2);//读取文件内容
    	if (FAILED(hr))
    		return 0;
     
    	XAUDIO2_BUFFER buffer1 = {0};//将读取的文件数据,赋值XAUDIO2_BUFFER
     	buffer1.AudioBytes = size1;
     	buffer1.pAudioData = pData1;
    	buffer1.Flags = XAUDIO2_END_OF_STREAM;
    
    	XAUDIO2_BUFFER buffer2 = { 0 };//将读取的文件数据。赋值XAUDIO2_BUFFER
    	buffer2.AudioBytes = size2;
    	buffer2.pAudioData = pData2;
    	buffer2.Flags = XAUDIO2_END_OF_STREAM;
     
     	hr = pSourceVoice1->SubmitSourceBuffer(&buffer1);//提交内存数据
     	if (FAILED(hr))
     		return 0;
    
    	hr = pSourceVoice2->SubmitSourceBuffer(&buffer2);//提交内存数据
    	if (FAILED(hr))
    		return 0;
     
     	hr = pSourceVoice1->Start(0);//启动源声音
     	if (FAILED(hr))
     		return 0;
    
    	hr = pSourceVoice2->Start(0);//启动源声音
    	if (FAILED(hr))
    		return 0;
     
    	XAUDIO2_VOICE_STATE state;
    	pSourceVoice1->GetState(&state);//获取状态
    	while (state.BuffersQueued)
    	{
    		WaitForSingleObject(voiceCallBack1.hBufferEndEvent, INFINITE);
    		pSourceVoice2->GetState(&state);
    		WaitForSingleObject(voiceCallBack2.hBufferEndEvent, INFINITE);
    	}
     
     	pMasterVoice->DestroyVoice();//释放资源
    	pSubmixVoice->DestroyVoice();//
    	pSubmixVoice1->DestroyVoice();//
    	pSubmixVoice2->DestroyVoice();//
     	pSourceVoice1->DestroyVoice();//释放资源
    	pSourceVoice2->DestroyVoice();//释放资源
     	pEngine->Release();//释放资源
     	CoUninitialize();//释放资源
    
    	delete []pData1;//释放资源
    	pData1 = NULL;
    
    	delete[]pData2;//释放资源
    	pData2 = NULL;
    
     	return 0;
     }
    
    交流QQ:1245178753

    本文地址:http://blog.csdn.net/u011417605/article/details/51051039

    源代码下载:http://download.csdn.net/detail/u011417605/9480309

  • 相关阅读:
    ASP创建对象及中文显示解决方法
    webservice解读
    top监控工具
    Crontab实例
    javascript闭包的理解
    98万买下51.com域名,51.com不止2000万美金
    百度08年网页搜索份额73.2% 创历史新高
    讲故事投资 天使投资人的中国式生存
    下个谷歌将诞生于中国或印度
    Twitter入选10大搜索引擎
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/7284841.html
Copyright © 2020-2023  润新知