1class Tone:
2 TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
3
4 def __init__(self, name):
5 if name not in Tone.TONES:
6 raise ValueError("Invalid tone name.")
7 self.name = name
8 self.index = Tone.TONES.index(name)
9
10 def __str__(self):
11 return self.name
12
13 def __add__(self, other):
14 if isinstance(other, Tone):
15 return Chord(self, other)
16 elif isinstance(other, Interval):
17 new_index = (self.index + other.semitones) % 12
18 return Tone(Tone.TONES[new_index])
19 raise TypeError("Invalid operation")
20
21 def __sub__(self, other):
22 if isinstance(other, Tone):
23 semitone_diff = (self.index - other.index) % 12
24 return Interval(semitone_diff)
25 elif isinstance(other, Interval):
26 new_index = (self.index - other.semitones) % 12
27 return Tone(Tone.TONES[new_index])
28 raise TypeError("Invalid operation")
29
30
31class Interval:
32 INTERVAL_NAMES = [
33 "unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
34 "perfect 4th", "augmented 4th", "perfect 5th", "minor 6th",
35 "major 6th", "minor 7th", "major 7th"
36 ]
37
38 def __init__(self, semitones):
39 self.semitones = semitones % 12
40
41 def __str__(self):
42 return self.INTERVAL_NAMES[self.semitones]
43
44 def __add__(self, other):
45 if isinstance(other, Interval):
46 return Interval(self.semitones + other.semitones)
47 raise TypeError("Invalid operation")
48
49
50class Chord:
51 def __init__(self, root, *tones):
52 self.root = root
53 unique_tones = {root}
54 for tone in tones:
55 unique_tones.add(tone)
56 if len(unique_tones) < 2:
57 raise TypeError("Cannot have a chord made of only 1 unique tone")
58 self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12)
59
60 def __str__(self):
61 return "-".join(str(tone) for tone in self.tones)
62
63 def is_minor(self):
64 return any((tone - self.root).semitones == 3 for tone in self.tones if tone != self.root)
65
66 def is_major(self):
67 return any((tone - self.root).semitones == 4 for tone in self.tones if tone != self.root)
68
69 def is_power_chord(self):
70 return not self.is_minor() and not self.is_major()
71
72 def __add__(self, other):
73 if isinstance(other, Tone):
74 if other not in self.tones:
75 new_tones = self.tones + [other]
76 else:
77 new_tones = self.tones
78 return Chord(*new_tones)
79 elif isinstance(other, Chord):
80 combined_tones = set(self.tones) | set(other.tones)
81 return Chord(*combined_tones)
82 raise TypeError("Invalid operation")
83
84 def __sub__(self, other):
85 if isinstance(other, Tone):
86 if other not in self.tones:
87 raise TypeError(f"Cannot remove tone {other} from chord {self}")
88 new_tones = [tone for tone in self.tones if tone != other]
89 if len(new_tones) < 2:
90 raise TypeError("Cannot have a chord made of only 1 unique tone")
91 return Chord(*new_tones)
92 raise TypeError("Invalid operation")
93
94 def transposed(self, interval):
95 if not isinstance(interval, Interval):
96 raise TypeError("Invalid interval type for transposition")
97 transposed_tones = [tone + interval for tone in self.tones]
98 return Chord(*transposed_tones)
F..F....EE.E.F.FF.....F....F..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'
======================================================================
ERROR: test_subtract_tone_from_chord (test.TestOperations.test_subtract_tone_from_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 275, in test_subtract_tone_from_chord
result_chord = f_minor_chord - Tone("C")
~~~~~~~~~~~~~~^~~~~~~~~~~
File "/tmp/solution.py", line 87, in __sub__
raise TypeError(f"Cannot remove tone {other} from chord {self}")
TypeError: Cannot remove tone C from chord F-G#-C
======================================================================
FAIL: test_chord_not_enough_tones (test.TestBasicChordFunctionality.test_chord_not_enough_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 83, in test_chord_not_enough_tones
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised
======================================================================
FAIL: test_chord_tone_repetition (test.TestBasicChordFunctionality.test_chord_tone_repetition)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 74, in test_chord_tone_repetition
self.assertEqual(str(a_minor_chord), "A-C-E")
AssertionError: 'A-A-A-A-A-A-A-C-C-C-C-C-C-C-C-C-C-C-C-C-C-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E' != 'A-C-E'
- A-A-A-A-A-A-A-C-C-C-C-C-C-C-C-C-C-C-C-C-C-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E
+ A-C-E
======================================================================
FAIL: test_interval_str (test.TestBasicIntervalFunctionality.test_interval_str)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 42, in test_interval_str
self.assertEqual(str(Interval(index)), interval)
AssertionError: 'augmented 4th' != 'diminished 5th'
- augmented 4th
+ diminished 5th
======================================================================
FAIL: test_add_chords (test.TestOperations.test_add_chords)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 299, in test_add_chords
self.assertEqual(str(result_chord), "C-G-A-B")
AssertionError: 'G-A-B-C' != 'C-G-A-B'
- G-A-B-C
? --
+ C-G-A-B
? ++
======================================================================
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: 'G-G-C-C' != 'C-G'
- G-G-C-C
+ C-G
======================================================================
FAIL: test_add_tone_to_chord_existing_tone (test.TestOperations.test_add_tone_to_chord_existing_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 270, in test_add_tone_to_chord_existing_tone
self.assertEqual(str(result_chord), "F-G#-C")
AssertionError: 'F-F-G#-G#-C-C' != 'F-G#-C'
- F-F-G#-G#-C-C
+ F-G#-C
======================================================================
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_tone_addition_same_tone (test.TestOperations.test_tone_addition_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 166, in test_tone_addition_same_tone
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised
----------------------------------------------------------------------
Ran 37 tests in 0.003s
FAILED (failures=8, errors=4)
Виктор Бечев
05.11.2024 10:34Тъй е по-добре... Че иначе имаше 1 точка защото беше сменил името с главни букви горе и после го беше ползвал пак с малки.
|
Димитър Илиев
05.11.2024 10:10Качих трети вариант, надявам се да се вижда!
Поздрави!
Халанд от Алиекспрес
|
Виктор Бечев
04.11.2024 16:20А пусна ли новата версия?
П.П. Това, което ти казах за константата важи и на други места, не само където съм го отбелязал изрично.
|
Димитър Илиев
04.11.2024 11:11Привет, благодаря за обратната връзка, ще кача нова версия!
Поздрави!
Димитър
|
Виктор Бечев
02.11.2024 21:55Отвъд горните забележки - изглежда добре. :)
|
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"] | ||
n | 3 | n | 3 | ||
4 | def __init__(self, name): | 4 | def __init__(self, name): | ||
n | 5 | if name not in Tone.tones: | n | 5 | if name not in Tone.TONES: |
6 | raise ValueError("Invalid tone name.") | 6 | raise ValueError("Invalid tone name.") | ||
7 | self.name = name | 7 | self.name = name | ||
n | 8 | self.index = Tone.tones.index(name) | n | 8 | self.index = Tone.TONES.index(name) |
9 | 9 | ||||
10 | def __str__(self): | 10 | def __str__(self): | ||
11 | return self.name | 11 | return self.name | ||
n | 12 | n | 12 | ||
13 | def __add__(self, other): | 13 | def __add__(self, other): | ||
14 | if isinstance(other, Tone): | 14 | if isinstance(other, Tone): | ||
15 | return Chord(self, other) | 15 | return Chord(self, other) | ||
16 | elif isinstance(other, Interval): | 16 | elif isinstance(other, Interval): | ||
17 | new_index = (self.index + other.semitones) % 12 | 17 | new_index = (self.index + other.semitones) % 12 | ||
n | 18 | return Tone(Tone.tones[new_index]) | n | 18 | return Tone(Tone.TONES[new_index]) |
19 | raise TypeError("Invalid operation") | 19 | raise TypeError("Invalid operation") | ||
n | 20 | n | 20 | ||
21 | def __sub__(self, other): | 21 | def __sub__(self, other): | ||
22 | if isinstance(other, Tone): | 22 | if isinstance(other, Tone): | ||
23 | semitone_diff = (self.index - other.index) % 12 | 23 | semitone_diff = (self.index - other.index) % 12 | ||
24 | return Interval(semitone_diff) | 24 | return Interval(semitone_diff) | ||
25 | elif isinstance(other, Interval): | 25 | elif isinstance(other, Interval): | ||
26 | new_index = (self.index - other.semitones) % 12 | 26 | new_index = (self.index - other.semitones) % 12 | ||
n | 27 | return Tone(Tone.tones[new_index]) | n | 27 | return Tone(Tone.TONES[new_index]) |
28 | raise TypeError("Invalid operation") | 28 | raise TypeError("Invalid operation") | ||
29 | 29 | ||||
30 | 30 | ||||
31 | class Interval: | 31 | class Interval: | ||
n | 32 | intervals = [ | n | 32 | INTERVAL_NAMES = [ |
33 | "unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", | 33 | "unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", | ||
34 | "perfect 4th", "augmented 4th", "perfect 5th", "minor 6th", | 34 | "perfect 4th", "augmented 4th", "perfect 5th", "minor 6th", | ||
35 | "major 6th", "minor 7th", "major 7th" | 35 | "major 6th", "minor 7th", "major 7th" | ||
36 | ] | 36 | ] | ||
37 | 37 | ||||
38 | def __init__(self, semitones): | 38 | def __init__(self, semitones): | ||
39 | self.semitones = semitones % 12 | 39 | self.semitones = semitones % 12 | ||
40 | 40 | ||||
41 | def __str__(self): | 41 | def __str__(self): | ||
n | 42 | return self.intervals[self.semitones] | n | 42 | return self.INTERVAL_NAMES[self.semitones] |
43 | 43 | ||||
44 | def __add__(self, other): | 44 | def __add__(self, other): | ||
45 | if isinstance(other, Interval): | 45 | if isinstance(other, Interval): | ||
46 | return Interval(self.semitones + other.semitones) | 46 | return Interval(self.semitones + other.semitones) | ||
47 | raise TypeError("Invalid operation") | 47 | raise TypeError("Invalid operation") | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Chord: | 50 | class Chord: | ||
51 | def __init__(self, root, *tones): | 51 | def __init__(self, root, *tones): | ||
52 | self.root = root | 52 | self.root = root | ||
53 | unique_tones = {root} | 53 | unique_tones = {root} | ||
54 | for tone in tones: | 54 | for tone in tones: | ||
55 | unique_tones.add(tone) | 55 | unique_tones.add(tone) | ||
56 | if len(unique_tones) < 2: | 56 | if len(unique_tones) < 2: | ||
57 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 57 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
58 | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) | 58 | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) | ||
n | 59 | n | 59 | ||
60 | def __str__(self): | 60 | def __str__(self): | ||
61 | return "-".join(str(tone) for tone in self.tones) | 61 | return "-".join(str(tone) for tone in self.tones) | ||
n | 62 | n | 62 | ||
63 | def is_minor(self): | 63 | def is_minor(self): | ||
64 | return any((tone - self.root).semitones == 3 for tone in self.tones if tone != self.root) | 64 | return any((tone - self.root).semitones == 3 for tone in self.tones if tone != self.root) | ||
n | 65 | n | 65 | ||
66 | def is_major(self): | 66 | def is_major(self): | ||
67 | return any((tone - self.root).semitones == 4 for tone in self.tones if tone != self.root) | 67 | return any((tone - self.root).semitones == 4 for tone in self.tones if tone != self.root) | ||
n | 68 | n | 68 | ||
69 | def is_power_chord(self): | 69 | def is_power_chord(self): | ||
70 | return not self.is_minor() and not self.is_major() | 70 | return not self.is_minor() and not self.is_major() | ||
n | 71 | n | 71 | ||
72 | def __add__(self, other): | 72 | def __add__(self, other): | ||
73 | if isinstance(other, Tone): | 73 | if isinstance(other, Tone): | ||
n | 74 | new_tones = self.tones + [other] if other not in self.tones else self.tones | n | 74 | if other not in self.tones: |
75 | new_tones = self.tones + [other] | ||||
76 | else: | ||||
77 | new_tones = self.tones | ||||
75 | return Chord(*new_tones) | 78 | return Chord(*new_tones) | ||
76 | elif isinstance(other, Chord): | 79 | elif isinstance(other, Chord): | ||
77 | combined_tones = set(self.tones) | set(other.tones) | 80 | combined_tones = set(self.tones) | set(other.tones) | ||
78 | return Chord(*combined_tones) | 81 | return Chord(*combined_tones) | ||
79 | raise TypeError("Invalid operation") | 82 | raise TypeError("Invalid operation") | ||
n | 80 | n | 83 | ||
81 | def __sub__(self, other): | 84 | def __sub__(self, other): | ||
82 | if isinstance(other, Tone): | 85 | if isinstance(other, Tone): | ||
83 | if other not in self.tones: | 86 | if other not in self.tones: | ||
84 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | 87 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | ||
85 | new_tones = [tone for tone in self.tones if tone != other] | 88 | new_tones = [tone for tone in self.tones if tone != other] | ||
86 | if len(new_tones) < 2: | 89 | if len(new_tones) < 2: | ||
87 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 90 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
88 | return Chord(*new_tones) | 91 | return Chord(*new_tones) | ||
89 | raise TypeError("Invalid operation") | 92 | raise TypeError("Invalid operation") | ||
t | 90 | t | 93 | ||
91 | def transposed(self, interval): | 94 | def transposed(self, interval): | ||
92 | if not isinstance(interval, Interval): | 95 | if not isinstance(interval, Interval): | ||
93 | raise TypeError("Invalid interval type for transposition") | 96 | raise TypeError("Invalid interval type for transposition") | ||
94 | transposed_tones = [tone + interval for tone in self.tones] | 97 | transposed_tones = [tone + interval for tone in self.tones] | ||
95 | return Chord(*transposed_tones) | 98 | return Chord(*transposed_tones) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class Tone: | f | 1 | class Tone: |
n | 2 | tones = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | n | 2 | TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] |
3 | 3 | ||||
4 | def __init__(self, name): | 4 | def __init__(self, name): | ||
5 | if name not in Tone.tones: | 5 | if name not in Tone.tones: | ||
6 | raise ValueError("Invalid tone name.") | 6 | raise ValueError("Invalid tone name.") | ||
7 | self.name = name | 7 | self.name = name | ||
8 | self.index = Tone.tones.index(name) | 8 | self.index = Tone.tones.index(name) | ||
9 | 9 | ||||
10 | def __str__(self): | 10 | def __str__(self): | ||
11 | return self.name | 11 | return self.name | ||
12 | 12 | ||||
13 | def __add__(self, other): | 13 | def __add__(self, other): | ||
14 | if isinstance(other, Tone): | 14 | if isinstance(other, Tone): | ||
15 | return Chord(self, other) | 15 | return Chord(self, other) | ||
16 | elif isinstance(other, Interval): | 16 | elif isinstance(other, Interval): | ||
17 | new_index = (self.index + other.semitones) % 12 | 17 | new_index = (self.index + other.semitones) % 12 | ||
18 | return Tone(Tone.tones[new_index]) | 18 | return Tone(Tone.tones[new_index]) | ||
19 | raise TypeError("Invalid operation") | 19 | raise TypeError("Invalid operation") | ||
20 | 20 | ||||
21 | def __sub__(self, other): | 21 | def __sub__(self, other): | ||
22 | if isinstance(other, Tone): | 22 | if isinstance(other, Tone): | ||
23 | semitone_diff = (self.index - other.index) % 12 | 23 | semitone_diff = (self.index - other.index) % 12 | ||
24 | return Interval(semitone_diff) | 24 | return Interval(semitone_diff) | ||
25 | elif isinstance(other, Interval): | 25 | elif isinstance(other, Interval): | ||
26 | new_index = (self.index - other.semitones) % 12 | 26 | new_index = (self.index - other.semitones) % 12 | ||
27 | return Tone(Tone.tones[new_index]) | 27 | return Tone(Tone.tones[new_index]) | ||
28 | raise TypeError("Invalid operation") | 28 | raise TypeError("Invalid operation") | ||
29 | 29 | ||||
30 | 30 | ||||
31 | class Interval: | 31 | class Interval: | ||
n | 32 | intervals = { | n | 32 | intervals = [ |
33 | 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd", 4: "major 3rd", | 33 | "unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", | ||
34 | 5: "perfect 4th", 6: "augmented 4th", 7: "perfect 5th", | 34 | "perfect 4th", "augmented 4th", "perfect 5th", "minor 6th", | ||
35 | 8: "minor 6th", 9: "major 6th", 10: "minor 7th", 11: "major 7th", 0: "unison" | 35 | "major 6th", "minor 7th", "major 7th" | ||
36 | } | 36 | ] | ||
37 | 37 | ||||
38 | def __init__(self, semitones): | 38 | def __init__(self, semitones): | ||
39 | self.semitones = semitones % 12 | 39 | self.semitones = semitones % 12 | ||
n | 40 | n | 40 | ||
41 | def __str__(self): | 41 | def __str__(self): | ||
t | 42 | return self.intervals.get(self.semitones, "unison") | t | 42 | return self.intervals[self.semitones] |
43 | 43 | ||||
44 | def __add__(self, other): | 44 | def __add__(self, other): | ||
45 | if isinstance(other, Interval): | 45 | if isinstance(other, Interval): | ||
46 | return Interval(self.semitones + other.semitones) | 46 | return Interval(self.semitones + other.semitones) | ||
47 | raise TypeError("Invalid operation") | 47 | raise TypeError("Invalid operation") | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Chord: | 50 | class Chord: | ||
51 | def __init__(self, root, *tones): | 51 | def __init__(self, root, *tones): | ||
52 | self.root = root | 52 | self.root = root | ||
53 | unique_tones = {root} | 53 | unique_tones = {root} | ||
54 | for tone in tones: | 54 | for tone in tones: | ||
55 | unique_tones.add(tone) | 55 | unique_tones.add(tone) | ||
56 | if len(unique_tones) < 2: | 56 | if len(unique_tones) < 2: | ||
57 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 57 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
58 | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) | 58 | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) | ||
59 | 59 | ||||
60 | def __str__(self): | 60 | def __str__(self): | ||
61 | return "-".join(str(tone) for tone in self.tones) | 61 | return "-".join(str(tone) for tone in self.tones) | ||
62 | 62 | ||||
63 | def is_minor(self): | 63 | def is_minor(self): | ||
64 | return any((tone - self.root).semitones == 3 for tone in self.tones if tone != self.root) | 64 | return any((tone - self.root).semitones == 3 for tone in self.tones if tone != self.root) | ||
65 | 65 | ||||
66 | def is_major(self): | 66 | def is_major(self): | ||
67 | return any((tone - self.root).semitones == 4 for tone in self.tones if tone != self.root) | 67 | return any((tone - self.root).semitones == 4 for tone in self.tones if tone != self.root) | ||
68 | 68 | ||||
69 | def is_power_chord(self): | 69 | def is_power_chord(self): | ||
70 | return not self.is_minor() and not self.is_major() | 70 | return not self.is_minor() and not self.is_major() | ||
71 | 71 | ||||
72 | def __add__(self, other): | 72 | def __add__(self, other): | ||
73 | if isinstance(other, Tone): | 73 | if isinstance(other, Tone): | ||
74 | new_tones = self.tones + [other] if other not in self.tones else self.tones | 74 | new_tones = self.tones + [other] if other not in self.tones else self.tones | ||
75 | return Chord(*new_tones) | 75 | return Chord(*new_tones) | ||
76 | elif isinstance(other, Chord): | 76 | elif isinstance(other, Chord): | ||
77 | combined_tones = set(self.tones) | set(other.tones) | 77 | combined_tones = set(self.tones) | set(other.tones) | ||
78 | return Chord(*combined_tones) | 78 | return Chord(*combined_tones) | ||
79 | raise TypeError("Invalid operation") | 79 | raise TypeError("Invalid operation") | ||
80 | 80 | ||||
81 | def __sub__(self, other): | 81 | def __sub__(self, other): | ||
82 | if isinstance(other, Tone): | 82 | if isinstance(other, Tone): | ||
83 | if other not in self.tones: | 83 | if other not in self.tones: | ||
84 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | 84 | raise TypeError(f"Cannot remove tone {other} from chord {self}") | ||
85 | new_tones = [tone for tone in self.tones if tone != other] | 85 | new_tones = [tone for tone in self.tones if tone != other] | ||
86 | if len(new_tones) < 2: | 86 | if len(new_tones) < 2: | ||
87 | 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") | ||
88 | return Chord(*new_tones) | 88 | return Chord(*new_tones) | ||
89 | raise TypeError("Invalid operation") | 89 | raise TypeError("Invalid operation") | ||
90 | 90 | ||||
91 | def transposed(self, interval): | 91 | def transposed(self, interval): | ||
92 | if not isinstance(interval, Interval): | 92 | if not isinstance(interval, Interval): | ||
93 | raise TypeError("Invalid interval type for transposition") | 93 | raise TypeError("Invalid interval type for transposition") | ||
94 | transposed_tones = [tone + interval for tone in self.tones] | 94 | transposed_tones = [tone + interval for tone in self.tones] | ||
95 | return Chord(*transposed_tones) | 95 | return Chord(*transposed_tones) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|