现在来分析静音检测
语音通话,基本上是一方听,一方说,采用静音检测可以起到节省一半带宽的作用

网络上有很多静音检测的代码,基本的思路,都是构造一个自适应的能量探测试,
低于阀值时,就认为出现静音

g723的思路基本与此相同
Comp_Vad 这个函数负责静音栽决,看代码吧,
这里笔者只分析算法,不再纠结定点数运算引起的数值缩放的问题了

g723的静音检测,检测了当前帧的180个样点(后60样点由于没有在当前帧里处理)
首先看到ScfTab这个静态数组
因为门限值的计算涉及到log,采用了类似711里的算法,用一系列折线段来近似指数函数
底为0.89 参考门限值公式10^(-0.05)约等于0.89

static Word16 ScfTab[11] = {//lsc 这里是一系列折线的斜率,用于计算近似的指数函数 注意:因为采用的是归一化的位移作自变量,所以这个表是递增的,把0.89的指数函数的第一象限"反"过来看(这里显得很绕,笔者也纠结了很久)
9170 ,
9170 ,
9170 ,
9170 ,//lsc 0.277 * 32768 = 9093 这个点基本吻合 0.277 为 0.89^11
10289 ,//lsc 0.313995361328125=10,
11544 ,//lsc 0.352294921875=9?
12953 ,//lsc 0.395=8?
14533 ,//lsc 0.4435=0.89^7 ?
16306 ,//lsc 6 0.49761962890625=0.89^6
18296 ,//lsc 5 0.558349609375=0.89^5
20529 ,//lsc 0.626=0.89^4
} ;
这个数组里的值为0.89^(n)扩大32768倍, n取值范围(4~11)

从四个子帧里找出基音周基最小的一个,存入Minp
/* Find Minimum pitch period */ //lsc VadStat.Polp 是从Line.Olp中取来的,每一帧保存两个(因为基音周期是每120采样计算一次)
Minp = PitchMax ;
for ( i = 0 ; i < 4 ; i ++ ) {
if ( Minp > VadStat.Polp[i] )
Minp = VadStat.Polp[i] ;
}

判断当前帧是否处理浊音段,依据为,如果所有子帧的基音周期都约为Minp的整数倍,
即认为当前帧是浊音段,代码片段
//lsc itu的中文翻译有误,当tm2=4时,应认为是浊音,见itu的英文版,是voice
Tm2 = 0 ;
for ( i = 0 ; i < 4 ; i ++ ) {
Tm1 = Minp ;
for ( j = 0 ; j < 8 ; j ++ ) {
Tm0 = sub( Tm1, VadStat.Polp[i] ) ;
Tm0 = abs_s( Tm0 ) ;
if ( Tm0 <= 3 )//lsc 如果在倍数附近,差值不大于3,为浊音加分,都在倍数附近,就是浊音了
Tm2 ++ ;
Tm1 = add( Tm1, Minp ) ;//lsc 用减法和加法,循环8次,代替除法
}
}

尾响处理,如果是浊音,之后的6个帧会被认为非静音,这个处理是避免元音段被不正确地截了
代码片段
/* Update adaptation enable counter if not periodic and not sine */
if ( (Tm2 == 4) || (CodStat.SinDet < 0) )//lsc 浊音,要添加尾响
VadStat.Aen += 2 ;
else
VadStat.Aen -- ;

/* Clip it */
if ( VadStat.Aen > 6 )//lsc 尾响限制为6帧
VadStat.Aen = 6 ;
if ( VadStat.Aen < 0 )
VadStat.Aen = 0 ;

与网络上流行的算法不同的是,g723做了滤波,对静音的判断是基于激励的能量
逆向滤波代码片段如下:
//lsc 逆向滤波
/* Inverse filter the data */
Acc1 = 0L ;
for ( i = SubFrLen ; i < Frame ; i ++ ) {

Acc0 = L_mult( Dpnt[i], 0x2000 ) ;
for ( j = 0 ; j < LpcOrder ; j ++ )
Acc0 = L_msu( Acc0, Dpnt[i-j-1], VadStat.NLpc[j] ) ;
Tm0 = round ( Acc0 ) ;
Acc1 = L_mac( Acc1, Tm0, Tm0 ) ;//lsc 计算出能量
}
其中的VadStat.NLpc这个数组,是在计算舒适背景音时,形成的一个平均滤波器,笔者将
在介绍舒适背景音时详细介绍这个lpc系数的生成,这里,只需要知道它是一个滤波器,
可以得到残差信号即可

噪声能量估值
/* Scale the rezidual energy */
Acc1 = L_mls( Acc1, (Word16) 2913 ) ;//lsc 这可能是除11.22(32768/2913=11.24),噪声能量估值 2913 * 11.22 = 32684(32767?) 10^1.05 = 11.220184543019634355910389464779
这里要注意,观察itu g723文档的vad章节的 A-5公式,它把10^1.05这个因子挪过来了,而把80这个因子移给了thrd的计算,绕得很

对噪声能量做个限制
/* Clip noise level in any case */ //lsc 如果噪声能量太大,更新噪声的能量,加前一帧噪声能量估值的3/4,再取1/4,形成当前噪声能量
if ( VadStat.Nlev > VadStat.Penr ) {
Acc0 = L_sub( VadStat.Penr, L_shr( VadStat.Penr, 2 ) ) ;
VadStat.Nlev = L_add( Acc0, L_shr( VadStat.Nlev, 2 ) ) ;
}

根据当前帧是元音还是辅音,做一个适当放大处理,盖因辅音段,在g723的编码模型里,就认为是由一个随机信号激励形成的
/* Update the noise level, if adaptation is enabled */
if ( !VadStat.Aen ) {//lsc 如果是清音
VadStat.Nlev = L_add( VadStat.Nlev, L_shr( VadStat.Nlev, 5 ) ) ;
}
/* Decay Nlev by small amount */
else {//lsc 如果是浊音,或者处于尾响阶段
VadStat.Nlev = L_sub( VadStat.Nlev, L_shr( VadStat.Nlev,11 ) ) ;
}

近一步限制噪声能量的取值范围 最小128 最大16383
/* Update previous energy */
VadStat.Penr = Acc1 ;

/* CLip Noise Level */
if ( VadStat.Nlev < 0x00000080L )
VadStat.Nlev = 0x00000080L ;
if ( VadStat.Nlev > 0x0001ffffL )
VadStat.Nlev = 0x0001ffffL ;

接来计算门限系数,这里涉及到用折线段来模拟指数函数,
知道是这么处理的就可以了.
最后将噪声能量估值与门限系数相乘,然后与激励能量比较,来判断是否为静音帧
代码片段如下:
/* Compute the threshold */ //lsc 这里计算门限,本质而言,还是一个能量探测器
Acc0 = L_shl( VadStat.Nlev, 13 ) ;
Tm0 = norm_l( Acc0 ) ;
Acc0 = L_shl( Acc0, Tm0 ) ;
Acc0 &= 0x3f000000L ;//lsc 笔者认为,itu可能把10这个因子塞在这里了,把10拆成(10^0.005)^20,塞进指数里,做了缩放,纠结的运算啊
Acc0 <<= 1 ;//lsc
Tm1 = extract_h( Acc0 ) ;
Acc0 = L_deposit_h( ScfTab[Tm0] ) ;
Acc0 = L_mac( Acc0, Tm1, ScfTab[Tm0-1] ) ;//lsc 这两行计算斜率,插值
Acc0 = L_msu( Acc0, Tm1, ScfTab[Tm0] ) ;
Tm1 = extract_h( Acc0 ) ;
Tm0 = extract_l( L_shr( VadStat.Nlev, 2 ) ) ;
Acc0 = L_mult( Tm0, Tm1 ) ;
Acc0 >>= 11 ;//lsc 这里隐含着扩大8位, 15+1-2=14 而只右移11位,则扩大了8倍,这样基本算是找到了文档的1/80分之一的因子了

/* Compare with the threshold */ //lsc 0表示为静音 笔者认为文档中的描述有误,应该是thr*nlev与能量比较,至少从代码看,是这样,纠结啊
if ( Acc0 > Acc1 )
VadState = 0 ;

尾响处理,如果是元音,后面的6帧认为非静音,比较简单,笔者就不列出代码了

总结:
g723的能量检测仍然基于能量检测的

林绍川
2012.1.5 于杭州

g723源码详细分析-15-静音检测相关推荐

  1. g723源码详细分析(-)

    完成了g723源代码的分析,现作一些整理 1 信号高通滤波 Rem_Dc: 这个函数做高通滤波用的.将低频噪声滤除 滤波器的系统函数为 H(z)=(1-z^(-1)) / (1 - (127/128) ...

  2. g723源码详细分析-11-多脉码激励编码

    上一节分析了g723低速率下的固定码本搜索, 在高速率下面,对去了自适应激励成份后的语音信号, g723采用的是多脉冲编码方式.本文现做一个简要的闸述 在分析代码之前,仍然是要做一些公式推导,否则不易 ...

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

    g723对网络丢包行为了一些处理 涉及的函数为Comp_Info Regen Comp_Info:负责计算插值依据 它的四个参数 Word16 *Buff:激励数组,包含之前的145个激励 Word1 ...

  4. LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  5. linkedhashmap 顺序_LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  6. FBReader源码详细分析 序言

    2019独角兽企业重金招聘Python工程师标准>>> FBReader源码详细分析 -- 序言 有关FBReader源码的分析,网络上已经有一位叫做"谋哥"的大 ...

  7. HashMap 源码详细分析(JDK1.8)

    1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值 ...

  8. vboot源码详细分析-1

    最近一直在研究bootloader之vboot,vboot短小精悍,如果只是用来进行系统的引导,而不要提供其他复杂的功能时候,我认为这是绝佳的上选.这里以MINI2440开发板配套的源码进行分析.这个 ...

  9. android view 源码分析,Android ViewPager源码详细分析

    1.问题 由于Android Framework源码很庞大,所以读源码必须带着问题来读!没有问题,创造问题再来读!否则很容易迷失在无数的方法与属性之中,最后无功而返. 那么,关于ViewPager有什 ...

最新文章

  1. 【深度学习理论】(4) 权重初始化,Batch Normalization
  2. 快讯 | 中国胆管癌研究会成员大会暨胆管癌临床研究数据标准发布会在清华大学召开...
  3. Silicon Labs收购业界RTOS厂商
  4. Kali Linux”下列签名无效“解决办法
  5. 计算机的云是什么意思_高考倒计时!现在学什么专业好?答案是……
  6. 自我学习SSM框架集成(二)
  7. c# 调用音库开发英语单词记忆本
  8. Xcode模拟器和真机生成的日志查看(ios必知必会)
  9. 3.深度学习练习:Planar data classification with one hidden layer
  10. linux下利用nohup后台运行jar文件包程序
  11. 需求文档:没有标准,只有沟通
  12. 为托管应用程序添加DPI Aware支持
  13. c++ 捕获所有异常
  14. php 嵌套函数公式解析,Pyparsing,使用嵌套解析器解析php函数注释块的内容
  15. SSIS高级转换任务—导出列
  16. Java 将图片或者视频模糊化(附代码) | Java工具类
  17. mysql error1682_mysql5.7报错 1546、1577和1682问题分析
  18. 微信小程序开发之——用户登录-登录流程(1)
  19. Believe in yourself
  20. MFC CPropertySheet 多页面切换 事例

热门文章

  1. 关于打的 umd 包在使用时,报 require is not defined 错误的问题出处
  2. 软件测试复习09:集成测试、系统测试、验收测试、回归测试
  3. 人间仙境 绵山水涛沟秋季美景
  4. 使用Python下载抖音无水印视频
  5. html页面如果想要字体比12px还小
  6. switchcase:根据用指定月份,打印该月份所属的季节。3,4,5春季。6,7,8夏季。9,10,11秋季。12,1,2冬季。
  7. Linux错安装libpng12的问题
  8. 解决:nrm throw new ERR_INVALID_ARG_TYPE(name, ‘string‘, value); 问题
  9. MFC程序调用Windwos CMD命令打印图片 MFC 控件显示层次调整,即(叠放次序)和绘制遮挡置于底层顶层灰色
  10. 铭瑄H610itx升级E1.4G版本BIOS后HDMI不能输出音频(无HD audio选项)解决方法