I am trying to create a function/algorithm which takes a list of notes, like the C Major chord notes of C E G, and for a 6-stringed guitar (or n-stringed instrument), which has a particular "tuning" (note per fret per string), and figures out all the possible chord variations it can make on the fretboard. The variations can be 3 notes minimum (to satisfy the definition of a chord), and maximum the number of strings, so the chord can have 6 notes on the guitar.

How do you get back a list of chords like this (grouped by number of strings in chord)?

[
  {
    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" },
      ],
    ],
    // ...
  },
  // ...
]

That assumes a chord like this on the guitar:

I get stuck at how complex this algorithm seems at first:

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++
  }
}

The tunings can be these notes, starting with any of them and ending with the last one in the loop. Let's say there can be 24 frets, so there are 2 full octaves basically, or two 12 sets of notes per string.

const POSSIBLE_NOTES = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']

A tuning for the guitar would be like:

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#"],
]

How can you figure out this algorithm to generate all possible chords from 3-6 strings in length? It has been mind-bending for me.

Some other notes:

  • Let's say a chord variation is 3 notes. Those notes can be on any 3 strings, not just sequential strings.
  • Given 3 strings and one chord to lookup, there can be many placements of the chord on those 3 strings alone (probably different octaves).
1

There are 1 best solutions below

0
Jonathan On

sorry I took so long I completely forgot about this.

I think I was on the right path the last time I tried solving this but I can't find my code. Anyway, since recursive algorithms kept me up at night in CS class, Forgive me but I will not write it from scratch again.

ANYWAYS, I'll briefly tell you what my approach was.

    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#"],
]

using this list, I would return coordinates to represent chords. and then translate it back when necessary to notes, which is easy. Basically, the recursive function will work like this:

  1. Get the chord C E G.
  2. find the first instance of one of the notes
  3. store its location in a 2d array. the location of the first note in this case would be [0,0]
  4. Now add the second note that appears, in order, even if it's repetitive.
  5. once the current chord answers two conditions (Length>=3 && has(E, C, G)) you can add this chord to a larger 2d array. this one contains all of the completed chords.

pretty straightforward. there are a few exceptions that are harder to crack but I'm not even sure if they are that necessary. for example: EEEECG. this algorithm won't find this.

I don't even know if you're still at this problem but hope I helped anyway.

If you are still completely out of ideas, let me know, and perhaps I'll conquer my greatest enemy for you, a recursive function.. Cheers (;