python设计一个函数定义计算并返回n价调和函数_音乐编程语言musicpy教程(第三期) musicpy的基础语法(二)...

这个是我在github上给我的项目musicpy写的wiki,分为数据结构,基础语法,实际应用三大部分来为大家讲解这门音乐编程语言,主要是想给大家写一个musicpy的详细的教程与介绍,目前wiki只写了一部分,不过已经有非常多的东西了。我在这里把github上我目前写的musicpy的wiki分成几期连载。github上我的项目musicpy的wiki的地址:

https://github.com/Rainbow-Dreamer/musicpy/wiki

(注:musicpy是我个人开发的一门基于python实现的内部DSL(领域特定语言),整体是一个python库,我以python的类的运算符重写以及其他的magic methods的重写,将musicpy变成了一门符号化的音乐编程语言,有自己的一套独特的语法与数据结构,musicpy的作曲代码看上去和python会长得完全不一样(不过当然也可以写成很像2333),以后我会更新一些musicpy的作曲代码示例,给大家体验一下musicpy的符号化作曲语法)

正文:

Basic grammar of musicpy Part 2 基础语法(二)

得到一个和弦的所有音符的音名

首先,如果只是得到一个和弦A的音符的列表,那么只需要

A.notes

即可,得到的是和弦A的音符列表,比如A是一个A小七和弦,那么得到的是

[A5, C6, E6, G6]

如果想要得到和弦A的所有音符的音名的列表,那么就可以使用和弦的其中一个内置函数names,比如

chd('A','m7').names()

就可以得到

['A', 'C', 'E', 'G']

对两个和弦或者两个音乐片段进行合并连接(声部合并,声部拼接)

和弦类型的内置函数add可以合并两个和弦(或者两个音乐片段)。 比如现在有两个音乐片段(和弦类型本身也可以是音乐片段)A 和 B。

参数mode可以用来选择合并的模式,

当mode == 'head'的时候,

A.add(B, mode='head')

可以得到合并A和B两个音乐片段后的新的音乐片段,B的开头对齐到A的开头,也就是A和B同时从头开始进行演奏的音乐片段。

合并的机制是重新计算合并过后的音的间隔,然后把A和B的音符按照计算的间隔,调整好顺序进行重新的合并排列。 add函数还有一个参数start,可以用来设定B要从A的什么地方开始进行合并,也就是B的开头对齐到A的什么地方, 单位为小节,换句话说,就是B延后A开始多少小节开始进行演奏。比如:

A.add(B, mode='head', start=8)

可以得到B从A的第8小节开始演奏的合并过后的音乐片段。

进阶写法:

A & B

A & (B, start)

当mode == 'tail'的时候,

A.add(B, mode='tail')

可以得到音乐片段B追加到音乐片段A之后的新的音乐片段,不过需要注意的是,这个模式是直接把B的音符列表追加到A的音符列表之后, 然后把B的音符间隔列表也追加到A的音符间隔列表之后,如果音乐片段A的最后几个音符间隔是0的话,那么可能会出现音乐片段B的开始几个音与A的最后几个音重叠在一起的情况,如果很确定A的最后几个音符间隔不是0,那么这个模式可以放心地使用。 等价于

A + B

当mode == 'after'的时候,

A.add(B, mode='after')

可以得到音乐片段B追加到音乐片段A之后的新的音乐片段,与tail模式的区别在于,这个模式会特别计算A与B之间是否需要多一些音符间隔, 以避免tail模式里面某些情况下A的结尾与B的开头会重叠的情况。所以当不确定A的最后几个音符间隔是否为0的时候,使用这个模式最好。

进阶写法:

A // B

或者

A | B

对一个和弦内的音符做出修改

之前我已经讲过如何通过索引值访问一个和弦内的音符,比如A[1]就会得到和弦A的第一个音符。 想要对一个和弦内的音符作出修改,比如和弦A是一个C大七和弦,

(原位的形式,C, E, G, B)我们想把和弦A的第二个音(三度音)换成F,也就是把和弦A变成一个maj7sus4和弦,我们可以这样写:

A[2] = 'F5'

然后我们再打印一下和弦A,

[C5, F5, G5, B5] with interval [0, 0, 0, 0]

会看到和弦A的第二个音已经从E5变成了F5。 请注意,更改的音符可以是音符类型(note('A', 5)这样子通过note的初始化函数得到的),也可以是表示音符的字符串, 但是一定要有八度数,不能只有音名,比如'F'这样子就不能用在这里,必须要有一个八度数,比如'F5'这样子。

对一个和弦的某些音符进行删除,或者在某个位置插入新的音符

可以参考python的列表的逻辑,使用

del A[n]

可以删除和弦A的第n个音,使用

A.pop()

可以去掉和弦A的最后一个音,并且返回的是和弦A的最后一个音,使用

A.insert(i, b)

可以在和弦A的第i个位置插入音符b

A.append(b)

可以往和弦A添加音符b 此外,extend, remove函数和列表的同名内置方法使用逻辑也是一样的。 当你想去掉和弦A里的一个音时,可以使用'-'号来进行去除,比如

A - 'B5'

如果和弦A中有B5这个音符,则会返回一个新的去掉B5这个音的和弦,如果没有,则会返回未经修改的和弦A。

往一个和弦加上一个最低音(加一个贝斯音符)

比如现在和弦A是一个G major和弦(G大三和弦),组成音依次为G5, B5, D6, 我们现在想往和弦A的下面加上一个C音当做最低音, 那么可以写

A.on('C5')

得到的是和弦A加上C5作为最低音的新的和弦, 表示出来是

[C5, G5, B5, D6] with interval [0, 0, 0, 0]

进阶写法:

A / 'C5'

查找和弦内某个音是第几个音

比如和弦A为一个F大九和弦,根音为F5,原位和弦,想找到'E6'这个音在第几个音,那么可以写

A.index('E6')

得到的结果是4,说明音符E在F大九和弦的第4个音。 如果音符不在和弦内,则返回-1, 也可以省略八度数,只写音名进行查找,返回的是第一个音名相同的音符的位置,比如

A.index('G')

得到的结果是5,说明音符G在F大九和弦的第5个音。

往一个和弦后添加休止符

如果要往和弦A的后面添加n小节的休止符,那么可以使用和弦类的内置函数period,

A.period(n)

表示往和弦A后面添加休止符n小节,得到的是一个新的和弦,内容为和弦A加上n小节的休止符。

进阶写法:

A // n

或者

A | n

和弦名解析结构

trans函数可以直接输入完整的和弦名进行解析,返回的是对应的和弦。支持原位和弦表示,转位和弦表示,复合和弦表示等等。 trans函数的第一个参数是和弦名,第二个参数是和弦根音的音高(默认值为4), 第三个参数是duration(音符的长度,默认值为0.25),第四个参数是interval(音符的间隔,默认值为None,返回的和弦interval都为0), 比如

trans('Dmaj7')

可以得到

[D5, F#5, A5, C#6] with interval [0, 0, 0, 0]

trans('F/C')

可以得到

[C5, F5, A5] with interval [0, 0, 0]

trans('C')

可以得到

[C5, E5, G5] with interval [0, 0, 0]

trans('Am/Gm')

可以得到

[G5, A#5, D6, A6, C7, E7] with interval [0, 0, 0, 0, 0, 0]

trans('G/C', 6, 1, 1)

可以得到

[C6, G6, B6, D7] with interval [1, 1, 1, 1]

trans函数的简写方法:

C(和弦名, 其他的参数)

C表示的是和弦chord的首字母大写

对一个和弦进行更高级的操作(变化音,省略音,复合和弦)

比如和弦A是一个C属七和弦,那么如果想要得到C属七升九和弦,可以这么写:

A('#9')

得到的是

[C5, E5, G5, A#5, D#6] with interval [0, 0, 0, 0, 0]

C属七降九和弦则是

A('b9')

比如B是一个C大九和弦,那么如果想要省略三度音,可以这么写:

B('omit3')

或者

B('no3')

多个升降音和省略音可以使用英文的逗号分隔开来,比如

A('#5, b9, omit3')

如果和弦A是C属七和弦,那么得到的是C属七升五降九和弦省略三度音。

如果要构建复合和弦,只需要用'/'连接两个和弦即可,除了两个和弦叠在一起的情况, 还有一个和弦下面外加一个最低音构成的复合和弦,这两种情况都是使用'/'即可。 比如:

C('Amaj7') / 'D'

得到的是

[D5, A5, C#6, E6, G#6] with interval [0, 0, 0, 0, 0]

也就是Amaj7和弦底下加上D作为最低音。 两个和弦的复合和弦的情况,比如:

C('A') / C('G')

得到的是

[G5, B5, D6, A5, C#6, E6] with interval [0, 0, 0, 0, 0, 0]

也就是G大三和弦叠在A大三和弦下面构成的复合和弦。

和弦转位一个音转位到最高音

比如和弦A是C大三和弦原位C, E, G, 现在想把E转位到最高音,那么可以写

A.inversion_highest(2)

也就是把和弦A的第二个音放到最高音,得到的和弦的音为C, G, E 进阶写法:

A / -2

或者

A ^ 2

(A / -n 表示把和弦A的第n个音转位到最高音)

把一个和弦的所有音都转位到一个八度以内

比如和弦A有5个音,最高的几个音分布在比低的几个音更高的八度,那么

A.inoctave()

会返回一个把和弦A的所有的音都放到同一个八度内的和弦类型,八度数为和弦A的第一个音的八度数。

把一个和弦标准化

把和弦A标准化,可以用standardize函数,

A.standardize()

得到的是和弦A标准化之后的新的和弦。

这里标准化的定义是:

1. 如果和弦内有出现重复的音名(即使在不同的八度),那么只保留音高最低(八度数最小)的音。

2. 把所有的音都限制在两个八度以内,也就是到最低音的15度之内,如果有的音比最低音高的半音数超过两个八度,那么就往下减一个八度,直到所有的音都在最低音往上的两个八度之内。

3. 把所有的音名全部统一成没有升降号或者只有#号的格式,如果有b号的就转换成十二平均律里等音高的有#号的音名。

标准化之后的和弦的最低音的音高和标准化之前一样。返回的是和弦A标准化过后的新的和弦。

把一个和弦按照音高数进行排序

如果一个和弦里的音并不是按照音高从小到大进行排序的,比如和弦A的音符依次是E5, C5, G5,那么可以写

A.sortchord()

返回的是和弦A的音符的音高按照从低到高排序好的新的和弦。

按照设定的音阶得到一个和弦的负面和声

比如和弦A是C大七和弦,想要得到和弦A关于C大调音阶的负面和声的转换,那么可以写:

negative_harmony(scale('C', 'major'), A)

得到的是和弦A的音符关于C大调音阶的负面和声的转换过后的组成的新的和弦。

negative_harmony函数的其他参数:

get_map_dict,为True的时候,返回的是第一个参数音阶的每个音符按照负面和声映射到的音的字典。

为False的时候,如果不传入任何和弦类型,那么返回的是传入的音阶类型的负面和声音阶类型,比如

negative_harmony(scale('C', 'major'))

得到的是

scale name: C5 minor scale

scale intervals: [2, 1, 2, 2, 1, 2, 2]

scale notes: [C5, D5, D#5, F5, G5, G#5, A#5, C6]

还有一个参数sort,为True的时候,会把和弦a转换为负面和声版本之后,将音符按照音高从低到高排序。默认值为True。

音阶类型的基础语法

按照音程关系或者调式名构建音阶

scale类(音阶类),这个类可以表示一个特定的音阶。

使用这个类可以快速按照音的间隔来构建调式,比如大调的音的排列是全全半全全全半(全代表全音,半代表半音),

那么如果想构建一个C大调音阶,就可以写

scale('C5', interval = [2,2,1,2,2,2,1])

这样就得到了以C5为根音的C大调音阶。

当然,对于大部分知名的调式来说,只需要输入调式的名称就行了。比如

scale('C5', 'major')

就可以得到以C5为根音的C大调音阶,

scale('C5', 'minor')

得到以C5为根音的C小调音阶。

在database.py里面的scaleTypes是所有musicpy自带的调式,用户也可以自己定制调式。

转调的具体实例

比如现在有一个音乐片段p是A大调,现在想转到A小调,那么就可以写:

p.modulation(scale('A', 'major'), scale('A', 'minor'))

这样就把音乐片段p从A大调转到A小调啦~

关于音阶类的几个重要的内置方法的介绍

按照音阶的级数选取对应的和弦

比如C大调的4级三和弦是F,6级三和弦是Am,这时候可以用pickchord_by_degree函数,其中的参数degree1是和弦级数,

num是选取多少个音,step是每一次跨越几个音阶中的音。按照默认值,

scale('C', 'major').pickchord_by_degree(5)

会得到一个G大三和弦。

按照五度圈将一个调式进行转调

fifth函数可以按照五度圈将当前的调式进行转调,其中的参数step是顺着五度圈移动多少步,如果step大于0,那么就会顺时针转调,如果step小于0则是逆时针转调。fourth函数同理,只是换成了四度圈。

按照和声功能选取一个音阶的和弦

音阶类有内置一组较为完整的调式和弦选取函数。比如现在有一个调式A。那么调式A的主和弦就是

A.tonic_chord()

下属和弦就是

A.subdom_chord()

属和弦是

A.dom_chord()

等等。想得到调式内某一级的副属和弦可以用

A.secondary_dom(degree)

其中degree是级数。

得到一个调式的关系调和平行调

relative_key函数可以得到关系调,比如大调的关系小调或者小调的关系大调。

parallel_key函数可以得到同主音大小调。

对一个音阶进行升降调(整体升降或者个别的音的升降)

音符类型,和弦类型的up和down函数以及其进阶语法也同样适用于音阶。

对一个音阶(调式)名进行解析

toScale函数可以直接输入一个音阶(调式)名进行解析,返回的是输入的音阶(调式)名对应的音阶类型,主音的八度数(也是音阶所在的八度数)

由第二个参数pitch决定,默认值为4。比如

toScale('C major')

可以得到以C5为主音的大调音阶,

toScale('G lydian', 6)

可以得到以G6为主音的lydian音阶。

简写为

S('C major')

S表示的是音阶scale的首字母大写

按照和弦级数提取和弦进行

使用音阶类型的内置函数pattern,可以输入一串表示和弦级数的字符串或者整数来提取一个调式的和弦进行,比如

S('C major').pattern(6451)

可以得到C大调音阶的6,4,5,1进行的和弦的列表,

也可以写

S('C major').pattern('6451')

pattern函数的其他参数:

interval为和弦进行里每个和弦的音符之间的间隔,默认值为0,也就是每个和弦的音符都是一起弹。

duration为和弦进行里每个和弦的音符的长度,默认值为0.25,也就是音符长度为1个小节。

num为按照级数提取调式内的和弦时,每一个和弦提取几个音,比如num为3就是提取三和弦, num为4就是提取七和弦等等。

step为提取和弦时每一步跳过多少个音阶内的音,默认值为2,也就是每次跳过2个音阶内的音(自己算一个音),比如C大调音阶的1级自然三和弦C E G,

每一次都是跳过两个音阶内的音,C,跳两个音到E,再跳两个音到G。(在这里跳过几个音就是往前走几步的意思,每走一步就是走到音阶内的下一个音)

进阶写法:

S('C major') % 6451

这里给大家附上几个musicpy语言的音乐代码示例

1. 东方主旋律:

play((getchord_by_interval('D#4', [5,7,10,7,5], 1/2, 1/8)*3 + getchord_by_interval('F4', [1,0,-4], 1/2, 1/8)) * 3, 150)

2. a = C('Am7')

play(a.period(1/8)*4 + a.up(2).period(1/8)*4 + chd(a[1].up(3), 'maj7').set(interval=1/8))

演奏出A小七和弦后接休止符半拍4遍,然后B小七和弦后接休止符半拍4遍,然后C大七和弦分解和弦1遍。

(以上这两个例子都是没有使用进阶写法的,使用进阶写法可以让musicpy语言看起来更加紧凑,简短)

3. a = C('Dmaj7') % (1/4,1/4) | C('Cmaj7') | C('Fadd9',3) | C('D#maj7',4) | (C('Dmaj7',3)/-2) % (5/4,)

b = chord(['F#5','G5','A5','B5','G5'], 1/8,1/8)

play(a & b, 140, instrument=1)

(第3个例子使用了很多进阶写法,代码看起来紧凑了很多,而且对于两个和弦类型的连接的进阶写法使用分隔符'|'也可以有类似小节线的感觉,可以增强代码的可读性。除此之外,和弦连接的分隔符'|'也可以使用'//'来替代,可以看个人喜好使用)

4. a = (C('Amaj7')/2|0.25)*4 + (C('G#m7')/2|0.25)*4 + (C('Gmaj7')/2|0.25)*4 + (C('F#m7')/2|0.25)*4

play(a + a % (1/4,1/4), 165, instrument=9)

(半音下行大七小七和弦交替)

5. a = C('Bmaj9',3)/[2,3,4,1,5]

b = C('Bmaj9',3)/[2,3,4,1,5,2]

q = a + ~a[2:-1]

q2 = b + ~b[4:-1]

t = (q % (1/8,1/8) + q2 % (1/8,1/8)) * 2

adding = chord(['Bb5','Ab5','Gb5','Ab5']) % (1/2,1/2) * 2

t2 = t & adding

play(t2 + (t2 - 3), 100, instrument=47)

(一段有恐怖氛围的音乐)

这几个例子大家都可以直接复制粘贴到代码编辑器里运行,就可以马上听到对应的音乐了。(不要忘记最开始要先from musicpy import *,也就是要记得 先import musicpy这个库)

(下一期更新musicpy的基础语法第三部分)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值