当前课程知识点:计算机音乐 > 第六章 高音跟踪 > 6.2 时域音高跟踪 > 时域音高跟踪
同学们
大家好
这节课我们会来介绍一下
在时域上进行音高跟踪的经典算法
尽管人耳对很多时域的音频特征
并不是特别的敏感
但是时域处理方法是直接处理计算机存储的
原始音频
因此从效率上或者说运行速度上会有比较大的
优势
时域的音高跟踪算法
基本上是基于一种叫做自相关的思想
那么这种方法需要两个步骤
第二个步骤就是对信号进行分窗的处理
然后对这个窗口进行平移
跟原始窗口进行比对
那么第二个步骤就是需要在平移的过程中去
计算一个相似度的函数
这就需要引入一个相似度函数
比如说我们引入ACF自相关函数
那么这自相关函数就是对两个信号
它可能第二个信号是平舆过的
那么我们对它进行逐点的相乘
最后再加起来
那么在AC F就是自相关函数的定义下面
如果两个信号它的趋势比较接近
或者说完全重叠
那么它计算出来的ACF的值正的跟正的相乘
负的跟负的相乘
它就会显得比较大
那么如果这两个信号它趋势是相反的
比如说正的跟负的相乘
这时候得到的值都是负数
它得到了SF总的值就会比较小
比如说如果这个信号是周期的
那么按理说它在评过一个周期之后
应该会达到一个极大值
那么我们只需要在整个平移的过程中去计算
ACF的值
那么去求极大值所在的时间的点的位置就可以
得到周期
那么得到周期之后
我们就能计算出频率
也就是能计算出音高
我们来看一下这个过程
那么当
第二个信号在平移的过程中
我们就能通过相乘得到一个ACF对应的值
我们看到在平过这一小段距离之后
第一个信号的波谷对应的是第二个信号的波峰
所以这时候它的趋势是完全相反的时候
得到的值会达到一个极小值
那么紧接着我们再平移一小段
再评一小段之后
我们发现这两个第一个信号的第二个波峰跟第
一个信号的第一个波峰是对在一起的
因为波峰对在一起
所以它的趋势是一样的
这样话得到的ACF值就会比较大
我们就会看到ACF会达到一个极大值
那么再经过一段时间的平移
平信号的第一个波峰又会对应于
原始信号的第二个波谷
所以我们又看到了有一个极小值出现
那么紧接着我们再进行平移
那么这时候波峰又对着波峰
所以我们又会看到有一个极大值出现
那么这个过程会一直进行到
平移信号正好是平移过一个周期的情况下
假设这个信号是周期的
我们一定能够保证
这个信号的开头
跟第二个周期的开头是完全一样
那么这样的话计算出来
ACF的值就会比较大
这里面我们会看到一个非常大的极大值
因此我们的根本的目标就是去计算出极大值的
坐标
由于ACF的定义
它在不平的时候一定是完全重合的
所以第一个极大值是没有意义的
因此我们总的目标是找除了第一个极大值
以外的最大的值
那么这一个过程我们用python可以进行
一个简单的实现
好
在测试我们的ACF函数的时候
我们可以先截取一段刚才我们录制的
Youku里里的音频中的一个部分
用来测试ACF的性能
我们其实不需要一定要严格地抓取整数个周期
我们只需要抓取其中一段
来做测试就可以了
那么把这一段进行复制
然后存储成一个text文件
保存
好
那么接下来我们就在python里面来完成
这ACF的计算
那么由于numpy下面有一个内积的函数
所以我们计算ACF会变得很简单
假设原始的窗口是X
在窗口移动的过程中
原始的窗口跟移动窗口的重叠部分
在原始的窗口里面
它的索引号是从零到N减I
而移动的窗口的需要
是从A到N这样的话我们只需要计算一下
这两个重叠部分的内积就可以了
这样的话我们来读取刚才的音频文件
test ACF点wav
然后我们要对它进行
一个标准化
因为我们在计算ACF的时候
它是一个内积
它的值域会变大很多
那么为了不要超出整数的最大值域
我们首先还是要对它进行一个标准化
保证它在负1到1之间
然后再去计算ACF
之后可以把它显示出来
运行一下
我们看到显示出来的ACF的形状
我们其实就直接可以在这形状里面
去找到最大值
最大值所在的位置就是周期的对应的频率了
现在我们看到了ACF的值
虽然它的峰值是比较明显
但从总的趋势上来看
它是一个递减的一个状态
那么这时候我们去找峰值的时候
有些时候是会遇到一些困难的
因为有时候第一个峰值可能并不是特别的明显
但是因为它有递减状态
会使得这第一个峰值又变得非常的明显
我们是需要来处理一下这样的一个趋势的
在刚才计算过程中
我们可以看到在平移的过程中
ACF总的值是在呈递减的趋势的
那么这是因为原始窗口跟平行窗口的重叠的
部分
它是一直在递减的
随着移动的过程
它的重叠部分一直是在递减的
那么这种趋势在
估计极大值的时候是会有影响的
比如说如果
第一个极大值本身是比较大的
但是因为有一个递减趋势
它被削的比较小
这时候极大值可能会不那么明显
因此我们需要用一个算法来进行修改
我们只需要修改一下屏窗口的大小
把它修改成原来的一半
这样话它跟原始窗口的重叠部分就是只有原始
窗口的一半
那么只要我们保证在平移的过程中
平移的量不要超过半个窗口的大小
这样话在平移过程中
它跟原始窗口的重叠部分一直是保持不变的
让我们把修改加到我们程序中
并且来找到最大值的位置
下面我们就来实现一下半窗的算法
我们首先复制一下ASF的函数
然后现在的窗口大小是原来的一半
然后我们再进行窗口的
内积计算时候原始的窗口
它的索引的项是从N到N加I这样的半个窗口
的大小
而这平移的窗口一直是从零到N好
那么这样计算之后
我们看一下
相应的结果
比如说Y1等于acf和Y2等于AC F2X
然后我们把Y1跟Y2都进行一个显示
运行下
我们可以看到使用了半窗技术之后
这里的所有的峰值的高度都被标准化了
也就是不会出现这种递减的状态
所以我们可以比较容易的能够检测出
峰值的大的位置
那么接下来我们就使用numpy下面的
findpeaks函数
来检测它的位置
那么在scipy里面提供了findpeaks这样
的找到峰值的方法
要使用这个方法
就需要把import进来
然后我们需要给定寻找峰值的窗口宽度
那么一般来说我们就用
默认的arange12这样的
一格的这样的宽度
左右各一格的这样宽度就可以了
然后我们把寻找出来的inde
它的峰值的横坐标下标
记录在peak indices里面
然后去调用find peaks
CWT从
Y跟peak width作为一个作为它们的输入
然后并且计算出它的峰值的高度是多少
直接复制这一个就可以了
接下来我们把峰值都画在图上
看找的对不对
我们通过绘制散点的方式
去绘制它的横坐标是pesk indices
纵坐标是peaks
然后它的形式是marker
是以圆圈的形式
并且圆圈的中心射程没有颜色
边缘呢设成蓝色
好
最后在
show出来
在这里我们是widths现象
好
我们看到在这个图里面基本上比较高的峰值
都是找的比较准确的
而比较低的峰值
有些地方它因为窗口精度并不是很够
所以找的会有点点偏差
但总来说这个结果应该是能够让我们满意的
我们只要设定阈值
看看哪些峰值呢
达到我们的阈值之上
我们就可以认为这个峰值
它所在的这个位置
就是周期的大小
那么接下来我们就可以直接设定阈值
找出峰值的位置
那么接下来我们就在这些峰值里面设定一个
阈值
比如说for idx in peak indices
那么首先它不能是第一个峰值了
因为第一个峰值它的高度肯定是最大的
所以第一个峰值我们是不要的
所以首先idx不等于1
第一个峰值肯定会在一这个点上找到
因为它要在边缘上去去找
所以至少要往后移一个点
并且它的峰值I dx叫大于第一个点的
值的
比如说0.9吧
那么这个值它的设定就比较经验了
找到之后这idx所对应的那个点就是所谓的
周期了
那么我们可以用采样率除以周期来计算出它的
频率
那么print
并且中断中断这个循环
运行一下
这样我们看到计算出来结果是432
那么跟440其实差的不是特别的远
那么中间会有一些计算上的一些误差
那么接下来我们就可以去录制一段声音
并且通过分窗的形式计算每个窗口的音高
从而得到一段声音的音高曲线
那么接下来我们来演奏一段实际的音乐
来看一下在一段连续的音乐当中
它的音高曲线是什么样的
一
在刚才的计算过程中
我们看到在求最大值的时候需要设定一个阈值
那么因为acf的范围是不固定的
它跟窗口的长度还有原来信号的值域也是有关
的
所以我们去确定这个阈值并不那么容易
但是我们可以对ASF做一个标准化
那么我们可以在原来ACF的计算基础之上
再去除以ST的平方加上ST减τ的平方
那么我们可以用高中学过的一个基本的不等式
来证明这个式子一定是小于等于一的
因为我们学过
2AB是
小于等于A平方加B平方
这个式子
可以用均值不等式来解释
那么也可以把2ab移到右边
这样话它就是A减B的平方
当然无论这边是正还是负的
它都是成立的
所以我们一定能够确保2AB呢除以A平方
加B平方是大于等于1
小于等于1的
所以做了这样的一个处理之后
那么如果我们再把
窗口的个数给除掉
那么一定能够
能保证这一个式子是小于等于1大于等于负1的
跟ACF类似的函数是平均
显著差异函数AMDF
那么它的定义是两个信号逐帧相减
那么求绝对值之后再加起来
所以它跟ACF体现的地方就不太一样
ACF体现的是这两个信号的相似度
而AMDF体现的是这两个信号的差异
所以当这两个信号平移的距离正好是一个周期
的时候
它们的差异应该是最小的
因此我们需要在窗口评过程中去求一个最小值
那么当然了
一开始的时候两个窗口是完全重叠在一起的
所以最小值同样也是在最开始
那么我们要求的是除了第一个点之外的
剩下的那些点中的一个最小值
那么整个计算过程跟ACF基本上是一样的
具体的实现我们就由同学们在课下完成
我们就不再演示
除此之外
我们还可以结合ACF跟AMDF
因为在周期所在的点对于ACF来说是一个峰值
而对MDF来说是一个谷值
那么峰值处于谷值就会
形成一个非常显着的峰值
那么也许在ASF跟AMDF里面这两个值都
不是特别的显着
但是如果做了相除之后
我们可以看到这个周期所在地方会被极大的
放大
这样话我们就能够更容易的找到周期的点
很多经典的时域音高跟踪算法都是使用ACF
跟AMDF结合
比如说Kawahara发明的音算法
就是在ACF跟AMDF结合的基础之上
再配合曲线插值求峰值
从而检测出音高
那么这个算法也成为很多著名的音频处理软件
的标配
我们将会在最后一个小节来使用这个算法
时域的算法从性能上并不算特别优秀
最关键的是它无法在检测音高的同时
获得音与音之间的边缘
但是由于它的高效的性能
让它可以为实质性比较高的系统服务
那么以上就是有关时域应该跟踪算法的介绍
下一节我们将会从平域的角度来介绍音高跟踪
-欢迎辞
-1.1 计算机音乐导言
--计算机音乐导言
-1.2 计算机音乐课程主要内容
-1.3计算机音乐课程资源
-1.4 音乐的基本表达
--音乐的基本表达
-第一章作业
-2.1时域音频处理概述
--时域音频处理概述
-2.2 分窗处理1:OLA叠放
-2.3 分窗处理2:音量计算
-2.4 端点检测
--端点检测
-2.5 振幅包络
--振幅包络
-2.6 音频信号相乘
--音频信号相乘
-2.7 环形调制
--环形调制
-2.8 频率调制
--频率调制
-2.9 频率调制在音乐上的应用
-第二章作业
-3.1 频谱概述
--频谱概述
-3.2 傅里叶变换
--傅里叶变换
-3.3 短时傅里叶变换
--短时傅里叶变换
-3.4 加法合成
--加法合成
-3.5 线性滤波器
--线性滤波器
-3.6 京剧锣鼓经分析
--京剧锣鼓经分析
-第三章作业
-4.1 音色合成概述
--音色合成概述
-4.2 质点弹簧阻尼模型
--质点弹簧阻尼模型
-4.3 双线性滤波器
--双线性滤波器
-4.4 Modal合成
--Modal合成
-第四章测试
-5.1 一维振动模型概述
--一维振动模型概述
-5.2 弦振动模型
--弦振动模型
-5.3 达朗贝尔的行波解
--达朗贝尔的行波解
-5.4 梳状滤波器
--梳状滤波器
-5.5 Karplus Strong算法
-5.6 管状气鸣乐器模型
--管状气鸣乐器模型
-第五章作业
-6.1 音高跟踪概述
--音高跟踪
-6.2 时域音高跟踪
--时域音高跟踪
-6.3 频域音高跟踪
--频域音高跟踪
-6.4 K歌评分
--K歌评分
-第六章作业
-7.1 音频同步概述
--音频同步概述
-7.2 音乐特征提取 CQT
-7.3 音乐特征提取 Chroma
-7.4 动态时间规划概述
--动态时间规划概述
-7.5 动态时间规划实现
--动态时间规划实现
-第七章作业