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 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|