给定和弦中的一组音符,计算吉他上所有可能的和弦(即所有可能的音符组合)的算法?

问题描述 投票:0回答:1

我正在尝试创建一个函数/算法,它采用音符列表,例如

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 个长度的字符串生成所有可能的和弦?这对我来说真是令人费解。

其他一些注意事项:

  • 假设和弦变奏是 3 个音符。这些音符可以位于任意 3 个字符串上,而不仅仅是连续的字符串。
  • 给定 3 根弦和一个要查找的和弦,仅在这 3 根弦上就可以有很多和弦的位置(可能是不同的八度)。
algorithm combinations
1个回答
0
投票

抱歉,我花了这么长时间,我完全忘记了这一点。

我认为上次尝试解决此问题时我走在正确的道路上,但我找不到我的代码。不管怎样,既然递归算法让我在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#"],
]

使用这个列表,我将返回代表和弦的坐标。然后在必要的时候翻译回笔记,这很容易。 基本上,递归函数将像这样工作:

  1. 获取和弦
    C E G
  2. 找到其中一个笔记的第一个实例
  3. 将其位置存储在二维数组中。在这种情况下第一个音符的位置将是 [0,0]
  4. 现在按顺序添加出现的第二个注释,即使它是重复的。
  5. 一旦当前和弦满足两个条件(长度>=3 && has(E, C, G)),您可以将此和弦添加到更大的二维数组中。这个包含所有已完成的和弦。

非常简单。 有一些例外情况很难破解,但我什至不确定它们是否有必要。例如:EEEECG。这个算法找不到这个。

我什至不知道你是否仍然遇到这个问题,但希望我能有所帮助。

如果你仍然完全没有想法,请告诉我,也许我会为你战胜我最大的敌人,递归函数..干杯(;

© www.soinside.com 2019 - 2024. All rights reserved.