改进型归一化混音算法

改进型归一化混音算法

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值