Skip to content

按照乐理逻辑判断任意一组音组成的和弦类型的算法

Rainbow Dreamer edited this page Jan 29, 2023 · 16 revisions

这是我在musicpy里面开发的按照乐理逻辑判断任意一组音组成的和弦类型的算法。

这个算法是一个逻辑比较复杂的算法,我从头到尾讲一遍可能要写一大堆,因此我就挑重点来讲。

这个算法判断和弦类型的效果非常好,首先,这个算法可以判断任何一组音组成的和弦,无论这组音组成的和弦听上去有多复杂,无论这组音有多少个音,都可以判断出来和弦类型,而且在乐理分析上一定是正确的。虽然在不同的场合下,即使是完全相同的一个和弦也可能有不同的叫法,因为可能有完全不同的功能,但是按照这个算法返回的结果来推算和弦,一定会得到你输入的那组音,而且顺序也一样。

这个算法可以判断各种各样复杂的和弦类型,包括原位和弦,转位和弦,和弦的voicings(和弦音的各种不同的排序),复合和弦,有变化音的和弦(比如属七升9和弦,属七降9升13和弦),有省略音的和弦(比如C大9和弦省略3度音), 有很多重复音的和弦(相差一个或者多个八度的音)。

而且这个算法也可以判断上面说的这些情况混合起来的和弦,比如同时有省略音和转位和有变化音的和弦。

这个和弦判断的算法在detect函数里,接下来讲讲detect函数的用法。

detect(current_chord,
       change_from_first=True,
       original_first=True,
       same_note_special=False,
       whole_detect=True,
       poly_chord_first=False,
       root_preference=False,
       show_degree=False,
       get_chord_type=False,
       original_first_ratio=0.86,
       similarity_ratio=0.6,
       custom_mapping=None)
  • current_chord: 一组音符,可以有多种不同的表示方式,可以是一个和弦类型,也可以是一个音符类型的列表, 也可以是一个表示音符的字符串的列表,也可以是一个单独的字符串(里面是用逗号隔开的音符)。音符可以只有音名,没有八度数,在这种情况下会按照标准化和弦的规则来对音名进行和弦的构建。
  • change_from_first: 为True的时候,优先对于一组音是否为某种和弦通过变化音(升降音,比如#5, b5, #9, b9, #11, b13这种)而得到的进行乐理逻辑分析。返回的和弦判断结果也会比较大概率是某种和弦加上变化音(会给出具体的变化音的音名以及升降的具体情况)。默认值为True。
  • original_first: 在这个算法中,会先对和弦的音符的本来顺序进行乐理逻辑分析,(先检查是否符合原位和弦的音程关系)然后将a进行转位(包括最低音转位和最高音转位),然后对于每个转位进行乐理逻辑分析,在途中只要成功判断出来和弦类型就立即返回结果。original_first为True的时候,如果和弦的音符的本来顺序的和弦类型的判断有结果,那么会在这个结果的和弦相似程度大于或等于和弦相似阈值并且结果的类型不是变化音类型的时候直接返回结果,而不进行之后把和弦进行转位的乐理逻辑分析。original_first为False的时候,则不会进行这一步,在判断了和弦的音符的本来顺序的和弦类型之后,接着乐理逻辑分析和弦的各个转位的和弦类型。如果和弦的本来顺序的和弦相似程度为1,也就是完全匹配,那么无论original_first的值为True还是False,都会直接返回和弦的本来顺序的和弦判断的结果。至于为什么在original_first为True的时候和弦的本来顺序的判断结果不是变化音类型的时候才可以返回,是因为如果是变化音类型,那么在将和弦的顺序进行变换或者分成两部分之后可能会有更好的更合理的乐理逻辑分析结果(比如省略音,voicings,复合和弦等等)。默认值为True。
  • same_note_special: 为True的时候,如果和弦的音符的音名集合等价于某种和弦的音符的音名集合(音符的音名构成一样,不考虑顺序),那么对于那种和弦的和弦相似程度就会设置为1,也就是会优先选择音名集合相同的和弦类型作为判断的结果。默认值为False。
  • whole_detect: 为True的时候,在和弦的组成音极其复杂,使用本来顺序,各种转位也无法分析出来和弦类型的时候,会对于和弦的每个转位使用detect函数再来判断一次,也就是几乎可以判断和弦的音符的所有排序的情况下可能出现的和弦类型,只要有一种情况判断出来和弦类型就立即返回结果。默认值为True。
  • poly_chord_first: 为True的时候,在需要进行whole_detect之前,会直接将和弦的音拆成上下两部分,分开进行乐理逻辑分析,返回的结果以复合和弦的形式表示。如果和弦的音符数量小于4,那么还是继续进行whole_detect的判断,如果大于或等于4,小于6的时候,会把和弦分解成最底下是第一个音,上面是剩下的音组成的新的和弦,返回的结果为上面的和弦的判断结果/最底下的音。如果大于6的时候,会把和弦按照长度分成上下两个和弦,其中下面的和弦的音符数量为和弦的音符数量除以2的向下取整,上面的和弦则为除了下面的和弦以外剩下的音。比如和弦有7个音,那么下面的和弦就是和弦的前3个音,上面的和弦就是和弦的后4个音,上下两个和弦分开进行detect函数的判断,返回的结果为上面的和弦的判断结果/下面的和弦的判断结果。poly_chord_first为True可以让这个算法在很复杂的和弦判断中的速度快很多,非常适用于爵士乐的和弦分析(尤其是实时和弦分析)。默认值为False。
  • root_preference: 为True的时候,如果当前的和弦不是原位和弦,会先尝试以当前的和弦的最低音为根音进行和弦的相似度匹配,如果符合某种原位和弦的声部排列或者省略音,返回当前结果。默认值为False。
  • show_degree: 为False的时候,返回的和弦类型如果有涉及到省略音,变化音等需要提到和弦内的某一些音的变动的时候,会直接把变动的那些音的音名写出来,比如Cmaj7 (omit E)。为True的时候,会计算变动的那些音在这个和弦里的位置(和根音的音程关系,或者说度数),并且以度数的形式显示出来,比如Cmaj7 (omit 3)。默认值为False。
  • get_chord_type: 如果为True,返回和弦类型实例,而不是字符串。
  • original_first_ratio: 当分析的和弦在原始顺序时,分析的和弦与原位和弦的匹配率的阈值。
  • similarity_ratio: 当分析的和弦在非原始顺序时,分析的和弦与原位和弦的匹配率的阈值。
  • custom_mapping: 和弦分析的自定义映射,应该是一个[a1, a2, a3]的列表,其中a1是一个字典,映射整数与音程名称(参考database中的INTERVAL),a2是一个match实例,映射整数元组到和弦类型(参考database中的 detectTypes),a3是一个match实例,映射和弦类型到整数元组(参考database中的 chordTypes)

detect函数返回的是输入的音符构成的和弦类型具体名称的字符串(包括根音的名称与和弦类型),比如Cmaj7,Cmaj9(omit 3),Em/G

# 这几个例子都是正确的,都会对A5, C5, E5, G5这组音符进行乐理逻辑分析,返回的是这组音符组成的和弦类型(包括根音的音名)。

import musicpy as mp

>>> mp.alg.detect(chord(['A5', 'C5', 'E5', 'G5']))
>>> mp.alg.detect(chord('A, C, E, G'))
>>> mp.alg.detect([N('A5'), N('C5'), N('E5'), N('G5')])
>>> mp.alg.detect([N('A'), N('C'), N('E'), N('G')])
>>> mp.alg.detect(['A5', 'C5', 'E5', 'G5'])
>>> mp.alg.detect(['A', 'C', 'E', 'G'])
>>> mp.alg.detect('A5, C5, E5, G5')
>>> mp.alg.detect('A, C, E, G')
Am7

这个算法的分析步骤如下:

  1. 首先将输入的音符组成的和弦进行标准化,这个是musicpy的乐理系统里的一个独特的概念,具体的定义请到基础语法的章节里面看,简单来说就是去除所有重复音名的音(八度等价的音),然后在不影响音的顺序的前提下调整所有音的八度数,使得最低音与最高音相差15度之内。标准化的关键点是标准化前后的两组音实际上组成的和弦是等价的,因为我们只是去除了八度等价的音和在不影响音符顺序的情况下让这组音变得集中一些,好处是让这个算法能够更加流畅地对这组音符进行乐理逻辑分析组成的和弦类型。
  2. 计算第二个音到最后一个音和第一个音的音程关系,然后看看是否符合某个原位和弦的音程关系。在database.py这个文件里面的chordTypes是目前支持判断的原位和弦的类型,原位和弦都是通过输入的音符的从第二个音起每一个音和第一个音的音程关系来判断的,比如你输入的音是C5, E5, G5, B5,那么这个算法会计算E5, G5, B5到C5的音程关系,分别是大三度,纯五度和大七度,我们以半音数来表示这些度数,也就是4, 7, 11,如果一组音符从第二个音到最后一个音和第一个音的音程关系是4, 7, 11,那么就是大七和弦的原位,因此原位和弦的判断是最简单的,这些半音数的信息是直接写在chordTypes里面的。
  3. 如果没有任何一个原位和弦的音程关系可以匹配,那么就开始考虑可能是转位和弦。转位和弦的乐理逻辑分析的步骤比较复杂,我在这里不多做讲解,感兴趣的可以直接看detect函数的代码。
  4. 如果也不是某种和弦的转位和弦,那么就会进行乐理逻辑分析是否有省略音或者变化音(或者两者都有),这部分的算法同样也是非常复杂的,感兴趣的可以去看代码。与此同时,也会乐理逻辑分析输入的音符是否为某种和弦的voicings(某种和弦的音符的其中一种排序),具体的算法是判断是否和某种和弦的组成音相同(顺序可以不同)。
  5. 如果还是没有匹配到,那么就会考虑是否为复合和弦,然后以复合和弦的角度对输入的音符进行乐理逻辑分析,把输入的音符按照音符数量分为上下两部分,(如果输入的音符的数量小于6个,那么会分成第一个音,其他的音两部分,如果大于或等于6个,那么会平均分成两部分,如果是奇数,那么第一个部分就是前一半取整的个数的音,第二个部分是其他的音)分别判断两个部分的和弦类型,然后以复合和弦的形式返回(也是字符串)。

大家也可以在database.py里面的chordTypes自己定制加入想要的原位和弦类型,语法是和弦类型名称的列表 : 和弦里每一个音到根音的音程关系

这个算法的效果非常好,而且不是依靠和弦查表(网上有很多查询和弦类型的网站都是靠直接查和弦表来返回结果,并不是按照乐理逻辑分析的算法来进行和弦的判断,而只是查字典而已,因此有很多非常复杂的情况无法判断),而且有很多的乐理逻辑参数可以进行设置,也可以设置返回的和弦类型的显示内容。在我写的钢琴软件Ideal Piano的实时进行乐理逻辑分析并且显示你当前演奏的音符组成的和弦类型的功能,用的就是这个算法,效果非常好,而且Ideal Piano的其中一个模式,播放MIDI文件演示也是实时进行乐理逻辑分析并且显示当前演奏的音符组成的和弦类型的,这个算法让想扒一首曲子的和弦进行的小伙伴可以实时看到当前的和弦类型,非常方便。

Clone this wiki locally