改进型归一化混音算法

来源:互联网 发布:房地产网络端口是什么 编辑:程序博客网 时间:2024/05/21 16:26

改进型归一化混音算法

linear PCM格式的音频混音

音频混音的原理: 量化的语音信号的叠加等价于空气中声波的叠加。

反应到PCM音频数据上,也就是把同一个声道的数值进行简单的相加,但是这样同时会产生一个问题,那就是相加的结果可能会溢出,当然为了解决这个问题已经有很多方案了.

假设音频文件采样率、通道数、采样精度一样。

另外要注意的是,在源音频数据中是按照little-endian的顺序来排放的,PCM值为0表示没声音(振幅为0)。

源码如下:

bufferA 音频A的首地址

bufferB 音频B的首地址

static void pcmAudioMix(SInt16 *bufferA, SInt16 *bufferB, UInt32 bufferLength){    char * sourseFile[2];    sourseFile[0] = (char *)bufferA;    sourseFile[1] = (char *)bufferB;    bufferLength *= 2;    Mix(sourseFile, 2, (char *)bufferB, bufferLength);}static void Mix(char ** sourseFile,int number,char *objectFile, UInt32 bufferLength){    //归一化混音    int const MAX = 32767;    int const MIN = -32768;        double f = 1;    int output;    for (int i = 0; i < bufferLength/2; i++)    {        int temp = 0;        for (int j = 0; j < number; j++)        {                        char *point = sourseFile[j];                        if (j == 0) {                int mixTemp = *(short *)(point + i*2);                temp += (int)(mixTemp);            }else{                temp += *(short *)(point + i*2);            }        }                output = (int)(temp * f);                if (output > MAX)        {            f = (double)MAX / (double)(output);            output = MAX;        }        if (output < MIN)        {            f = (double)MIN / (double)(output);            output = MIN;        }        if (f < 1)        {    //此处取SETPSIZE 为 32            f += ((double)1 - f) / (double)32;        }        *(short *)(objectFile + i*2) = (short)output;    }}

算法如下所述:

1. f 初始化为1.

2. 对于一帧中的样本按顺序处理:

    (a) output[i] = mixing[i] × f.

    (b) 如果output[i] > MAX,求得最大的 f0满足 output[i] × f0< MAX,然后 f = f0, output[i] = MAX.

    (c) 如果output[i] < MIN,求得最大的 f0满足 output[i]×f0> MIN,然后 f = f0, output[i] = MIN.

3. 如果f < 1, f = f + STEPSIZE. 继续处理下一帧, 2.


  其中f 为衰减因子, f0为新的衰减因子; mixing[]为所有音频流的某一帧线性叠加值,实际实现的时候如式(4)所示; output[]为归一化以后的输出帧. MAX为正的最大值; MIN 为负的最大值. STEPSIZE f 变化的步长,通常取为 (1 − f)/16或者 (1 − f)/32.


SETPSIZEf的变化步长,通常的取值为(1-f)/VALUE 其中(1-f)为固定值只是后面的VALUE值可以取 8, 16, 32,64,128. SETPSIZE取值较大时,运算复杂度低,但语言平滑度不够细腻,STEPSIZE取值较小时,运算复杂度高,但语言平滑度比较细腻。


  特别的, 就是在衰减以后的值溢出的情况下,求新的衰减因子 f0的方法不同,新的 f0需要满足 output[i] × f0< MAX或者 output[i] × f0> MIN,而不是直接使用mixing[i].也就是说,使用衰减以后的值output[i]来计算f0,而不是原始值mixing[i],这样将使得衰减因子的变化更为平滑.

  用数学来表达, S 为溢出的一个样本值,S × f仍然溢出的情况下, 可以比较一下计算出来的新衰减因子的大小:假设是上溢, forig是原始算法计算出的新的衰减因子,f`orig<(MAX/S), 我们改进的算法得出的新衰减因子 f`new<(MAX/(S×f)),因为 S > (S × f),所以(MAX/S) <(MAX/(S×f)),那么 f`new很大程度上要大于f`orig.衰减因子大了(更接近1),相邻的数据变化不会特别大,所以跳跃的现象不会特别明显.

参考文章:

http://blog.csdn.net/jeffasd/article/details/77155187

http://blog.csdn.net/jeffasd/article/details/77151557

http://www.cnblogs.com/caosiyang/archive/2012/07/16/2594029.html

http://soundfile.sapp.org/doc/WaveFormat/

https://my.oschina.net/daxia/blog/636074