最近重新启动了长期的激情项目Glorious Voice Leader,旨在使用 Elixir 和 Phoenix LiveView 重建该应用。作为项目的一部分,需要一种生成拼写正确的音阶的方法。
对于 Glorious Voice Leader 用例,特别感兴趣的是生成大调音阶,但这种方法也可能推广到其他音阶。
问题域及相关术语定义:
- 所谓“音阶”),是指根音与一组与根音有特定关系的音符的组合,根音与音阶中其他音符的关系定义了音阶的“类型”。
- 例如,根音为
C
,加上C
、D
、E
、F
、G
、A
、B
构成“C 大调音阶”;根音为G
,加上G
、A
、B
、C
、D
、E
、F#
构成“G 大调音阶”。 - 由根音开始,音符间距离为
0
、2
、4
、5
、7
、9
、11
半音的音阶为“大调音阶”;由根音开始,音符间距离为0
、2
、3
、5
、7
、8
、10
半音的音阶为“自然小调音阶”,不同的距离组合定义了不同类型的音阶,后续将此距离列表称为音阶的“公式”。
编写函数生成音阶:
- 定义函数
Glorious.Scale.get_scale/2
,接受根音和音阶公式作为参数。 - 对于七声音阶,每个音符名称必须使用一次,通过添加升降号(
#
/b
)来调整音符以符合公式。 - 定义
Glorious.Note.get_notes/1
函数,根据给定的音符类型返回过滤后的音符列表。 - 找到根音在自然音符列表中的索引,将自然音符列表旋转,使根音位于首位。
- 将旋转后的自然音符列表与音阶公式进行配对,计算每个音符与根音的半音距离,并根据距离添加升降号,构建音符列表。
- 最后返回包含公式、音符和根音的
Glorious.Scale
结构体。
测试函数:
- 测试用例表明函数能够正确生成 C 大调和 F 大调音阶。
- 目前的解决方案仅适用于全音阶,生成更多或更少音符的音阶需要更多人工干预。若要生成非全音阶,需提供
spelling
(音符拼写列表)。例如生成包含重复音符的八声音阶,如Barry Harris’ Sixth Diminished 音阶。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。