mzk/mzk/functions.py

191 lines
7.8 KiB
Python
Raw Permalink Normal View History

2019-07-13 15:52:23 -07:00
#!/usr/bin/env python
2023-05-08 20:59:37 -07:00
# mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk)
2019-07-13 15:52:23 -07:00
# functions.py
import constants
2023-05-08 20:59:37 -07:00
def chromatic_scale(key):
notes = list(constants.notes)
2019-07-13 15:52:23 -07:00
while notes[0] != key:
notes.append(notes.pop(0))
return notes
2023-05-08 20:59:37 -07:00
def generate_scale_string(string, scale_notes, full=False):
notes = chromatic_scale(string.upper())*2 if full else chromatic_scale(string.upper())
2019-07-24 21:58:26 -07:00
notes.append(notes[0])
2019-07-13 15:52:23 -07:00
for index,note in enumerate(notes):
if note in scale_notes:
notes[index] = notes[index].center(5, '-')
else:
notes[index] = '-'*5
return notes
def get_pattern(pattern):
new_pattern = list()
for step in pattern:
if step == '1' : new_pattern.append('H')
elif step == '2' : new_pattern.append('W')
elif step == '3' : new_pattern.append('WH')
return ' '.join(new_pattern)
2023-05-18 17:29:41 -07:00
def chord_notes(type, key):
notes = scale_notes(type, key)
pattern = constants.chords[type]['pattern']
_notes = [key,]
for step in pattern.split()[1:]: #1 b3 5
if len(step) == 2:
if step[:1] == 'b':
_notes.append(notes[int(step)-2])
elif step[:1] == '#':
_notes.append(notes[int(step)])
else:
_notes.append(notes[int(step)-1])
return _notes
2024-01-20 17:48:05 -08:00
def print_scale(root, type, full=False, chord=False):
frets = (24,147) if full else (12,75)
print(f'{root.upper()} {type.upper()} SCALE'.center(frets[1]))
print('' + ''.join(''*5 for x in range(frets[0])) + '')
print('0 │' + ''.join(str(x).center(5) for x in range(1,frets[0]+1)) + '')
print('' + ''.join(''*5 for x in range(frets[0])) + '')
notes = chord_notes(type, root) if chord else scale_notes(type, root)
for string in ('eBGDAE'):
string_notes = generate_scale_string(string, notes, full)
print(string + '' + ''.join(note.center(5, '-') for note in string_notes[1:]) + '')
print('' + ''.join(''*5 for x in range(frets[0])) + '')
print((', '.join(notes) + ' / ' + get_pattern(constants.scales[type])).rjust(frets[1]))
2023-05-08 20:59:37 -07:00
def scale_notes(type, key):
2019-07-13 15:52:23 -07:00
last = 0
2023-05-08 20:59:37 -07:00
all_notes = chromatic_scale(key)*2
scale_notes = [all_notes[0],]
2019-07-24 21:58:26 -07:00
for step in constants.scales[type]:
2019-07-13 15:52:23 -07:00
last += int(step)
2023-05-08 20:59:37 -07:00
scale_notes.append(all_notes[last])
2019-07-13 15:52:23 -07:00
return scale_notes
2023-05-08 20:59:37 -07:00
def print_chord(root, type):
2019-07-13 15:52:23 -07:00
# todo: finish this
print('◯ ⬤ ')
print('''
2023-05-08 20:59:37 -07:00
E A D G B e''')
print(''' ◯ ◯
2019-07-13 15:52:23 -07:00
E A D G B e''')
2023-05-08 20:59:37 -07:00
2019-07-13 15:52:23 -07:00
def print_circle_of_fifths():
2019-07-24 21:58:26 -07:00
'''definition:
2019-07-13 15:52:23 -07:00
the relationship among the 12 tones of the chromatic scale, their corresponding key signatures, & the associated major/minor keys
accidentals:
sharps - F, C, G, D, A, E, B
flats - B, E, A, D, G, C, F
intervals:
unison
perfect fifth
major sencond
major sixth
major third
major seventh
augmented fourth
minor second
minor sixth
minor third
minor seventh
2019-07-24 21:58:26 -07:00
perfect fourth'''
2019-07-13 15:52:23 -07:00
circle = constants.circle.replace('\n',' \n') + ' ' # todo: fix this
for note in ('major','C','F','B♭','E♭','A♭','D♭','C♯','G♭/F♯','B','C♭','E','A','D','G'): # todo: reverse
circle = circle.replace(f' {note} ', f' \033[91m{note}\033[0m ')
for item in ('','1♭','2♭','3♭','4♭','5♭/7♯','6♭/6♯','7♭/5♯','4','3♯','2♯','1♯'):
circle = circle.replace(f' {item} ', f' \033[90m{item}\033[0m ')
for note in ('minor','a','d','g','c','f','b♭','e♭/d♯','g♯','c♯','f♯','b','c'):
circle = circle.replace(f' {note} ', f' \033[92m{note}\033[0m ')
print(circle)
2019-07-24 21:58:26 -07:00
print(print_circle_of_fifths.__doc__)
2019-07-13 15:52:23 -07:00
2019-07-24 23:12:59 -07:00
def print_help():
2019-07-24 23:11:07 -07:00
print('usage: python mzk.py [OPTIONS]')
print('\noptions:')
print('--chord=KEY_TYPE │ print a TYPE chord in the key of KEY')
print('--circle │ print the circle of fifths')
print('--intervals │ print list of intervals')
print('--scale=KEY_TYPE │ print a TYPE scale in the key of KEY')
print('--scales │ print list of scale types & patterns')
print('\nnote: KEY_TYPE must be formatted as such: c_major, f#_mixolydian, etc.')
2019-07-13 15:52:23 -07:00
def print_intervals():
2019-07-24 21:58:26 -07:00
'''definition:
2019-07-13 15:52:23 -07:00
the distance between two notes or pitches
note:
2019-07-24 21:58:26 -07:00
semitone - half step (b/c & e/f is a half step)
tone - whole step
2019-07-13 15:52:23 -07:00
types:
harmonic interval - notes played simultaneously
melodic interval - notes played successively
makeup:
quantity - distance between two notes
quality - number of semitones between notes
qualities:
major/minor - 2nds, 3rds, 6ths, 7ths
perfect - 4ths, 5ths, octaves
diminished - minor/perfect - 1 semitone
2019-07-24 21:58:26 -07:00
augmented - major/perfect + 1 semitone'''
2019-07-24 23:11:07 -07:00
print('I N T E R V A L S'.center(38))
print('┌───────────┬────────────────┬───────┐')
print('│ semitones │ quality │ short │')
print('├───────────┼────────────────┼───────┤')
2019-07-13 15:52:23 -07:00
for interval, info in constants.intervals.items():
2019-07-24 23:11:07 -07:00
print('{0}{1}{2}'.format(str(info['semitones']).rjust(9), interval.ljust(14), info['short_name'].ljust(5)))
print('└───────────┴────────────────┴───────┘')
2023-05-08 20:59:37 -07:00
print('\nC O M P O U N D I N T E R V A L S'.center(42))
2019-07-24 23:36:25 -07:00
print('┌───────────┬────────────────────┬───────┐')
print('│ semitones │ quality │ short │')
print('├───────────┼────────────────────┼───────┤')
for interval, info in constants.compound_intervals.items():
print('{0}{1}{2}'.format(str(info['semitones']).rjust(9), interval.ljust(18), info['short_name'].ljust(5)))
print('└───────────┴────────────────────┴───────┘')
2023-05-08 20:59:37 -07:00
print(print_intervals.__doc__)
2019-07-13 15:52:23 -07:00
def print_scales():
2019-07-24 21:58:26 -07:00
'''definition:
2019-07-13 15:52:23 -07:00
any set of musical notes ordered by fundamental frequency or pitch
note:
1 - half step
2 - whole step
3 - whole step half step'''
2019-07-24 21:58:26 -07:00
print('S C A L E S'.center(43))
2019-07-13 15:52:23 -07:00
print('┌───────────────────────┬─────────────────┐')
print('│ name │ intervals │')
print('├───────────────────────┼─────────────────┤')
for name, pattern in constants.scales.items():
print(f'{name.ljust(21)}{get_pattern(pattern).rjust(15)}')
print('└───────────────────────┴─────────────────┘')
2019-07-24 23:11:43 -07:00
print(print_scales.__doc__)