1TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11}
2TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
3INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"]
4MAX_INDEX = 12
5
6class Tone:
7 def __init__(self, name):
8 self.name = 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 if isinstance(other, Interval):
17 total_len = other.lenght + self.index
18 correct_index = int(total_len / MAX_INDEX)
19 correct_len = total_len - correct_index*MAX_INDEX
20 return Tone(TONE_VALUE_LIST[correct_len])
21
22 def __sub__(self, other):
23 if isinstance(other, Tone):
24 len = self.index - other.index
25 if self.index < other.index:
26 len = self.index + MAX_INDEX - other.index
27 return Interval(len)
28 if isinstance(other, Interval):
29 wanted_index = self.index - other.lenght
30 if self.index < other.lenght:
31 wanted_index = self.index - other.lenght + MAX_INDEX
32 return TONE_VALUE_LIST[wanted_index]
33
34 @property
35 def index(self):
36 return TONE_INDEX_DICT[self.name]
37
38class Interval:
39 def __init__(self, lenght):
40 correct_index = int(lenght / MAX_INDEX)
41 self.lenght = lenght - correct_index*MAX_INDEX
42
43 def __str__(self):
44 return INTERVAL_VALUE_LIST[self.lenght]
45
46 def __add__(self,other):
47 if isinstance(other,Tone):
48 raise TypeError("Invalid operation")
49 if isinstance(other,Interval):
50 total_len = self.lenght + other.lenght
51 correct_index = int(total_len / MAX_INDEX)
52 correct_len = total_len - correct_index*MAX_INDEX
53 return INTERVAL_VALUE_LIST[correct_len]
54
55 def __sub__(self,other):
56 if isinstance(other,Tone):
57 raise TypeError("Invalid operation")
58
59 def __neg__(self):
60 return Interval(MAX_INDEX - self.lenght)
61
62class Chord:
63 def __init_sorted_tones(self):
64 main_index = self.main_tone.index
65 tones_dict = {self.main_tone.name : main_index}
66 self.all_tones_list_objs = [self.main_tone]
67 for tone_name in self.unique_tones:
68 tone_index = Tone(tone_name).index
69 self.without_main_tones_list_objs.append(Tone(tone_name))
70 self.all_tones_list_objs.append(Tone(tone_name))
71 if main_index > tone_index:
72 tones_dict[tone_name] = tone_index + MAX_INDEX
73 else:
74 tones_dict[tone_name] = tone_index
75 self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])]
76
77 def __init__(self, main_tone, *tones):
78 self.main_tone = main_tone
79 self.unique_tones= set()
80 self.sorted_tones = []
81 self.all_tones_list_objs = []
82 self.without_main_tones_list_objs = []
83 self.unique_tones.add(main_tone.name)
84 for tone in tones:
85 self.unique_tones.add(tone.name)
86 valid_len = len(self.unique_tones)
87 if valid_len <= 1:
88 raise TypeError("Cannot have a chord made of only 1 unique tone")
89 self.unique_tones.discard(main_tone.name)
90 self.__init_sorted_tones()
91
92 def __add__(self, other):
93 new_tones = self.without_main_tones_list_objs
94 if isinstance(other, Tone):
95 new_tones.append(other)
96 if isinstance(other,Chord):
97 for tone in other.all_tones_list_objs:
98 new_tones.append(tone)
99 return Chord(self.main_tone, *new_tones)
100
101 def __sub__(self, other):
102 if other.name not in self.sorted_tones:
103 raise TypeError(f"Cannot remove tone {other.name} from chord {self}")
104 if len(self.unique_tones) < 2:
105 raise TypeError("Cannot have a chord made of only 1 unique tone")
106 new_tones = self.without_main_tones_list_objs
107 main_tone = self.main_tone
108 if isinstance(other, Tone):
109 if main_tone.name == other.name:
110 main_tone = self.without_main_tones_list_objs[0]
111 new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones)
112 else:
113 new_tones = filter(lambda tone: tone.name != other.name, new_tones)
114 return Chord(main_tone, *new_tones)
115
116 def __str__(self):
117 return "-".join(self.sorted_tones)
118
119 def is_minor(self):
120 for tone in self.without_main_tones_list_objs:
121 interval = tone - self.main_tone
122 if str(interval) == "minor 3rd":
123 return True
124 return False
125
126 def is_major(self):
127 for tone in self.without_main_tones_list_objs:
128 interval = tone - self.main_tone
129 if str(interval) == "major 3rd":
130 return True
131 return False
132
133 def is_power_chord(self):
134 return not self.is_major() and not self.is_minor()
135
136 def transposed(self, interval):
137 transposed_tones = [tone + interval for tone in self.all_tones_list_objs]
138 return Chord(transposed_tones[0], *transposed_tones[1:])
........................FFF.FF.......
======================================================================
FAIL: test_interval_addition (test.TestOperations.test_interval_addition)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 240, in test_interval_addition
self.assertIsInstance(major_3rd, Interval)
AssertionError: 'major 3rd' is not an instance of <class 'solution.Interval'>
======================================================================
FAIL: test_interval_addition_overflow (test.TestOperations.test_interval_addition_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 246, in test_interval_addition_overflow
self.assertIsInstance(unison, Interval)
AssertionError: 'unison' is not an instance of <class 'solution.Interval'>
======================================================================
FAIL: test_subtract_interval_from_tone (test.TestOperations.test_subtract_interval_from_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 216, in test_subtract_interval_from_tone
self.assertIsInstance(f_sharp, Tone)
AssertionError: 'F#' is not an instance of <class 'solution.Tone'>
======================================================================
FAIL: test_subtract_interval_from_tone_oveflow (test.TestOperations.test_subtract_interval_from_tone_oveflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 228, in test_subtract_interval_from_tone_oveflow
self.assertIsInstance(g, Tone)
AssertionError: 'G' is not an instance of <class 'solution.Tone'>
======================================================================
FAIL: test_subtract_interval_from_tone_same_tone (test.TestOperations.test_subtract_interval_from_tone_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 222, in test_subtract_interval_from_tone_same_tone
self.assertIsInstance(still_g, Tone)
AssertionError: 'G' is not an instance of <class 'solution.Tone'>
----------------------------------------------------------------------
Ran 37 tests in 0.002s
FAILED (failures=5)
Виктор Бечев
06.11.2024 13:34Търсим интервалът между двата, релативен спрямо основния тон. Как ще го имплементираш зависи от теб, но `tone - main_tone` ми звучи правилно.
|
Дейвид Барух
05.11.2024 22:28Един последен дразнещ въпрос, при мажорите вадим от тона roota нали, за да намерим разстоянитето между тях . Демек (tone - main_tone)
|
Дейвид Барух
05.11.2024 16:08Да разбрах на обратно от мойте разбирания е. Разстоянието примерно А-С е разстоянието между С и А
|
Виктор Бечев
05.11.2024 15:24Добре, разбирам от къде идва объркването.
Все пак - спазвай примера от по-долу, където съм ти дал за `A-C` и `C-A`. Приеми го за аксиома, ако го смяташ за неинтуитивно.
|
Дейвид Барух
05.11.2024 11:06Не сър на примера не е C -G 😂😂 a e G -C демек от G до C e g#,a,a#,b,c, поне аз схващам че G-C e разстоянието от G до C освен ако не визирате обратното
|
Виктор Бечев
05.11.2024 10:32![](https://py-fmi.org/media/resources/chromatic-scale_edited.png)
- 0 - unison
- 1 - minor 2nd
- 2 - major 2nd
- 3 - minor 3rd
- 4 - major 3rd
- 5 - perfect 4th
- 6 - diminished 5th
- **7 - perfect 5th**
- 8 - minor 6th
- 9 - major 6th
- 10 - minor 7th
- 11 - major 7th
|
Дейвид Барух
05.11.2024 00:06е то на примера е G-C сър, c, g = Tone("C"), Tone("G"); interval = g - c, трябва да е perfect 4th
|
Виктор Бечев
04.11.2024 23:00Полутоновете между G и C са 5. Между C и G са 7.
Ако си представиш, че всеки тон си има индекс, ако C е с индекс 0, то G би било с индекс 7. `g - c` -> 7. 7 полутона разстояние е `"perfect 5th"`.
|
Дейвид Барух
04.11.2024 18:14тук не е ли perfect 4th защото полутоновете между C и G са 5 : c, g = Tone("C"), Tone("G")
result_interval = g - c # result_interval е обект от тип Interval
print(result_interval) "perfect 5th"
|
Виктор Бечев
04.11.2024 18:11Да. Но с посока, а не абсолютна стойност.
Затова между A и C имаме 3 полутона, а между C и A - 9.
Ако говорим за операция изваждане - `A-C=9`, `C-A=3`.
|
Дейвид Барух
04.11.2024 17:12Извинявай, но се обърках малко. Разстоянието(боря полутонове) между два тона е разликата им нали?
|
Виктор Бечев
04.11.2024 16:14Имаме цикличност, но имаме и релативност спрямо основния тон. Разстоянието между A и C е 3 полутона _(A#, B, C)_, но между C и А _(в случай, когато root е C)_ - 9 полутона.
С други думи за F#-D-E имаме 8 полутона между F# и D.
|
Дейвид Барух
04.11.2024 15:45демек така както го правя сега е грешно?
|
Дейвид Барух
04.11.2024 15:43и за разлика на тонове приерно А-C ще се даде 2 не 9 , защото си поддържаме цикличност?
|
Дейвид Барух
04.11.2024 15:38за ismajor и isminor ако имаме нещо от сорта F#-D-E , то тогава за разстоянието между F# и D примерно приемаме че имаме 4 или 9 демек да се продължваме по цикъла един вид ?
|
Виктор Бечев
03.11.2024 21:19Да, интервалите са циклични.
|
Дейвид Барух
03.11.2024 14:21За интервалите имали също цикличност примерно за последния пример да дадем : d_minor_chord = c_minor_chord.transposed(Interval(20)) то да се приеме като Interval(8)?
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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 | if isinstance(other, Interval): | 16 | if isinstance(other, Interval): | ||
17 | total_len = other.lenght + self.index | 17 | total_len = other.lenght + self.index | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other, Tone): | 23 | if isinstance(other, Tone): | ||
n | 24 | # len = other.index - self.index | n | ||
25 | # if self.index > other.index: | ||||
26 | # len = other.index + MAX_INDEX - self.index | ||||
27 | # return Interval(len) | ||||
28 | len = self.index - other.index | 24 | len = self.index - other.index | ||
29 | if self.index < other.index: | 25 | if self.index < other.index: | ||
30 | len = self.index + MAX_INDEX - other.index | 26 | len = self.index + MAX_INDEX - other.index | ||
31 | return Interval(len) | 27 | return Interval(len) | ||
32 | if isinstance(other, Interval): | 28 | if isinstance(other, Interval): | ||
33 | wanted_index = self.index - other.lenght | 29 | wanted_index = self.index - other.lenght | ||
34 | if self.index < other.lenght: | 30 | if self.index < other.lenght: | ||
35 | wanted_index = self.index - other.lenght + MAX_INDEX | 31 | wanted_index = self.index - other.lenght + MAX_INDEX | ||
36 | return TONE_VALUE_LIST[wanted_index] | 32 | return TONE_VALUE_LIST[wanted_index] | ||
37 | 33 | ||||
38 | @property | 34 | @property | ||
39 | def index(self): | 35 | def index(self): | ||
40 | return TONE_INDEX_DICT[self.name] | 36 | return TONE_INDEX_DICT[self.name] | ||
41 | 37 | ||||
42 | class Interval: | 38 | class Interval: | ||
43 | def __init__(self, lenght): | 39 | def __init__(self, lenght): | ||
44 | correct_index = int(lenght / MAX_INDEX) | 40 | correct_index = int(lenght / MAX_INDEX) | ||
45 | self.lenght = lenght - correct_index*MAX_INDEX | 41 | self.lenght = lenght - correct_index*MAX_INDEX | ||
46 | 42 | ||||
47 | def __str__(self): | 43 | def __str__(self): | ||
t | 48 | print(f"len is {self.lenght}") | t | ||
49 | return INTERVAL_VALUE_LIST[self.lenght] | 44 | return INTERVAL_VALUE_LIST[self.lenght] | ||
50 | 45 | ||||
51 | def __add__(self,other): | 46 | def __add__(self,other): | ||
52 | if isinstance(other,Tone): | 47 | if isinstance(other,Tone): | ||
53 | raise TypeError("Invalid operation") | 48 | raise TypeError("Invalid operation") | ||
54 | if isinstance(other,Interval): | 49 | if isinstance(other,Interval): | ||
55 | total_len = self.lenght + other.lenght | 50 | total_len = self.lenght + other.lenght | ||
56 | correct_index = int(total_len / MAX_INDEX) | 51 | correct_index = int(total_len / MAX_INDEX) | ||
57 | correct_len = total_len - correct_index*MAX_INDEX | 52 | correct_len = total_len - correct_index*MAX_INDEX | ||
58 | return INTERVAL_VALUE_LIST[correct_len] | 53 | return INTERVAL_VALUE_LIST[correct_len] | ||
59 | 54 | ||||
60 | def __sub__(self,other): | 55 | def __sub__(self,other): | ||
61 | if isinstance(other,Tone): | 56 | if isinstance(other,Tone): | ||
62 | raise TypeError("Invalid operation") | 57 | raise TypeError("Invalid operation") | ||
63 | 58 | ||||
64 | def __neg__(self): | 59 | def __neg__(self): | ||
65 | return Interval(MAX_INDEX - self.lenght) | 60 | return Interval(MAX_INDEX - self.lenght) | ||
66 | 61 | ||||
67 | class Chord: | 62 | class Chord: | ||
68 | def __init_sorted_tones(self): | 63 | def __init_sorted_tones(self): | ||
69 | main_index = self.main_tone.index | 64 | main_index = self.main_tone.index | ||
70 | tones_dict = {self.main_tone.name : main_index} | 65 | tones_dict = {self.main_tone.name : main_index} | ||
71 | self.all_tones_list_objs = [self.main_tone] | 66 | self.all_tones_list_objs = [self.main_tone] | ||
72 | for tone_name in self.unique_tones: | 67 | for tone_name in self.unique_tones: | ||
73 | tone_index = Tone(tone_name).index | 68 | tone_index = Tone(tone_name).index | ||
74 | self.without_main_tones_list_objs.append(Tone(tone_name)) | 69 | self.without_main_tones_list_objs.append(Tone(tone_name)) | ||
75 | self.all_tones_list_objs.append(Tone(tone_name)) | 70 | self.all_tones_list_objs.append(Tone(tone_name)) | ||
76 | if main_index > tone_index: | 71 | if main_index > tone_index: | ||
77 | tones_dict[tone_name] = tone_index + MAX_INDEX | 72 | tones_dict[tone_name] = tone_index + MAX_INDEX | ||
78 | else: | 73 | else: | ||
79 | tones_dict[tone_name] = tone_index | 74 | tones_dict[tone_name] = tone_index | ||
80 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 75 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
81 | 76 | ||||
82 | def __init__(self, main_tone, *tones): | 77 | def __init__(self, main_tone, *tones): | ||
83 | self.main_tone = main_tone | 78 | self.main_tone = main_tone | ||
84 | self.unique_tones= set() | 79 | self.unique_tones= set() | ||
85 | self.sorted_tones = [] | 80 | self.sorted_tones = [] | ||
86 | self.all_tones_list_objs = [] | 81 | self.all_tones_list_objs = [] | ||
87 | self.without_main_tones_list_objs = [] | 82 | self.without_main_tones_list_objs = [] | ||
88 | self.unique_tones.add(main_tone.name) | 83 | self.unique_tones.add(main_tone.name) | ||
89 | for tone in tones: | 84 | for tone in tones: | ||
90 | self.unique_tones.add(tone.name) | 85 | self.unique_tones.add(tone.name) | ||
91 | valid_len = len(self.unique_tones) | 86 | valid_len = len(self.unique_tones) | ||
92 | if valid_len <= 1: | 87 | if valid_len <= 1: | ||
93 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 88 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
94 | self.unique_tones.discard(main_tone.name) | 89 | self.unique_tones.discard(main_tone.name) | ||
95 | self.__init_sorted_tones() | 90 | self.__init_sorted_tones() | ||
96 | 91 | ||||
97 | def __add__(self, other): | 92 | def __add__(self, other): | ||
98 | new_tones = self.without_main_tones_list_objs | 93 | new_tones = self.without_main_tones_list_objs | ||
99 | if isinstance(other, Tone): | 94 | if isinstance(other, Tone): | ||
100 | new_tones.append(other) | 95 | new_tones.append(other) | ||
101 | if isinstance(other,Chord): | 96 | if isinstance(other,Chord): | ||
102 | for tone in other.all_tones_list_objs: | 97 | for tone in other.all_tones_list_objs: | ||
103 | new_tones.append(tone) | 98 | new_tones.append(tone) | ||
104 | return Chord(self.main_tone, *new_tones) | 99 | return Chord(self.main_tone, *new_tones) | ||
105 | 100 | ||||
106 | def __sub__(self, other): | 101 | def __sub__(self, other): | ||
107 | if other.name not in self.sorted_tones: | 102 | if other.name not in self.sorted_tones: | ||
108 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 103 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
109 | if len(self.unique_tones) < 2: | 104 | if len(self.unique_tones) < 2: | ||
110 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 105 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
111 | new_tones = self.without_main_tones_list_objs | 106 | new_tones = self.without_main_tones_list_objs | ||
112 | main_tone = self.main_tone | 107 | main_tone = self.main_tone | ||
113 | if isinstance(other, Tone): | 108 | if isinstance(other, Tone): | ||
114 | if main_tone.name == other.name: | 109 | if main_tone.name == other.name: | ||
115 | main_tone = self.without_main_tones_list_objs[0] | 110 | main_tone = self.without_main_tones_list_objs[0] | ||
116 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 111 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
117 | else: | 112 | else: | ||
118 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 113 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
119 | return Chord(main_tone, *new_tones) | 114 | return Chord(main_tone, *new_tones) | ||
120 | 115 | ||||
121 | def __str__(self): | 116 | def __str__(self): | ||
122 | return "-".join(self.sorted_tones) | 117 | return "-".join(self.sorted_tones) | ||
123 | 118 | ||||
124 | def is_minor(self): | 119 | def is_minor(self): | ||
125 | for tone in self.without_main_tones_list_objs: | 120 | for tone in self.without_main_tones_list_objs: | ||
126 | interval = tone - self.main_tone | 121 | interval = tone - self.main_tone | ||
127 | if str(interval) == "minor 3rd": | 122 | if str(interval) == "minor 3rd": | ||
128 | return True | 123 | return True | ||
129 | return False | 124 | return False | ||
130 | 125 | ||||
131 | def is_major(self): | 126 | def is_major(self): | ||
132 | for tone in self.without_main_tones_list_objs: | 127 | for tone in self.without_main_tones_list_objs: | ||
133 | interval = tone - self.main_tone | 128 | interval = tone - self.main_tone | ||
134 | if str(interval) == "major 3rd": | 129 | if str(interval) == "major 3rd": | ||
135 | return True | 130 | return True | ||
136 | return False | 131 | return False | ||
137 | 132 | ||||
138 | def is_power_chord(self): | 133 | def is_power_chord(self): | ||
139 | return not self.is_major() and not self.is_minor() | 134 | return not self.is_major() and not self.is_minor() | ||
140 | 135 | ||||
141 | def transposed(self, interval): | 136 | def transposed(self, interval): | ||
142 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | 137 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | ||
143 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 138 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
144 | 139 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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 | if isinstance(other, Interval): | 16 | if isinstance(other, Interval): | ||
17 | total_len = other.lenght + self.index | 17 | total_len = other.lenght + self.index | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other, Tone): | 23 | if isinstance(other, Tone): | ||
n | 24 | len = other.index - self.index | n | 24 | # len = other.index - self.index |
25 | if self.index > other.index: | 25 | # if self.index > other.index: | ||
26 | print("here") | ||||
27 | len = other.index + MAX_INDEX - self.index | 26 | # len = other.index + MAX_INDEX - self.index | ||
27 | # return Interval(len) | ||||
28 | len = self.index - other.index | ||||
29 | if self.index < other.index: | ||||
30 | len = self.index + MAX_INDEX - other.index | ||||
28 | return Interval(len) | 31 | return Interval(len) | ||
29 | if isinstance(other, Interval): | 32 | if isinstance(other, Interval): | ||
30 | wanted_index = self.index - other.lenght | 33 | wanted_index = self.index - other.lenght | ||
31 | if self.index < other.lenght: | 34 | if self.index < other.lenght: | ||
32 | wanted_index = self.index - other.lenght + MAX_INDEX | 35 | wanted_index = self.index - other.lenght + MAX_INDEX | ||
33 | return TONE_VALUE_LIST[wanted_index] | 36 | return TONE_VALUE_LIST[wanted_index] | ||
34 | 37 | ||||
35 | @property | 38 | @property | ||
36 | def index(self): | 39 | def index(self): | ||
37 | return TONE_INDEX_DICT[self.name] | 40 | return TONE_INDEX_DICT[self.name] | ||
38 | 41 | ||||
39 | class Interval: | 42 | class Interval: | ||
40 | def __init__(self, lenght): | 43 | def __init__(self, lenght): | ||
41 | correct_index = int(lenght / MAX_INDEX) | 44 | correct_index = int(lenght / MAX_INDEX) | ||
42 | self.lenght = lenght - correct_index*MAX_INDEX | 45 | self.lenght = lenght - correct_index*MAX_INDEX | ||
43 | 46 | ||||
44 | def __str__(self): | 47 | def __str__(self): | ||
n | n | 48 | print(f"len is {self.lenght}") | ||
45 | return INTERVAL_VALUE_LIST[self.lenght] | 49 | return INTERVAL_VALUE_LIST[self.lenght] | ||
46 | 50 | ||||
47 | def __add__(self,other): | 51 | def __add__(self,other): | ||
48 | if isinstance(other,Tone): | 52 | if isinstance(other,Tone): | ||
49 | raise TypeError("Invalid operation") | 53 | raise TypeError("Invalid operation") | ||
50 | if isinstance(other,Interval): | 54 | if isinstance(other,Interval): | ||
51 | total_len = self.lenght + other.lenght | 55 | total_len = self.lenght + other.lenght | ||
52 | correct_index = int(total_len / MAX_INDEX) | 56 | correct_index = int(total_len / MAX_INDEX) | ||
53 | correct_len = total_len - correct_index*MAX_INDEX | 57 | correct_len = total_len - correct_index*MAX_INDEX | ||
54 | return INTERVAL_VALUE_LIST[correct_len] | 58 | return INTERVAL_VALUE_LIST[correct_len] | ||
55 | 59 | ||||
56 | def __sub__(self,other): | 60 | def __sub__(self,other): | ||
57 | if isinstance(other,Tone): | 61 | if isinstance(other,Tone): | ||
58 | raise TypeError("Invalid operation") | 62 | raise TypeError("Invalid operation") | ||
59 | 63 | ||||
60 | def __neg__(self): | 64 | def __neg__(self): | ||
61 | return Interval(MAX_INDEX - self.lenght) | 65 | return Interval(MAX_INDEX - self.lenght) | ||
62 | 66 | ||||
63 | class Chord: | 67 | class Chord: | ||
64 | def __init_sorted_tones(self): | 68 | def __init_sorted_tones(self): | ||
65 | main_index = self.main_tone.index | 69 | main_index = self.main_tone.index | ||
66 | tones_dict = {self.main_tone.name : main_index} | 70 | tones_dict = {self.main_tone.name : main_index} | ||
67 | self.all_tones_list_objs = [self.main_tone] | 71 | self.all_tones_list_objs = [self.main_tone] | ||
68 | for tone_name in self.unique_tones: | 72 | for tone_name in self.unique_tones: | ||
69 | tone_index = Tone(tone_name).index | 73 | tone_index = Tone(tone_name).index | ||
70 | self.without_main_tones_list_objs.append(Tone(tone_name)) | 74 | self.without_main_tones_list_objs.append(Tone(tone_name)) | ||
71 | self.all_tones_list_objs.append(Tone(tone_name)) | 75 | self.all_tones_list_objs.append(Tone(tone_name)) | ||
72 | if main_index > tone_index: | 76 | if main_index > tone_index: | ||
73 | tones_dict[tone_name] = tone_index + MAX_INDEX | 77 | tones_dict[tone_name] = tone_index + MAX_INDEX | ||
74 | else: | 78 | else: | ||
75 | tones_dict[tone_name] = tone_index | 79 | tones_dict[tone_name] = tone_index | ||
76 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 80 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
77 | 81 | ||||
78 | def __init__(self, main_tone, *tones): | 82 | def __init__(self, main_tone, *tones): | ||
79 | self.main_tone = main_tone | 83 | self.main_tone = main_tone | ||
80 | self.unique_tones= set() | 84 | self.unique_tones= set() | ||
81 | self.sorted_tones = [] | 85 | self.sorted_tones = [] | ||
82 | self.all_tones_list_objs = [] | 86 | self.all_tones_list_objs = [] | ||
83 | self.without_main_tones_list_objs = [] | 87 | self.without_main_tones_list_objs = [] | ||
84 | self.unique_tones.add(main_tone.name) | 88 | self.unique_tones.add(main_tone.name) | ||
85 | for tone in tones: | 89 | for tone in tones: | ||
86 | self.unique_tones.add(tone.name) | 90 | self.unique_tones.add(tone.name) | ||
87 | valid_len = len(self.unique_tones) | 91 | valid_len = len(self.unique_tones) | ||
88 | if valid_len <= 1: | 92 | if valid_len <= 1: | ||
89 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 93 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
90 | self.unique_tones.discard(main_tone.name) | 94 | self.unique_tones.discard(main_tone.name) | ||
91 | self.__init_sorted_tones() | 95 | self.__init_sorted_tones() | ||
92 | 96 | ||||
93 | def __add__(self, other): | 97 | def __add__(self, other): | ||
94 | new_tones = self.without_main_tones_list_objs | 98 | new_tones = self.without_main_tones_list_objs | ||
95 | if isinstance(other, Tone): | 99 | if isinstance(other, Tone): | ||
96 | new_tones.append(other) | 100 | new_tones.append(other) | ||
97 | if isinstance(other,Chord): | 101 | if isinstance(other,Chord): | ||
98 | for tone in other.all_tones_list_objs: | 102 | for tone in other.all_tones_list_objs: | ||
99 | new_tones.append(tone) | 103 | new_tones.append(tone) | ||
100 | return Chord(self.main_tone, *new_tones) | 104 | return Chord(self.main_tone, *new_tones) | ||
101 | 105 | ||||
102 | def __sub__(self, other): | 106 | def __sub__(self, other): | ||
103 | if other.name not in self.sorted_tones: | 107 | if other.name not in self.sorted_tones: | ||
104 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 108 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
105 | if len(self.unique_tones) < 2: | 109 | if len(self.unique_tones) < 2: | ||
106 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 110 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
107 | new_tones = self.without_main_tones_list_objs | 111 | new_tones = self.without_main_tones_list_objs | ||
108 | main_tone = self.main_tone | 112 | main_tone = self.main_tone | ||
109 | if isinstance(other, Tone): | 113 | if isinstance(other, Tone): | ||
110 | if main_tone.name == other.name: | 114 | if main_tone.name == other.name: | ||
111 | main_tone = self.without_main_tones_list_objs[0] | 115 | main_tone = self.without_main_tones_list_objs[0] | ||
112 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 116 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
113 | else: | 117 | else: | ||
114 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 118 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
115 | return Chord(main_tone, *new_tones) | 119 | return Chord(main_tone, *new_tones) | ||
116 | 120 | ||||
117 | def __str__(self): | 121 | def __str__(self): | ||
118 | return "-".join(self.sorted_tones) | 122 | return "-".join(self.sorted_tones) | ||
119 | 123 | ||||
120 | def is_minor(self): | 124 | def is_minor(self): | ||
121 | for tone in self.without_main_tones_list_objs: | 125 | for tone in self.without_main_tones_list_objs: | ||
n | 122 | interval = self.main_tone - tone | n | 126 | interval = tone - self.main_tone |
123 | if str(interval) == "minor 3rd": | 127 | if str(interval) == "minor 3rd": | ||
124 | return True | 128 | return True | ||
125 | return False | 129 | return False | ||
126 | 130 | ||||
127 | def is_major(self): | 131 | def is_major(self): | ||
128 | for tone in self.without_main_tones_list_objs: | 132 | for tone in self.without_main_tones_list_objs: | ||
t | 129 | interval = self.main_tone - tone | t | 133 | interval = tone - self.main_tone |
130 | if str(interval) == "major 3rd": | 134 | if str(interval) == "major 3rd": | ||
131 | return True | 135 | return True | ||
132 | return False | 136 | return False | ||
133 | 137 | ||||
134 | def is_power_chord(self): | 138 | def is_power_chord(self): | ||
135 | return not self.is_major() and not self.is_minor() | 139 | return not self.is_major() and not self.is_minor() | ||
136 | 140 | ||||
137 | def transposed(self, interval): | 141 | def transposed(self, interval): | ||
138 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | 142 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | ||
139 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 143 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
140 | 144 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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 | if isinstance(other, Interval): | 16 | if isinstance(other, Interval): | ||
n | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | n | 17 | total_len = other.lenght + self.index |
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other, Tone): | 23 | if isinstance(other, Tone): | ||
n | 24 | return Interval(abs(self.index - other.index)) | n | 24 | len = other.index - self.index |
25 | if self.index > other.index: | ||||
26 | print("here") | ||||
27 | len = other.index + MAX_INDEX - self.index | ||||
28 | return Interval(len) | ||||
25 | if isinstance(other, Interval): | 29 | if isinstance(other, Interval): | ||
n | 26 | cur_index = TONE_INDEX_DICT[self.name] | n | 30 | wanted_index = self.index - other.lenght |
31 | if self.index < other.lenght: | ||||
27 | wanted_index = cur_index - other.lenght + MAX_INDEX | 32 | wanted_index = self.index - other.lenght + MAX_INDEX | ||
28 | return TONE_VALUE_LIST[wanted_index] | 33 | return TONE_VALUE_LIST[wanted_index] | ||
29 | 34 | ||||
30 | @property | 35 | @property | ||
31 | def index(self): | 36 | def index(self): | ||
32 | return TONE_INDEX_DICT[self.name] | 37 | return TONE_INDEX_DICT[self.name] | ||
33 | 38 | ||||
34 | class Interval: | 39 | class Interval: | ||
35 | def __init__(self, lenght): | 40 | def __init__(self, lenght): | ||
36 | correct_index = int(lenght / MAX_INDEX) | 41 | correct_index = int(lenght / MAX_INDEX) | ||
37 | self.lenght = lenght - correct_index*MAX_INDEX | 42 | self.lenght = lenght - correct_index*MAX_INDEX | ||
38 | 43 | ||||
39 | def __str__(self): | 44 | def __str__(self): | ||
40 | return INTERVAL_VALUE_LIST[self.lenght] | 45 | return INTERVAL_VALUE_LIST[self.lenght] | ||
41 | 46 | ||||
42 | def __add__(self,other): | 47 | def __add__(self,other): | ||
43 | if isinstance(other,Tone): | 48 | if isinstance(other,Tone): | ||
44 | raise TypeError("Invalid operation") | 49 | raise TypeError("Invalid operation") | ||
45 | if isinstance(other,Interval): | 50 | if isinstance(other,Interval): | ||
46 | total_len = self.lenght + other.lenght | 51 | total_len = self.lenght + other.lenght | ||
47 | correct_index = int(total_len / MAX_INDEX) | 52 | correct_index = int(total_len / MAX_INDEX) | ||
48 | correct_len = total_len - correct_index*MAX_INDEX | 53 | correct_len = total_len - correct_index*MAX_INDEX | ||
49 | return INTERVAL_VALUE_LIST[correct_len] | 54 | return INTERVAL_VALUE_LIST[correct_len] | ||
50 | 55 | ||||
51 | def __sub__(self,other): | 56 | def __sub__(self,other): | ||
52 | if isinstance(other,Tone): | 57 | if isinstance(other,Tone): | ||
53 | raise TypeError("Invalid operation") | 58 | raise TypeError("Invalid operation") | ||
54 | 59 | ||||
55 | def __neg__(self): | 60 | def __neg__(self): | ||
56 | return Interval(MAX_INDEX - self.lenght) | 61 | return Interval(MAX_INDEX - self.lenght) | ||
57 | 62 | ||||
58 | class Chord: | 63 | class Chord: | ||
59 | def __init_sorted_tones(self): | 64 | def __init_sorted_tones(self): | ||
60 | main_index = self.main_tone.index | 65 | main_index = self.main_tone.index | ||
61 | tones_dict = {self.main_tone.name : main_index} | 66 | tones_dict = {self.main_tone.name : main_index} | ||
62 | self.all_tones_list_objs = [self.main_tone] | 67 | self.all_tones_list_objs = [self.main_tone] | ||
63 | for tone_name in self.unique_tones: | 68 | for tone_name in self.unique_tones: | ||
64 | tone_index = Tone(tone_name).index | 69 | tone_index = Tone(tone_name).index | ||
65 | self.without_main_tones_list_objs.append(Tone(tone_name)) | 70 | self.without_main_tones_list_objs.append(Tone(tone_name)) | ||
66 | self.all_tones_list_objs.append(Tone(tone_name)) | 71 | self.all_tones_list_objs.append(Tone(tone_name)) | ||
67 | if main_index > tone_index: | 72 | if main_index > tone_index: | ||
68 | tones_dict[tone_name] = tone_index + MAX_INDEX | 73 | tones_dict[tone_name] = tone_index + MAX_INDEX | ||
69 | else: | 74 | else: | ||
70 | tones_dict[tone_name] = tone_index | 75 | tones_dict[tone_name] = tone_index | ||
71 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 76 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
72 | 77 | ||||
73 | def __init__(self, main_tone, *tones): | 78 | def __init__(self, main_tone, *tones): | ||
74 | self.main_tone = main_tone | 79 | self.main_tone = main_tone | ||
75 | self.unique_tones= set() | 80 | self.unique_tones= set() | ||
76 | self.sorted_tones = [] | 81 | self.sorted_tones = [] | ||
77 | self.all_tones_list_objs = [] | 82 | self.all_tones_list_objs = [] | ||
78 | self.without_main_tones_list_objs = [] | 83 | self.without_main_tones_list_objs = [] | ||
79 | self.unique_tones.add(main_tone.name) | 84 | self.unique_tones.add(main_tone.name) | ||
80 | for tone in tones: | 85 | for tone in tones: | ||
81 | self.unique_tones.add(tone.name) | 86 | self.unique_tones.add(tone.name) | ||
82 | valid_len = len(self.unique_tones) | 87 | valid_len = len(self.unique_tones) | ||
83 | if valid_len <= 1: | 88 | if valid_len <= 1: | ||
84 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 89 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
85 | self.unique_tones.discard(main_tone.name) | 90 | self.unique_tones.discard(main_tone.name) | ||
86 | self.__init_sorted_tones() | 91 | self.__init_sorted_tones() | ||
87 | 92 | ||||
88 | def __add__(self, other): | 93 | def __add__(self, other): | ||
89 | new_tones = self.without_main_tones_list_objs | 94 | new_tones = self.without_main_tones_list_objs | ||
90 | if isinstance(other, Tone): | 95 | if isinstance(other, Tone): | ||
91 | new_tones.append(other) | 96 | new_tones.append(other) | ||
92 | if isinstance(other,Chord): | 97 | if isinstance(other,Chord): | ||
93 | for tone in other.all_tones_list_objs: | 98 | for tone in other.all_tones_list_objs: | ||
94 | new_tones.append(tone) | 99 | new_tones.append(tone) | ||
95 | return Chord(self.main_tone, *new_tones) | 100 | return Chord(self.main_tone, *new_tones) | ||
96 | 101 | ||||
97 | def __sub__(self, other): | 102 | def __sub__(self, other): | ||
98 | if other.name not in self.sorted_tones: | 103 | if other.name not in self.sorted_tones: | ||
99 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 104 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
100 | if len(self.unique_tones) < 2: | 105 | if len(self.unique_tones) < 2: | ||
101 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 106 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
n | 102 | new_tones = self.all_tones_list_objs | n | 107 | new_tones = self.without_main_tones_list_objs |
103 | main_tone = self.main_tone | 108 | main_tone = self.main_tone | ||
104 | if isinstance(other, Tone): | 109 | if isinstance(other, Tone): | ||
105 | if main_tone.name == other.name: | 110 | if main_tone.name == other.name: | ||
n | 106 | main_tone = Tone(self.sorted_tones[0]) | n | 111 | main_tone = self.without_main_tones_list_objs[0] |
107 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 112 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
108 | else: | 113 | else: | ||
109 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 114 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
110 | return Chord(main_tone, *new_tones) | 115 | return Chord(main_tone, *new_tones) | ||
111 | 116 | ||||
112 | def __str__(self): | 117 | def __str__(self): | ||
113 | return "-".join(self.sorted_tones) | 118 | return "-".join(self.sorted_tones) | ||
114 | 119 | ||||
115 | def is_minor(self): | 120 | def is_minor(self): | ||
n | 116 | main_index = self.main_tone.index | n | ||
117 | for tone in self.without_main_tones_list_objs: | 121 | for tone in self.without_main_tones_list_objs: | ||
n | 118 | interval = Interval(abs(main_index - tone.index)) | n | 122 | interval = self.main_tone - tone |
119 | if str(interval) == "minor 3rd": | 123 | if str(interval) == "minor 3rd": | ||
120 | return True | 124 | return True | ||
121 | return False | 125 | return False | ||
122 | 126 | ||||
123 | def is_major(self): | 127 | def is_major(self): | ||
n | 124 | main_index = self.main_tone.index | n | ||
125 | for tone in self.without_main_tones_list_objs: | 128 | for tone in self.without_main_tones_list_objs: | ||
n | 126 | interval = Interval(abs(main_index - tone.index)) | n | 129 | interval = self.main_tone - tone |
127 | if str(interval) == "major 3rd": | 130 | if str(interval) == "major 3rd": | ||
128 | return True | 131 | return True | ||
129 | return False | 132 | return False | ||
130 | 133 | ||||
131 | def is_power_chord(self): | 134 | def is_power_chord(self): | ||
132 | return not self.is_major() and not self.is_minor() | 135 | return not self.is_major() and not self.is_minor() | ||
133 | 136 | ||||
134 | def transposed(self, interval): | 137 | def transposed(self, interval): | ||
135 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | 138 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] | ||
136 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 139 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
137 | 140 | ||||
t | 138 | t |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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 | if isinstance(other, Interval): | 16 | if isinstance(other, Interval): | ||
17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other, Tone): | 23 | if isinstance(other, Tone): | ||
24 | return Interval(abs(self.index - other.index)) | 24 | return Interval(abs(self.index - other.index)) | ||
25 | if isinstance(other, Interval): | 25 | if isinstance(other, Interval): | ||
26 | cur_index = TONE_INDEX_DICT[self.name] | 26 | cur_index = TONE_INDEX_DICT[self.name] | ||
27 | wanted_index = cur_index - other.lenght + MAX_INDEX | 27 | wanted_index = cur_index - other.lenght + MAX_INDEX | ||
28 | return TONE_VALUE_LIST[wanted_index] | 28 | return TONE_VALUE_LIST[wanted_index] | ||
29 | 29 | ||||
30 | @property | 30 | @property | ||
31 | def index(self): | 31 | def index(self): | ||
32 | return TONE_INDEX_DICT[self.name] | 32 | return TONE_INDEX_DICT[self.name] | ||
33 | 33 | ||||
34 | class Interval: | 34 | class Interval: | ||
35 | def __init__(self, lenght): | 35 | def __init__(self, lenght): | ||
36 | correct_index = int(lenght / MAX_INDEX) | 36 | correct_index = int(lenght / MAX_INDEX) | ||
37 | self.lenght = lenght - correct_index*MAX_INDEX | 37 | self.lenght = lenght - correct_index*MAX_INDEX | ||
38 | 38 | ||||
39 | def __str__(self): | 39 | def __str__(self): | ||
40 | return INTERVAL_VALUE_LIST[self.lenght] | 40 | return INTERVAL_VALUE_LIST[self.lenght] | ||
41 | 41 | ||||
42 | def __add__(self,other): | 42 | def __add__(self,other): | ||
43 | if isinstance(other,Tone): | 43 | if isinstance(other,Tone): | ||
44 | raise TypeError("Invalid operation") | 44 | raise TypeError("Invalid operation") | ||
45 | if isinstance(other,Interval): | 45 | if isinstance(other,Interval): | ||
46 | total_len = self.lenght + other.lenght | 46 | total_len = self.lenght + other.lenght | ||
47 | correct_index = int(total_len / MAX_INDEX) | 47 | correct_index = int(total_len / MAX_INDEX) | ||
48 | correct_len = total_len - correct_index*MAX_INDEX | 48 | correct_len = total_len - correct_index*MAX_INDEX | ||
49 | return INTERVAL_VALUE_LIST[correct_len] | 49 | return INTERVAL_VALUE_LIST[correct_len] | ||
50 | 50 | ||||
51 | def __sub__(self,other): | 51 | def __sub__(self,other): | ||
52 | if isinstance(other,Tone): | 52 | if isinstance(other,Tone): | ||
53 | raise TypeError("Invalid operation") | 53 | raise TypeError("Invalid operation") | ||
54 | 54 | ||||
55 | def __neg__(self): | 55 | def __neg__(self): | ||
56 | return Interval(MAX_INDEX - self.lenght) | 56 | return Interval(MAX_INDEX - self.lenght) | ||
57 | 57 | ||||
58 | class Chord: | 58 | class Chord: | ||
59 | def __init_sorted_tones(self): | 59 | def __init_sorted_tones(self): | ||
60 | main_index = self.main_tone.index | 60 | main_index = self.main_tone.index | ||
61 | tones_dict = {self.main_tone.name : main_index} | 61 | tones_dict = {self.main_tone.name : main_index} | ||
n | n | 62 | self.all_tones_list_objs = [self.main_tone] | ||
62 | for tone in self.uniques_to_list_objs_tones: | 63 | for tone_name in self.unique_tones: | ||
63 | tone_index = tone.index | 64 | tone_index = Tone(tone_name).index | ||
65 | self.without_main_tones_list_objs.append(Tone(tone_name)) | ||||
66 | self.all_tones_list_objs.append(Tone(tone_name)) | ||||
64 | if main_index > tone_index: | 67 | if main_index > tone_index: | ||
n | 65 | tones_dict[tone.name] = tone_index + MAX_INDEX | n | 68 | tones_dict[tone_name] = tone_index + MAX_INDEX |
66 | else: | 69 | else: | ||
n | 67 | tones_dict[tone.name] = tone_index | n | 70 | tones_dict[tone_name] = tone_index |
68 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 71 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
n | 69 | n | |||
70 | @property | ||||
71 | def sorted_to_list_objs_tones(self): | ||||
72 | tones_objs_list = [] | ||||
73 | for tone in self.sorted_tones: | ||||
74 | tones_objs_list.append(Tone(tone)) | ||||
75 | return tones_objs_list | ||||
76 | |||||
77 | @property | ||||
78 | def uniques_to_list_objs_tones(self): | ||||
79 | tones_objs_list = [] | ||||
80 | for tone in self.unique_tones: | ||||
81 | tones_objs_list.append(Tone(tone)) | ||||
82 | return tones_objs_list | ||||
83 | 72 | ||||
84 | def __init__(self, main_tone, *tones): | 73 | def __init__(self, main_tone, *tones): | ||
85 | self.main_tone = main_tone | 74 | self.main_tone = main_tone | ||
86 | self.unique_tones= set() | 75 | self.unique_tones= set() | ||
87 | self.sorted_tones = [] | 76 | self.sorted_tones = [] | ||
n | n | 77 | self.all_tones_list_objs = [] | ||
78 | self.without_main_tones_list_objs = [] | ||||
88 | self.unique_tones.add(main_tone.name) | 79 | self.unique_tones.add(main_tone.name) | ||
89 | for tone in tones: | 80 | for tone in tones: | ||
90 | self.unique_tones.add(tone.name) | 81 | self.unique_tones.add(tone.name) | ||
91 | valid_len = len(self.unique_tones) | 82 | valid_len = len(self.unique_tones) | ||
92 | if valid_len <= 1: | 83 | if valid_len <= 1: | ||
93 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 84 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
94 | self.unique_tones.discard(main_tone.name) | 85 | self.unique_tones.discard(main_tone.name) | ||
95 | self.__init_sorted_tones() | 86 | self.__init_sorted_tones() | ||
96 | 87 | ||||
97 | def __add__(self, other): | 88 | def __add__(self, other): | ||
n | 98 | new_tones = self.uniques_to_list_objs_tones | n | 89 | new_tones = self.without_main_tones_list_objs |
99 | if isinstance(other, Tone): | 90 | if isinstance(other, Tone): | ||
100 | new_tones.append(other) | 91 | new_tones.append(other) | ||
101 | if isinstance(other,Chord): | 92 | if isinstance(other,Chord): | ||
n | 102 | for tone in other.sorted_to_list_objs_tones: | n | 93 | for tone in other.all_tones_list_objs: |
103 | new_tones.append(tone) | 94 | new_tones.append(tone) | ||
104 | return Chord(self.main_tone, *new_tones) | 95 | return Chord(self.main_tone, *new_tones) | ||
105 | 96 | ||||
106 | def __sub__(self, other): | 97 | def __sub__(self, other): | ||
107 | if other.name not in self.sorted_tones: | 98 | if other.name not in self.sorted_tones: | ||
108 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 99 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
109 | if len(self.unique_tones) < 2: | 100 | if len(self.unique_tones) < 2: | ||
110 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 101 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
n | 111 | new_tones = self.sorted_to_list_objs_tones | n | 102 | new_tones = self.all_tones_list_objs |
112 | main_tone = self.main_tone | 103 | main_tone = self.main_tone | ||
113 | if isinstance(other, Tone): | 104 | if isinstance(other, Tone): | ||
114 | if main_tone.name == other.name: | 105 | if main_tone.name == other.name: | ||
115 | main_tone = Tone(self.sorted_tones[0]) | 106 | main_tone = Tone(self.sorted_tones[0]) | ||
116 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 107 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
117 | else: | 108 | else: | ||
118 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 109 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
119 | return Chord(main_tone, *new_tones) | 110 | return Chord(main_tone, *new_tones) | ||
120 | 111 | ||||
121 | def __str__(self): | 112 | def __str__(self): | ||
122 | return "-".join(self.sorted_tones) | 113 | return "-".join(self.sorted_tones) | ||
123 | 114 | ||||
124 | def is_minor(self): | 115 | def is_minor(self): | ||
125 | main_index = self.main_tone.index | 116 | main_index = self.main_tone.index | ||
n | 126 | for tone in self.uniques_to_list_objs_tones: | n | 117 | for tone in self.without_main_tones_list_objs: |
127 | interval = Interval(abs(main_index - tone.index)) | 118 | interval = Interval(abs(main_index - tone.index)) | ||
128 | if str(interval) == "minor 3rd": | 119 | if str(interval) == "minor 3rd": | ||
129 | return True | 120 | return True | ||
130 | return False | 121 | return False | ||
131 | 122 | ||||
132 | def is_major(self): | 123 | def is_major(self): | ||
133 | main_index = self.main_tone.index | 124 | main_index = self.main_tone.index | ||
n | 134 | for tone in self.uniques_to_list_objs_tones: | n | 125 | for tone in self.without_main_tones_list_objs: |
135 | interval = Interval(abs(main_index - tone.index)) | 126 | interval = Interval(abs(main_index - tone.index)) | ||
136 | if str(interval) == "major 3rd": | 127 | if str(interval) == "major 3rd": | ||
137 | return True | 128 | return True | ||
138 | return False | 129 | return False | ||
139 | 130 | ||||
140 | def is_power_chord(self): | 131 | def is_power_chord(self): | ||
141 | return not self.is_major() and not self.is_minor() | 132 | return not self.is_major() and not self.is_minor() | ||
142 | 133 | ||||
143 | def transposed(self, interval): | 134 | def transposed(self, interval): | ||
t | 144 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] | t | 135 | transposed_tones = [tone + interval for tone in self.all_tones_list_objs] |
145 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 136 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
146 | 137 | ||||
147 | 138 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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 | if isinstance(other, Interval): | 16 | if isinstance(other, Interval): | ||
17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other, Tone): | 23 | if isinstance(other, Tone): | ||
24 | return Interval(abs(self.index - other.index)) | 24 | return Interval(abs(self.index - other.index)) | ||
25 | if isinstance(other, Interval): | 25 | if isinstance(other, Interval): | ||
26 | cur_index = TONE_INDEX_DICT[self.name] | 26 | cur_index = TONE_INDEX_DICT[self.name] | ||
27 | wanted_index = cur_index - other.lenght + MAX_INDEX | 27 | wanted_index = cur_index - other.lenght + MAX_INDEX | ||
28 | return TONE_VALUE_LIST[wanted_index] | 28 | return TONE_VALUE_LIST[wanted_index] | ||
29 | 29 | ||||
30 | @property | 30 | @property | ||
31 | def index(self): | 31 | def index(self): | ||
32 | return TONE_INDEX_DICT[self.name] | 32 | return TONE_INDEX_DICT[self.name] | ||
33 | 33 | ||||
34 | class Interval: | 34 | class Interval: | ||
35 | def __init__(self, lenght): | 35 | def __init__(self, lenght): | ||
36 | correct_index = int(lenght / MAX_INDEX) | 36 | correct_index = int(lenght / MAX_INDEX) | ||
37 | self.lenght = lenght - correct_index*MAX_INDEX | 37 | self.lenght = lenght - correct_index*MAX_INDEX | ||
38 | 38 | ||||
39 | def __str__(self): | 39 | def __str__(self): | ||
40 | return INTERVAL_VALUE_LIST[self.lenght] | 40 | return INTERVAL_VALUE_LIST[self.lenght] | ||
41 | 41 | ||||
42 | def __add__(self,other): | 42 | def __add__(self,other): | ||
43 | if isinstance(other,Tone): | 43 | if isinstance(other,Tone): | ||
44 | raise TypeError("Invalid operation") | 44 | raise TypeError("Invalid operation") | ||
45 | if isinstance(other,Interval): | 45 | if isinstance(other,Interval): | ||
46 | total_len = self.lenght + other.lenght | 46 | total_len = self.lenght + other.lenght | ||
47 | correct_index = int(total_len / MAX_INDEX) | 47 | correct_index = int(total_len / MAX_INDEX) | ||
48 | correct_len = total_len - correct_index*MAX_INDEX | 48 | correct_len = total_len - correct_index*MAX_INDEX | ||
49 | return INTERVAL_VALUE_LIST[correct_len] | 49 | return INTERVAL_VALUE_LIST[correct_len] | ||
50 | 50 | ||||
51 | def __sub__(self,other): | 51 | def __sub__(self,other): | ||
52 | if isinstance(other,Tone): | 52 | if isinstance(other,Tone): | ||
53 | raise TypeError("Invalid operation") | 53 | raise TypeError("Invalid operation") | ||
54 | 54 | ||||
55 | def __neg__(self): | 55 | def __neg__(self): | ||
t | 56 | correct_index = int(self.lenght / MAX_INDEX) | t | ||
57 | self.lenght = self.lenght - correct_index*MAX_INDEX | ||||
58 | return Interval(MAX_INDEX-self.lenght) | 56 | return Interval(MAX_INDEX - self.lenght) | ||
59 | 57 | ||||
60 | class Chord: | 58 | class Chord: | ||
61 | def __init_sorted_tones(self): | 59 | def __init_sorted_tones(self): | ||
62 | main_index = self.main_tone.index | 60 | main_index = self.main_tone.index | ||
63 | tones_dict = {self.main_tone.name : main_index} | 61 | tones_dict = {self.main_tone.name : main_index} | ||
64 | for tone in self.uniques_to_list_objs_tones: | 62 | for tone in self.uniques_to_list_objs_tones: | ||
65 | tone_index = tone.index | 63 | tone_index = tone.index | ||
66 | if main_index > tone_index: | 64 | if main_index > tone_index: | ||
67 | tones_dict[tone.name] = tone_index + MAX_INDEX | 65 | tones_dict[tone.name] = tone_index + MAX_INDEX | ||
68 | else: | 66 | else: | ||
69 | tones_dict[tone.name] = tone_index | 67 | tones_dict[tone.name] = tone_index | ||
70 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 68 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
71 | 69 | ||||
72 | @property | 70 | @property | ||
73 | def sorted_to_list_objs_tones(self): | 71 | def sorted_to_list_objs_tones(self): | ||
74 | tones_objs_list = [] | 72 | tones_objs_list = [] | ||
75 | for tone in self.sorted_tones: | 73 | for tone in self.sorted_tones: | ||
76 | tones_objs_list.append(Tone(tone)) | 74 | tones_objs_list.append(Tone(tone)) | ||
77 | return tones_objs_list | 75 | return tones_objs_list | ||
78 | 76 | ||||
79 | @property | 77 | @property | ||
80 | def uniques_to_list_objs_tones(self): | 78 | def uniques_to_list_objs_tones(self): | ||
81 | tones_objs_list = [] | 79 | tones_objs_list = [] | ||
82 | for tone in self.unique_tones: | 80 | for tone in self.unique_tones: | ||
83 | tones_objs_list.append(Tone(tone)) | 81 | tones_objs_list.append(Tone(tone)) | ||
84 | return tones_objs_list | 82 | return tones_objs_list | ||
85 | 83 | ||||
86 | def __init__(self, main_tone, *tones): | 84 | def __init__(self, main_tone, *tones): | ||
87 | self.main_tone = main_tone | 85 | self.main_tone = main_tone | ||
88 | self.unique_tones= set() | 86 | self.unique_tones= set() | ||
89 | self.sorted_tones = [] | 87 | self.sorted_tones = [] | ||
90 | self.unique_tones.add(main_tone.name) | 88 | self.unique_tones.add(main_tone.name) | ||
91 | for tone in tones: | 89 | for tone in tones: | ||
92 | self.unique_tones.add(tone.name) | 90 | self.unique_tones.add(tone.name) | ||
93 | valid_len = len(self.unique_tones) | 91 | valid_len = len(self.unique_tones) | ||
94 | if valid_len <= 1: | 92 | if valid_len <= 1: | ||
95 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 93 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
96 | self.unique_tones.discard(main_tone.name) | 94 | self.unique_tones.discard(main_tone.name) | ||
97 | self.__init_sorted_tones() | 95 | self.__init_sorted_tones() | ||
98 | 96 | ||||
99 | def __add__(self, other): | 97 | def __add__(self, other): | ||
100 | new_tones = self.uniques_to_list_objs_tones | 98 | new_tones = self.uniques_to_list_objs_tones | ||
101 | if isinstance(other, Tone): | 99 | if isinstance(other, Tone): | ||
102 | new_tones.append(other) | 100 | new_tones.append(other) | ||
103 | if isinstance(other,Chord): | 101 | if isinstance(other,Chord): | ||
104 | for tone in other.sorted_to_list_objs_tones: | 102 | for tone in other.sorted_to_list_objs_tones: | ||
105 | new_tones.append(tone) | 103 | new_tones.append(tone) | ||
106 | return Chord(self.main_tone, *new_tones) | 104 | return Chord(self.main_tone, *new_tones) | ||
107 | 105 | ||||
108 | def __sub__(self, other): | 106 | def __sub__(self, other): | ||
109 | if other.name not in self.sorted_tones: | 107 | if other.name not in self.sorted_tones: | ||
110 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 108 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
111 | if len(self.unique_tones) < 2: | 109 | if len(self.unique_tones) < 2: | ||
112 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 110 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
113 | new_tones = self.sorted_to_list_objs_tones | 111 | new_tones = self.sorted_to_list_objs_tones | ||
114 | main_tone = self.main_tone | 112 | main_tone = self.main_tone | ||
115 | if isinstance(other, Tone): | 113 | if isinstance(other, Tone): | ||
116 | if main_tone.name == other.name: | 114 | if main_tone.name == other.name: | ||
117 | main_tone = Tone(self.sorted_tones[0]) | 115 | main_tone = Tone(self.sorted_tones[0]) | ||
118 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 116 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
119 | else: | 117 | else: | ||
120 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 118 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
121 | return Chord(main_tone, *new_tones) | 119 | return Chord(main_tone, *new_tones) | ||
122 | 120 | ||||
123 | def __str__(self): | 121 | def __str__(self): | ||
124 | return "-".join(self.sorted_tones) | 122 | return "-".join(self.sorted_tones) | ||
125 | 123 | ||||
126 | def is_minor(self): | 124 | def is_minor(self): | ||
127 | main_index = self.main_tone.index | 125 | main_index = self.main_tone.index | ||
128 | for tone in self.uniques_to_list_objs_tones: | 126 | for tone in self.uniques_to_list_objs_tones: | ||
129 | interval = Interval(abs(main_index - tone.index)) | 127 | interval = Interval(abs(main_index - tone.index)) | ||
130 | if str(interval) == "minor 3rd": | 128 | if str(interval) == "minor 3rd": | ||
131 | return True | 129 | return True | ||
132 | return False | 130 | return False | ||
133 | 131 | ||||
134 | def is_major(self): | 132 | def is_major(self): | ||
135 | main_index = self.main_tone.index | 133 | main_index = self.main_tone.index | ||
136 | for tone in self.uniques_to_list_objs_tones: | 134 | for tone in self.uniques_to_list_objs_tones: | ||
137 | interval = Interval(abs(main_index - tone.index)) | 135 | interval = Interval(abs(main_index - tone.index)) | ||
138 | if str(interval) == "major 3rd": | 136 | if str(interval) == "major 3rd": | ||
139 | return True | 137 | return True | ||
140 | return False | 138 | return False | ||
141 | 139 | ||||
142 | def is_power_chord(self): | 140 | def is_power_chord(self): | ||
143 | return not self.is_major() and not self.is_minor() | 141 | return not self.is_major() and not self.is_minor() | ||
144 | 142 | ||||
145 | def transposed(self, interval): | 143 | def transposed(self, interval): | ||
146 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] | 144 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] | ||
147 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 145 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
148 | 146 | ||||
149 | 147 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] | ||
3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = 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): | ||
n | 14 | if isinstance(other,Tone): | n | 14 | if isinstance(other, Tone): |
15 | return Chord(self,other) | 15 | return Chord(self, other) | ||
16 | if isinstance(other,Interval): | 16 | if isinstance(other, Interval): | ||
17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_LIST[correct_len]) | 20 | return Tone(TONE_VALUE_LIST[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
n | 23 | if isinstance(other,Tone): | n | 23 | if isinstance(other, Tone): |
24 | return Interval(abs(self.index - other.index)) | 24 | return Interval(abs(self.index - other.index)) | ||
n | 25 | if isinstance(other,Interval): | n | 25 | if isinstance(other, Interval): |
26 | cur_index = TONE_INDEX_DICT[self.name] | 26 | cur_index = TONE_INDEX_DICT[self.name] | ||
27 | wanted_index = cur_index - other.lenght + MAX_INDEX | 27 | wanted_index = cur_index - other.lenght + MAX_INDEX | ||
28 | return TONE_VALUE_LIST[wanted_index] | 28 | return TONE_VALUE_LIST[wanted_index] | ||
29 | 29 | ||||
30 | @property | 30 | @property | ||
31 | def index(self): | 31 | def index(self): | ||
32 | return TONE_INDEX_DICT[self.name] | 32 | return TONE_INDEX_DICT[self.name] | ||
33 | 33 | ||||
34 | class Interval: | 34 | class Interval: | ||
35 | def __init__(self, lenght): | 35 | def __init__(self, lenght): | ||
36 | correct_index = int(lenght / MAX_INDEX) | 36 | correct_index = int(lenght / MAX_INDEX) | ||
n | 37 | self.lenght = lenght - correct_index*MAX_INDEX | n | 37 | self.lenght = lenght - correct_index*MAX_INDEX |
38 | 38 | ||||
39 | def __str__(self): | 39 | def __str__(self): | ||
n | 40 | n | |||
41 | return INTERVAL_VALUE_LIST[self.lenght] | 40 | return INTERVAL_VALUE_LIST[self.lenght] | ||
42 | 41 | ||||
43 | def __add__(self,other): | 42 | def __add__(self,other): | ||
44 | if isinstance(other,Tone): | 43 | if isinstance(other,Tone): | ||
45 | raise TypeError("Invalid operation") | 44 | raise TypeError("Invalid operation") | ||
46 | if isinstance(other,Interval): | 45 | if isinstance(other,Interval): | ||
47 | total_len = self.lenght + other.lenght | 46 | total_len = self.lenght + other.lenght | ||
48 | correct_index = int(total_len / MAX_INDEX) | 47 | correct_index = int(total_len / MAX_INDEX) | ||
49 | correct_len = total_len - correct_index*MAX_INDEX | 48 | correct_len = total_len - correct_index*MAX_INDEX | ||
50 | return INTERVAL_VALUE_LIST[correct_len] | 49 | return INTERVAL_VALUE_LIST[correct_len] | ||
51 | 50 | ||||
52 | def __sub__(self,other): | 51 | def __sub__(self,other): | ||
53 | if isinstance(other,Tone): | 52 | if isinstance(other,Tone): | ||
54 | raise TypeError("Invalid operation") | 53 | raise TypeError("Invalid operation") | ||
55 | 54 | ||||
56 | def __neg__(self): | 55 | def __neg__(self): | ||
57 | correct_index = int(self.lenght / MAX_INDEX) | 56 | correct_index = int(self.lenght / MAX_INDEX) | ||
58 | self.lenght = self.lenght - correct_index*MAX_INDEX | 57 | self.lenght = self.lenght - correct_index*MAX_INDEX | ||
59 | return Interval(MAX_INDEX-self.lenght) | 58 | return Interval(MAX_INDEX-self.lenght) | ||
60 | 59 | ||||
61 | class Chord: | 60 | class Chord: | ||
62 | def __init_sorted_tones(self): | 61 | def __init_sorted_tones(self): | ||
63 | main_index = self.main_tone.index | 62 | main_index = self.main_tone.index | ||
64 | tones_dict = {self.main_tone.name : main_index} | 63 | tones_dict = {self.main_tone.name : main_index} | ||
65 | for tone in self.uniques_to_list_objs_tones: | 64 | for tone in self.uniques_to_list_objs_tones: | ||
66 | tone_index = tone.index | 65 | tone_index = tone.index | ||
67 | if main_index > tone_index: | 66 | if main_index > tone_index: | ||
68 | tones_dict[tone.name] = tone_index + MAX_INDEX | 67 | tones_dict[tone.name] = tone_index + MAX_INDEX | ||
69 | else: | 68 | else: | ||
70 | tones_dict[tone.name] = tone_index | 69 | tones_dict[tone.name] = tone_index | ||
71 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 70 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
72 | 71 | ||||
73 | @property | 72 | @property | ||
74 | def sorted_to_list_objs_tones(self): | 73 | def sorted_to_list_objs_tones(self): | ||
75 | tones_objs_list = [] | 74 | tones_objs_list = [] | ||
76 | for tone in self.sorted_tones: | 75 | for tone in self.sorted_tones: | ||
77 | tones_objs_list.append(Tone(tone)) | 76 | tones_objs_list.append(Tone(tone)) | ||
78 | return tones_objs_list | 77 | return tones_objs_list | ||
79 | 78 | ||||
80 | @property | 79 | @property | ||
81 | def uniques_to_list_objs_tones(self): | 80 | def uniques_to_list_objs_tones(self): | ||
82 | tones_objs_list = [] | 81 | tones_objs_list = [] | ||
83 | for tone in self.unique_tones: | 82 | for tone in self.unique_tones: | ||
84 | tones_objs_list.append(Tone(tone)) | 83 | tones_objs_list.append(Tone(tone)) | ||
85 | return tones_objs_list | 84 | return tones_objs_list | ||
86 | 85 | ||||
87 | def __init__(self, main_tone, *tones): | 86 | def __init__(self, main_tone, *tones): | ||
88 | self.main_tone = main_tone | 87 | self.main_tone = main_tone | ||
89 | self.unique_tones= set() | 88 | self.unique_tones= set() | ||
90 | self.sorted_tones = [] | 89 | self.sorted_tones = [] | ||
91 | self.unique_tones.add(main_tone.name) | 90 | self.unique_tones.add(main_tone.name) | ||
92 | for tone in tones: | 91 | for tone in tones: | ||
n | 93 | self.unique_tones.add(tone.name) | n | 92 | self.unique_tones.add(tone.name) |
94 | |||||
95 | valid_len = len(self.unique_tones) | 93 | valid_len = len(self.unique_tones) | ||
96 | if valid_len <= 1: | 94 | if valid_len <= 1: | ||
97 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 95 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
98 | self.unique_tones.discard(main_tone.name) | 96 | self.unique_tones.discard(main_tone.name) | ||
99 | self.__init_sorted_tones() | 97 | self.__init_sorted_tones() | ||
100 | 98 | ||||
101 | def __add__(self, other): | 99 | def __add__(self, other): | ||
102 | new_tones = self.uniques_to_list_objs_tones | 100 | new_tones = self.uniques_to_list_objs_tones | ||
103 | if isinstance(other, Tone): | 101 | if isinstance(other, Tone): | ||
104 | new_tones.append(other) | 102 | new_tones.append(other) | ||
105 | if isinstance(other,Chord): | 103 | if isinstance(other,Chord): | ||
106 | for tone in other.sorted_to_list_objs_tones: | 104 | for tone in other.sorted_to_list_objs_tones: | ||
107 | new_tones.append(tone) | 105 | new_tones.append(tone) | ||
108 | return Chord(self.main_tone, *new_tones) | 106 | return Chord(self.main_tone, *new_tones) | ||
109 | 107 | ||||
n | 110 | n | |||
111 | def __sub__(self, other): | 108 | def __sub__(self, other): | ||
112 | if other.name not in self.sorted_tones: | 109 | if other.name not in self.sorted_tones: | ||
113 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 110 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
114 | if len(self.unique_tones) < 2: | 111 | if len(self.unique_tones) < 2: | ||
115 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 112 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
116 | new_tones = self.sorted_to_list_objs_tones | 113 | new_tones = self.sorted_to_list_objs_tones | ||
117 | main_tone = self.main_tone | 114 | main_tone = self.main_tone | ||
118 | if isinstance(other, Tone): | 115 | if isinstance(other, Tone): | ||
119 | if main_tone.name == other.name: | 116 | if main_tone.name == other.name: | ||
120 | main_tone = Tone(self.sorted_tones[0]) | 117 | main_tone = Tone(self.sorted_tones[0]) | ||
121 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | 118 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
122 | else: | 119 | else: | ||
123 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | 120 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) | ||
124 | return Chord(main_tone, *new_tones) | 121 | return Chord(main_tone, *new_tones) | ||
125 | 122 | ||||
126 | def __str__(self): | 123 | def __str__(self): | ||
127 | return "-".join(self.sorted_tones) | 124 | return "-".join(self.sorted_tones) | ||
128 | 125 | ||||
129 | def is_minor(self): | 126 | def is_minor(self): | ||
130 | main_index = self.main_tone.index | 127 | main_index = self.main_tone.index | ||
131 | for tone in self.uniques_to_list_objs_tones: | 128 | for tone in self.uniques_to_list_objs_tones: | ||
132 | interval = Interval(abs(main_index - tone.index)) | 129 | interval = Interval(abs(main_index - tone.index)) | ||
133 | if str(interval) == "minor 3rd": | 130 | if str(interval) == "minor 3rd": | ||
134 | return True | 131 | return True | ||
135 | return False | 132 | return False | ||
136 | 133 | ||||
137 | def is_major(self): | 134 | def is_major(self): | ||
138 | main_index = self.main_tone.index | 135 | main_index = self.main_tone.index | ||
139 | for tone in self.uniques_to_list_objs_tones: | 136 | for tone in self.uniques_to_list_objs_tones: | ||
140 | interval = Interval(abs(main_index - tone.index)) | 137 | interval = Interval(abs(main_index - tone.index)) | ||
141 | if str(interval) == "major 3rd": | 138 | if str(interval) == "major 3rd": | ||
142 | return True | 139 | return True | ||
143 | return False | 140 | return False | ||
144 | 141 | ||||
145 | def is_power_chord(self): | 142 | def is_power_chord(self): | ||
146 | return not self.is_major() and not self.is_minor() | 143 | return not self.is_major() and not self.is_minor() | ||
147 | 144 | ||||
148 | def transposed(self, interval): | 145 | def transposed(self, interval): | ||
149 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] | 146 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] | ||
t | 150 | t | |||
151 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 147 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
152 | 148 | ||||
153 | 149 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
n | 2 | TONE_VALUE_DICT = {0 : "C", 1: "C#" , 2 : "D" , 3 : "D#" , 4 : "E" , 5 : "F" , 6 : "F#" , 7 : "G" , 8 : "G#" , 9 : "A" , 10 : "A#" , 11 : "B" } | n | 2 | TONE_VALUE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] |
3 | INTERVAL_VALUE_DICT = {0 : "unison", 1 : "minor 2nd", 2 : "major 2nd", 3 : "minor 3rd", 4 : "major 3rd", 5 : "perfect 4th", 6 : "diminished 5th", 7 : "perfect 5th", 8 : "minor 6th", 9 : "major 6th", 10 : "minor 7th", 11 : "major 7th"} | 3 | INTERVAL_VALUE_LIST = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th", "major 6th", "minor 7th", "major 7th"] | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = name | ||
9 | 9 | ||||
10 | def __str__(self): | 10 | def __str__(self): | ||
n | 11 | return f"{self.name}" | n | 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 | if isinstance(other,Interval): | 16 | if isinstance(other,Interval): | ||
17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
n | 20 | return Tone(TONE_VALUE_DICT[correct_len]) | n | 20 | return Tone(TONE_VALUE_LIST[correct_len]) |
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other,Tone): | 23 | if isinstance(other,Tone): | ||
n | 24 | return Interval(abs(self.get_index()-other.get_index())) | n | 24 | return Interval(abs(self.index - other.index)) |
25 | if isinstance(other,Interval): | 25 | if isinstance(other,Interval): | ||
n | 26 | correct_index = int(other.lenght / MAX_INDEX) | n | ||
27 | correct_len = other.lenght - correct_index*MAX_INDEX | ||||
28 | cur_index = TONE_INDEX_DICT[self.name] | 26 | cur_index = TONE_INDEX_DICT[self.name] | ||
n | 29 | wanted_index = cur_index - correct_len + MAX_INDEX | n | 27 | wanted_index = cur_index - other.lenght + MAX_INDEX |
30 | return TONE_VALUE_DICT[wanted_index] | 28 | return TONE_VALUE_LIST[wanted_index] | ||
31 | 29 | ||||
30 | @property | ||||
32 | def get_index(self): | 31 | def index(self): | ||
33 | return TONE_INDEX_DICT[self.name] | 32 | return TONE_INDEX_DICT[self.name] | ||
34 | 33 | ||||
35 | @staticmethod | ||||
36 | def get_index_for_name(name): | ||||
37 | return TONE_INDEX_DICT[name] | ||||
38 | |||||
39 | |||||
40 | |||||
41 | class Interval: | 34 | class Interval: | ||
42 | def __init__(self, lenght): | 35 | def __init__(self, lenght): | ||
n | 43 | self.lenght = lenght | n | 36 | correct_index = int(lenght / MAX_INDEX) |
44 | 37 | self.lenght = lenght - correct_index*MAX_INDEX | |||
38 | |||||
45 | def __str__(self): | 39 | def __str__(self): | ||
n | 46 | correct_index = int(self.lenght / MAX_INDEX) | n | 40 | |
47 | correct_len = self.lenght - correct_index*MAX_INDEX | ||||
48 | return INTERVAL_VALUE_DICT[correct_len] | 41 | return INTERVAL_VALUE_LIST[self.lenght] | ||
49 | 42 | ||||
50 | def __add__(self,other): | 43 | def __add__(self,other): | ||
51 | if isinstance(other,Tone): | 44 | if isinstance(other,Tone): | ||
52 | raise TypeError("Invalid operation") | 45 | raise TypeError("Invalid operation") | ||
53 | if isinstance(other,Interval): | 46 | if isinstance(other,Interval): | ||
54 | total_len = self.lenght + other.lenght | 47 | total_len = self.lenght + other.lenght | ||
55 | correct_index = int(total_len / MAX_INDEX) | 48 | correct_index = int(total_len / MAX_INDEX) | ||
56 | correct_len = total_len - correct_index*MAX_INDEX | 49 | correct_len = total_len - correct_index*MAX_INDEX | ||
n | 57 | return INTERVAL_VALUE_DICT[correct_len] | n | 50 | return INTERVAL_VALUE_LIST[correct_len] |
58 | 51 | ||||
59 | def __sub__(self,other): | 52 | def __sub__(self,other): | ||
60 | if isinstance(other,Tone): | 53 | if isinstance(other,Tone): | ||
61 | raise TypeError("Invalid operation") | 54 | raise TypeError("Invalid operation") | ||
62 | 55 | ||||
63 | def __neg__(self): | 56 | def __neg__(self): | ||
n | n | 57 | correct_index = int(self.lenght / MAX_INDEX) | ||
58 | self.lenght = self.lenght - correct_index*MAX_INDEX | ||||
64 | return Interval(-self.lenght) | 59 | return Interval(MAX_INDEX-self.lenght) | ||
65 | 60 | ||||
66 | class Chord: | 61 | class Chord: | ||
67 | def __init_sorted_tones(self): | 62 | def __init_sorted_tones(self): | ||
n | 68 | main_index = self.main_tone.get_index() | n | 63 | main_index = self.main_tone.index |
69 | tones_dict = {self.main_tone.name : main_index} | 64 | tones_dict = {self.main_tone.name : main_index} | ||
n | 70 | for tone_name in self.unique_tones: | n | 65 | for tone in self.uniques_to_list_objs_tones: |
71 | tone_index = Tone.get_index_for_name(tone_name) | 66 | tone_index = tone.index | ||
72 | if main_index > tone_index: | 67 | if main_index > tone_index: | ||
n | 73 | tones_dict[tone_name] = tone_index + 10 | n | 68 | tones_dict[tone.name] = tone_index + MAX_INDEX |
74 | else: | 69 | else: | ||
n | 75 | tones_dict[tone_name] = tone_index | n | 70 | tones_dict[tone.name] = tone_index |
76 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 71 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
n | n | 72 | |||
73 | @property | ||||
74 | def sorted_to_list_objs_tones(self): | ||||
75 | tones_objs_list = [] | ||||
76 | for tone in self.sorted_tones: | ||||
77 | tones_objs_list.append(Tone(tone)) | ||||
78 | return tones_objs_list | ||||
79 | |||||
80 | @property | ||||
81 | def uniques_to_list_objs_tones(self): | ||||
82 | tones_objs_list = [] | ||||
83 | for tone in self.unique_tones: | ||||
84 | tones_objs_list.append(Tone(tone)) | ||||
85 | return tones_objs_list | ||||
77 | 86 | ||||
78 | def __init__(self, main_tone, *tones): | 87 | def __init__(self, main_tone, *tones): | ||
79 | self.main_tone = main_tone | 88 | self.main_tone = main_tone | ||
80 | self.unique_tones= set() | 89 | self.unique_tones= set() | ||
81 | self.sorted_tones = [] | 90 | self.sorted_tones = [] | ||
82 | self.unique_tones.add(main_tone.name) | 91 | self.unique_tones.add(main_tone.name) | ||
83 | for tone in tones: | 92 | for tone in tones: | ||
84 | self.unique_tones.add(tone.name) | 93 | self.unique_tones.add(tone.name) | ||
85 | 94 | ||||
86 | valid_len = len(self.unique_tones) | 95 | valid_len = len(self.unique_tones) | ||
87 | if valid_len <= 1: | 96 | if valid_len <= 1: | ||
n | 88 | raise TypeError(f"Cannot have a chord made of only {valid_len} unique tone") | n | 97 | raise TypeError("Cannot have a chord made of only 1 unique tone") |
89 | self.unique_tones.discard(main_tone.name) | 98 | self.unique_tones.discard(main_tone.name) | ||
90 | self.__init_sorted_tones() | 99 | self.__init_sorted_tones() | ||
91 | 100 | ||||
92 | def __add__(self, other): | 101 | def __add__(self, other): | ||
n | n | 102 | new_tones = self.uniques_to_list_objs_tones | ||
93 | if isinstance(other, Tone): | 103 | if isinstance(other, Tone): | ||
n | 94 | self.unique_tones.add(other.name) | n | 104 | new_tones.append(other) |
95 | if isinstance(other,Chord): | 105 | if isinstance(other,Chord): | ||
n | 96 | for tone_name in other.sorted_tones: | n | 106 | for tone in other.sorted_to_list_objs_tones: |
97 | self.unique_tones.add(tone_name) | 107 | new_tones.append(tone) | ||
98 | return self | 108 | return Chord(self.main_tone, *new_tones) | ||
99 | 109 | ||||
100 | 110 | ||||
101 | def __sub__(self, other): | 111 | def __sub__(self, other): | ||
n | 102 | if not other.name in self.sorted_tones: | n | 112 | if other.name not in self.sorted_tones: |
103 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 113 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
104 | if len(self.unique_tones) < 2: | 114 | if len(self.unique_tones) < 2: | ||
105 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 115 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
n | n | 116 | new_tones = self.sorted_to_list_objs_tones | ||
117 | main_tone = self.main_tone | ||||
106 | if isinstance(other, Tone): | 118 | if isinstance(other, Tone): | ||
n | 107 | if self.main_tone.name == other.name: | n | 119 | if main_tone.name == other.name: |
108 | self.main_tone = Tone(self.sorted_tones[0]) | 120 | main_tone = Tone(self.sorted_tones[0]) | ||
109 | self.unique_tones.discard(self.main_tone.name) | 121 | new_tones = filter(lambda tone: tone.name != main_tone.name, new_tones) | ||
110 | else: | 122 | else: | ||
n | 111 | self.unique_tones.discard(other.name) | n | 123 | new_tones = filter(lambda tone: tone.name != other.name, new_tones) |
112 | return self | 124 | return Chord(main_tone, *new_tones) | ||
113 | 125 | ||||
114 | def __str__(self): | 126 | def __str__(self): | ||
n | 115 | self.__init_sorted_tones() | n | ||
116 | return "-".join(self.sorted_tones) | 127 | return "-".join(self.sorted_tones) | ||
117 | 128 | ||||
118 | def is_minor(self): | 129 | def is_minor(self): | ||
n | 119 | main_index = self.main_tone.get_index() | n | 130 | main_index = self.main_tone.index |
120 | for tone_name in self.unique_tones: | 131 | for tone in self.uniques_to_list_objs_tones: | ||
121 | tone_index = Tone.get_index_for_name(tone_name) | ||||
122 | interval = Interval(abs(main_index - tone_index)) | 132 | interval = Interval(abs(main_index - tone.index)) | ||
123 | if str(interval) == "minor 3rd": | 133 | if str(interval) == "minor 3rd": | ||
124 | return True | 134 | return True | ||
125 | return False | 135 | return False | ||
126 | 136 | ||||
127 | def is_major(self): | 137 | def is_major(self): | ||
n | 128 | main_index = self.main_tone.get_index() | n | 138 | main_index = self.main_tone.index |
129 | for tone_name in self.unique_tones: | 139 | for tone in self.uniques_to_list_objs_tones: | ||
130 | tone_index = Tone.get_index_for_name(tone_name) | ||||
131 | interval = Interval(abs(main_index - tone_index)) | 140 | interval = Interval(abs(main_index - tone.index)) | ||
132 | if str(interval) == "major 3rd": | 141 | if str(interval) == "major 3rd": | ||
133 | return True | 142 | return True | ||
134 | return False | 143 | return False | ||
135 | 144 | ||||
136 | def is_power_chord(self): | 145 | def is_power_chord(self): | ||
137 | return not self.is_major() and not self.is_minor() | 146 | return not self.is_major() and not self.is_minor() | ||
138 | 147 | ||||
139 | def transposed(self, interval): | 148 | def transposed(self, interval): | ||
n | 140 | transposing = interval.lenght | n | 149 | transposed_tones = [tone + interval for tone in self.sorted_to_list_objs_tones] |
141 | transposed_tones = [] | 150 | |||
142 | tone_name_transposed = "" | 151 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
143 | for tone_name in self.sorted_tones: | ||||
144 | index = Tone.get_index_for_name(tone_name) | ||||
145 | if(transposing >= 0): | ||||
146 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | ||||
147 | else: | ||||
148 | if(index + transposing < 0): | ||||
149 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing + MAX_INDEX]) | ||||
150 | else: | ||||
151 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | ||||
152 | 152 | ||||
153 | 153 | ||||
t | 154 | transposed_tones.append(Tone(tone_name_transposed)) | t | ||
155 | |||||
156 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||||
157 | |||||
158 | |||||
159 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} | f | 1 | TONE_INDEX_DICT = {"C" : 0, "C#" : 1, "D" : 2, "D#" : 3, "E" : 4, "F" : 5, "F#" : 6, "G" : 7, "G#" : 8, "A" : 9, "A#" : 10, "B" : 11} |
2 | TONE_VALUE_DICT = {0 : "C", 1: "C#" , 2 : "D" , 3 : "D#" , 4 : "E" , 5 : "F" , 6 : "F#" , 7 : "G" , 8 : "G#" , 9 : "A" , 10 : "A#" , 11 : "B" } | 2 | TONE_VALUE_DICT = {0 : "C", 1: "C#" , 2 : "D" , 3 : "D#" , 4 : "E" , 5 : "F" , 6 : "F#" , 7 : "G" , 8 : "G#" , 9 : "A" , 10 : "A#" , 11 : "B" } | ||
3 | INTERVAL_VALUE_DICT = {0 : "unison", 1 : "minor 2nd", 2 : "major 2nd", 3 : "minor 3rd", 4 : "major 3rd", 5 : "perfect 4th", 6 : "diminished 5th", 7 : "perfect 5th", 8 : "minor 6th", 9 : "major 6th", 10 : "minor 7th", 11 : "major 7th"} | 3 | INTERVAL_VALUE_DICT = {0 : "unison", 1 : "minor 2nd", 2 : "major 2nd", 3 : "minor 3rd", 4 : "major 3rd", 5 : "perfect 4th", 6 : "diminished 5th", 7 : "perfect 5th", 8 : "minor 6th", 9 : "major 6th", 10 : "minor 7th", 11 : "major 7th"} | ||
4 | MAX_INDEX = 12 | 4 | MAX_INDEX = 12 | ||
5 | 5 | ||||
6 | class Tone: | 6 | class Tone: | ||
7 | def __init__(self, name): | 7 | def __init__(self, name): | ||
8 | self.name = name | 8 | self.name = name | ||
9 | 9 | ||||
10 | def __str__(self): | 10 | def __str__(self): | ||
11 | return f"{self.name}" | 11 | return f"{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 | if isinstance(other,Interval): | 16 | if isinstance(other,Interval): | ||
17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | 17 | total_len = other.lenght + TONE_INDEX_DICT[self.name] | ||
18 | correct_index = int(total_len / MAX_INDEX) | 18 | correct_index = int(total_len / MAX_INDEX) | ||
19 | correct_len = total_len - correct_index*MAX_INDEX | 19 | correct_len = total_len - correct_index*MAX_INDEX | ||
20 | return Tone(TONE_VALUE_DICT[correct_len]) | 20 | return Tone(TONE_VALUE_DICT[correct_len]) | ||
21 | 21 | ||||
22 | def __sub__(self, other): | 22 | def __sub__(self, other): | ||
23 | if isinstance(other,Tone): | 23 | if isinstance(other,Tone): | ||
24 | return Interval(abs(self.get_index()-other.get_index())) | 24 | return Interval(abs(self.get_index()-other.get_index())) | ||
25 | if isinstance(other,Interval): | 25 | if isinstance(other,Interval): | ||
26 | correct_index = int(other.lenght / MAX_INDEX) | 26 | correct_index = int(other.lenght / MAX_INDEX) | ||
27 | correct_len = other.lenght - correct_index*MAX_INDEX | 27 | correct_len = other.lenght - correct_index*MAX_INDEX | ||
28 | cur_index = TONE_INDEX_DICT[self.name] | 28 | cur_index = TONE_INDEX_DICT[self.name] | ||
29 | wanted_index = cur_index - correct_len + MAX_INDEX | 29 | wanted_index = cur_index - correct_len + MAX_INDEX | ||
30 | return TONE_VALUE_DICT[wanted_index] | 30 | return TONE_VALUE_DICT[wanted_index] | ||
31 | 31 | ||||
32 | def get_index(self): | 32 | def get_index(self): | ||
33 | return TONE_INDEX_DICT[self.name] | 33 | return TONE_INDEX_DICT[self.name] | ||
34 | 34 | ||||
35 | @staticmethod | 35 | @staticmethod | ||
36 | def get_index_for_name(name): | 36 | def get_index_for_name(name): | ||
37 | return TONE_INDEX_DICT[name] | 37 | return TONE_INDEX_DICT[name] | ||
38 | 38 | ||||
39 | 39 | ||||
40 | 40 | ||||
41 | class Interval: | 41 | class Interval: | ||
42 | def __init__(self, lenght): | 42 | def __init__(self, lenght): | ||
43 | self.lenght = lenght | 43 | self.lenght = lenght | ||
44 | 44 | ||||
45 | def __str__(self): | 45 | def __str__(self): | ||
46 | correct_index = int(self.lenght / MAX_INDEX) | 46 | correct_index = int(self.lenght / MAX_INDEX) | ||
47 | correct_len = self.lenght - correct_index*MAX_INDEX | 47 | correct_len = self.lenght - correct_index*MAX_INDEX | ||
48 | return INTERVAL_VALUE_DICT[correct_len] | 48 | return INTERVAL_VALUE_DICT[correct_len] | ||
49 | 49 | ||||
50 | def __add__(self,other): | 50 | def __add__(self,other): | ||
51 | if isinstance(other,Tone): | 51 | if isinstance(other,Tone): | ||
52 | raise TypeError("Invalid operation") | 52 | raise TypeError("Invalid operation") | ||
53 | if isinstance(other,Interval): | 53 | if isinstance(other,Interval): | ||
54 | total_len = self.lenght + other.lenght | 54 | total_len = self.lenght + other.lenght | ||
55 | correct_index = int(total_len / MAX_INDEX) | 55 | correct_index = int(total_len / MAX_INDEX) | ||
56 | correct_len = total_len - correct_index*MAX_INDEX | 56 | correct_len = total_len - correct_index*MAX_INDEX | ||
57 | return INTERVAL_VALUE_DICT[correct_len] | 57 | return INTERVAL_VALUE_DICT[correct_len] | ||
58 | 58 | ||||
59 | def __sub__(self,other): | 59 | def __sub__(self,other): | ||
60 | if isinstance(other,Tone): | 60 | if isinstance(other,Tone): | ||
61 | raise TypeError("Invalid operation") | 61 | raise TypeError("Invalid operation") | ||
62 | 62 | ||||
63 | def __neg__(self): | 63 | def __neg__(self): | ||
64 | return Interval(-self.lenght) | 64 | return Interval(-self.lenght) | ||
65 | 65 | ||||
66 | class Chord: | 66 | class Chord: | ||
67 | def __init_sorted_tones(self): | 67 | def __init_sorted_tones(self): | ||
68 | main_index = self.main_tone.get_index() | 68 | main_index = self.main_tone.get_index() | ||
69 | tones_dict = {self.main_tone.name : main_index} | 69 | tones_dict = {self.main_tone.name : main_index} | ||
70 | for tone_name in self.unique_tones: | 70 | for tone_name in self.unique_tones: | ||
71 | tone_index = Tone.get_index_for_name(tone_name) | 71 | tone_index = Tone.get_index_for_name(tone_name) | ||
72 | if main_index > tone_index: | 72 | if main_index > tone_index: | ||
73 | tones_dict[tone_name] = tone_index + 10 | 73 | tones_dict[tone_name] = tone_index + 10 | ||
74 | else: | 74 | else: | ||
75 | tones_dict[tone_name] = tone_index | 75 | tones_dict[tone_name] = tone_index | ||
76 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | 76 | self.sorted_tones = [key for key, value in sorted(tones_dict.items(), key=lambda item: item[1])] | ||
77 | 77 | ||||
78 | def __init__(self, main_tone, *tones): | 78 | def __init__(self, main_tone, *tones): | ||
79 | self.main_tone = main_tone | 79 | self.main_tone = main_tone | ||
80 | self.unique_tones= set() | 80 | self.unique_tones= set() | ||
81 | self.sorted_tones = [] | 81 | self.sorted_tones = [] | ||
82 | self.unique_tones.add(main_tone.name) | 82 | self.unique_tones.add(main_tone.name) | ||
83 | for tone in tones: | 83 | for tone in tones: | ||
84 | self.unique_tones.add(tone.name) | 84 | self.unique_tones.add(tone.name) | ||
85 | 85 | ||||
86 | valid_len = len(self.unique_tones) | 86 | valid_len = len(self.unique_tones) | ||
87 | if valid_len <= 1: | 87 | if valid_len <= 1: | ||
88 | raise TypeError(f"Cannot have a chord made of only {valid_len} unique tone") | 88 | raise TypeError(f"Cannot have a chord made of only {valid_len} unique tone") | ||
89 | self.unique_tones.discard(main_tone.name) | 89 | self.unique_tones.discard(main_tone.name) | ||
90 | self.__init_sorted_tones() | 90 | self.__init_sorted_tones() | ||
91 | 91 | ||||
92 | def __add__(self, other): | 92 | def __add__(self, other): | ||
93 | if isinstance(other, Tone): | 93 | if isinstance(other, Tone): | ||
94 | self.unique_tones.add(other.name) | 94 | self.unique_tones.add(other.name) | ||
95 | if isinstance(other,Chord): | 95 | if isinstance(other,Chord): | ||
96 | for tone_name in other.sorted_tones: | 96 | for tone_name in other.sorted_tones: | ||
97 | self.unique_tones.add(tone_name) | 97 | self.unique_tones.add(tone_name) | ||
98 | return self | 98 | return self | ||
99 | 99 | ||||
100 | 100 | ||||
101 | def __sub__(self, other): | 101 | def __sub__(self, other): | ||
102 | if not other.name in self.sorted_tones: | 102 | if not other.name in self.sorted_tones: | ||
103 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | 103 | raise TypeError(f"Cannot remove tone {other.name} from chord {self}") | ||
104 | if len(self.unique_tones) < 2: | 104 | if len(self.unique_tones) < 2: | ||
105 | raise TypeError("Cannot have a chord made of only 1 unique tone") | 105 | raise TypeError("Cannot have a chord made of only 1 unique tone") | ||
106 | if isinstance(other, Tone): | 106 | if isinstance(other, Tone): | ||
107 | if self.main_tone.name == other.name: | 107 | if self.main_tone.name == other.name: | ||
108 | self.main_tone = Tone(self.sorted_tones[0]) | 108 | self.main_tone = Tone(self.sorted_tones[0]) | ||
109 | self.unique_tones.discard(self.main_tone.name) | 109 | self.unique_tones.discard(self.main_tone.name) | ||
110 | else: | 110 | else: | ||
111 | self.unique_tones.discard(other.name) | 111 | self.unique_tones.discard(other.name) | ||
112 | return self | 112 | return self | ||
113 | 113 | ||||
114 | def __str__(self): | 114 | def __str__(self): | ||
115 | self.__init_sorted_tones() | 115 | self.__init_sorted_tones() | ||
116 | return "-".join(self.sorted_tones) | 116 | return "-".join(self.sorted_tones) | ||
117 | 117 | ||||
118 | def is_minor(self): | 118 | def is_minor(self): | ||
119 | main_index = self.main_tone.get_index() | 119 | main_index = self.main_tone.get_index() | ||
120 | for tone_name in self.unique_tones: | 120 | for tone_name in self.unique_tones: | ||
121 | tone_index = Tone.get_index_for_name(tone_name) | 121 | tone_index = Tone.get_index_for_name(tone_name) | ||
122 | interval = Interval(abs(main_index - tone_index)) | 122 | interval = Interval(abs(main_index - tone_index)) | ||
123 | if str(interval) == "minor 3rd": | 123 | if str(interval) == "minor 3rd": | ||
124 | return True | 124 | return True | ||
125 | return False | 125 | return False | ||
126 | 126 | ||||
127 | def is_major(self): | 127 | def is_major(self): | ||
128 | main_index = self.main_tone.get_index() | 128 | main_index = self.main_tone.get_index() | ||
129 | for tone_name in self.unique_tones: | 129 | for tone_name in self.unique_tones: | ||
130 | tone_index = Tone.get_index_for_name(tone_name) | 130 | tone_index = Tone.get_index_for_name(tone_name) | ||
131 | interval = Interval(abs(main_index - tone_index)) | 131 | interval = Interval(abs(main_index - tone_index)) | ||
132 | if str(interval) == "major 3rd": | 132 | if str(interval) == "major 3rd": | ||
133 | return True | 133 | return True | ||
134 | return False | 134 | return False | ||
135 | 135 | ||||
136 | def is_power_chord(self): | 136 | def is_power_chord(self): | ||
137 | return not self.is_major() and not self.is_minor() | 137 | return not self.is_major() and not self.is_minor() | ||
138 | 138 | ||||
t | 139 | def transposed(self,interval): | t | 139 | def transposed(self, interval): |
140 | transposing = interval.lenght | 140 | transposing = interval.lenght | ||
141 | transposed_tones = [] | 141 | transposed_tones = [] | ||
142 | tone_name_transposed = "" | 142 | tone_name_transposed = "" | ||
143 | for tone_name in self.sorted_tones: | 143 | for tone_name in self.sorted_tones: | ||
144 | index = Tone.get_index_for_name(tone_name) | 144 | index = Tone.get_index_for_name(tone_name) | ||
145 | if(transposing >= 0): | 145 | if(transposing >= 0): | ||
146 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | 146 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | ||
147 | else: | 147 | else: | ||
148 | if(index + transposing < 0): | 148 | if(index + transposing < 0): | ||
149 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing + MAX_INDEX]) | 149 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing + MAX_INDEX]) | ||
150 | else: | 150 | else: | ||
151 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | 151 | tone_name_transposed = (TONE_VALUE_DICT[index + transposing]) | ||
152 | 152 | ||||
153 | 153 | ||||
154 | transposed_tones.append(Tone(tone_name_transposed)) | 154 | transposed_tones.append(Tone(tone_name_transposed)) | ||
155 | 155 | ||||
156 | return Chord(transposed_tones[0], *transposed_tones[1:]) | 156 | return Chord(transposed_tones[0], *transposed_tones[1:]) | ||
157 | 157 | ||||
158 | 158 | ||||
159 | 159 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|