Compare commits
10 Commits
c5f05ae1bc
...
57bbc0ef4e
Author | SHA1 | Date | |
---|---|---|---|
57bbc0ef4e | |||
385132b9e2 | |||
400703d72f | |||
703aacb1d5 | |||
e9326b22d9 | |||
f2506cd785 | |||
99519b0d9e | |||
ff5d07b842 | |||
47e74cd31f | |||
b2c7601714 |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
ISC License
|
ISC License
|
||||||
|
|
||||||
Copyright (c) 2019, acidvegas <acid.vegas@acid.vegas>
|
Copyright (c) 2024, 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
|
||||||
|
22
README.md
22
README.md
@ -1,17 +1,31 @@
|
|||||||
# 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.
@ -1,7 +1,25 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
|
# mzk music theory helper - developed by acidvegas in python (https://git.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
|
||||||
@ -34,6 +52,21 @@ 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'},
|
||||||
@ -50,7 +83,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#')
|
notes = ('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#') # Chromatic scale
|
||||||
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')
|
||||||
|
|
||||||
@ -58,7 +91,6 @@ 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',
|
||||||
@ -74,4 +106,4 @@ scales = {
|
|||||||
'phrygian' : '1222122',
|
'phrygian' : '1222122',
|
||||||
'whole_half_diminished' : '21212121',
|
'whole_half_diminished' : '21212121',
|
||||||
'whole_tone' : '2222222'
|
'whole_tone' : '2222222'
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
|
# mzk music theory helper - developed by acidvegas in python (https://git.acid.vegas/mzk)
|
||||||
# functions.py
|
# functions.py
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
|
|
||||||
def generate_notes(key):
|
def chromatic_scale(key):
|
||||||
notes = ['A','A#','B','C','C#','D','D#','E','F','F#','G','G#']
|
notes = list(constants.notes)
|
||||||
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, scale_notes, full=False):
|
def generate_scale_string(string, scale_notes, full=False):
|
||||||
notes = generate_notes(string.upper())*2 if full else generate_notes(string.upper())
|
notes = chromatic_scale(string.upper())*2 if full else chromatic_scale(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,18 +28,43 @@ 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 scale(type, key):
|
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
|
||||||
|
|
||||||
|
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
|
||||||
notes = generate_notes(key)
|
all_notes = chromatic_scale(key)*2
|
||||||
scale_notes = [notes[0],]
|
scale_notes = [all_notes[0],]
|
||||||
for step in constants.scales[type]:
|
for step in constants.scales[type]:
|
||||||
last += int(step)
|
last += int(step)
|
||||||
if last >= len(notes):
|
scale_notes.append(all_notes[last])
|
||||||
last -= len(notes)
|
|
||||||
scale_notes.append(notes[last])
|
|
||||||
return scale_notes
|
return scale_notes
|
||||||
|
|
||||||
def print_chord():
|
def print_chord(root, type):
|
||||||
# todo: finish this
|
# todo: finish this
|
||||||
print('◯ ⬤ ')
|
print('◯ ⬤ ')
|
||||||
print('''╳ ╳ ╳ ╳ ╳ ╳
|
print('''╳ ╳ ╳ ╳ ╳ ╳
|
||||||
@ -55,6 +80,20 @@ def print_chord():
|
|||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
└───┴───┴───┴───┴───┘
|
└───┴───┴───┴───┴───┘
|
||||||
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:
|
||||||
@ -87,7 +126,7 @@ def print_circle_of_fifths():
|
|||||||
print(circle)
|
print(circle)
|
||||||
print(print_circle_of_fifths.__doc__)
|
print(print_circle_of_fifths.__doc__)
|
||||||
|
|
||||||
def help():
|
def print_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')
|
||||||
@ -125,21 +164,15 @@ 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
|
||||||
@ -155,6 +188,4 @@ def print_scales():
|
|||||||
for name, pattern in constants.scales.items():
|
for name, pattern in constants.scales.items():
|
||||||
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')
|
|
24
mzk/main.py
24
mzk/main.py
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# mzk music theory helper - developed by acidvegas in python (https://acid.vegas/mzk)
|
# mzk music theory helper - developed by acidvegas in python (https://git.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:
|
||||||
sys.argv[1] = sys.argv[1].lower()
|
print(sys.argv[1])
|
||||||
if sys.argv[1].startswith('--chord='):
|
if sys.argv[1] == '--chords':
|
||||||
|
functions.print_chords()
|
||||||
|
elif sys.argv[1].startswith('--chord='):
|
||||||
chord = sys.argv[1][8:]
|
chord = sys.argv[1][8:]
|
||||||
key = chord.split('_')[0]
|
key = chord.split('_')[0].upper()
|
||||||
type = chord[len(key)+1:]
|
type = chord[len(key)+1:].lower()
|
||||||
if key in constants.notes and type in constants.scales:
|
if key in constants.notes and type in constants.chords:
|
||||||
functions.print_chord(key, type)
|
functions.print_scale(key, type, chord=True)
|
||||||
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()
|
functions.print_circle_of_fifths()
|
||||||
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]
|
key = scale.split('_')[0].upper()
|
||||||
type = scale[len(key)+1:]
|
type = scale[len(key)+1:].lower()
|
||||||
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:
|
||||||
|
Loading…
Reference in New Issue
Block a user