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__)