g723源码详细分析-18-丢包补偿

g723对网络丢包行为了一些处理
涉及的函数为Comp_Info Regen

Comp_Info:负责计算插值依据
它的四个参数
Word16 *Buff:激励数组,包含之前的145个激励
Word16 Olp:当前帧的基音周期
Word16 *Gain:输入增益(归一化的)
Word16 *ShGain:输出增益的缩放位移
返回值是激励插值的延后

现在来看Comp_Info函数
道先做一个归一化处理,得到能量的归一化所需要位移位数
    /* Normalize the excitation */
    *ShGain = Vec_Norm( Buff, (Word16) (PitchMax+Frame) ) ;

在基音周期附近(Olp-3,Olp+3)这个范围内寻找自相关最大的120个样点取值,

代码片段如下:
    for ( i = (int)Olp-3 ; i <= (int)Olp+3 ; i ++ ) { //lsc 在基音周期附近搜索自相关最大的一个索引

        Acc0 = (Word32) 0 ;
        for ( j = 0 ; j < 2*SubFrLen ; j ++ )
            Acc0 = L_mac( Acc0, Buff[PitchMax+Frame-2*SubFrLen+j],
                                    Buff[PitchMax+Frame-2*SubFrLen-i+j] ) ;

        if ( Acc0 > Acc1 ) {
            Acc1 = Acc0 ;//lsc Acc1保存基音周延后自相关最大的
            Indx = (Word16) i ;
        }
    }
找出来的基音延后序列我们记录 x[n-Indx]
    
计算最后120个样点的能量 Tenr 这个是x[n]的能量(最后120个样点)
    /* Compute target energy */ //lsc 计算最后120个样点的能量
    Acc0 = (Word32) 0 ;
    for ( j = 0 ; j < 2*SubFrLen ; j ++ )
        Acc0 = L_mac( Acc0, Buff[PitchMax+Frame-2*SubFrLen+j],
                                    Buff[PitchMax+Frame-2*SubFrLen+j] ) ;
    Tenr = round( Acc0 ) ;
    *Gain = Tenr;
    
计算最佳基音延后的能量 Enr 这个是x[n-Indx]的能量(连续120个)
    /* Compute best energy */ //lsc 计算基音周期延后的能量Acc0
    Acc0 = (Word32) 0 ;
    for ( j = 0 ; j < 2*SubFrLen ; j ++ )
        Acc0 = L_mac( Acc0, Buff[PitchMax+Frame-2*SubFrLen-(int)Indx+j],
                            Buff[PitchMax+Frame-2*SubFrLen-(int)Indx+j] ) ;

得到能量以相基音延后的自相关之后,
就可以判断x[n-Indx] x[n]的相似度了
x[n-Indx] x[n]相关,在代码中是Ccr

(Enr * Tenr)/16 < Ccr^2 就认为这两个序列是相关的,
当丢包时,插值依据就是x[n-Indx],否则取x[n]
代码片段:

    Ccr = round( Acc1 ) ;

    if ( Ccr <= (Word16) 0 )
        return (Word16) 0 ;

    Enr = round( Acc0 ) ;

    Acc0 = L_mult( Enr, Tenr ) ;//lsc Enr 为基音周期最佳延后的能量 Tenr为最后120个样点的能量
    Acc0 = L_shr( Acc0, (Word16) 3 ) ;

    Acc0 = L_msu( Acc0, Ccr, Ccr ) ;//lsc Ccr为最佳基音延迟自相关

    if ( Acc0 < (Word32) 0 )//lsc Acc0小 说明相关性大 可能会作为插值的依据,否则插值的依据就是前面的120个点
        return Indx ;
    else
        return (Word16) 0 ;


再来看Regen,它负责在出现丢包时,做插值
是否丢包,是由调用Decod时传的一个参数crc来触发
            Regen( DataBuff, Temp, DecStat.InterIndx, DecStat.InterGain,
                                        DecStat.Ecount, &DecStat.Rseed ) ;

DecStat.InterIndx就是Comp_Info计算得到的基音延后Temp保存145个历史解码激励,
DataBuff为输出的插值激励
其中DecStat.InterGain是由以前帧得到的
如果没有丢包,取中间两子帧的平均,
丢包则按0.75的衰减取值
        /*
        * In case of no erasure, update the interpolation gain memory.
        * Otherwise compute the interpolation gain (Text: Section 3.10)
        */
        if ( DecStat.Ecount == (Word16) 0 ) {
            DecStat.InterGain = add( Line.Sfs[SubFrames-2].Mamp,
                                            Line.Sfs[SubFrames-1].Mamp ) ;
            DecStat.InterGain = shr( DecStat.InterGain, (Word16) 1 ) ;//lsc 取中间两帧增益的平均,作为丢包时的插值增益
            DecStat.InterGain = FcbkGainTable[DecStat.InterGain] ;
        }
        else
            DecStat.InterGain = mult_r( DecStat.InterGain, (Word16) 0x6000 ) ;//lsc 丢包时,按0.75衰减

Regen的函数过程
如果错误次数超为6,则不做插值
错误次数小于6,按DecStat.InterIndx是否为0,
DecStat.InterIndx不为0,取相应的基音延后历史激励插值
            /* Voiced case */
            for ( i = 0 ; i < Frame ; i ++ )
                Buff[PitchMax+i] = Buff[PitchMax-(int)Lag+i] ;//lsc 利用基音延后,构造一个周期激励
            for ( i = 0 ; i < Frame ; i ++ )
                DataBuff[i] = Buff[PitchMax+i] = mult( Buff[PitchMax+i],
                            (Word16) 0x6000 ) ;//lsc 做一个0.75的衰减
                            
如果为0,认为处于清音段,用随机激励插值
            /* Unvoiced case */
            for ( i = 0 ; i < Frame ; i ++ )
                DataBuff[i] = mult( Gain, Rand_lbc( Sd ) ) ;//lsc 模拟一个随机激励
            /* Clear buffer to reset memory */
            for ( i = 0 ; i < Frame+PitchMax ; i ++ )
                Buff[i] = (Word16) 0 ;


下一章节将分析基音后置滤波与共振峰后置滤波
                                              林绍川
                                              2012.01.16于杭州


posted @ 2012-01-16 12:30  飞天大蟾蜍  阅读(28)  评论(0编辑  收藏  举报