-
Notifications
You must be signed in to change notification settings - Fork 245
Description
I've been trying to figure this out for 3 days. I've scoured the web, tried phrasing my question dozens of different ways to ChatGPT, Perplexity, and Claude, and I am feeling like what I want to build has to be completely put on hold for me to learn music theory first, and, call me lazy, but I am building this thing so that I don't have to learn theory lmaooo.
@colshacol (#275) seems to have been seeking the same outcome I am.
Use case.
In my app, I need the user to select a key ("B", for example), and a scale type ("minor") and in the background I need to prepare a big list of chords that the user can then choose from and assign chords to keys on the keyboard for them to play.
export const ROOT_NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
// Arbitrary subset of scale names I would like to support.
export const SCALE_NAMES = [ 'major', 'minor', 'lydian', 'mixolydian', 'harmonic major', 'harmonic minor', 'dorian', 'chromatic', 'enigmatic', 'flamenco', 'bebop', 'locrian', 'oriental', 'persian', 'phrygian', 'prometheus', 'ultralocrian' ]Reference for clarity.
A good reference for what I need to achieve is the music production plugin, Scaler 2.
- The user can select the key and scale type:
- With key and scale type selected, the user can browse chords that are in-scale:
Attempts
My first attempt was to use the advertised Tonal APIs, but without music theory knowledge, I got outputs that were not intuitive to me. Asking for Tonal.Scale.scaleChords("B minor") gives me ['5', '7#5sus4', 'sus4', '7sus4', 'm#5', 'm7#5', 'm', 'm7', '4', 'madd4', 'm7add11', 'sus2', 'sus24', '11', '9sus4', 'm9#5', 'madd9', 'm9', 'm11A', 'm11'], but these are just variations / symbols. Does this mean that any note in B minor (['B', 'C#', 'D', 'E', 'F#', 'G', 'A']) can be applied to any of these variations, and the chord fit in B minor?
My second attempt was to use this list of symbols and...
scalesWithChords = { }
for each rootNote {
for each scaleType {
scaleName = rootNote + " " + scaleType
scalesWithChords[scaleName] = [ ]
scaleNotes = Tonal.Scale.get().notes
for each symbol {
for each scaleNote {
chordName = scaleNote + symbol
chordNotes = Tonal.Chord.notes(chordName)
if scaleNotes includes all chordNotes {
scalesWithChords[scaleName].push(chordName)
}
}
}
}
}
But this added sooooo much code to my codebase. It quickly became hard to maintain, and I also did not feel confident that this was the right solution. (Here is the data I generated with this approach.)
My third attempt was... I wrote a script to generate chords for scales (not using Tonal) but, honestly, not only do I know it is not exhaustive, I don't trust it at all to be accurate, haha. Here is the output.
Conclusion
Can somebody please help me understand how I can accurately and efficiently achieve what I need using tonal?


