高质量音频混音算法及应用

一、音频数据格式:

        处理16bit的PCM音频数据;

二、音频混音算法的原理:

        混音的原理其实很简单,只要多路语音数据做线性叠加即可,但是叠加后的音频数据容易产生溢出,而且混合的路数越多,溢出的可能性越大,所以要做溢出处理,保证数据再32767~(-32768)之间,其实如何完美的处理混音叠加后溢出问题才是混音算法的关键;

1、衰减因子:

        为了更好的解决溢出问题,可以使用一个衰减因子, 对音频数据进行逐渐衰减, 衰减因子会随着数据而变化. 当溢出时, 衰减因子比较小, 使溢出的音频数据衰减以后处于临界值以内, 当没有溢出时, 衰减因子会慢慢增加, 尽量保持数据的平滑变化. 而不是对于整帧使用同一个衰减因子来进行;采用衰减因子的方式进行调整以后, 混音的数据从听觉上基本感觉不到背景噪音,会感觉很舒适,也基本上不会出现爆破音,这种方式比较推荐;

2、平均法:

        叠加以后再取平均值,这样不容易产生溢出,但是会照成音质衰减过大,各路音量会逐步变小,影响通话质量,所以一般不采取求平均这种方式;但是可以扩展一下,考虑参与混音的多路音视频信号自身特点,以它们自身的比例作为权重,比如如果是背景音乐可以适当权重低一些,领导讲话可以适当权重高一些,这样混合后的效果也会随着场景的应用会更合适一些。

3、边界值法:

        将每一路的语音线性相加进行溢出检测,如果溢出,以最大值或最小值来替代。这样会造成声音波形的人为削峰,在破坏语音信号特性;

4、newlc算法:

算法原型:
Y = A + B - (A * B / (-(2 pow(n-1) -1)))
Y = A + B - (A * B / (2 pow(n-1))

这个算法目前也比较火,可以尝试。

三、去除本路

        混音的时候, 一般情况是需要去除本路的音频数据,  这样就不会听到本地的声音, 只能听到其他 n − 1 路的声音;混音后通常会产生噪音,所以一般做一次降噪处理效果很更好。

下面是我做的一个测试程序以及部分测试代码说明:

int main(int argc, char* argv[])
{
	FILE *input1_fd = NULL, *input2_fd = NULL, *input3_fd = NULL, *output_fd = NULL;
	short shSpeechOut[DEFAULT_SAMPLE_FRAME_LEN];
	short shSpeechIn1[DEFAULT_SAMPLE_FRAME_LEN];
	short shSpeechIn2[DEFAULT_SAMPLE_FRAME_LEN];
	short shSpeechIn3[DEFAULT_SAMPLE_FRAME_LEN];

	short* pshVoiceOut = NULL;
	short* pshVoiceIn[3];

	int iRet = 0;

	/*输入文件1  输入文件2 输入文件3  混音后的文件 */
	if(argc < 5)
	{
		printf("Error:argc=%d\n",argc);
		printf("usage: inputfile1 inputfile2 inputfile3 mixfile\n");

		return (-1);
	};
	
	input1_fd = fopen(argv[1], "rb");
	if(input1_fd == NULL)
	{
		printf("Error:can not open audio input1 file %s.\n", argv[1]);
		return (-1);
	};

	input2_fd = fopen(argv[2], "rb");
	if (input2_fd == NULL)
	{
		printf("Error:can not open audio input2 file %s.\n", argv[2]);
		return (-1);
	};

	input3_fd = fopen(argv[3], "rb");
	if (input3_fd == NULL)
	{
		printf("Error:can not open audio input3 file %s.\n", argv[3]);
		return (-1);
	};

	output_fd = fopen(argv[4], "wb");
	if (output_fd == NULL)
	{
		printf("Error:can not open audio input3 file %s.\n", argv[4]);
		return (-1);
	};

	pshVoiceOut = shSpeechOut;

	while (!feof(input1_fd))
	{
		if((iRet = fread(shSpeechIn1, sizeof(short), DEFAULT_SAMPLE_FRAME_LEN, input1_fd))!= DEFAULT_SAMPLE_FRAME_LEN)
		{
			printf("file over.\n ");	
			break;
		}

		if ((iRet = fread(shSpeechIn2, sizeof(short), DEFAULT_SAMPLE_FRAME_LEN, input2_fd)) != DEFAULT_SAMPLE_FRAME_LEN)
		{
			printf("file over.\n ");
			break;
		}

		if ((iRet = fread(shSpeechIn3, sizeof(short), DEFAULT_SAMPLE_FRAME_LEN, input3_fd)) != DEFAULT_SAMPLE_FRAME_LEN)
		{
			printf("file over.\n ");
			break;
		}
		
		pshVoiceIn[0] = shSpeechIn1;
		pshVoiceIn[1] = shSpeechIn2;
		pshVoiceIn[2] = shSpeechIn3;
		
		uniqueMixVoice(pshVoiceIn, pshVoiceOut, DEFAULT_SAMPLE_FRAME_LEN,3);

		fwrite(shSpeechOut, sizeof(short), DEFAULT_SAMPLE_FRAME_LEN, output_fd);
	}

	fclose(input1_fd);
	fclose(input2_fd);
	fclose(input3_fd);
	fclose(output_fd);

	return 0;
}

 

项目地址:https://download.csdn.net/download/unique_no1/84992369

        里面包含测试程序和可执行文件,windows平台和linux平台的我都已经编译好了,大家可以测试看下效果,接口调用也比较简单;

联系方式:

vx:unique_no_1

-----------------------------------------------------------------------------------------------------------------------------------------


版权声明:本文为unique_no1原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。