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于杭州