1class Tone:
2 def __init__(self, name):
3 self.name = name
4 self.value = self.get_value()
5
6 def get_value(self):
7 tones_list = ('C', 'C#', 'D', 'D#', 'E',
8 'F', 'F#', 'G', 'G#', 'A',
9 'A#', 'B', 'C')
10
11 for value in range(0, len(tones_list)):
12 if tones_list[value] == self.name:
13 return value
14 raise TypeError('Wrong Tone')
15
16 def set_name(self, index):
17 self.value = index % 12
18 self.name = ('C', 'C#', 'D', 'D#', 'E',
19 'F', 'F#', 'G', 'G#', 'A',
20 'A#', 'B', 'C')[self. value]
21
22 def __str__(self):
23 return self.name
24
25 def addition(self, other):
26 if isinstance(other, Tone):
27 return Chord(self, other)
28
29 if isinstance(other, Interval):
30 result = Tone('C')
31 result.set_name(self.value + other.value)
32 return result
33
34 def subtraction(self, other):
35 if isinstance(other, Tone):
36 return Interval(self.value - other.value)
37
38 if isinstance(other, Interval):
39 result = Tone('C')
40 result.set_name(self.value - other.value)
41 return result
42
43 __add__ = addition
44
45 __sub__ = subtraction
46
47
48class Interval:
49 def __init__(self, value=0, name='unison'):
50 if value != 0:
51 self.value = value % 12
52 self.name = self.set_name()
53 else:
54 self.value = value % 12
55 self.name = name
56
57 def set_name(self):
58 return ('unison', 'minor 2nd', 'major 2nd',
59 'minor 3rd', 'major 3rd', 'perfect 4th',
60 'diminished 5th', 'perfect 5th', 'minor 6th',
61 'major 6th', 'minor 7th', 'major 7th')[self.value]
62
63 def __str__(self):
64 return self.name
65
66 def addition(self, other):
67 if isinstance(other, Tone):
68 raise TypeError('Invalid operation')
69
70 if isinstance(other, Interval):
71 return Interval(self.value + other.value)
72
73 def subtraction(self, other):
74 if isinstance(other, Tone):
75 raise TypeError('Invalid operation')
76
77 __add__ = addition
78
79 __sub__ = subtraction
80
81
82class Chord:
83 def __init__(self, *args):
84 self.unique_tones = []
85 self.set_unique_tones(*args)
86 self.is_valid()
87 self.root = self.unique_tones[0]
88 self.names = []
89 self.sort_tones()
90
91 def set_unique_tones(self, *args):
92 names = []
93 for tones in args:
94 if not isinstance(tones, Tone):
95 raise TypeError('Wrong args in Chord')
96 else:
97 if tones.name not in names:
98 names.append(tones.name)
99 self.unique_tones.append(tones)
100
101 def sort_tones(self):
102 tones_values = []
103 for tones in self.unique_tones:
104 if isinstance(tones, Tone) and isinstance(self.root, Tone):
105 if tones.value < self.root.value:
106 tones_values.append(tones.value + 12)
107 else:
108 tones_values.append(tones.value)
109
110 tones_values.sort()
111 self.unique_tones.clear()
112
113 for values in tones_values:
114 temp = Tone('C')
115 temp.set_name(values)
116 self.unique_tones.append(temp)
117 self.names.append(temp.name)
118
119 def is_valid(self):
120
121 if len(self.unique_tones) <= 1:
122 raise TypeError('Cannot have a chord made of only 1 unique tone')
123
124 def __str__(self):
125 return '-'.join(f'{tone}' for tone in self.unique_tones)
126
127 def addition(self, other):
128 if isinstance(other, Tone):
129 if other.name not in self.names:
130 self.unique_tones.append(other)
131 self.set_unique_tones()
132 self.is_valid()
133 self.sort_tones()
134 return self
135
136 if isinstance(other, Chord):
137 self.unique_tones = list(set(self.unique_tones + other.unique_tones))
138 self.set_unique_tones()
139 self.is_valid()
140 self.sort_tones()
141 return self
142
143 def subtraction(self, other):
144 if isinstance(other, Tone):
145 for tone in range(0, len(self.unique_tones)):
146 if self.names[tone] == other.name:
147 self.names.remove(self.names[tone])
148 self.unique_tones.remove(self.unique_tones[tone])
149 self.set_unique_tones()
150 self.is_valid()
151 self.sort_tones()
152 return self
153
154 raise TypeError('Cannot remove tone {} from chord {}'.format(other, self))
155
156 __add__ = addition
157
158 __sub__ = subtraction
159
160 def is_minor(self):
161 if isinstance(self.unique_tones[0], Tone):
162 root_value = self.unique_tones[0].value
163
164 for values in range(1, len(self.unique_tones)):
165 if isinstance(self.unique_tones[values], Tone):
166 if (self.unique_tones[values].value + root_value) % 12 == 3:
167 return True
168 return False
169
170 def is_major(self):
171 if isinstance(self.unique_tones[0], Tone):
172 root_value = self.unique_tones[0].value
173
174 for values in range(1, len(self.unique_tones)):
175 if isinstance(self.unique_tones[values], Tone):
176 if (self.unique_tones[values].value + root_value) % 12 == 4:
177 return True
178 return False
179
180 def is_power_chord(self):
181 return not self.is_minor() and not self.is_major()
182
183 def transposed(self, interval):
184 if isinstance(interval, Interval):
185 temp1 = Tone(self.names[0]) + interval
186 temp2 = Tone(self.names[1]) + interval
187 result_chord = Chord(temp1, temp2)
188
189 for x in range(2, len(self.names)):
190 result_chord.unique_tones.append(Tone(self.names[x]) + interval)
191
192 result_chord.set_unique_tones()
193 result_chord.is_valid()
194 result_chord.sort_tones()
195
196 return result_chord
....FFF.EE.E....F....................
======================================================================
ERROR: test_transposed_negative (test.TestBasicChordFunctionality.test_transposed_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 136, in test_transposed_negative
result_chord = e_minor_chord.transposed(-Interval(2))
^^^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
ERROR: test_transposed_negative_overflow (test.TestBasicChordFunctionality.test_transposed_negative_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 150, in test_transposed_negative_overflow
result_chord = e_minor_chord.transposed(-Interval(8))
^^^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
ERROR: test_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 50, in test_interval_negative
minor_2nd = -major_7th
^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
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_chords_repeating_notes (test.TestOperations.test_add_chords_repeating_notes)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 305, in test_add_chords_repeating_notes
self.assertEqual(str(result_chord), "C-G")
AssertionError: 'C-C-G-G' != 'C-G'
- C-C-G-G
+ C-G
----------------------------------------------------------------------
Ran 37 tests in 0.002s
FAILED (failures=4, errors=3)
07.11.2024 10:17
07.11.2024 10:15
07.11.2024 10:16
07.11.2024 10:18
07.11.2024 10:19
07.11.2024 10:20
07.11.2024 10:21
07.11.2024 10:23
07.11.2024 10:23
07.11.2024 10:24
07.11.2024 10:25
07.11.2024 10:27
07.11.2024 10:28