最近学了一点即兴伴奏,想训练自己分辨和弦,编配和弦的能力,但是手头没有钢琴去尝试,只有光遇游戏里的十五键钢琴(惨奥)。
无意之中发现了这么个项目 https://github.com/Rainbow-Dreamer/musicpy/
顿时来了灵感,这么熟练python了,为什么不用python来写音乐呢
作者的思想是用代码来写音乐,达到一定的抽象程度,短短几十几百个字节能够表达出一个midi文件轨道记录的几千个音符。
我所了解到的即兴伴奏的思想就是左手基本上就是几个套路(如隔三空二四二之类的),而用midi文件来表达这些的话,却要把每个音符全都无脑的记录下来。
其实呢,只需要主旋律,和这个小节对应的和弦,再加上伴奏的织体,就足以表达了。
那么我可不可以开发这样一个项目呢,能够随意改动和弦和织体,然后不断的试听和感受不同和弦不同织体产生的效果,达到很好的训练目的(而这一需求,要是用一些专业软件不断的调整音轨里面的高度来实现,将是灾难性的麻烦),我希望我改个和弦只需要改一个字母!!
最终决定,用文本格式表达简谱的内容,包含主旋律、和弦、织体等信息,自己定义其格式,然后编写一个简谱解释器,能够播放出来或者转换成音轨记录到 midi 文件里面。
初步的规则如下
- 用 1~7 表达简谱中的音符,0 代表休止符,和简谱一致
- 在一个音符后面,用 ` 代表高音,用 . 代表低音,可以叠加
- 在一个音符后面,用 _ 代表八分音符(可叠加成十六分音符等),用 - 代表延音,用 ^ 表示连音线,用 * 表示附点
- 在一个音符后面,用 b 代表降音,用 # 代表升音
- 用中括号 [] 括起来的音符表示同时发音
- 用括号 () 括起来的音符,可以同时进行 `._b#的运算,降低表达长度
- 在小括号后面加 $ 表示括号内全部连音,比如 (222)$ 表示一个四分音符内三连音
- 用 | 表示小节线,每一行可以放任意多小节,换行表示两个小节叠加成不同的声部,用单独的一减号 - 表示另起一个小节,而不是叠加声部。
- 能够按特定的格式提前定义若干个织体格式,然后将织体当成一个函数,参数是和弦,程序自动计算出织体加和弦对应的若干个音符,进而得到整个伴奏。
织体究竟该怎么定义,这是个头大的问题,因为实际应用中,可以很灵活应用,比如我可以隔三空二四,可以隔三空二四二,还可以减法法则,从后往前减去若干个音符。
最终决定用替换法,比如 C 大调和弦 C E G,我用 1 表示 C,2 表示 E,3表示 5,4表示高音C,5表示高音E,以此类推。那么我隔三空二就可以表示为 1343,隔三空二四二是 13435343,隔三永远是 13,那么我可以把13用一个字母代替,比如a,把43和53分别用 b和c表示,那隔三空二四二就表示为 abcb,隔三空二二二就可以是 abbb,哈哈哈哈哈哈哈。
精心设计之后,决定织体定义格式如下
texture <织体名>: {
@ = <默认的织体标识> # 可选,<默认的织体标识> 可以是下面等号左边的任意一个值,表示默认值。
<织体标识1> = <织体内容1>
<织体标识2> = <织体内容2>
...
}
织体标识就相当于上面讲到的 a b c ,织体内容就是上面讲到的 13435343。
实际解析时,会先将若干个织体标识组转换为织体内容,然后织体内容最终会被转换成具体的音符。
下面举例
texture s:{
@ = 1
1 = (13434343).._
a = (13).._
b = (43).._
c = (53).._
}
这样一定义,再定义如何调用:
织体名(和弦[,织体标识组][,和弦转位][,减法法则])
国际惯例,中括号是可选参数
那么, s(C,abcb) 替换里面的标识就等价于 (13).._(43).._(53).._ 进而等价于 (15).._(1`5).._(3`5).._(1`5).._
也就是说 s(C,abcb) 就表示 C 和弦的隔三空二四二,只需要改一个字母把 C 改成 F,就成了四级和弦的隔三空二四二!
下面介绍各个参数
- 织体标识组省略:省略的情况下,默认是 @ 指向的织体。
- 和弦转位:用 +1 或 +2 等等表示,+1 表示第一转位,即 s(C,+1) 最终会被解析成(31`).._(`3`1).._(3`1`).._(3`1`).._
- 减法法则:用 -1 或 -3 等等表示,表示减去多少个音符,即 s(C,-1) 最终会被解析成 (15).._(1`5).._(1`5).._(1`0).._
三个参数位置可以随意调整和缺省,因为解析的时候,前面带有+就是和弦转位,-就是减法法则,不带就是织体标识,参数之间用逗号隔开。
此外还有一些细节,在示例中说到,详见 summer.txt。
经过几天的调试努力,最终诞生,取名为 simp-score,用法参数如下:
simp-score <src> [dest]
表示将 src 文件里记录的简谱,解析并输出到 dest 的 midi 文件中。
还有一些可选参数,详见 --help
我将菊次郎的夏天作为示例乐谱 summer.txt,最终生成 summer.mid
注意我调用了 mingus 库的内容,需要 pip install mingus 安装这个库,才能正常运行。
如果后序改进,可能会添加自定义和弦的功能,预设了大多和弦在程序开头,或许万一有别的特殊需要呢。