Compare commits

..

No commits in common. "57bbc0ef4e326d5ea7d8d2e1ac07d26b66bef1af" and "c5f05ae1bc58f5f9dae89d3e698fc955682ce5e6" have entirely different histories.

9 changed files with 50 additions and 127 deletions

View File

@ -1,6 +1,6 @@
ISC License ISC License
Copyright (c) 2024, acidvegas <acid.vegas@acid.vegas> Copyright (c) 2019, acidvegas <acid.vegas@acid.vegas>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@ -1,31 +1,17 @@
# mzk # mzk
> music theory helper > music theory helper
![](.screens/circle.png) ![](screens/circle.png)
![](.screens/intervals_scales.png) ![](screens/intervals_scales.png)
![](.screens/scale.png) ![](screens/scale.png)
## Information ## Information
This repository originally started off as a means of using Python to learn music theory, specifcally guitar theory, since the basis of musical sound can be described mathematically *(in acoustics)* and exhibits a remarkable array of number properties. This repository originally started off as a means of using Python to learn music theory, specifcally guitar theory, since the basis of musical sound can be described mathematically *(in acoustics)* and exhibits a remarkable array of number properties.
It is still a work in progress, so some functions and features may not work as excepted or at all. Would love some collaboration on this project! It is still a work in progress, so some functions and features may not work as excepted or at all. Would love some collaboration on this project!
## Notes
A chromatic scale is comprised of all the semitones between an octave:
A A# B C C# D D# E F F# G G#
Using the root of C, we can apply the pattern of the major scale to the C chromatic scale:
C C# D D# E F F# G G# A A# B C
C D E F G A B C
W W H W W W H
## Todo ## Todo
* Dynamic table sizing based on item/key lengths * Dynamic table sizing based on item/key lengths
* Finish chord generation * Finish chord generation
* Color support for windows * Color support for windows
* Scale/chord ASCII coloring * Scale/chord ASCII coloring
___
###### Mirrors for this repository: [acid.vegas](https://git.acid.vegas/mzk) • [SuperNETs](https://git.supernets.org/acidvegas/mzk) • [GitHub](https://github.com/acidvegas/mzk) • [GitLab](https://gitlab.com/acidvegas/mzk) • [Codeberg](https://codeberg.org/acidvegas/mzk)

Binary file not shown.

View File

@ -1,25 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk) # mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
# constants.py # constants.py
chords = {
'major' : {'symbol':'', 'pattern':'1 3 5'},
'minor' : {'symbol':'m', 'pattern':'1 b3 5'},
'7th' : {'symbol':'7', 'pattern':'1 3 5 b7'},
'minor_7th' : {'symbol':'m7', 'pattern':'1 b3 5 b7'},
'major_7th' : {'symbol':'maj7', 'pattern':'1 3 5 7'},
'minor_7th_flat_5th' : {'symbol':'m7b5', 'pattern':'1 b3 b5 b7'},
'suspended_4th' : {'symbol':'sus4', 'pattern':'1 4 5'},
'diminished' : {'symbol':'dim', 'pattern':'1 b3 b5'},
'augmented' : {'symbol':'aug', 'pattern':'1 3 #5'},
'6th' : {'symbol':'6', 'pattern':'1 3 5 6'},
'minor_6th' : {'symbol':'m6', 'pattern':'1 b3 5 6'},
'minor_6th_add_9th' : {'symbol':'6add9', 'pattern':'1 3 5 6 9'},
'9th' : {'symbol':'9', 'pattern':'1 3 5 b7 9'},
'minor_9th' : {'symbol':'m9', 'pattern':'1 b3 5 b7 9'},
'major_9th' : {'symbol':'maj9', 'pattern':'1 3 5 7 9'}
}
circle = ''' major circle = ''' major
C C
@ -52,21 +34,6 @@ colors = {
'reset' : '\033[0m' 'reset' : '\033[0m'
} }
compound_intervals = {
'minor_ninth' : {'semitones':13, 'short_name':'m9'},
'major_ninth' : {'semitones':14, 'short_name':'M9'},
'minor_tenth' : {'semitones':15, 'short_name':'m10'},
'major_tenth' : {'semitones':16, 'short_name':'M10'},
'perfect_eleventh' : {'semitones':17, 'short_name':'P11'},
'augmented_eleventh' : {'semitones':18, 'short_name':'TT'},
'perfect_twelfth' : {'semitones':19, 'short_name':'P12'},
'minor_thirteenth' : {'semitones':20, 'short_name':'m13'},
'major_thirteenth' : {'semitones':21, 'short_name':'M13'},
'minor_fourteenth' : {'semitones':22, 'short_name':'m14'},
'major_fourteenth' : {'semitones':23, 'short_name':'M14'},
'double_octave' : {'semitones':24, 'short_name':'15ma'}
}
intervals = { intervals = {
'perfect_unison' : {'semitones':0, 'short_name':'P1'}, 'perfect_unison' : {'semitones':0, 'short_name':'P1'},
'minor_second' : {'semitones':1, 'short_name':'m2'}, 'minor_second' : {'semitones':1, 'short_name':'m2'},
@ -83,7 +50,7 @@ intervals = {
'perfect_octave' : {'semitones':12, 'short_name':'P8'} 'perfect_octave' : {'semitones':12, 'short_name':'P8'}
} }
notes = ('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#') # Chromatic scale notes = ('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#')
numerals = ('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII') numerals = ('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII')
scale_degrees = ('tonic','supertonic','mediant','subdominant','dominant''submediant','subtonic') scale_degrees = ('tonic','supertonic','mediant','subdominant','dominant''submediant','subtonic')
@ -91,6 +58,7 @@ scales = {
'algerian' : '2131131', 'algerian' : '2131131',
'aeolian' : '2122122', 'aeolian' : '2122122',
'blues' : '321132', 'blues' : '321132',
'chromatic' : '1111111',
'dorian' : '2122212', 'dorian' : '2122212',
'half_whole_diminished' : '12121212', 'half_whole_diminished' : '12121212',
'harmonic_minor' : '2122131', 'harmonic_minor' : '2122131',

View File

@ -1,17 +1,17 @@
#!/usr/bin/env python #!/usr/bin/env python
# mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk) # mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
# functions.py # functions.py
import constants import constants
def chromatic_scale(key): def generate_notes(key):
notes = list(constants.notes) notes = ['A','A#','B','C','C#','D','D#','E','F','F#','G','G#']
while notes[0] != key: while notes[0] != key:
notes.append(notes.pop(0)) notes.append(notes.pop(0))
return notes return notes
def generate_scale_string(string, scale_notes, full=False): def generate_scale(string, scale_notes, full=False):
notes = chromatic_scale(string.upper())*2 if full else chromatic_scale(string.upper()) notes = generate_notes(string.upper())*2 if full else generate_notes(string.upper())
notes.append(notes[0]) notes.append(notes[0])
for index,note in enumerate(notes): for index,note in enumerate(notes):
if note in scale_notes: if note in scale_notes:
@ -28,43 +28,18 @@ def get_pattern(pattern):
elif step == '3' : new_pattern.append('WH') elif step == '3' : new_pattern.append('WH')
return ' '.join(new_pattern) return ' '.join(new_pattern)
def chord_notes(type, key): def scale(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
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]))
def scale_notes(type, key):
last = 0 last = 0
all_notes = chromatic_scale(key)*2 notes = generate_notes(key)
scale_notes = [all_notes[0],] scale_notes = [notes[0],]
for step in constants.scales[type]: for step in constants.scales[type]:
last += int(step) last += int(step)
scale_notes.append(all_notes[last]) if last >= len(notes):
last -= len(notes)
scale_notes.append(notes[last])
return scale_notes return scale_notes
def print_chord(root, type): def print_chord():
# todo: finish this # todo: finish this
print('◯ ⬤ ') print('◯ ⬤ ')
print(''' print('''
@ -80,20 +55,6 @@ def print_chord(root, type):
E A D G B e''') E A D G B e''')
print(''' ◯ ◯
E A D G B e''')
def print_circle_of_fifths(): def print_circle_of_fifths():
'''definition: '''definition:
@ -126,7 +87,7 @@ def print_circle_of_fifths():
print(circle) print(circle)
print(print_circle_of_fifths.__doc__) print(print_circle_of_fifths.__doc__)
def print_help(): def help():
print('usage: python mzk.py [OPTIONS]') print('usage: python mzk.py [OPTIONS]')
print('\noptions:') print('\noptions:')
print('--chord=KEY_TYPE │ print a TYPE chord in the key of KEY') print('--chord=KEY_TYPE │ print a TYPE chord in the key of KEY')
@ -164,15 +125,21 @@ def print_intervals():
for interval, info in constants.intervals.items(): for interval, info in constants.intervals.items():
print('{0}{1}{2}'.format(str(info['semitones']).rjust(9), interval.ljust(14), info['short_name'].ljust(5))) print('{0}{1}{2}'.format(str(info['semitones']).rjust(9), interval.ljust(14), info['short_name'].ljust(5)))
print('└───────────┴────────────────┴───────┘') print('└───────────┴────────────────┴───────┘')
print('\nC O M P O U N D I N T E R V A L S'.center(42))
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('└───────────┴────────────────────┴───────┘')
print(print_intervals.__doc__) print(print_intervals.__doc__)
def print_scale(root, type, full=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])) + '')
scale_notes = scale(type, root)
for string in ('eBGDAE'):
string_notes = generate_scale(string, scale_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(scale_notes) + ' / ' + get_pattern(constants.scales[type])).rjust(frets[1]))
def print_scales(): def print_scales():
'''definition: '''definition:
any set of musical notes ordered by fundamental frequency or pitch any set of musical notes ordered by fundamental frequency or pitch
@ -189,3 +156,5 @@ def print_scales():
print(f'{name.ljust(21)}{get_pattern(pattern).rjust(15)}') print(f'{name.ljust(21)}{get_pattern(pattern).rjust(15)}')
print('└───────────────────────┴─────────────────┘') print('└───────────────────────┴─────────────────┘')
print(print_scales.__doc__) print(print_scales.__doc__)
print_scale('C','major')

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk) # mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
# main.py # main.py
import sys import sys
@ -12,26 +12,26 @@ import functions
if len(sys.argv) != 2: if len(sys.argv) != 2:
functions.print_help() functions.print_help()
else: else:
print(sys.argv[1]) sys.argv[1] = sys.argv[1].lower()
if sys.argv[1] == '--chords': if sys.argv[1].startswith('--chord='):
functions.print_chords()
elif sys.argv[1].startswith('--chord='):
chord = sys.argv[1][8:] chord = sys.argv[1][8:]
key = chord.split('_')[0].upper() key = chord.split('_')[0]
type = chord[len(key)+1:].lower() type = chord[len(key)+1:]
if key in constants.notes and type in constants.chords: if key in constants.notes and type in constants.scales:
functions.print_scale(key, type, chord=True) functions.print_chord(key, type)
else: else:
print('error: invalid key or chord type\n\n') print('error: invalid key or chord type\n\n')
functions.print_help() functions.print_help()
elif sys.argv[1] == '--chords':
functions.print_chords()
elif sys.argv[1] == '--circle': elif sys.argv[1] == '--circle':
functions.print_circle_of_fifths() functions.print_circle()
elif sys.argv[1] == '--intervals': elif sys.argv[1] == '--intervals':
functions.print_intervals() functions.print_intervals()
elif sys.argv[1].startswith('--scale='): elif sys.argv[1].startswith('--scale='):
scale = sys.argv[1][8:] scale = sys.argv[1][8:]
key = scale.split('_')[0].upper() key = scale.split('_')[0]
type = scale[len(key)+1:].lower() type = scale[len(key)+1:]
if key in constants.notes and type in constants.scales: if key in constants.notes and type in constants.scales:
functions.print_scale(key, type) functions.print_scale(key, type)
else: else:

View File

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB