博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XAudio2学习之混音
阅读量:5778 次
发布时间:2019-06-18

本文共 5808 字,大约阅读时间需要 19 分钟。

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://jhkyx.baihongyu.com/

你可能感兴趣的文章
两个有序数组的中位数
查看>>
什么是家?
查看>>
iOS应用程序多语言本地化解决方案
查看>>
使用SQLCMD在SQLServer执行多个脚本
查看>>
Sql Server系列:聚合函数
查看>>
careercup-栈与队列 3.4
查看>>
Linux学习(一):linux更改ip地址命令_更改DNS_更改默认网关_更改子网掩码_主机名...
查看>>
111
查看>>
最简单的视音频播放示例4:Direct3D播放RGB(通过Texture)
查看>>
PLSQL_基础系列06_判断操作NVL / NULLIF / COALESCE / NVL2(案例)
查看>>
C#软件监控外部程序运行状态
查看>>
使用 WorkflowIdentity 和版本控制
查看>>
unity3d插件Daikon Forge GUI 中文教程-5-高级控件listbox和progress bar的使用
查看>>
-[ASIDataCompressor compressBytes:length:error:shouldFinish:] in ASIDataCompressor.o
查看>>
Rotating Image Slider - 图片旋转切换特效
查看>>
如何获取UITableView中cell的frame值
查看>>
【转】每天一个linux命令(18):locate 命令
查看>>
android adb常用指令
查看>>
纯Shading Language绘制飞机火焰效果
查看>>
最小生成树(普利姆算法、克鲁斯卡尔算法)
查看>>