1VALID_TONES_SET = {'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'}
2VALID_TONES_LIST = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
3INTERVALS = {
4 0: 'unison',
5 1: 'minor 2nd',
6 2: 'major 2nd',
7 3: 'minor 3rd',
8 4: 'major 3rd',
9 5: 'perfect 4th',
10 6: 'diminished 5th',
11 7: 'perfect 5th',
12 8: 'minor 6th',
13 9: 'major 6th',
14 10: 'minor 7th',
15 11: 'major 7th'}
16
17
18class Tone:
19 """Represents a musical tone."""
20
21 def __init__(self, note):
22 self.note = note
23
24 @property
25 def note(self):
26 return self._note
27
28 @note.setter
29 def note(self, value):
30 if value not in VALID_TONES_SET:
31 raise ValueError(f'{value} is not a valid musical tone')
32 self._note = value
33
34 def __str__(self):
35 return self._note
36
37 def __eq__(self, other):
38 if isinstance(other, Tone):
39 return self._note == other._note
40 return False
41
42 def __hash__(self):
43 return hash(self._note)
44
45 def __add__(self, other):
46 if type(other) == Tone:
47 return Chord(self, other)
48 elif type(other) == Interval:
49 tone_index = VALID_TONES_LIST.index(self._note)
50 new_index = (tone_index + other.steps) % len(VALID_TONES_LIST)
51 return Tone(VALID_TONES_LIST[new_index])
52 else:
53 raise TypeError('Invalid operation')
54
55 def __sub__(self, other):
56 if type(other) == Tone:
57 first_tone_index = VALID_TONES_LIST.index(self._note)
58 second_tone_index = VALID_TONES_LIST.index(str(other))
59 steps = (first_tone_index - second_tone_index) % len(VALID_TONES_LIST)
60 return Interval(steps)
61 elif type(other) == Interval:
62 tone_index = VALID_TONES_LIST.index(self._note)
63 new_index = (tone_index - other.steps) % len(VALID_TONES_LIST)
64 return Tone(VALID_TONES_LIST[new_index])
65 else:
66 raise TypeError('Invalid operation')
67
68
69class Interval:
70 """Represents a musical interval."""
71
72 def __init__(self, steps):
73 self._steps = steps
74
75 @property
76 def steps(self):
77 return self._steps
78
79 @steps.setter
80 def steps(self, value):
81 if value < 0:
82 raise ValueError(f'{value} is not a positive number')
83
84 self._steps = value % 12
85
86 def __str__(self):
87 return INTERVALS[self._steps]
88
89 def __add__(self, other):
90 if type(other) == Interval:
91 new_steps = (self.steps + other.steps) % 12
92 return Interval(new_steps)
93
94 raise TypeError(f'Cannot add {type(other)} to Interval')
95
96 def __neg__(self):
97 return Interval(-self._steps)
98
99
100class Chord:
101 """Represents a musical chord."""
102
103 def __init__(self, main_tone, *tones):
104 self._tones = {main_tone, *tones}
105 self._main_tone = main_tone # Keep root so we don't cast to list
106 if len(self._tones) < 2:
107 raise TypeError('Cannot have a chord made of only 1 unique tone')
108
109 def __str__(self):
110 root_index = VALID_TONES_LIST.index(str(self._main_tone))
111 sorted_tones = sorted(self._tones, key=lambda tone: (VALID_TONES_LIST.index(str(tone)) - root_index) % len(VALID_TONES_LIST))
112
113 return "-".join(str(tone) for tone in sorted_tones)
114
115 def __add__(self, other):
116 if type(other) == Tone:
117 new_tones = self._tones | {other} # Union of sets
118 return Chord(self._main_tone, *new_tones)
119 elif type(other) == Chord:
120 new_tones = self._tones | other._tones # Union of sets
121 new_main_tone = self._main_tone
122 return Chord(new_main_tone, *new_tones)
123 else:
124 raise TypeError('Invalid operation')
125
126 def __sub__(self, other):
127 if type(other) == Tone:
128 if other not in self._tones:
129 raise TypeError(f"Cannot remove tone {other} from chord {self}")
130
131 new_tones = self._tones - {other}
132 if len(new_tones) < 2:
133 raise TypeError("Cannot have a chord made of only 1 unique tone")
134
135 new_main_tone = next(iter(new_tones))
136 return Chord(new_main_tone, *(new_tones - {new_main_tone}))
137
138 raise TypeError(f"Cannot subtract {type(other)} from Chord")
139
140 def is_minor(self):
141 main_tone_index = VALID_TONES_LIST.index(str(self._main_tone))
142 for tone in self._tones:
143 if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 3:
144 return True
145
146 return False
147
148 def is_major(self):
149 steps = 0
150 main_tone_index = VALID_TONES_LIST.index(str(self._main_tone))
151 for tone in self._tones:
152 if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 4:
153 return True
154
155 return False
156
157 def is_power_chord(self):
158 if not self.is_minor() and not self.is_major():
159 return True
160
161 return False
162
163 def transposed(self, interval):
164 if type(interval) != Interval:
165 raise TypeError("Transposition requires an Interval object")
166
167 transposed_tones = set()
168 for tone in self._tones:
169 original_index = VALID_TONES_LIST.index(str(tone))
170 transposed_index = (original_index + interval.steps) % 12
171 transposed_tone = Tone(VALID_TONES_LIST[transposed_index])
172 transposed_tones.add(transposed_tone)
173
174 main_tone_index = VALID_TONES_LIST.index(str(self._main_tone))
175 transposed_main_tone_index = (main_tone_index + interval.steps) % 12
176 transposed_main_tone = Tone(VALID_TONES_LIST[transposed_main_tone_index])
177
178 return Chord(transposed_main_tone, *transposed_tones)
....FFF....EE.....F........F..F......
======================================================================
ERROR: test_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 51, in test_interval_negative
self.assertEqual(str(minor_2nd), "minor 2nd")
^^^^^^^^^^^^^^
File "/tmp/solution.py", line 87, in __str__
return INTERVALS[self._steps]
~~~~~~~~~^^^^^^^^^^^^^
KeyError: -11
======================================================================
ERROR: test_interval_overflow (test.TestBasicIntervalFunctionality.test_interval_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 46, in test_interval_overflow
self.assertEqual(str(major_7th), "major 7th")
^^^^^^^^^^^^^^
File "/tmp/solution.py", line 87, in __str__
return INTERVALS[self._steps]
~~~~~~~~~^^^^^^^^^^^^^
KeyError: 155
======================================================================
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 211, in test_add_interval_to_tone_left_side_error
self.assertEqual(str(err.exception), INVALID_OPERATION)
AssertionError: "Cannot add <class 'solution.Tone'> to Interval" != 'Invalid operation'
- Cannot add <class 'solution.Tone'> to Interval
+ Invalid operation
======================================================================
FAIL: test_subtract_interval_from_tone_left_side_error (test.TestOperations.test_subtract_interval_from_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 235, in test_subtract_interval_from_tone_left_side_error
self.assertEqual(str(err.exception), INVALID_OPERATION)
AssertionError: "unsupported operand type(s) for -: 'Interval' and 'Tone'" != 'Invalid operation'
- unsupported operand type(s) for -: 'Interval' and 'Tone'
+ Invalid operation
======================================================================
FAIL: test_subtract_tone_from_chord (test.TestOperations.test_subtract_tone_from_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 277, in test_subtract_tone_from_chord
self.assertEqual(str(result_chord), "F-G#")
AssertionError: 'G#-F' != 'F-G#'
- G#-F
+ F-G#
----------------------------------------------------------------------
Ran 37 tests in 0.002s
FAILED (failures=6, errors=2)
Владимир Коцев
05.11.2024 13:16Окей, благодаря!
|
Георги Кунчев
05.11.2024 13:12Ние няма да тестваме с невалидни данни, така че ако грешките ти се хвърлят само в такива неочаквани случаи, не би трябвало никога да стигнем до тях.
|
Владимир Коцев
05.11.2024 12:43Хвърлям допълнителни грешки спрямо условието и имайки в предвид ООП-то смятам, че трябва да бъдат покрити edge кейсовете. Ако биха били проблем за тестовете при оценяване ще ги премахна
|
f | 1 | VALID_TONES_SET = {'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'} | f | 1 | VALID_TONES_SET = {'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'} |
2 | VALID_TONES_LIST = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] | 2 | VALID_TONES_LIST = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] | ||
3 | INTERVALS = { | 3 | INTERVALS = { | ||
4 | 0: 'unison', | 4 | 0: 'unison', | ||
5 | 1: 'minor 2nd', | 5 | 1: 'minor 2nd', | ||
6 | 2: 'major 2nd', | 6 | 2: 'major 2nd', | ||
7 | 3: 'minor 3rd', | 7 | 3: 'minor 3rd', | ||
8 | 4: 'major 3rd', | 8 | 4: 'major 3rd', | ||
9 | 5: 'perfect 4th', | 9 | 5: 'perfect 4th', | ||
10 | 6: 'diminished 5th', | 10 | 6: 'diminished 5th', | ||
11 | 7: 'perfect 5th', | 11 | 7: 'perfect 5th', | ||
12 | 8: 'minor 6th', | 12 | 8: 'minor 6th', | ||
13 | 9: 'major 6th', | 13 | 9: 'major 6th', | ||
14 | 10: 'minor 7th', | 14 | 10: 'minor 7th', | ||
15 | 11: 'major 7th'} | 15 | 11: 'major 7th'} | ||
16 | 16 | ||||
17 | 17 | ||||
18 | class Tone: | 18 | class Tone: | ||
19 | """Represents a musical tone.""" | 19 | """Represents a musical tone.""" | ||
20 | 20 | ||||
21 | def __init__(self, note): | 21 | def __init__(self, note): | ||
22 | self.note = note | 22 | self.note = note | ||
23 | 23 | ||||
24 | @property | 24 | @property | ||
25 | def note(self): | 25 | def note(self): | ||
26 | return self._note | 26 | return self._note | ||
27 | 27 | ||||
28 | @note.setter | 28 | @note.setter | ||
29 | def note(self, value): | 29 | def note(self, value): | ||
30 | if value not in VALID_TONES_SET: | 30 | if value not in VALID_TONES_SET: | ||
31 | raise ValueError(f'{value} is not a valid musical tone') | 31 | raise ValueError(f'{value} is not a valid musical tone') | ||
32 | self._note = value | 32 | self._note = value | ||
33 | 33 | ||||
34 | def __str__(self): | 34 | def __str__(self): | ||
35 | return self._note | 35 | return self._note | ||
36 | 36 | ||||
37 | def __eq__(self, other): | 37 | def __eq__(self, other): | ||
38 | if isinstance(other, Tone): | 38 | if isinstance(other, Tone): | ||
39 | return self._note == other._note | 39 | return self._note == other._note | ||
40 | return False | 40 | return False | ||
41 | 41 | ||||
42 | def __hash__(self): | 42 | def __hash__(self): | ||
43 | return hash(self._note) | 43 | return hash(self._note) | ||
44 | 44 | ||||
45 | def __add__(self, other): | 45 | def __add__(self, other): | ||
46 | if type(other) == Tone: | 46 | if type(other) == Tone: | ||
47 | return Chord(self, other) | 47 | return Chord(self, other) | ||
48 | elif type(other) == Interval: | 48 | elif type(other) == Interval: | ||
49 | tone_index = VALID_TONES_LIST.index(self._note) | 49 | tone_index = VALID_TONES_LIST.index(self._note) | ||
50 | new_index = (tone_index + other.steps) % len(VALID_TONES_LIST) | 50 | new_index = (tone_index + other.steps) % len(VALID_TONES_LIST) | ||
51 | return Tone(VALID_TONES_LIST[new_index]) | 51 | return Tone(VALID_TONES_LIST[new_index]) | ||
52 | else: | 52 | else: | ||
53 | raise TypeError('Invalid operation') | 53 | raise TypeError('Invalid operation') | ||
54 | 54 | ||||
55 | def __sub__(self, other): | 55 | def __sub__(self, other): | ||
56 | if type(other) == Tone: | 56 | if type(other) == Tone: | ||
57 | first_tone_index = VALID_TONES_LIST.index(self._note) | 57 | first_tone_index = VALID_TONES_LIST.index(self._note) | ||
58 | second_tone_index = VALID_TONES_LIST.index(str(other)) | 58 | second_tone_index = VALID_TONES_LIST.index(str(other)) | ||
59 | steps = (first_tone_index - second_tone_index) % len(VALID_TONES_LIST) | 59 | steps = (first_tone_index - second_tone_index) % len(VALID_TONES_LIST) | ||
60 | return Interval(steps) | 60 | return Interval(steps) | ||
61 | elif type(other) == Interval: | 61 | elif type(other) == Interval: | ||
62 | tone_index = VALID_TONES_LIST.index(self._note) | 62 | tone_index = VALID_TONES_LIST.index(self._note) | ||
63 | new_index = (tone_index - other.steps) % len(VALID_TONES_LIST) | 63 | new_index = (tone_index - other.steps) % len(VALID_TONES_LIST) | ||
64 | return Tone(VALID_TONES_LIST[new_index]) | 64 | return Tone(VALID_TONES_LIST[new_index]) | ||
65 | else: | 65 | else: | ||
66 | raise TypeError('Invalid operation') | 66 | raise TypeError('Invalid operation') | ||
67 | 67 | ||||
68 | 68 | ||||
69 | class Interval: | 69 | class Interval: | ||
70 | """Represents a musical interval.""" | 70 | """Represents a musical interval.""" | ||
71 | 71 | ||||
72 | def __init__(self, steps): | 72 | def __init__(self, steps): | ||
73 | self._steps = steps | 73 | self._steps = steps | ||
74 | 74 | ||||
75 | @property | 75 | @property | ||
76 | def steps(self): | 76 | def steps(self): | ||
77 | return self._steps | 77 | return self._steps | ||
78 | 78 | ||||
79 | @steps.setter | 79 | @steps.setter | ||
80 | def steps(self, value): | 80 | def steps(self, value): | ||
81 | if value < 0: | 81 | if value < 0: | ||
82 | raise ValueError(f'{value} is not a positive number') | 82 | raise ValueError(f'{value} is not a positive number') | ||
83 | 83 | ||||
84 | self._steps = value % 12 | 84 | self._steps = value % 12 | ||
85 | 85 | ||||
86 | def __str__(self): | 86 | def __str__(self): | ||
87 | return INTERVALS[self._steps] | 87 | return INTERVALS[self._steps] | ||
88 | 88 | ||||
89 | def __add__(self, other): | 89 | def __add__(self, other): | ||
90 | if type(other) == Interval: | 90 | if type(other) == Interval: | ||
91 | new_steps = (self.steps + other.steps) % 12 | 91 | new_steps = (self.steps + other.steps) % 12 | ||
92 | return Interval(new_steps) | 92 | return Interval(new_steps) | ||
93 | 93 | ||||
94 | raise TypeError(f'Cannot add {type(other)} to Interval') | 94 | raise TypeError(f'Cannot add {type(other)} to Interval') | ||
95 | 95 | ||||
96 | def __neg__(self): | 96 | def __neg__(self): | ||
97 | return Interval(-self._steps) | 97 | return Interval(-self._steps) | ||
98 | 98 | ||||
99 | 99 | ||||
100 | class Chord: | 100 | class Chord: | ||
101 | """Represents a musical chord.""" | 101 | """Represents a musical chord.""" | ||
102 | 102 | ||||
103 | def __init__(self, main_tone, *tones): | 103 | def __init__(self, main_tone, *tones): | ||
104 | self._tones = {main_tone, *tones} | 104 | self._tones = {main_tone, *tones} | ||
105 | self._main_tone = main_tone # Keep root so we don't cast to list | 105 | self._main_tone = main_tone # Keep root so we don't cast to list | ||
106 | if len(self._tones) < 2: | 106 | if len(self._tones) < 2: | ||
107 | raise TypeError('Cannot have a chord made of only 1 unique tone') | 107 | raise TypeError('Cannot have a chord made of only 1 unique tone') | ||
108 | 108 | ||||
109 | def __str__(self): | 109 | def __str__(self): | ||
110 | root_index = VALID_TONES_LIST.index(str(self._main_tone)) | 110 | root_index = VALID_TONES_LIST.index(str(self._main_tone)) | ||
111 | sorted_tones = sorted(self._tones, key=lambda tone: (VALID_TONES_LIST.index(str(tone)) - root_index) % len(VALID_TONES_LIST)) | 111 | sorted_tones = sorted(self._tones, key=lambda tone: (VALID_TONES_LIST.index(str(tone)) - root_index) % len(VALID_TONES_LIST)) | ||
112 | 112 | ||||
113 | return "-".join(str(tone) for tone in sorted_tones) | 113 | return "-".join(str(tone) for tone in sorted_tones) | ||
114 | 114 | ||||
115 | def __add__(self, other): | 115 | def __add__(self, other): | ||
116 | if type(other) == Tone: | 116 | if type(other) == Tone: | ||
117 | new_tones = self._tones | {other} # Union of sets | 117 | new_tones = self._tones | {other} # Union of sets | ||
118 | return Chord(self._main_tone, *new_tones) | 118 | return Chord(self._main_tone, *new_tones) | ||
119 | elif type(other) == Chord: | 119 | elif type(other) == Chord: | ||
120 | new_tones = self._tones | other._tones # Union of sets | 120 | new_tones = self._tones | other._tones # Union of sets | ||
121 | new_main_tone = self._main_tone | 121 | new_main_tone = self._main_tone | ||
122 | return Chord(new_main_tone, *new_tones) | 122 | return Chord(new_main_tone, *new_tones) | ||
123 | else: | 123 | else: | ||
124 | raise TypeError('Invalid operation') | 124 | raise TypeError('Invalid operation') | ||
125 | 125 | ||||
126 | def __sub__(self, other): | 126 | def __sub__(self, other): | ||
127 | if type(other) == Tone: | 127 | if type(other) == Tone: | ||
128 | if other not in self._tones: | 128 | if other not in self._tones: | ||
129 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | 129 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | ||
130 | 130 | ||||
131 | new_tones = self._tones - {other} | 131 | new_tones = self._tones - {other} | ||
132 | if len(new_tones) < 2: | 132 | if len(new_tones) < 2: | ||
133 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 133 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
134 | 134 | ||||
135 | new_main_tone = next(iter(new_tones)) | 135 | new_main_tone = next(iter(new_tones)) | ||
136 | return Chord(new_main_tone, *(new_tones - {new_main_tone})) | 136 | return Chord(new_main_tone, *(new_tones - {new_main_tone})) | ||
137 | 137 | ||||
138 | raise TypeError(f"Cannot subtract {type(other)} from Chord") | 138 | raise TypeError(f"Cannot subtract {type(other)} from Chord") | ||
139 | 139 | ||||
140 | def is_minor(self): | 140 | def is_minor(self): | ||
141 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | 141 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | ||
142 | for tone in self._tones: | 142 | for tone in self._tones: | ||
143 | if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 3: | 143 | if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 3: | ||
144 | return True | 144 | return True | ||
145 | 145 | ||||
146 | return False | 146 | return False | ||
147 | 147 | ||||
148 | def is_major(self): | 148 | def is_major(self): | ||
149 | steps = 0 | 149 | steps = 0 | ||
150 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | 150 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | ||
151 | for tone in self._tones: | 151 | for tone in self._tones: | ||
152 | if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 4: | 152 | if VALID_TONES_LIST.index(str(tone)) - main_tone_index == 4: | ||
153 | return True | 153 | return True | ||
154 | 154 | ||||
155 | return False | 155 | return False | ||
156 | 156 | ||||
157 | def is_power_chord(self): | 157 | def is_power_chord(self): | ||
158 | if not self.is_minor() and not self.is_major(): | 158 | if not self.is_minor() and not self.is_major(): | ||
159 | return True | 159 | return True | ||
160 | 160 | ||||
161 | return False | 161 | return False | ||
162 | 162 | ||||
163 | def transposed(self, interval): | 163 | def transposed(self, interval): | ||
164 | if type(interval) != Interval: | 164 | if type(interval) != Interval: | ||
165 | raise TypeError("Transposition requires an Interval object") | 165 | raise TypeError("Transposition requires an Interval object") | ||
166 | 166 | ||||
167 | transposed_tones = set() | 167 | transposed_tones = set() | ||
168 | for tone in self._tones: | 168 | for tone in self._tones: | ||
169 | original_index = VALID_TONES_LIST.index(str(tone)) | 169 | original_index = VALID_TONES_LIST.index(str(tone)) | ||
170 | transposed_index = (original_index + interval.steps) % 12 | 170 | transposed_index = (original_index + interval.steps) % 12 | ||
171 | transposed_tone = Tone(VALID_TONES_LIST[transposed_index]) | 171 | transposed_tone = Tone(VALID_TONES_LIST[transposed_index]) | ||
172 | transposed_tones.add(transposed_tone) | 172 | transposed_tones.add(transposed_tone) | ||
173 | 173 | ||||
174 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | 174 | main_tone_index = VALID_TONES_LIST.index(str(self._main_tone)) | ||
175 | transposed_main_tone_index = (main_tone_index + interval.steps) % 12 | 175 | transposed_main_tone_index = (main_tone_index + interval.steps) % 12 | ||
176 | transposed_main_tone = Tone(VALID_TONES_LIST[transposed_main_tone_index]) | 176 | transposed_main_tone = Tone(VALID_TONES_LIST[transposed_main_tone_index]) | ||
177 | 177 | ||||
178 | return Chord(transposed_main_tone, *transposed_tones) | 178 | return Chord(transposed_main_tone, *transposed_tones) | ||
t | 179 | t | |||
180 | c_major_chord = Chord(Tone("C"), Tone("E"), Tone("G")) | ||||
181 | result_chord = c_major_chord - Tone("E") | ||||
182 | print(str(result_chord)) | ||||
183 | #self.assertEqual(str(result_chord), "C-G") |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
06.11.2024 13:57
06.11.2024 13:56
06.11.2024 13:59
06.11.2024 14:00
06.11.2024 14:03
06.11.2024 14:08
06.11.2024 14:11
06.11.2024 14:12