当前课程知识点:计算机音乐 > 第七章 音频同步 > 7.5 动态时间规划实现 > 动态时间规划实现
同学们大家好
在这一节里面
我们将使用python程序来实现
动态时间规划算法
那么在上一节当中我们知道
动态时间规划的目标
其实就是在代价矩阵里面
去规划出一条最优的路径
那么在最初的时间过程中
我们不妨假设要进行同步的两段数据
其实就是
每个元素都是一维的整数
那么这两个整数的距离
我们可以用它们的差的绝对值来表示
这样的话我们对两个数列两两相减
就可以得到这样的一个代价矩阵
那么我们的目标就是在代价矩阵里面
去寻找出一条代价总和最小的一条路径
那么当这条路径
完成之后
我们就可以从这条路径里面推算出
这两个数据所对应的时间点是哪些
那在动态规划算法里面
我们使用一种递推的形式来求最优的解
我们假设D(n,m)是从左下角走到
n,m这个点的一条
最优的路径当中
经历过的点的代价的总和
那么我们最终求的目标其实就是
D(N,M)这样的一个目标
但D(N,M)的值算出来之后
我们就可以反过来去推算出
他所经历的路径是哪一些
那么在计算过程中
我们希望是能够使用
递推的方式来计算的
利用D(n,m)的前一个点
它可能是D(n,m-1)
有可能是D(n-1,m)
有可能是D(n-1,m-1)
总之是D(n,m)前面的一个点
我们只需要比较一下
这些点当中哪一个的地址
比较小就可以了
如果用递推公式表示出来
也就是说我们需要
优化的是D(n,m)这个值
他计算我们可以用
D(n-1,m)D(n.m-1)D(n-1,m-1)
他们的一个最小值再加上
当前所在的点的一个距离
就可以求出它的一个最优值
那么接下来
我们就使用python来实现这段程序
接下来让我们就来简单的实现一下
动态时间规划算法
那么我们把输入的两个音频
简化成两个列表
这样的话每一个点就是一个数字
点与点的距离就是
这两个值之间的差的绝对值
首先我们来完成一个求最优的代价总和的
这个函数
利用这个函数我们
就可以反推出
最优的代价总和是
沿着哪条路径计算出来的
那么这个代价总和首先我们有一个是
小的处理
就是我们给
大家综合的矩阵在最上方以及
最左边加上了
一行一列的无穷大的值
这是为了保证
最优的路径总是可以从左下角开始
然后到右上角结束
因为加了这一行一列
所以它的横坐标上会发生
一个错位
那么我们在计算距离的时候要注意这一点
好那么接下来就是我们通过
下面的一个循环
递归的计算出
Dij的值
这里面我们用了前面的这最优化公式
也就是说我们要计算
Dij就要计算
i跟j两个点的距离
因为我们加了一行一列
所以这里面有一个错位发生
按照我们算法设计
Dij值是由D(i-1,j)D(I,j-1)D(i-1,j-1)
这三个值中的最小值再加上
i跟j的距离得到的
所以我们通过这样的递归计算
就可以算出一个最优化的
路径所对应的代价总和
利用这个代价总和
我们就可以反推出路径
是什么样的点
我们简单的来运行一下
好运行之后我们可以看一下
代价总和
利用D的矩阵我们就可以从
右上角反推出
通过寻找最小值的方式
反推出一条最佳的一个路径
我们只要去调用path
就可以知道它对应的点的关系
在完成动态时间规划的简单实现之后
我们只要把
输入的两个数据替换成音频的特征
就可以进行音频的同步了
接下来
我们把输入的两个向量替换成两段音频
为此我们可以用
哨笛录制一段凯尔特的民歌
那么这一段片段来自tall trees long shadows
第一遍演奏我们使用
比较慢的一个速度
第二遍
我们在使用较快的速度来进行演奏
最后我们希望使用
动态时间规划算法来进行
两段音频的同步
好那么接下来我们就在刚才的
DTW算法基础之上
把输入的两个项替换成音频的特征
那么这里面我们就要注意
这里面引入的距离
我们就需要用一个距离函数来表示了
我们可以用欧几里得距离
也可以用其他的一些距离
我们就需要用scipy下面的
spatial的模块
然后下面有些距离函数
现在我们暂时用
欧几里得距离作为默认值
在实际的计算中
我们实际上用了这个cityblock
也就是我们在
前面的讲稿里面
使用的一减去
相关度这样的一个距离
好那么作为输入
我们读取了一快一慢两段音频
并且提取了他的chroma cens特征
之前我们提取过了特征
然后这两个特征之间的距离
我们用cityblock来这种距离来表示
完成前面的递矩阵的计算
并且计算出它的路径
反推出它的路径
那么接下来我们就把
这个路径上对应的点的结果用
图表的形式显示出来
在最上方绘制的是
第一段音频的特征图像
在最下方绘制的是
第二段音频的特征图像
对应的点我们用黑线连起来
并且
如果我们直接点对点相连了
黑线就会太多
所以我们每30个点一组
那么做了一个分组
运行一下
我们看一下结果
我们运行结束之后
我们可以从这个图中看出
其实这个
音频同步的结果还是比较理想的
在每一个对应的窗口
它的音频特征虽然有一点点差别
但是基本上是匹配的
这样我们就实现了同一段音频
用同一件乐器
不同速度的演奏版本的
音频同步
那么在接下来时间当中
我们将会使用不同的乐器
来演奏阳关三叠
那么首先我们使用埙这件乐器来演奏
它是F调的
我第二个版本
我们使用来自云南的一件乐器
叫做巴乌来演奏
那么虽然音色上是不一样的
而且它的发声原理也不一样
刚才的埙是边棱音的乐器
而巴乌是簧片类的乐器
但是他们是同一个调的
都是F调的
那么最后一个版本呢
我们使用箫这件乐器来演奏
那么跟前面不同的是
这次的这个版本我们用一个
不同调的版本
我们用G调的版本来演奏
那么我们将会用动态时间规划来看一下
这三段版本的同步的情况
让我们先来比较一下埙跟巴乌两个版本的
匹配结果
我们看到虽然两件乐器的音色是不同的
所以我们看到它的频谱分布
具有比较大的差别
但是主要能量都集中在
主要音高上面
所以我们在匹配的时候
基本上
我们看到匹配的这个窗口
它的音高都是一样的
那么从整个同步的效果来看
它效果还是比较好的
之后我们来比较一下埙跟箫
两个乐器的匹配的结果
再次运行下这个程序
我们看到这个匹配结果
就比较糟糕了
其实箫跟埙的音色从频谱上
其实是比较接近的
但是因为这是不同调的两件乐器
我们用了不同调来演奏
所以我们看到它的主音
并不在同一个位置
比如说
箫的这个唻因为它是F调的
所以这个唻所在的这个位置是
G这个位置
而下面的箫它是G掉了
所以它的唻的位置在A这个位置
这两者其实在计算距离的时候
我们因为是点对点匹配
所以它的差距是比较远的
这里面我们看到本来
这样的一个模块
它对应的应该是这个模块
但这里面就产生了错位
所以整个结果来看是比较糟糕的
因此对不同调的版本之间匹配
我们无论在距离的计算上
还是在特征的提取上面
都是需要去做一点功夫的
最后让我们来稍作总结
在这一章当中
我们提取了音频的半音阶特征
并且用动态时间规划的算法
求出了两段音频的对应关系
这个特征在两段音频的演奏的过程中
我们需要假设他演奏的是同一段乐谱
在这样的假设之下
我们看到效果是比较好的
而在刚才的实验当中我们也看到
如果改变音色并没有太大的一个影响
用埙用巴乌
虽然他们的发声原理都不一样
但是他们的同步效果还是比较好的
但是如果我们进行了移调之后
比如说像箫跟埙两个版本
虽然它从音色上比较接近
但是因为他们调性是不一样的
所以结果就会比较差了
那么有关音频同步的应用
我们就介绍到这里
下次我们再见
-欢迎辞
-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 动态时间规划实现
--动态时间规划实现
-第七章作业