mzk- 🎸 music theory helper 🎵 |
git clone git://git.acid.vegas/mzk.git |
Log | Files | Refs | Archive | README | LICENSE |
functions.py (7962B)
1 #!/usr/bin/env python 2 # mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk) 3 # functions.py 4 5 import constants 6 7 def chromatic_scale(key): 8 notes = list(constants.notes) 9 while notes[0] != key: 10 notes.append(notes.pop(0)) 11 return notes 12 13 def generate_scale_string(string, scale_notes, full=False): 14 notes = chromatic_scale(string.upper())*2 if full else chromatic_scale(string.upper()) 15 notes.append(notes[0]) 16 for index,note in enumerate(notes): 17 if note in scale_notes: 18 notes[index] = notes[index].center(5, '-') 19 else: 20 notes[index] = '-'*5 21 return notes 22 23 def get_pattern(pattern): 24 new_pattern = list() 25 for step in pattern: 26 if step == '1' : new_pattern.append('H') 27 elif step == '2' : new_pattern.append('W') 28 elif step == '3' : new_pattern.append('WH') 29 return ' '.join(new_pattern) 30 31 def chord_notes(type, key): 32 notes = scale_notes(type, key) 33 pattern = constants.chords[type]['pattern'] 34 _notes = [key,] 35 for step in pattern.split()[1:]: #1 b3 5 36 if len(step) == 2: 37 if step[:1] == 'b': 38 _notes.append(notes[int(step)-2]) 39 elif step[:1] == '#': 40 _notes.append(notes[int(step)]) 41 else: 42 _notes.append(notes[int(step)-1]) 43 return _notes 44 45 def print_scale(root, type, full=False, chord=False): 46 frets = (24,147) if full else (12,75) 47 print(f'{root.upper()} {type.upper()} SCALE'.center(frets[1])) 48 print(' ┌' + '┬'.join('─'*5 for x in range(frets[0])) + '┐') 49 print('0 │' + '│'.join(str(x).center(5) for x in range(1,frets[0]+1)) + '│') 50 print(' ├' + '┼'.join('─'*5 for x in range(frets[0])) + '┤') 51 notes = chord_notes(type, root) if chord else scale_notes(type, root) 52 for string in ('eBGDAE'): 53 string_notes = generate_scale_string(string, notes, full) 54 print(string + ' │' + '│'.join(note.center(5, '-') for note in string_notes[1:]) + '│') 55 print(' └' + '┴'.join('─'*5 for x in range(frets[0])) + '┘') 56 print((', '.join(notes) + ' / ' + get_pattern(constants.scales[type])).rjust(frets[1])) 57 58 def scale_notes(type, key): 59 last = 0 60 all_notes = chromatic_scale(key)*2 61 scale_notes = [all_notes[0],] 62 for step in constants.scales[type]: 63 last += int(step) 64 scale_notes.append(all_notes[last]) 65 return scale_notes 66 67 def print_chord(root, type): 68 # todo: finish this 69 print('◯ ⬤ ') 70 print('''╳ ╳ ╳ ╳ ╳ ╳ 71 ┌───┬───┬───┬───┬───┐ 72 │ │ │ │ │ │ 73 ├───┼───┼───┼───┼───┤ 74 │ │ │ │ │ │ 75 ├───┼───┼───┼───┼───┤ 76 │ │ │ │ │ │ 77 ├───┼───┼───┼───┼───┤ 78 │ │ │ │ │ │ 79 ├───┼───┼───┼───┼───┤ 80 │ │ │ │ │ │ 81 └───┴───┴───┴───┴───┘ 82 E A D G B e''') 83 print('''╳ ◯ ◯ 84 ┌───┬───┬───┬───┬───┐ 85 │ │ │ │ │ │ 86 ├───┼───┼───┼───⬤───┤ 87 │ │ │ │ │ │ 88 ├───┼───⬤───┼───┼───┤ 89 │ │ │ │ │ │ 90 ├───⬤───┼───┼───┼───┤ 91 │ │ │ │ │ │ 92 ├───┼───┼───┼───┼───┤ 93 │ │ │ │ │ │ 94 └───┴───┴───┴───┴───┘ 95 E A D G B e''') 96 97 98 def print_circle_of_fifths(): 99 '''definition: 100 the relationship among the 12 tones of the chromatic scale, their corresponding key signatures, & the associated major/minor keys 101 102 accidentals: 103 sharps - F, C, G, D, A, E, B 104 flats - B, E, A, D, G, C, F 105 106 intervals: 107 unison 108 perfect fifth 109 major sencond 110 major sixth 111 major third 112 major seventh 113 augmented fourth 114 minor second 115 minor sixth 116 minor third 117 minor seventh 118 perfect fourth''' 119 circle = constants.circle.replace('\n',' \n') + ' ' # todo: fix this 120 for note in ('major','C','F','B♭','E♭','A♭','D♭','C♯','G♭/F♯','B','C♭','E','A','D','G'): # todo: reverse 121 circle = circle.replace(f' {note} ', f' \033[91m{note}\033[0m ') 122 for item in ('♮','1♭','2♭','3♭','4♭','5♭/7♯','6♭/6♯','7♭/5♯','4','3♯','2♯','1♯'): 123 circle = circle.replace(f' {item} ', f' \033[90m{item}\033[0m ') 124 for note in ('minor','a','d','g','c','f','b♭','e♭/d♯','g♯','c♯','f♯','b','c'): 125 circle = circle.replace(f' {note} ', f' \033[92m{note}\033[0m ') 126 print(circle) 127 print(print_circle_of_fifths.__doc__) 128 129 def print_help(): 130 print('usage: python mzk.py [OPTIONS]') 131 print('\noptions:') 132 print('--chord=KEY_TYPE │ print a TYPE chord in the key of KEY') 133 print('--circle │ print the circle of fifths') 134 print('--intervals │ print list of intervals') 135 print('--scale=KEY_TYPE │ print a TYPE scale in the key of KEY') 136 print('--scales │ print list of scale types & patterns') 137 print('\nnote: KEY_TYPE must be formatted as such: c_major, f#_mixolydian, etc.') 138 139 def print_intervals(): 140 '''definition: 141 the distance between two notes or pitches 142 143 note: 144 semitone - half step (b/c & e/f is a half step) 145 tone - whole step 146 147 types: 148 harmonic interval - notes played simultaneously 149 melodic interval - notes played successively 150 151 makeup: 152 quantity - distance between two notes 153 quality - number of semitones between notes 154 155 qualities: 156 major/minor - 2nds, 3rds, 6ths, 7ths 157 perfect - 4ths, 5ths, octaves 158 diminished - minor/perfect - 1 semitone 159 augmented - major/perfect + 1 semitone''' 160 print('I N T E R V A L S'.center(38)) 161 print('┌───────────┬────────────────┬───────┐') 162 print('│ semitones │ quality │ short │') 163 print('├───────────┼────────────────┼───────┤') 164 for interval, info in constants.intervals.items(): 165 print('│ {0} │ {1} │ {2} │'.format(str(info['semitones']).rjust(9), interval.ljust(14), info['short_name'].ljust(5))) 166 print('└───────────┴────────────────┴───────┘') 167 print('\nC O M P O U N D I N T E R V A L S'.center(42)) 168 print('┌───────────┬────────────────────┬───────┐') 169 print('│ semitones │ quality │ short │') 170 print('├───────────┼────────────────────┼───────┤') 171 for interval, info in constants.compound_intervals.items(): 172 print('│ {0} │ {1} │ {2} │'.format(str(info['semitones']).rjust(9), interval.ljust(18), info['short_name'].ljust(5))) 173 print('└───────────┴────────────────────┴───────┘') 174 print(print_intervals.__doc__) 175 176 def print_scales(): 177 '''definition: 178 any set of musical notes ordered by fundamental frequency or pitch 179 180 note: 181 1 - half step 182 2 - whole step 183 3 - whole step half step''' 184 print('S C A L E S'.center(43)) 185 print('┌───────────────────────┬─────────────────┐') 186 print('│ name │ intervals │') 187 print('├───────────────────────┼─────────────────┤') 188 for name, pattern in constants.scales.items(): 189 print(f'│ {name.ljust(21)} │ {get_pattern(pattern).rjust(15)} │') 190 print('└───────────────────────┴─────────────────┘') 191 print(print_scales.__doc__)