1class Tone():
2 TONES = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')
3
4 def __init__(self,string):
5 self.string = string
6
7 def __str__(self):
8 return self.string
9
10 def __eq__(self, other):
11 if isinstance(other, Tone):
12 return self.string == other.string
13 return False
14
15 def __hash__(self):
16 return hash(self.string)
17
18 def __add__(self, other):
19 if isinstance(other, Tone):
20 return Chord(self, other)
21 elif isinstance(other, Interval):
22 new_index = Tone.TONES.index(self.string)
23 new_index += other.number_of_semitones
24 new_chord = Tone.TONES[new_index % 12]
25 return Tone(new_chord)
26
27 def __radd__(self, other):
28 if isinstance(other, Tone):
29 return other.__add__(self)
30 elif isinstance(other, Chord):
31 return other.__add__(self)
32 else:
33 raise TypeError("Invalid operation")
34
35 def __sub__(self, other):
36 if isinstance(other, Tone):
37 self_index = Tone.TONES.index(self.string)
38 other_index = Tone.TONES.index(other.string)
39 return Interval((self_index - other_index) % 12)
40
41 elif isinstance(other, Interval):
42 new_index = Tone.TONES.index(self.string)
43 new_index -= other.number_of_semitones
44 new_chord = Tone.TONES[new_index % 12]
45 return Tone(new_chord)
46
47 def __rsub__(self, other):
48 if isinstance(other, Tone):
49 return other.__sub__(self)
50 raise TypeError("Invalid operation")
51
52
53class Interval():
54 INTERVALS = (
55 "unison", "minor 2nd", "major 2nd", "minor 3rd",
56 "major 3rd", "perfect 4th", "diminished 5th",
57 "perfect 5th", "minor 6th", "major 6th",
58 "minor 7th", "major 7th"
59 )
60
61 def __init__(self, integer):
62 self.number_of_semitones = integer % 12
63
64 def __str__(self):
65 return self.INTERVALS[self.number_of_semitones]
66
67 def __add__(self, other):
68 if isinstance(other, Interval):
69 new_interval = (self.number_of_semitones + other.number_of_semitones) % 12
70 return Interval(new_interval)
71
72 def __neg__(self):
73 return Interval(-self.number_of_semitones)
74
75class Chord():
76 def __init__(self, root, *args):
77
78 self.root = root
79 self.all_given_tones = [root]
80
81 for i in args:
82 self.all_given_tones.append(i)
83
84 self.unique_tones = set(self.all_given_tones)
85
86 if len(self.unique_tones) < 2:
87 raise TypeError("Cannot have a chord made of only 1 unique tone")
88
89
90 def __str__(self):
91 root_index = Tone.TONES.index(self.root.string)
92 sorted_tones = sorted(
93 self.unique_tones,
94 key=lambda tone: (Tone.TONES.index(tone.string) - root_index) % 12
95 )
96
97 return "-".join(tone.string for tone in sorted_tones)
98
99 def is_minor(self):
100 return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 3 for tone in self.unique_tones])
101
102 def is_major(self):
103 return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 4 for tone in self.unique_tones])
104
105 def is_power_chord(self):
106 return not self.is_minor() and not self.is_major()
107
108 def __add__(self, other):
109 if isinstance(other, Tone):
110 new_tones = [tone for tone in self.unique_tones] + [other]
111 return Chord(self.root, *new_tones)
112 elif isinstance(other, Chord):
113 new_tones = [tone for tone in self.unique_tones] + [tone for tone in other.unique_tones]
114 return Chord(self.root, *new_tones)
115
116
117 def __sub__(self, other):
118 if isinstance(other, Tone):
119 if other not in self.unique_tones:
120 raise TypeError (f'Cannot remove tone {other} from chord {self}')
121 else:
122 new_tones = [tone for tone in self.unique_tones if tone != other]
123 return Chord(self.root, *new_tones)
124
125 def transposed(self, interval):
126 if isinstance(interval, Interval):
127 transposed_tones = [tone + interval for tone in self.unique_tones if tone != self.root]
128 self.root += interval
129 return Chord(self.root, *transposed_tones)
....FFF...........F..................
======================================================================
FAIL: test_is_major (test.TestBasicChordFunctionality.test_is_major)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 107, in test_is_major
self.assertTrue(a_major_chord.is_major())
AssertionError: False is not true
======================================================================
FAIL: test_is_minor (test.TestBasicChordFunctionality.test_is_minor)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 90, in test_is_minor
self.assertTrue(a_minor_chord.is_minor())
AssertionError: False is not true
======================================================================
FAIL: test_is_power_chord (test.TestBasicChordFunctionality.test_is_power_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 116, in test_is_power_chord
self.assertFalse(a_minor_chord.is_power_chord())
AssertionError: True is not false
======================================================================
FAIL: test_add_interval_to_tone_left_side_error (test.TestOperations.test_add_interval_to_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 209, in test_add_interval_to_tone_left_side_error
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised
----------------------------------------------------------------------
Ran 37 tests in 0.002s
FAILED (failures=4)
f | 1 | class Tone(): | f | 1 | class Tone(): |
2 | TONES = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B') | 2 | TONES = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B') | ||
3 | 3 | ||||
4 | def __init__(self,string): | 4 | def __init__(self,string): | ||
5 | self.string = string | 5 | self.string = string | ||
6 | 6 | ||||
7 | def __str__(self): | 7 | def __str__(self): | ||
8 | return self.string | 8 | return self.string | ||
9 | 9 | ||||
10 | def __eq__(self, other): | 10 | def __eq__(self, other): | ||
11 | if isinstance(other, Tone): | 11 | if isinstance(other, Tone): | ||
12 | return self.string == other.string | 12 | return self.string == other.string | ||
13 | return False | 13 | return False | ||
14 | 14 | ||||
15 | def __hash__(self): | 15 | def __hash__(self): | ||
16 | return hash(self.string) | 16 | return hash(self.string) | ||
17 | 17 | ||||
18 | def __add__(self, other): | 18 | def __add__(self, other): | ||
19 | if isinstance(other, Tone): | 19 | if isinstance(other, Tone): | ||
n | 20 | return Chord(self.string, str(other)) | n | 20 | return Chord(self, other) |
21 | elif isinstance(other, Interval): | 21 | elif isinstance(other, Interval): | ||
22 | new_index = Tone.TONES.index(self.string) | 22 | new_index = Tone.TONES.index(self.string) | ||
23 | new_index += other.number_of_semitones | 23 | new_index += other.number_of_semitones | ||
24 | new_chord = Tone.TONES[new_index % 12] | 24 | new_chord = Tone.TONES[new_index % 12] | ||
25 | return Tone(new_chord) | 25 | return Tone(new_chord) | ||
26 | 26 | ||||
27 | def __radd__(self, other): | 27 | def __radd__(self, other): | ||
28 | if isinstance(other, Tone): | 28 | if isinstance(other, Tone): | ||
29 | return other.__add__(self) | 29 | return other.__add__(self) | ||
30 | elif isinstance(other, Chord): | 30 | elif isinstance(other, Chord): | ||
31 | return other.__add__(self) | 31 | return other.__add__(self) | ||
32 | else: | 32 | else: | ||
33 | raise TypeError("Invalid operation") | 33 | raise TypeError("Invalid operation") | ||
34 | 34 | ||||
35 | def __sub__(self, other): | 35 | def __sub__(self, other): | ||
36 | if isinstance(other, Tone): | 36 | if isinstance(other, Tone): | ||
37 | self_index = Tone.TONES.index(self.string) | 37 | self_index = Tone.TONES.index(self.string) | ||
38 | other_index = Tone.TONES.index(other.string) | 38 | other_index = Tone.TONES.index(other.string) | ||
39 | return Interval((self_index - other_index) % 12) | 39 | return Interval((self_index - other_index) % 12) | ||
40 | 40 | ||||
41 | elif isinstance(other, Interval): | 41 | elif isinstance(other, Interval): | ||
42 | new_index = Tone.TONES.index(self.string) | 42 | new_index = Tone.TONES.index(self.string) | ||
43 | new_index -= other.number_of_semitones | 43 | new_index -= other.number_of_semitones | ||
44 | new_chord = Tone.TONES[new_index % 12] | 44 | new_chord = Tone.TONES[new_index % 12] | ||
45 | return Tone(new_chord) | 45 | return Tone(new_chord) | ||
46 | 46 | ||||
47 | def __rsub__(self, other): | 47 | def __rsub__(self, other): | ||
48 | if isinstance(other, Tone): | 48 | if isinstance(other, Tone): | ||
49 | return other.__sub__(self) | 49 | return other.__sub__(self) | ||
50 | raise TypeError("Invalid operation") | 50 | raise TypeError("Invalid operation") | ||
51 | 51 | ||||
t | 52 | t | |||
53 | 52 | ||||
54 | class Interval(): | 53 | class Interval(): | ||
55 | INTERVALS = ( | 54 | INTERVALS = ( | ||
56 | "unison", "minor 2nd", "major 2nd", "minor 3rd", | 55 | "unison", "minor 2nd", "major 2nd", "minor 3rd", | ||
57 | "major 3rd", "perfect 4th", "diminished 5th", | 56 | "major 3rd", "perfect 4th", "diminished 5th", | ||
58 | "perfect 5th", "minor 6th", "major 6th", | 57 | "perfect 5th", "minor 6th", "major 6th", | ||
59 | "minor 7th", "major 7th" | 58 | "minor 7th", "major 7th" | ||
60 | ) | 59 | ) | ||
61 | 60 | ||||
62 | def __init__(self, integer): | 61 | def __init__(self, integer): | ||
63 | self.number_of_semitones = integer % 12 | 62 | self.number_of_semitones = integer % 12 | ||
64 | 63 | ||||
65 | def __str__(self): | 64 | def __str__(self): | ||
66 | return self.INTERVALS[self.number_of_semitones] | 65 | return self.INTERVALS[self.number_of_semitones] | ||
67 | 66 | ||||
68 | def __add__(self, other): | 67 | def __add__(self, other): | ||
69 | if isinstance(other, Interval): | 68 | if isinstance(other, Interval): | ||
70 | new_interval = (self.number_of_semitones + other.number_of_semitones) % 12 | 69 | new_interval = (self.number_of_semitones + other.number_of_semitones) % 12 | ||
71 | return Interval(new_interval) | 70 | return Interval(new_interval) | ||
72 | 71 | ||||
73 | def __neg__(self): | 72 | def __neg__(self): | ||
74 | return Interval(-self.number_of_semitones) | 73 | return Interval(-self.number_of_semitones) | ||
75 | 74 | ||||
76 | class Chord(): | 75 | class Chord(): | ||
77 | def __init__(self, root, *args): | 76 | def __init__(self, root, *args): | ||
78 | 77 | ||||
79 | self.root = root | 78 | self.root = root | ||
80 | self.all_given_tones = [root] | 79 | self.all_given_tones = [root] | ||
81 | 80 | ||||
82 | for i in args: | 81 | for i in args: | ||
83 | self.all_given_tones.append(i) | 82 | self.all_given_tones.append(i) | ||
84 | 83 | ||||
85 | self.unique_tones = set(self.all_given_tones) | 84 | self.unique_tones = set(self.all_given_tones) | ||
86 | 85 | ||||
87 | if len(self.unique_tones) < 2: | 86 | if len(self.unique_tones) < 2: | ||
88 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 87 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
89 | 88 | ||||
90 | 89 | ||||
91 | def __str__(self): | 90 | def __str__(self): | ||
92 | root_index = Tone.TONES.index(self.root.string) | 91 | root_index = Tone.TONES.index(self.root.string) | ||
93 | sorted_tones = sorted( | 92 | sorted_tones = sorted( | ||
94 | self.unique_tones, | 93 | self.unique_tones, | ||
95 | key=lambda tone: (Tone.TONES.index(tone.string) - root_index) % 12 | 94 | key=lambda tone: (Tone.TONES.index(tone.string) - root_index) % 12 | ||
96 | ) | 95 | ) | ||
97 | 96 | ||||
98 | return "-".join(tone.string for tone in sorted_tones) | 97 | return "-".join(tone.string for tone in sorted_tones) | ||
99 | 98 | ||||
100 | def is_minor(self): | 99 | def is_minor(self): | ||
101 | return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 3 for tone in self.unique_tones]) | 100 | return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 3 for tone in self.unique_tones]) | ||
102 | 101 | ||||
103 | def is_major(self): | 102 | def is_major(self): | ||
104 | return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 4 for tone in self.unique_tones]) | 103 | return any([abs(Tone.TONES.index(tone.string) - Tone.TONES.index(self.root.string)) == 4 for tone in self.unique_tones]) | ||
105 | 104 | ||||
106 | def is_power_chord(self): | 105 | def is_power_chord(self): | ||
107 | return not self.is_minor() and not self.is_major() | 106 | return not self.is_minor() and not self.is_major() | ||
108 | 107 | ||||
109 | def __add__(self, other): | 108 | def __add__(self, other): | ||
110 | if isinstance(other, Tone): | 109 | if isinstance(other, Tone): | ||
111 | new_tones = [tone for tone in self.unique_tones] + [other] | 110 | new_tones = [tone for tone in self.unique_tones] + [other] | ||
112 | return Chord(self.root, *new_tones) | 111 | return Chord(self.root, *new_tones) | ||
113 | elif isinstance(other, Chord): | 112 | elif isinstance(other, Chord): | ||
114 | new_tones = [tone for tone in self.unique_tones] + [tone for tone in other.unique_tones] | 113 | new_tones = [tone for tone in self.unique_tones] + [tone for tone in other.unique_tones] | ||
115 | return Chord(self.root, *new_tones) | 114 | return Chord(self.root, *new_tones) | ||
116 | 115 | ||||
117 | 116 | ||||
118 | def __sub__(self, other): | 117 | def __sub__(self, other): | ||
119 | if isinstance(other, Tone): | 118 | if isinstance(other, Tone): | ||
120 | if other not in self.unique_tones: | 119 | if other not in self.unique_tones: | ||
121 | raise TypeError (f'Cannot remove tone {other} from chord {self}') | 120 | raise TypeError (f'Cannot remove tone {other} from chord {self}') | ||
122 | else: | 121 | else: | ||
123 | new_tones = [tone for tone in self.unique_tones if tone != other] | 122 | new_tones = [tone for tone in self.unique_tones if tone != other] | ||
124 | return Chord(self.root, *new_tones) | 123 | return Chord(self.root, *new_tones) | ||
125 | 124 | ||||
126 | def transposed(self, interval): | 125 | def transposed(self, interval): | ||
127 | if isinstance(interval, Interval): | 126 | if isinstance(interval, Interval): | ||
128 | transposed_tones = [tone + interval for tone in self.unique_tones if tone != self.root] | 127 | transposed_tones = [tone + interval for tone in self.unique_tones if tone != self.root] | ||
129 | self.root += interval | 128 | self.root += interval | ||
130 | return Chord(self.root, *transposed_tones) | 129 | return Chord(self.root, *transposed_tones) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
07.11.2024 11:49
07.11.2024 11:50
07.11.2024 11:51
07.11.2024 11:52
07.11.2024 11:53
07.11.2024 11:53
07.11.2024 11:54