得到g729和自适应码本增益与固定码本增益后,
就可以根据两者解码出当前帧的激励,然后存放在历史激励数组当中
即更新自适应激励码本
代码片段:
for (i = 0; i < L_SUBFR; i++)
{
/* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */
/* exc[i] in Q0 gain_pit in Q14 */
/* code[i] in Q13 gain_cod in Q1 */
L_temp = L_mult(exc[i+i_subfr], gain_pit);
L_temp = L_mac(L_temp, code[i], gain_code);
L_temp = L_shl(L_temp, 1);
exc[i+i_subfr] = round(L_temp);
}
与g723的做法不大相同
g729对感知加权滤波器的初始状态更新与零输入响应状态的更新是混合在一起的,
这在一定程度上减少的计算了
我们再来回顾一个,g729对原始语音的感知加权与扣减零输入响应的代码片段(这在之前章节,为了突出重点,被忽略了,现在重提一下)
//lsc 这里计算目标向量,有可能做了去除零输入响应之类的操作,先用包含零输入响应的信号滤波(量化后的Az系数),得到残差信号
Residu(Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); /* LPC residual */
//lsc 再用残差信号还原,就得到去除零输入响应的语音信息
//lsc 将残差信号,输入Aq的系统,这里,应该考虑到系统有初始状态,即,上一帧语音编解码后,对当前系统的影响,应该是,上一帧的原始语音,应做为输入的一部分(对应感知加权的一部分),而上一帧的未感加权解码语音信号应扣减速(对应扣减速零输入响应)
Syn_filt(Aq, &exc[i_subfr], error, L_SUBFR, mem_err, 0);
//lsc 对语音信号进行感知加权(采用的是未量化的Az系数)
Residu(Ap1, error, xn, L_SUBFR);
//lsc 这里也分成两部分,(+上一帧的感知加权语音信号) (-上一帧 感知加权的解码语音信号) 这两个细节,就完成了感知加权的原始输入状态与零输入响应状态的更新
Syn_filt(Ap2, xn, xn, L_SUBFR, mem_w0, 0); /* target signal xn[]*/
这样,感知加权滤波的初始输入,与零输入响应的扣减,就一并完成了
最后是搬动内存块,比较简单
Copy(&old_speech[L_FRAME], &old_speech[0], L_TOTAL-L_FRAME);//lsc 更新语音拼合帧
Copy(&old_wsp[L_FRAME], &old_wsp[0], PIT_MAX);//lsc 更新加权语音拼合帧
Copy(&old_exc[L_FRAME], &old_exc[0], PIT_MAX+L_INTERPOL);//lsc 搬动,更新自适应码本
就是挪挪位置,方便下一帧搜索基音周期,并构成下一帧的自适应码本之前的
至此,g729的编码分析完毕
笔者将在下一章节分析解码,同样的g729的解码就是做一个语音合成,知道怎么编码,解码过程分析就相对容易
林绍川
2012.5.23于杭州
就可以根据两者解码出当前帧的激励,然后存放在历史激励数组当中
即更新自适应激励码本
代码片段:
for (i = 0; i < L_SUBFR; i++)
{
/* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */
/* exc[i] in Q0 gain_pit in Q14 */
/* code[i] in Q13 gain_cod in Q1 */
L_temp = L_mult(exc[i+i_subfr], gain_pit);
L_temp = L_mac(L_temp, code[i], gain_code);
L_temp = L_shl(L_temp, 1);
exc[i+i_subfr] = round(L_temp);
}
与g723的做法不大相同
g729对感知加权滤波器的初始状态更新与零输入响应状态的更新是混合在一起的,
这在一定程度上减少的计算了
我们再来回顾一个,g729对原始语音的感知加权与扣减零输入响应的代码片段(这在之前章节,为了突出重点,被忽略了,现在重提一下)
//lsc 这里计算目标向量,有可能做了去除零输入响应之类的操作,先用包含零输入响应的信号滤波(量化后的Az系数),得到残差信号
Residu(Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); /* LPC residual */
//lsc 再用残差信号还原,就得到去除零输入响应的语音信息
//lsc 将残差信号,输入Aq的系统,这里,应该考虑到系统有初始状态,即,上一帧语音编解码后,对当前系统的影响,应该是,上一帧的原始语音,应做为输入的一部分(对应感知加权的一部分),而上一帧的未感加权解码语音信号应扣减速(对应扣减速零输入响应)
Syn_filt(Aq, &exc[i_subfr], error, L_SUBFR, mem_err, 0);
//lsc 对语音信号进行感知加权(采用的是未量化的Az系数)
Residu(Ap1, error, xn, L_SUBFR);
//lsc 这里也分成两部分,(+上一帧的感知加权语音信号) (-上一帧 感知加权的解码语音信号) 这两个细节,就完成了感知加权的原始输入状态与零输入响应状态的更新
Syn_filt(Ap2, xn, xn, L_SUBFR, mem_w0, 0); /* target signal xn[]*/
这样,感知加权滤波的初始输入,与零输入响应的扣减,就一并完成了
最后是搬动内存块,比较简单
Copy(&old_speech[L_FRAME], &old_speech[0], L_TOTAL-L_FRAME);//lsc 更新语音拼合帧
Copy(&old_wsp[L_FRAME], &old_wsp[0], PIT_MAX);//lsc 更新加权语音拼合帧
Copy(&old_exc[L_FRAME], &old_exc[0], PIT_MAX+L_INTERPOL);//lsc 搬动,更新自适应码本
就是挪挪位置,方便下一帧搜索基音周期,并构成下一帧的自适应码本之前的
至此,g729的编码分析完毕
笔者将在下一章节分析解码,同样的g729的解码就是做一个语音合成,知道怎么编码,解码过程分析就相对容易
林绍川
2012.5.23于杭州