基于乐谱生成旋律路径动画(与音乐同步时间播放)
背景
- 基于乐谱的音符时值和音高生成平滑曲线路径
- 以乐谱时间为x,沿路径运动动画
animejs提供了svg路径动画能力,svg的点坐标是基于路径的长度获取的,整体的运动函数是线性函数,也就是说:
1 | f(x,y) = path.getPointAtLength(distance) |
时间t0点的 x坐标 取决于 路径总长度。不同乐谱在相同t0时间点的x坐标是不一致的。
图中红色为基于路径总长度的svg动画,黑色为linear直线动画,可以看到在当前时间点,x是对不上的。
而我们需要的音乐路径动画,是无论是什么乐谱,在t0点的x坐标是一致的
即: y = pathPoint(x) = g(x) ; x = maxX * t/duration = f(t);
1 | y = pathPoint(x) = g(x) |
或者降级为:音符内不严格 x=f(t), 每个音符结束的时间点符合 x = f(t);
实现正比于x|t的路径动画
切分乐谱的总svg路径,每个音符的svg为一个path,每个path生成一个路径动画,duration = 音符持续时间,全部动画拼成一个timeline,总时长= 乐谱时长, (中间休止符需要补全直线?)
图中蓝色块为每个音符起止时间点与x对应的动画(音符区间内x、t不严格对应)
demo:
https://codepen.io/Topppy/pen/dymGGrb
- 块1是x线性t的位移
- 块2是一整条svg路径动画
- 块3是两段path拼接的一条svg路径
块1作为基准,可以看出块2全程x都与块1无法对齐,块2在中间点和结束点是对齐的,但是中间的不规则路径跟块1的x位移没有对齐,点击seek1按钮定位时间到中间点,可以明显看出来。
块3是可以降级满足音乐旋律路径走谱的。
根据乐谱绘制平滑旋律路径
乐谱中需要占据时间的节点有两种
- 音符(svg C)
- 休止符(svg L/H),(也可以忽略休止符)
数据处理逻辑:(具体可以参考d3)
点数据: 合并有序数组音符(notes) 和 休止符(rests)- C曲线控制点数据: (这里percentage = 0.5)
- 控制点1: [x0 + 0.5 * (x1-x0), y0]
- 控制点2: [x0 + 0.5 * (x1-x0), y1]
- svgPathList:
- 如果onset=0的点不是note, 需要从(0,0)开始
- 终点(score.duration, 0)
曲线的的曲率变化
对称:p1.x =distance(x1,x2)- p2.x
非对称: p1.x = p2.x
也可以独立控制两个控制点的x的percentage
最后demo:
https://codepen.io/Topppy/pen/JjLGmBd?editors=1010
参考
svg路径编辑器
d3的curve效果:https://github.com/d3/d3-shape/blob/v3.1.0/README.md#curves
d3的natural curve 源码:https://github.com/d3/d3-shape/blob/main/src/curve/natural.js
web audio 调节播放音频的音高 : https://zpl.fi/pitch-shifting-in-web-audio-api/
midi文件格式解析:https://www.jianshu.com/p/59d74800b43b
Magenta魔改记-2:数据格式与数据集(涉及midi和mxl格式对比https://zhuanlan.zhihu.com/p/49539387
乐谱渲染:https://github.com/0xfe/vexflow
mxl乐谱渲染:https://github.com/opensheetmusicdisplay/opensheetmusicdisplayddemo
demo页:https://opensheetmusicdisplay.org/demos/public-typescript-demo/
❤️🔥基于机器学习的自动作曲:https://magenta.tensorflow.org/
https://magenta.tensorflow.org/demos/web/
https://github.com/magenta/magenta
music21 指南:计算音乐学分析python库:https://github.com/lukewys/Magenta-Modification/blob/master/Music21简明指南.ipynb