如果没有涵盖所有可能的音符,我想编写一个算法,在给定的 Octave 音阶中构建规则的 3 键钢琴和弦进行,然后转移到下一个 Octave 音阶。例如:
Cmaj 键会给出其进程中的所有音符/和弦,因为起始音符是 Octave 音阶的开始,它将在下一个 C 处终止。但是如果我从同一个 Octave 音阶的 B 音符开始,它将结束下一个也是B。
我想为大调和小调构建它,并能够在未来将其扩展为 7 和 9 型和弦。
这不是作业,我想用c#然后用f#重写,多学一点语言。
编辑:
我的问题是: 我应该为 Octave 音程(C 到 C)使用什么数据结构:LinkedList List 或者这可能需要完全不同的结构?
编辑2:
因此,如果我们像这样索引注释,我不确定这是否是一种正确的方法:
0 1 2 3 4 5 6 7 8 9 10 11 12
输入:音符 = C (0),音阶 = Maj
输出:0 4 7、2 5 9、4 7 12 等
最佳答案
或许,对此建模的最简单方法是使用 midi note mapping 的概念,因为键被枚举并且来自给定根的第一个反转三元组将是
root, root + 4, root + 7
下一个反转是
root + 4, root + 7, root + 12
下一个反转是
root + 7, root + 12, root + 16
其中 root 是根音的 MIDI 音符编号。
事实上,给定第一个转位的和弦,通过删除第一个条目,将其放在最后并添加 12 来生成所有其他转位是微不足道的。所以你的和弦真的开始看起来像这样:
public int GetChord(ChordName chord)
{
switch (chord) {
case ChordName.Major: return new int[] { 0, 4, 7 };
case ChordName.Minor: return new int[] { 0, 3, 7 };
case ChordName.Augmented: return new int[] { 0, 4, 8 };
case ChordName.Dominant7: return new int[] { 0, 4, 7, 10 };
case ChordName.Maj7: return new int[] { 0, 4, 7, 11 };
// etc
}
然后无论从此处返回什么(并且可能使用 List 会更好),您都可以编写一个返回每个反转的 IEnumerable。然后你将根的值添加到输出和 ta-da!你有了自己的和弦,现在非常容易输出为 midi。
public int[] InvertChord(int[] chord)
{
int[] inversion = new int[chord.Length];
for (int i = 1; i < chord.Length; i++) {
inversion[i-1] = chord[i];
}
inversion[inversion.Length-1] = chord[0] + 12;
return inversion;
}
public int[][] ChordAndAllInversions(int[] chord)
{
int[][] inversions = new int[chord.Length][];
inversions[0] = chord;
for (int i=1; i < chord.Length; i++) {
inversions[i] = InvertChord(inversions[i - 1]);
}
return inversions;
}
关于c# - 您将如何编写钢琴 Octave 音程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4454728/