Skip to content

Instantly share code, notes, and snippets.

@arnar
Created November 17, 2008 14:16
Show Gist options
  • Save arnar/25774 to your computer and use it in GitHub Desktop.
Save arnar/25774 to your computer and use it in GitHub Desktop.
Chord guesser for major keys
import re
NOTE_NUMBERS = {
'A': 0,
'A#': 1,
'Bb': 1,
'B': 2,
'C': 3,
'C#': 4,
'Db': 4,
'D': 5,
'D#': 6,
'Eb': 6,
'E': 7,
'F': 8,
'F#': 9,
'Gb': 9,
'G': 10,
'G#': 11,
'Ab': 11,
}
NOTE_NAMES = {
'flats': ('A','Bb','B','C','Db','D','Eb','E','F','Gb','G','Ab'),
'sharps': ('A','A#','B','C','C#','D','D#','E','F','F#','G','G#')
}
KEYS_FLAT_SHARP = {
'A': 'sharps',
'A#': 'flats',
'Bb': 'flats',
'B': 'sharps',
'C': 'sharps',
'C#': 'flats',
'Db': 'flats',
'D': 'sharps',
'D#': 'flats',
'Eb': 'flats',
'E': 'sharps',
'F': 'flats',
'F#': 'sharps',
'Gb': 'flats',
'G': 'sharps',
'G#': 'flats',
'Ab': 'flats',
}
def note_number(note):
return NOTE_NUMBERS[note]
def number_note(number, key='C'):
return NOTE_NAMES[KEYS_FLAT_SHARP[key]][number % 12]
def generate_chords(key):
root = note_number(key)
bases = [(root + i) % 12 for i in [0,2,4,5,7,9,11]]
major = ['','m','m','','','m','dim']
return [number_note(b) + m for (b,m) in zip(bases,major)]
KEY_CHORDS = dict([(key, generate_chords(key)) for key in NOTE_NUMBERS.keys()])
KEY_CHORD_SETS = dict([(key, set(chords)) for (key, chords) in KEY_CHORDS.items()])
def normalize_chord(chord):
chord = re.sub(r'(sus|add|maj|7).*$', '', chord)
chord = re.sub(r'moll.*$', 'm', chord)
if chord[0].islower():
chord = chord[0].upper() + "m" + chord[1:]
if chord[0] == 'H':
chord = 'B' + chord[1:]
assert re.match(r'^[ABCDEFG](#|b)?(m|dim)?$', chord)
return chord
def guess_key(chords):
# find the number of intersecting chords with each set
chords = map(normalize_chord, chords)
chord_set = set(chords)
max_overlap = 0
found_keys = []
for key, key_chords in KEY_CHORD_SETS.items():
overlap = len(chord_set & key_chords)
if overlap >= max_overlap:
if overlap > max_overlap:
found_keys = []
found_keys.append(key)
max_overlap = overlap
return found_keys
if __name__ == '__main__':
while True:
chords = raw_input('What chords? ').split()
if len(chords) == 0:
break
print "Likely keys: ", ','.join(guess_key(chords))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment