我正在尝试创建一个函数/算法,它采用音符列表,例如
C E G
的 C 大调和弦音符,以及 6 弦吉他(或 n 弦乐器),它具有特定的“调音” ”(每品每弦音符),并找出它可以在指板上产生的所有可能的和弦变化。变化最少可以是 3 个音符(以满足和弦的定义),最大可以是琴弦数量,因此和弦在吉他上可以有 6 个音符。
如何获取这样的和弦列表(按和弦中的弦数分组)?
[
{
chordSize: 3,
chords: [
[
// 0 indexed strings, 1 indexed frets, since the open string is fret 0
{ string: 1, fret: 3, note: "C" },
{ string: 2, fret: 2, note: "E" },
{ string: 3, fret: 0, note: "G" },
],
[
{ string: 2, fret: 2, note: "E" },
{ string: 3, fret: 0, note: "G" },
{ string: 4, fret: 1, note: "C" },
],
[
{ string: 3, fret: 0, note: "G" },
{ string: 4, fret: 1, note: "C" },
{ string: 5, fret: 0, note: "E" },
],
// ...
],
},
{
chordSize: 4,
chords: [
[
{ string: 1, fret: 3, note: "C" },
{ string: 2, fret: 2, note: "E" },
{ string: 3, fret: 0, note: "G" },
{ string: 4, fret: 1, note: "C" },
],
// ...
],
},
{
chordSize: 5,
chords: [
[
{ string: 1, fret: 3, note: "C" },
{ string: 2, fret: 2, note: "E" },
{ string: 3, fret: 0, note: "G" },
{ string: 4, fret: 1, note: "C" },
{ string: 5, fret: 0, note: "E" },
],
],
// ...
},
// ...
]
假设吉他上有这样的和弦:
我一开始就被这个算法看起来有多复杂所困扰:
function getPossibleStringedInstrumentChords({
numStrings = 6, notes, tuning, maxFretDistance = 6
}) {
// tuning is a list of strings, for each fret, marking the note.
// tuning = [ [ 'E', 'F', 'F#', 'G', ... ], ['A', 'A#', 'B', 'C', ...] ]
// notes is an array like ['C', 'E', 'G' ]
let i = 3 // minimum number of notes in a chord is 3.
while (i <= numStrings) {
let stringIndex = 0
let fretIndex = 0
let string = tuning[stringIndex]
while (fretIndex < string.length) {
const note = string[fretIndex++]
if (notes.includes(note)) {
// add it to the set...
} else {
// it's like parsing recursively, multiple trees
// my brain starts to explode!
}
}
i++
}
}
调音可以是这些音符,从其中任何一个开始,到循环中的最后一个结束。假设可以有 24 个音品,因此基本上有 2 个完整八度音阶,或者每根弦有两个 12 组音符。
const POSSIBLE_NOTES = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
吉他的调音如下:
const GUITAR_TUNING = [
["E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"],
["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"],
["D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#"],
["G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#"],
["B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"],
["E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"],
]
你如何找出这个算法来从 3-6 个长度的字符串生成所有可能的和弦?这对我来说真是令人费解。
其他一些注意事项:
抱歉,我花了这么长时间,我完全忘记了这一点。
我认为上次尝试解决此问题时我走在正确的道路上,但我找不到我的代码。不管怎样,既然递归算法让我在CS课上彻夜难眠,请原谅我,但我不会再从头开始写了。
无论如何,我会简要地告诉你我的方法是什么。
const GUITAR_TUNING = [
["E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"],
["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"],
["D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#"],
["G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#"],
["B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"],
["E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"],
]
使用这个列表,我将返回代表和弦的坐标。然后在必要的时候翻译回笔记,这很容易。 基本上,递归函数将像这样工作:
C E G
。非常简单。 有一些例外情况很难破解,但我什至不确定它们是否有必要。例如:EEEECG。这个算法找不到这个。
我什至不知道你是否仍然遇到这个问题,但希望我能有所帮助。
如果你仍然完全没有想法,请告诉我,也许我会为你战胜我最大的敌人,递归函数..干杯(;