-
Notifications
You must be signed in to change notification settings - Fork 0
/
chord_mod.py
161 lines (122 loc) · 4.15 KB
/
chord_mod.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
This file contains all of the chord modifier functions. Each modifier takes a FunChord, and returns
a new FunChord. There's also colors for modifiers/groups of modifiers in here.
"""
from typing import Callable, List
from fun_chord import FunChord, ScaleNote
mod_color_map = {} # FunMod -> 'color'
ModFunc = Callable[[FunChord], FunChord]
class FunMod(object):
def __init__(self, name: str, function: ModFunc):
self._name = name
self.function = function
def __repr__(self) -> str:
return self._name
def __eq__(self, other) -> bool:
return self._name == other._name
def __hash__(self):
return self._name.__hash__()
def get_func(self):
return self.function
# Sus
sus_color = 'blue'
def sus2(chord: FunChord) -> FunChord:
if ScaleNote(3) not in chord.triad_notes():
# Only sus if there's a 3 to substitute
return chord
new_additions = chord.copy_additions()
new_omissions = chord.copy_omissions()
new_additions.add(2)
new_omissions.add(3)
return FunChord(
chord.get_scale_name(),
chord.root_degree().get_name(),
additions=new_additions,
omissions=new_omissions)
def sus4(chord: FunChord) -> FunChord:
if ScaleNote(3) not in chord.triad_notes():
# Only sus if there's a 3 to substitute
return chord
new_additions = chord.copy_additions()
new_omissions = chord.copy_omissions()
new_additions.add(4)
new_omissions.add(3)
return FunChord(
chord.get_scale_name(),
chord.root_degree().get_name(),
additions=new_additions,
omissions=new_omissions)
Sus2 = FunMod('Sus2', sus2)
Sus4 = FunMod('Sus4', sus4)
sus_color = 'purple'
mod_color_map[Sus2] = sus_color
mod_color_map[Sus4] = sus_color
# Alternate Triad
def are_tones_major_triad(tones: List[int]) -> bool:
root = tones[0]
third_interval = tones[1] - root
return third_interval == 4
def are_tones_minor_triad(tones: List[int]) -> bool:
root = tones[0]
third_interval = tones[1] - root
return third_interval == 3
def diminished(chord: FunChord) -> FunChord:
raise NotImplementedError
def augmented(chord: FunChord) -> FunChord:
raise NotImplementedError
# TODO: implement augmented <-> diminished
def parallel(chord: FunChord) -> FunChord:
new_additions = chord.copy_additions()
new_omissions = chord.copy_omissions()
tones = chord.tones()
if are_tones_major_triad(tones):
new_additions.add('b3')
new_omissions.add(3)
elif are_tones_minor_triad(tones):
new_additions.add('#3')
new_omissions.add(3)
return FunChord(
chord.get_scale_name(),
chord.root_degree().get_name(),
additions=new_additions,
omissions=new_omissions)
Parallel = FunMod('Parallel', parallel)
mod_color_map[Parallel] = 'orange'
# Extensions
def extend(chord: FunChord, extended_note: List[int], omissions=[]) -> FunChord:
new_additions = chord.copy_additions()
new_omissions = chord.copy_omissions()
for note in extended_note:
new_additions.add(note)
for note in omissions:
new_omissions.add(note)
return FunChord(
chord.get_scale_name(),
chord.root_degree().get_name(),
additions=new_additions,
omissions=new_omissions)
def add7(chord: FunChord) -> FunChord:
return extend(chord, [7])
def add6(chord: FunChord) -> FunChord:
return extend(chord, [6], omissions=[7])
def add9(chord: FunChord) -> FunChord:
return extend(chord, [7, 9])
def add11(chord: FunChord) -> FunChord:
return extend(chord, [7, 9, 11])
Add6 = FunMod('Add6', add6)
Add7 = FunMod('Add7', add7)
Add9 = FunMod('Add9', add9)
Add11 = FunMod('Add11', add11)
extension_color = 'blue'
for extension_mod in [Add6, Add7, Add9, Add11]:
mod_color_map[extension_mod] = extension_color
# Borrowed scale
def seconday_fifth(chord: FunChord) -> FunChord:
new_additions = chord.copy_additions()
new_omissions = chord.copy_omissions()
new_scale = 0
return FunChord(
chord.get_scale_name(),
chord.root_degree().get_name(),
additions=new_additions,
omissions=new_omissions)