1ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
2ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"]
3NUMBER_OF_INTERVALS = 12
4NUMBER_FOR_MINOR_3RD = 3
5NUMBER_FOR_MAJOR_3RD = 4
6
7class Tone:
8 def __init__(self, tone):
9 if tone in ALL_VALID_TONES:
10 self.name = tone
11 self.index = ALL_VALID_TONES.index(tone)
12 else:
13 raise Exception("Invalid input.")
14
15 def __str__(self):
16 return self.name
17
18 def __add__(self, other):
19 if isinstance(other, Tone):
20 return Chord(self, other)
21 elif isinstance(other, Interval):
22 index_of_new_tone = (self.index + other.interval_number) % 12
23 return Tone(ALL_VALID_TONES[index_of_new_tone])
24
25 def __sub__(self, other):
26 if isinstance(other, Tone):
27 index_of_first_tone = self.index
28 index_of_second_tone = other.index
29 return Interval(index_of_first_tone - index_of_second_tone)
30 elif isinstance(other, Interval):
31 index_of_new_tone = self.index - other.interval_number
32 return Tone(ALL_VALID_TONES[index_of_new_tone])
33
34
35class Interval:
36 def __init__(self, number):
37 number %= NUMBER_OF_INTERVALS
38 self.interval_number = number
39 self.interval_name = ALL_VALID_INTERVALS[number]
40
41 def __str__(self):
42 return self.interval_name
43
44 def __add__(self, other):
45 if isinstance(other, Tone):
46 raise TypeError("Invalid operation")
47 elif isinstance(other, Interval):
48 return Interval(self.interval_number + other.interval_number)
49
50 def __sub__(self, other):
51 if isinstance(other, Tone):
52 raise TypeError("Invalid operation")
53
54 def __neg__(self):
55 return Interval(-self.interval_number)
56
57
58class Chord:
59 def __init__(self, root, *args):
60 self.unique_tone_names = {root.name}
61 self.tones = [root]
62 self.root = root
63 for tone in args:
64 if tone.name not in self.unique_tone_names:
65 self.tones.append(tone)
66 self.unique_tone_names.add(tone.name)
67 if len(self.tones) == 1:
68 raise TypeError("Cannot have a chord made of only 1 unique tone")
69 root_num = ALL_VALID_TONES.index(str(root))
70 self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12)
71
72 def __str__(self):
73 return "-".join(str(tone) for tone in self.sorted_tones)
74
75 def is_minor(self):
76 for tone in self.sorted_tones:
77 difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root)))
78 if difference < 0:
79 difference += NUMBER_OF_INTERVALS
80 if difference == NUMBER_FOR_MINOR_3RD:
81 return True
82 return False
83
84 def is_major(self):
85 for tone in self.sorted_tones:
86 difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root)))
87 if difference < 0:
88 difference += NUMBER_OF_INTERVALS
89 if difference == NUMBER_FOR_MAJOR_3RD:
90 return True
91 return False
92
93 def is_power_chord(self):
94 if self.is_minor() == True or self.is_major() == True:
95 return False
96 return True
97
98 def __add__(self, other):
99 if isinstance(other, Tone):
100 return Chord(*self.tones, other)
101 if isinstance(other, Chord):
102 tones_for_new_chord = self.sorted_tones
103 for tone in other.sorted_tones:
104 if not tone in tones_for_new_chord:
105 tones_for_new_chord.append(tone)
106 return Chord(*tones_for_new_chord)
107
108 def __sub__(self, other):
109 if isinstance(other, Tone):
110 if other.name not in self.unique_tone_names:
111 raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}")
112 elif len(self.sorted_tones) - 1 == 1:
113 raise TypeError("Cannot have a chord made of only 1 unique tone")
114 else:
115 tones_for_new_chord = list()
116 for tone in self.sorted_tones:
117 if not tone.name == other.name:
118 tones_for_new_chord.append(tone)
119 return Chord(*tones_for_new_chord)
120
121 def transposed(self, interval):
122 tones_in_new_chord = list()
123 if interval.interval_number >= 0:
124 for tone in self.sorted_tones:
125 tones_in_new_chord.append(tone + interval)
126 return Chord(*tones_in_new_chord)
127 else:
128 for tone in self.sorted_tones:
129 tones_in_new_chord.append(tone - interval)
130 return Chord(*tones_in_new_chord)
.....................................
----------------------------------------------------------------------
Ran 37 tests in 0.001s
OK
Виктор Бечев
04.11.2024 14:15Изцяло стилистично е - имаш 2 интервала след `if`-а, липсва ти интервал преди `==`, имаш един интервал преди `:`.
За `is_minor / is_major` функциите - за minor / major 3rd интервал интерпретираме само ако е в посока "нагоре".
П.П. От теоретична гледна точка - иначе бихме имали инверсии на акордите.
П.П.П. Друг път като не си сигурна - ако след 2-3 прочита пак не е ясно - питай ни овреме, защото иначе разчиташ на късмета да си го имплементирала правилно, тъй като рядко поправяме хората по отношение на имплементацията (обратната ни връзка цели подобряване на стила и запознаване с идиомите и похватите в Python, както и някои абстрактни концепции, а не да откриваме бъгове в кода и да ви ги споменаваме).
П.П.П.П. Ако има нещо друго неясно по условието - сега е моментът.
|
Вяра Тодорова
04.11.2024 13:50Относно 91 ред визираш, че съм пропуснала един интервал или че интервалите за проверката не са точни? Тъй като се чудех за is_major и is_minor дали трябва да връща True ако разликата е съответно 4 и 3 без значение в коя посока е тонът спрямо корена или само ако е по часовниковата стрелка?
|
| f | 1 | ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") | f | 1 | ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") |
| 2 | ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 2 | ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
| 3 | NUMBER_OF_INTERVALS = 12 | 3 | NUMBER_OF_INTERVALS = 12 | ||
| 4 | NUMBER_FOR_MINOR_3RD = 3 | 4 | NUMBER_FOR_MINOR_3RD = 3 | ||
| 5 | NUMBER_FOR_MAJOR_3RD = 4 | 5 | NUMBER_FOR_MAJOR_3RD = 4 | ||
| 6 | 6 | ||||
| 7 | class Tone: | 7 | class Tone: | ||
| 8 | def __init__(self, tone): | 8 | def __init__(self, tone): | ||
| 9 | if tone in ALL_VALID_TONES: | 9 | if tone in ALL_VALID_TONES: | ||
| 10 | self.name = tone | 10 | self.name = tone | ||
| 11 | self.index = ALL_VALID_TONES.index(tone) | 11 | self.index = ALL_VALID_TONES.index(tone) | ||
| 12 | else: | 12 | else: | ||
| 13 | raise Exception("Invalid input.") | 13 | raise Exception("Invalid input.") | ||
| 14 | 14 | ||||
| 15 | def __str__(self): | 15 | def __str__(self): | ||
| 16 | return self.name | 16 | return self.name | ||
| 17 | 17 | ||||
| 18 | def __add__(self, other): | 18 | def __add__(self, other): | ||
| 19 | if isinstance(other, Tone): | 19 | if isinstance(other, Tone): | ||
| 20 | return Chord(self, other) | 20 | return Chord(self, other) | ||
| 21 | elif isinstance(other, Interval): | 21 | elif isinstance(other, Interval): | ||
| 22 | index_of_new_tone = (self.index + other.interval_number) % 12 | 22 | index_of_new_tone = (self.index + other.interval_number) % 12 | ||
| 23 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | 23 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | ||
| 24 | 24 | ||||
| 25 | def __sub__(self, other): | 25 | def __sub__(self, other): | ||
| 26 | if isinstance(other, Tone): | 26 | if isinstance(other, Tone): | ||
| 27 | index_of_first_tone = self.index | 27 | index_of_first_tone = self.index | ||
| 28 | index_of_second_tone = other.index | 28 | index_of_second_tone = other.index | ||
| 29 | return Interval(index_of_first_tone - index_of_second_tone) | 29 | return Interval(index_of_first_tone - index_of_second_tone) | ||
| 30 | elif isinstance(other, Interval): | 30 | elif isinstance(other, Interval): | ||
| 31 | index_of_new_tone = self.index - other.interval_number | 31 | index_of_new_tone = self.index - other.interval_number | ||
| 32 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | 32 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | ||
| 33 | 33 | ||||
| 34 | 34 | ||||
| 35 | class Interval: | 35 | class Interval: | ||
| 36 | def __init__(self, number): | 36 | def __init__(self, number): | ||
| 37 | number %= NUMBER_OF_INTERVALS | 37 | number %= NUMBER_OF_INTERVALS | ||
| 38 | self.interval_number = number | 38 | self.interval_number = number | ||
| 39 | self.interval_name = ALL_VALID_INTERVALS[number] | 39 | self.interval_name = ALL_VALID_INTERVALS[number] | ||
| 40 | 40 | ||||
| 41 | def __str__(self): | 41 | def __str__(self): | ||
| 42 | return self.interval_name | 42 | return self.interval_name | ||
| 43 | 43 | ||||
| 44 | def __add__(self, other): | 44 | def __add__(self, other): | ||
| 45 | if isinstance(other, Tone): | 45 | if isinstance(other, Tone): | ||
| 46 | raise TypeError("Invalid operation") | 46 | raise TypeError("Invalid operation") | ||
| 47 | elif isinstance(other, Interval): | 47 | elif isinstance(other, Interval): | ||
| 48 | return Interval(self.interval_number + other.interval_number) | 48 | return Interval(self.interval_number + other.interval_number) | ||
| 49 | 49 | ||||
| 50 | def __sub__(self, other): | 50 | def __sub__(self, other): | ||
| 51 | if isinstance(other, Tone): | 51 | if isinstance(other, Tone): | ||
| 52 | raise TypeError("Invalid operation") | 52 | raise TypeError("Invalid operation") | ||
| 53 | 53 | ||||
| 54 | def __neg__(self): | 54 | def __neg__(self): | ||
| 55 | return Interval(-self.interval_number) | 55 | return Interval(-self.interval_number) | ||
| 56 | 56 | ||||
| 57 | 57 | ||||
| 58 | class Chord: | 58 | class Chord: | ||
| 59 | def __init__(self, root, *args): | 59 | def __init__(self, root, *args): | ||
| 60 | self.unique_tone_names = {root.name} | 60 | self.unique_tone_names = {root.name} | ||
| 61 | self.tones = [root] | 61 | self.tones = [root] | ||
| 62 | self.root = root | 62 | self.root = root | ||
| 63 | for tone in args: | 63 | for tone in args: | ||
| 64 | if tone.name not in self.unique_tone_names: | 64 | if tone.name not in self.unique_tone_names: | ||
| 65 | self.tones.append(tone) | 65 | self.tones.append(tone) | ||
| 66 | self.unique_tone_names.add(tone.name) | 66 | self.unique_tone_names.add(tone.name) | ||
| 67 | if len(self.tones) == 1: | 67 | if len(self.tones) == 1: | ||
| 68 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 68 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| 69 | root_num = ALL_VALID_TONES.index(str(root)) | 69 | root_num = ALL_VALID_TONES.index(str(root)) | ||
| 70 | self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12) | 70 | self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12) | ||
| 71 | 71 | ||||
| 72 | def __str__(self): | 72 | def __str__(self): | ||
| 73 | return "-".join(str(tone) for tone in self.sorted_tones) | 73 | return "-".join(str(tone) for tone in self.sorted_tones) | ||
| 74 | 74 | ||||
| 75 | def is_minor(self): | 75 | def is_minor(self): | ||
| 76 | for tone in self.sorted_tones: | 76 | for tone in self.sorted_tones: | ||
| 77 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) | 77 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) | ||
| 78 | if difference < 0: | 78 | if difference < 0: | ||
| 79 | difference += NUMBER_OF_INTERVALS | 79 | difference += NUMBER_OF_INTERVALS | ||
| 80 | if difference == NUMBER_FOR_MINOR_3RD: | 80 | if difference == NUMBER_FOR_MINOR_3RD: | ||
| n | 81 | return "True" | n | 81 | return True |
| 82 | return "False" | 82 | return False | ||
| 83 | 83 | ||||
| 84 | def is_major(self): | 84 | def is_major(self): | ||
| 85 | for tone in self.sorted_tones: | 85 | for tone in self.sorted_tones: | ||
| 86 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) | 86 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) | ||
| 87 | if difference < 0: | 87 | if difference < 0: | ||
| 88 | difference += NUMBER_OF_INTERVALS | 88 | difference += NUMBER_OF_INTERVALS | ||
| 89 | if difference == NUMBER_FOR_MAJOR_3RD: | 89 | if difference == NUMBER_FOR_MAJOR_3RD: | ||
| n | 90 | return "True" | n | 90 | return True |
| 91 | return "False" | 91 | return False | ||
| 92 | 92 | ||||
| 93 | def is_power_chord(self): | 93 | def is_power_chord(self): | ||
| n | 94 | if self.is_minor() == "True" or self.is_major() == "True": | n | 94 | if self.is_minor() == True or self.is_major() == True: |
| 95 | return "False" | 95 | return False | ||
| 96 | return "True" | 96 | return True | ||
| 97 | 97 | ||||
| 98 | def __add__(self, other): | 98 | def __add__(self, other): | ||
| 99 | if isinstance(other, Tone): | 99 | if isinstance(other, Tone): | ||
| 100 | return Chord(*self.tones, other) | 100 | return Chord(*self.tones, other) | ||
| 101 | if isinstance(other, Chord): | 101 | if isinstance(other, Chord): | ||
| 102 | tones_for_new_chord = self.sorted_tones | 102 | tones_for_new_chord = self.sorted_tones | ||
| 103 | for tone in other.sorted_tones: | 103 | for tone in other.sorted_tones: | ||
| 104 | if not tone in tones_for_new_chord: | 104 | if not tone in tones_for_new_chord: | ||
| 105 | tones_for_new_chord.append(tone) | 105 | tones_for_new_chord.append(tone) | ||
| 106 | return Chord(*tones_for_new_chord) | 106 | return Chord(*tones_for_new_chord) | ||
| 107 | 107 | ||||
| 108 | def __sub__(self, other): | 108 | def __sub__(self, other): | ||
| 109 | if isinstance(other, Tone): | 109 | if isinstance(other, Tone): | ||
| 110 | if other.name not in self.unique_tone_names: | 110 | if other.name not in self.unique_tone_names: | ||
| 111 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | 111 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | ||
| 112 | elif len(self.sorted_tones) - 1 == 1: | 112 | elif len(self.sorted_tones) - 1 == 1: | ||
| 113 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 113 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| 114 | else: | 114 | else: | ||
| 115 | tones_for_new_chord = list() | 115 | tones_for_new_chord = list() | ||
| 116 | for tone in self.sorted_tones: | 116 | for tone in self.sorted_tones: | ||
| 117 | if not tone.name == other.name: | 117 | if not tone.name == other.name: | ||
| 118 | tones_for_new_chord.append(tone) | 118 | tones_for_new_chord.append(tone) | ||
| 119 | return Chord(*tones_for_new_chord) | 119 | return Chord(*tones_for_new_chord) | ||
| 120 | 120 | ||||
| 121 | def transposed(self, interval): | 121 | def transposed(self, interval): | ||
| 122 | tones_in_new_chord = list() | 122 | tones_in_new_chord = list() | ||
| 123 | if interval.interval_number >= 0: | 123 | if interval.interval_number >= 0: | ||
| 124 | for tone in self.sorted_tones: | 124 | for tone in self.sorted_tones: | ||
| 125 | tones_in_new_chord.append(tone + interval) | 125 | tones_in_new_chord.append(tone + interval) | ||
| 126 | return Chord(*tones_in_new_chord) | 126 | return Chord(*tones_in_new_chord) | ||
| 127 | else: | 127 | else: | ||
| 128 | for tone in self.sorted_tones: | 128 | for tone in self.sorted_tones: | ||
| 129 | tones_in_new_chord.append(tone - interval) | 129 | tones_in_new_chord.append(tone - interval) | ||
| 130 | return Chord(*tones_in_new_chord) | 130 | return Chord(*tones_in_new_chord) | ||
| t | t | 131 | |||
| 132 | |||||
| 133 | |||||
| 134 | |||||
| 135 | |||||
| 136 | |||||
| 137 | |||||
| 138 | |||||
| 139 | |||||
| 140 |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") | f | 1 | ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") |
| 2 | ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 2 | ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
| 3 | NUMBER_OF_INTERVALS = 12 | 3 | NUMBER_OF_INTERVALS = 12 | ||
| 4 | NUMBER_FOR_MINOR_3RD = 3 | 4 | NUMBER_FOR_MINOR_3RD = 3 | ||
| 5 | NUMBER_FOR_MAJOR_3RD = 4 | 5 | NUMBER_FOR_MAJOR_3RD = 4 | ||
| 6 | 6 | ||||
| 7 | class Tone: | 7 | class Tone: | ||
| 8 | def __init__(self, tone): | 8 | def __init__(self, tone): | ||
| 9 | if tone in ALL_VALID_TONES: | 9 | if tone in ALL_VALID_TONES: | ||
| 10 | self.name = tone | 10 | self.name = tone | ||
| 11 | self.index = ALL_VALID_TONES.index(tone) | 11 | self.index = ALL_VALID_TONES.index(tone) | ||
| 12 | else: | 12 | else: | ||
| 13 | raise Exception("Invalid input.") | 13 | raise Exception("Invalid input.") | ||
| 14 | 14 | ||||
| 15 | def __str__(self): | 15 | def __str__(self): | ||
| 16 | return self.name | 16 | return self.name | ||
| 17 | 17 | ||||
| 18 | def __add__(self, other): | 18 | def __add__(self, other): | ||
| 19 | if isinstance(other, Tone): | 19 | if isinstance(other, Tone): | ||
| 20 | return Chord(self, other) | 20 | return Chord(self, other) | ||
| 21 | elif isinstance(other, Interval): | 21 | elif isinstance(other, Interval): | ||
| 22 | index_of_new_tone = (self.index + other.interval_number) % 12 | 22 | index_of_new_tone = (self.index + other.interval_number) % 12 | ||
| 23 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | 23 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | ||
| 24 | 24 | ||||
| 25 | def __sub__(self, other): | 25 | def __sub__(self, other): | ||
| 26 | if isinstance(other, Tone): | 26 | if isinstance(other, Tone): | ||
| 27 | index_of_first_tone = self.index | 27 | index_of_first_tone = self.index | ||
| 28 | index_of_second_tone = other.index | 28 | index_of_second_tone = other.index | ||
| 29 | return Interval(index_of_first_tone - index_of_second_tone) | 29 | return Interval(index_of_first_tone - index_of_second_tone) | ||
| 30 | elif isinstance(other, Interval): | 30 | elif isinstance(other, Interval): | ||
| 31 | index_of_new_tone = self.index - other.interval_number | 31 | index_of_new_tone = self.index - other.interval_number | ||
| 32 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | 32 | return Tone(ALL_VALID_TONES[index_of_new_tone]) | ||
| 33 | 33 | ||||
| 34 | 34 | ||||
| 35 | class Interval: | 35 | class Interval: | ||
| 36 | def __init__(self, number): | 36 | def __init__(self, number): | ||
| 37 | number %= NUMBER_OF_INTERVALS | 37 | number %= NUMBER_OF_INTERVALS | ||
| 38 | self.interval_number = number | 38 | self.interval_number = number | ||
| 39 | self.interval_name = ALL_VALID_INTERVALS[number] | 39 | self.interval_name = ALL_VALID_INTERVALS[number] | ||
| 40 | 40 | ||||
| 41 | def __str__(self): | 41 | def __str__(self): | ||
| 42 | return self.interval_name | 42 | return self.interval_name | ||
| 43 | 43 | ||||
| 44 | def __add__(self, other): | 44 | def __add__(self, other): | ||
| 45 | if isinstance(other, Tone): | 45 | if isinstance(other, Tone): | ||
| 46 | raise TypeError("Invalid operation") | 46 | raise TypeError("Invalid operation") | ||
| 47 | elif isinstance(other, Interval): | 47 | elif isinstance(other, Interval): | ||
| 48 | return Interval(self.interval_number + other.interval_number) | 48 | return Interval(self.interval_number + other.interval_number) | ||
| 49 | 49 | ||||
| 50 | def __sub__(self, other): | 50 | def __sub__(self, other): | ||
| 51 | if isinstance(other, Tone): | 51 | if isinstance(other, Tone): | ||
| 52 | raise TypeError("Invalid operation") | 52 | raise TypeError("Invalid operation") | ||
| 53 | 53 | ||||
| 54 | def __neg__(self): | 54 | def __neg__(self): | ||
| 55 | return Interval(-self.interval_number) | 55 | return Interval(-self.interval_number) | ||
| 56 | 56 | ||||
| 57 | 57 | ||||
| 58 | class Chord: | 58 | class Chord: | ||
| 59 | def __init__(self, root, *args): | 59 | def __init__(self, root, *args): | ||
| 60 | self.unique_tone_names = {root.name} | 60 | self.unique_tone_names = {root.name} | ||
| 61 | self.tones = [root] | 61 | self.tones = [root] | ||
| 62 | self.root = root | 62 | self.root = root | ||
| 63 | for tone in args: | 63 | for tone in args: | ||
| 64 | if tone.name not in self.unique_tone_names: | 64 | if tone.name not in self.unique_tone_names: | ||
| 65 | self.tones.append(tone) | 65 | self.tones.append(tone) | ||
| 66 | self.unique_tone_names.add(tone.name) | 66 | self.unique_tone_names.add(tone.name) | ||
| 67 | if len(self.tones) == 1: | 67 | if len(self.tones) == 1: | ||
| 68 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 68 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| 69 | root_num = ALL_VALID_TONES.index(str(root)) | 69 | root_num = ALL_VALID_TONES.index(str(root)) | ||
| 70 | self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12) | 70 | self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12) | ||
| 71 | 71 | ||||
| 72 | def __str__(self): | 72 | def __str__(self): | ||
| 73 | return "-".join(str(tone) for tone in self.sorted_tones) | 73 | return "-".join(str(tone) for tone in self.sorted_tones) | ||
| 74 | 74 | ||||
| 75 | def is_minor(self): | 75 | def is_minor(self): | ||
| 76 | for tone in self.sorted_tones: | 76 | for tone in self.sorted_tones: | ||
| n | 77 | difference = abs(ALL_VALID_TONES.index((str(self.root))) - ALL_VALID_TONES.index((str(tone)))) | n | 77 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) |
| 78 | if difference < 0: | ||||
| 79 | difference += NUMBER_OF_INTERVALS | ||||
| 78 | if difference == NUMBER_FOR_MINOR_3RD: | 80 | if difference == NUMBER_FOR_MINOR_3RD: | ||
| 79 | return "True" | 81 | return "True" | ||
| 80 | return "False" | 82 | return "False" | ||
| 81 | 83 | ||||
| 82 | def is_major(self): | 84 | def is_major(self): | ||
| 83 | for tone in self.sorted_tones: | 85 | for tone in self.sorted_tones: | ||
| t | 84 | difference = abs(ALL_VALID_TONES.index((str(self.root))) - ALL_VALID_TONES.index((str(tone)))) | t | 86 | difference = ALL_VALID_TONES.index((str(tone))) - ALL_VALID_TONES.index((str(self.root))) |
| 87 | if difference < 0: | ||||
| 88 | difference += NUMBER_OF_INTERVALS | ||||
| 85 | if difference == NUMBER_FOR_MAJOR_3RD: | 89 | if difference == NUMBER_FOR_MAJOR_3RD: | ||
| 86 | return "True" | 90 | return "True" | ||
| 87 | return "False" | 91 | return "False" | ||
| 88 | 92 | ||||
| 89 | def is_power_chord(self): | 93 | def is_power_chord(self): | ||
| 90 | if self.is_minor() == "True" or self.is_major() == "True": | 94 | if self.is_minor() == "True" or self.is_major() == "True": | ||
| 91 | return "False" | 95 | return "False" | ||
| 92 | return "True" | 96 | return "True" | ||
| 93 | 97 | ||||
| 94 | def __add__(self, other): | 98 | def __add__(self, other): | ||
| 95 | if isinstance(other, Tone): | 99 | if isinstance(other, Tone): | ||
| 96 | return Chord(*self.tones, other) | 100 | return Chord(*self.tones, other) | ||
| 97 | if isinstance(other, Chord): | 101 | if isinstance(other, Chord): | ||
| 98 | tones_for_new_chord = self.sorted_tones | 102 | tones_for_new_chord = self.sorted_tones | ||
| 99 | for tone in other.sorted_tones: | 103 | for tone in other.sorted_tones: | ||
| 100 | if not tone in tones_for_new_chord: | 104 | if not tone in tones_for_new_chord: | ||
| 101 | tones_for_new_chord.append(tone) | 105 | tones_for_new_chord.append(tone) | ||
| 102 | return Chord(*tones_for_new_chord) | 106 | return Chord(*tones_for_new_chord) | ||
| 103 | 107 | ||||
| 104 | def __sub__(self, other): | 108 | def __sub__(self, other): | ||
| 105 | if isinstance(other, Tone): | 109 | if isinstance(other, Tone): | ||
| 106 | if other.name not in self.unique_tone_names: | 110 | if other.name not in self.unique_tone_names: | ||
| 107 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | 111 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | ||
| 108 | elif len(self.sorted_tones) - 1 == 1: | 112 | elif len(self.sorted_tones) - 1 == 1: | ||
| 109 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 113 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| 110 | else: | 114 | else: | ||
| 111 | tones_for_new_chord = list() | 115 | tones_for_new_chord = list() | ||
| 112 | for tone in self.sorted_tones: | 116 | for tone in self.sorted_tones: | ||
| 113 | if not tone.name == other.name: | 117 | if not tone.name == other.name: | ||
| 114 | tones_for_new_chord.append(tone) | 118 | tones_for_new_chord.append(tone) | ||
| 115 | return Chord(*tones_for_new_chord) | 119 | return Chord(*tones_for_new_chord) | ||
| 116 | 120 | ||||
| 117 | def transposed(self, interval): | 121 | def transposed(self, interval): | ||
| 118 | tones_in_new_chord = list() | 122 | tones_in_new_chord = list() | ||
| 119 | if interval.interval_number >= 0: | 123 | if interval.interval_number >= 0: | ||
| 120 | for tone in self.sorted_tones: | 124 | for tone in self.sorted_tones: | ||
| 121 | tones_in_new_chord.append(tone + interval) | 125 | tones_in_new_chord.append(tone + interval) | ||
| 122 | return Chord(*tones_in_new_chord) | 126 | return Chord(*tones_in_new_chord) | ||
| 123 | else: | 127 | else: | ||
| 124 | for tone in self.sorted_tones: | 128 | for tone in self.sorted_tones: | ||
| 125 | tones_in_new_chord.append(tone - interval) | 129 | tones_in_new_chord.append(tone - interval) | ||
| 126 | return Chord(*tones_in_new_chord) | 130 | return Chord(*tones_in_new_chord) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| n | 1 | all_valid_tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") | n | 1 | ALL_VALID_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") |
| 2 | all_valid_intervals = {0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd", 4: "major 3rd", 5: "perfect 4th", | 2 | ALL_VALID_INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
| 3 | 6: "diminished 5th", 7: "perfect 5th", 8: "minor 6th", 9: "major 6th", 10: "minor 7th", 11: "major 7th"} | 3 | NUMBER_OF_INTERVALS = 12 | ||
| 4 | number_of_intervals = 12 | 4 | NUMBER_FOR_MINOR_3RD = 3 | ||
| 5 | number_for_minor_3rd = 3 | 5 | NUMBER_FOR_MAJOR_3RD = 4 | ||
| 6 | number_for_major_3rd = 4 | ||||
| 7 | 6 | ||||
| 8 | class Tone: | 7 | class Tone: | ||
| 9 | def __init__(self, tone): | 8 | def __init__(self, tone): | ||
| n | 10 | if tone in all_valid_tones: | n | 9 | if tone in ALL_VALID_TONES: |
| 11 | self.name = tone | 10 | self.name = tone | ||
| n | 12 | self.index = all_valid_tones.index(tone) | n | 11 | self.index = ALL_VALID_TONES.index(tone) |
| 13 | else: | 12 | else: | ||
| 14 | raise Exception("Invalid input.") | 13 | raise Exception("Invalid input.") | ||
| 15 | 14 | ||||
| 16 | def __str__(self): | 15 | def __str__(self): | ||
| n | 17 | return self.name | n | ||
| 18 | |||||
| 19 | def __getitem__(self, item): | ||||
| 20 | return self.name | 16 | return self.name | ||
| 21 | 17 | ||||
| 22 | def __add__(self, other): | 18 | def __add__(self, other): | ||
| 23 | if isinstance(other, Tone): | 19 | if isinstance(other, Tone): | ||
| 24 | return Chord(self, other) | 20 | return Chord(self, other) | ||
| 25 | elif isinstance(other, Interval): | 21 | elif isinstance(other, Interval): | ||
| 26 | index_of_new_tone = (self.index + other.interval_number) % 12 | 22 | index_of_new_tone = (self.index + other.interval_number) % 12 | ||
| n | 27 | return Tone(all_valid_tones[index_of_new_tone]) | n | 23 | return Tone(ALL_VALID_TONES[index_of_new_tone]) |
| 28 | 24 | ||||
| 29 | def __sub__(self, other): | 25 | def __sub__(self, other): | ||
| 30 | if isinstance(other, Tone): | 26 | if isinstance(other, Tone): | ||
| 31 | index_of_first_tone = self.index | 27 | index_of_first_tone = self.index | ||
| 32 | index_of_second_tone = other.index | 28 | index_of_second_tone = other.index | ||
| 33 | return Interval(index_of_first_tone - index_of_second_tone) | 29 | return Interval(index_of_first_tone - index_of_second_tone) | ||
| 34 | elif isinstance(other, Interval): | 30 | elif isinstance(other, Interval): | ||
| 35 | index_of_new_tone = self.index - other.interval_number | 31 | index_of_new_tone = self.index - other.interval_number | ||
| n | 36 | return Tone(all_valid_tones[index_of_new_tone]) | n | 32 | return Tone(ALL_VALID_TONES[index_of_new_tone]) |
| 37 | 33 | ||||
| 38 | 34 | ||||
| 39 | class Interval: | 35 | class Interval: | ||
| 40 | def __init__(self, number): | 36 | def __init__(self, number): | ||
| n | 41 | number %= number_of_intervals | n | 37 | number %= NUMBER_OF_INTERVALS |
| 42 | self.interval_number = number | 38 | self.interval_number = number | ||
| n | 43 | self.interval_name = all_valid_intervals[number] | n | 39 | self.interval_name = ALL_VALID_INTERVALS[number] |
| 44 | 40 | ||||
| 45 | def __str__(self): | 41 | def __str__(self): | ||
| 46 | return self.interval_name | 42 | return self.interval_name | ||
| 47 | 43 | ||||
| 48 | def __add__(self, other): | 44 | def __add__(self, other): | ||
| 49 | if isinstance(other, Tone): | 45 | if isinstance(other, Tone): | ||
| 50 | raise TypeError("Invalid operation") | 46 | raise TypeError("Invalid operation") | ||
| 51 | elif isinstance(other, Interval): | 47 | elif isinstance(other, Interval): | ||
| 52 | return Interval(self.interval_number + other.interval_number) | 48 | return Interval(self.interval_number + other.interval_number) | ||
| 53 | 49 | ||||
| 54 | def __sub__(self, other): | 50 | def __sub__(self, other): | ||
| 55 | if isinstance(other, Tone): | 51 | if isinstance(other, Tone): | ||
| 56 | raise TypeError("Invalid operation") | 52 | raise TypeError("Invalid operation") | ||
| 57 | 53 | ||||
| 58 | def __neg__(self): | 54 | def __neg__(self): | ||
| 59 | return Interval(-self.interval_number) | 55 | return Interval(-self.interval_number) | ||
| 60 | 56 | ||||
| 61 | 57 | ||||
| 62 | class Chord: | 58 | class Chord: | ||
| 63 | def __init__(self, root, *args): | 59 | def __init__(self, root, *args): | ||
| n | 64 | self.unique_tone_names = set() | n | ||
| 65 | self.tones = list() | ||||
| 66 | self.unique_tone_names.add(root.name) | 60 | self.unique_tone_names = {root.name} | ||
| 67 | self.tones.append(root) | 61 | self.tones = [root] | ||
| 68 | self.root = root | 62 | self.root = root | ||
| 69 | for tone in args: | 63 | for tone in args: | ||
| 70 | if tone.name not in self.unique_tone_names: | 64 | if tone.name not in self.unique_tone_names: | ||
| 71 | self.tones.append(tone) | 65 | self.tones.append(tone) | ||
| 72 | self.unique_tone_names.add(tone.name) | 66 | self.unique_tone_names.add(tone.name) | ||
| 73 | if len(self.tones) == 1: | 67 | if len(self.tones) == 1: | ||
| 74 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 68 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| n | 75 | root_num = all_valid_tones.index(str(root)) | n | 69 | root_num = ALL_VALID_TONES.index(str(root)) |
| 76 | self.sorted_tones = sorted(self.tones, key= lambda tone: (all_valid_tones.index(str(tone)) - root_num) % 12) | 70 | self.sorted_tones = sorted(self.tones, key= lambda tone: (ALL_VALID_TONES.index(str(tone)) - root_num) % 12) | ||
| 77 | 71 | ||||
| 78 | def __str__(self): | 72 | def __str__(self): | ||
| 79 | return "-".join(str(tone) for tone in self.sorted_tones) | 73 | return "-".join(str(tone) for tone in self.sorted_tones) | ||
| 80 | 74 | ||||
| 81 | def is_minor(self): | 75 | def is_minor(self): | ||
| 82 | for tone in self.sorted_tones: | 76 | for tone in self.sorted_tones: | ||
| n | 83 | difference = abs(all_valid_tones.index((str(self.root))) - all_valid_tones.index((str(tone)))) | n | 77 | difference = abs(ALL_VALID_TONES.index((str(self.root))) - ALL_VALID_TONES.index((str(tone)))) |
| 84 | if difference == number_for_minor_3rd or 12 - difference == number_for_minor_3rd: | 78 | if difference == NUMBER_FOR_MINOR_3RD: | ||
| 85 | return "True" | 79 | return "True" | ||
| 86 | return "False" | 80 | return "False" | ||
| 87 | 81 | ||||
| 88 | def is_major(self): | 82 | def is_major(self): | ||
| 89 | for tone in self.sorted_tones: | 83 | for tone in self.sorted_tones: | ||
| t | 90 | difference = abs(all_valid_tones.index((str(self.root))) - all_valid_tones.index((str(tone)))) | t | 84 | difference = abs(ALL_VALID_TONES.index((str(self.root))) - ALL_VALID_TONES.index((str(tone)))) |
| 91 | if difference== number_for_major_3rd or 12 - difference == number_for_major_3rd : | 85 | if difference == NUMBER_FOR_MAJOR_3RD: | ||
| 92 | return "True" | 86 | return "True" | ||
| 93 | return "False" | 87 | return "False" | ||
| 94 | 88 | ||||
| 95 | def is_power_chord(self): | 89 | def is_power_chord(self): | ||
| 96 | if self.is_minor() == "True" or self.is_major() == "True": | 90 | if self.is_minor() == "True" or self.is_major() == "True": | ||
| 97 | return "False" | 91 | return "False" | ||
| 98 | return "True" | 92 | return "True" | ||
| 99 | 93 | ||||
| 100 | def __add__(self, other): | 94 | def __add__(self, other): | ||
| 101 | if isinstance(other, Tone): | 95 | if isinstance(other, Tone): | ||
| 102 | return Chord(*self.tones, other) | 96 | return Chord(*self.tones, other) | ||
| 103 | if isinstance(other, Chord): | 97 | if isinstance(other, Chord): | ||
| 104 | tones_for_new_chord = self.sorted_tones | 98 | tones_for_new_chord = self.sorted_tones | ||
| 105 | for tone in other.sorted_tones: | 99 | for tone in other.sorted_tones: | ||
| 106 | if not tone in tones_for_new_chord: | 100 | if not tone in tones_for_new_chord: | ||
| 107 | tones_for_new_chord.append(tone) | 101 | tones_for_new_chord.append(tone) | ||
| 108 | return Chord(*tones_for_new_chord) | 102 | return Chord(*tones_for_new_chord) | ||
| 109 | 103 | ||||
| 110 | def __sub__(self, other): | 104 | def __sub__(self, other): | ||
| 111 | if isinstance(other, Tone): | 105 | if isinstance(other, Tone): | ||
| 112 | if other.name not in self.unique_tone_names: | 106 | if other.name not in self.unique_tone_names: | ||
| 113 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | 107 | raise TypeError(f"Cannot remove tone {other.name} from chord {str(self)}") | ||
| 114 | elif len(self.sorted_tones) - 1 == 1: | 108 | elif len(self.sorted_tones) - 1 == 1: | ||
| 115 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 109 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
| 116 | else: | 110 | else: | ||
| 117 | tones_for_new_chord = list() | 111 | tones_for_new_chord = list() | ||
| 118 | for tone in self.sorted_tones: | 112 | for tone in self.sorted_tones: | ||
| 119 | if not tone.name == other.name: | 113 | if not tone.name == other.name: | ||
| 120 | tones_for_new_chord.append(tone) | 114 | tones_for_new_chord.append(tone) | ||
| 121 | return Chord(*tones_for_new_chord) | 115 | return Chord(*tones_for_new_chord) | ||
| 122 | 116 | ||||
| 123 | def transposed(self, interval): | 117 | def transposed(self, interval): | ||
| 124 | tones_in_new_chord = list() | 118 | tones_in_new_chord = list() | ||
| 125 | if interval.interval_number >= 0: | 119 | if interval.interval_number >= 0: | ||
| 126 | for tone in self.sorted_tones: | 120 | for tone in self.sorted_tones: | ||
| 127 | tones_in_new_chord.append(tone + interval) | 121 | tones_in_new_chord.append(tone + interval) | ||
| 128 | return Chord(*tones_in_new_chord) | 122 | return Chord(*tones_in_new_chord) | ||
| 129 | else: | 123 | else: | ||
| 130 | for tone in self.sorted_tones: | 124 | for tone in self.sorted_tones: | ||
| 131 | tones_in_new_chord.append(tone - interval) | 125 | tones_in_new_chord.append(tone - interval) | ||
| 132 | return Chord(*tones_in_new_chord) | 126 | return Chord(*tones_in_new_chord) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||