Домашни > Pitches love the D > Решения > Решението на Павел Петков

Резултати
9 точки от тестове
0 точки от учител

9 точки общо

35 успешни теста
2 неуспешни теста
Код
Скрий всички коментари

  1NUMBER_OF_SEMITONES_TO_STR = {
  2    0: "unison",
  3    1: "minor 2nd",
  4    2: "major 2nd",
  5    3: "minor 3rd",
  6    4: "major 3rd",
  7    5: "perfect 4th",
  8    6: "diminished 5th",
  9    7: "perfect 5th",
 10    8: "minor 6th",
 11    9: "major 6th",
 12    10: "minor 7th",
 13    11: "major 7th"
 14}
 15INDEX_TO_TONE_STR = {
 16    0: "C",
 17    1: "C#",
 18    2: "D",
 19    3: "D#",
 20    4: "E",
 21    5: "F",
 22    6: "F#",
 23    7: "G",
 24    8: "G#",
 25    9: "A",
 26    10: "A#",
 27    11: "B",
 28}
 29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}
 30TONES_COUNT = 12
 31MINOR_THIRD_INDEX = 3
 32MAJOR_THIRD_INDEX = 4
 33
 34
 35class Tone:
 36
 37    def __init__(self, tone_str: str):
 38        self.__tone_str = tone_str
 39
 40    def __str__(self):
 41        return self.__tone_str
 42
 43    def __hash__(self):
 44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)
 45
 46    def __eq__(self, other):
 47        if isinstance(other, Tone):
 48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)
 49
 50    def __sub__(self, other):
 51        if isinstance(other, Tone):
 52            if self.get_tone_index() > other.get_tone_index():
 53                return Interval(self.get_tone_index() - other.get_tone_index())
 54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())
 55        elif isinstance(other, Interval):
 56            return self + (-other)
 57
 58    def __add__(self, other):
 59        if isinstance(other, Tone):
 60            return Chord(self, other)
 61        elif isinstance(other, Interval):
 62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT
 63            return Tone(INDEX_TO_TONE_STR[index])
 64
 65    @property
 66    def tone_str(self):
 67        return self.__tone_str
 68
 69    def get_tone_index(self):
 70        return TONE_STR_TO_INDEX[self.__tone_str]
 71
 72
 73class Interval:
 74
 75    def __init__(self, number_of_semitones: int):
 76        self.__number_of_semitones = number_of_semitones % TONES_COUNT
 77
 78    def __neg__(self):
 79        return Interval(-self.__number_of_semitones)
 80
 81    def __str__(self):
 82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]
 83
 84    def __add__(self, other):
 85        if isinstance(other, Interval):
 86            return Interval(self.number_of_semitones + other.number_of_semitones)
 87        elif isinstance(other, Tone):
 88            raise TypeError("Invalid operation")
 89
 90    def __sub__(self, other):
 91        if isinstance(other, Tone):
 92            raise TypeError("Invalid operation")
 93
 94    @property
 95    def number_of_semitones(self):
 96        return self.__number_of_semitones
 97
 98
 99class Chord:
100    def __init__(self, root: Tone, *args: [Tone]):
101        self.__root = root
102        self.__initialise_tones(args)
103
104    def __str__(self):
105        return "-".join(map(str, [self.__root, *self.__tones]))
106
107    def __sub__(self, other):
108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):
109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")
110
111        if other.get_tone_index() == self.__root.get_tone_index():
112            return Chord(self.__tones[0], *self.__tones[1:])
113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))
114
115    def __add__(self, other):
116        if isinstance(other, Tone):
117            return Chord(self.__root, *self.__tones, other)
118        elif isinstance(other, Chord):
119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)
120
121    def __initialise_tones(self, new_tones: [Tone]):
122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))
123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered
124
125        if len(new_tones) == 0:
126            raise TypeError("Cannot have a chord made of only 1 unique tone")
127
128        pivot = self.__root.get_tone_index()
129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))
130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))
131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))
132        self.__tones = [*upper_bound, *lower_bound]
133
134    def is_minor(self) -> bool:
135        return self.__seek_for_interval(MINOR_THIRD_INDEX)
136
137    def is_major(self) -> bool:
138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)
139
140    def is_power_chord(self) -> bool:
141        return not self.is_major() and not self.is_minor()
142
143    def __seek_for_interval(self, number_of_semitones: int) -> bool:
144        for tone in self.__tones:
145            current_interval = tone - self.__root
146            if current_interval.number_of_semitones == number_of_semitones:
147                return True
148        return False
149
150    def transposed(self, interval: Interval):
151        new_root = self.__root + interval
152        new_tones = [tone + interval for tone in self.__tones]
153        return Chord(new_root, *new_tones)

....F.F..............................
======================================================================
FAIL: test_is_major (test.TestBasicChordFunctionality.test_is_major)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 107, in test_is_major
self.assertTrue(a_major_chord.is_major())
AssertionError: False is not true

======================================================================
FAIL: test_is_power_chord (test.TestBasicChordFunctionality.test_is_power_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 120, in test_is_power_chord
self.assertFalse(a_major_chord.is_power_chord())
AssertionError: True is not false

----------------------------------------------------------------------
Ran 37 tests in 0.002s

FAILED (failures=2)

Дискусия
Георги Кунчев
04.11.2024 14:12

В Python обикновено сме по-консервативни от гледна точка на това. Правейки ги protected с една долна черта е достатъчно да "кажеш" на останалите да не го закачат. Ако пък нещо е публично, то следва класът ти да е написан така, че да е ок със ситуация, в която се сменя извън класа. Твоят клас `Tone` например е напълно валиден, дори някой да бръкне и да смени `__tone_str` отвън. Всичко ще работи. Иначе, ако наистина имаш полета, за които не можеш да гарантираш, че външна промяна няма да доведе до проблем, но искаш да може да се достъпва, подходът с `@property` е валиден и подходящ.
Павел Петков
04.11.2024 14:05

A гетърите съм ги написал, защото искам да не може да се променят член данните извън класа, а само вътре в него и в същото време да се взимат(ясно е ,че никой не ползва name-mangling)
Георги Кунчев
04.11.2024 13:46

Ясно. Мога да предложа да направиш така, че pivot да е индекса, имайки предвид, че `ordered_tones` се очаква да са подредени и `ordered_tones.index(pivot)` ще ти даде индекса, по който да направиш същата операция, но не съм сигурен, че това, което очаквам в тези колекции спрямо имената им, е това, което всъщност е там, затова не искам да рискувам да те подведа. От теб зависи дали ще си поиграеш да го опростиш.
Павел Петков
04.11.2024 13:08

Проблема е , че pivot = self.__root.get_tone_index() не връща индекс в масива , а каква числова репрезентация има от 0 до 11, съответно това с slice-а няма как да работи
История

f1NUMBER_OF_SEMITONES_TO_STR = {f1NUMBER_OF_SEMITONES_TO_STR = {
2    0: "unison",2    0: "unison",
3    1: "minor 2nd",3    1: "minor 2nd",
4    2: "major 2nd",4    2: "major 2nd",
5    3: "minor 3rd",5    3: "minor 3rd",
6    4: "major 3rd",6    4: "major 3rd",
7    5: "perfect 4th",7    5: "perfect 4th",
8    6: "diminished 5th",8    6: "diminished 5th",
9    7: "perfect 5th",9    7: "perfect 5th",
10    8: "minor 6th",10    8: "minor 6th",
11    9: "major 6th",11    9: "major 6th",
12    10: "minor 7th",12    10: "minor 7th",
13    11: "major 7th"13    11: "major 7th"
14}14}
15INDEX_TO_TONE_STR = {15INDEX_TO_TONE_STR = {
16    0: "C",16    0: "C",
17    1: "C#",17    1: "C#",
18    2: "D",18    2: "D",
19    3: "D#",19    3: "D#",
20    4: "E",20    4: "E",
21    5: "F",21    5: "F",
22    6: "F#",22    6: "F#",
23    7: "G",23    7: "G",
24    8: "G#",24    8: "G#",
25    9: "A",25    9: "A",
26    10: "A#",26    10: "A#",
27    11: "B",27    11: "B",
28}28}
29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}
30TONES_COUNT = 1230TONES_COUNT = 12
31MINOR_THIRD_INDEX = 331MINOR_THIRD_INDEX = 3
32MAJOR_THIRD_INDEX = 432MAJOR_THIRD_INDEX = 4
3333
3434
35class Tone:35class Tone:
3636
37    def __init__(self, tone_str: str):37    def __init__(self, tone_str: str):
38        self.__tone_str = tone_str38        self.__tone_str = tone_str
3939
40    def __str__(self):40    def __str__(self):
41        return self.__tone_str41        return self.__tone_str
4242
43    def __hash__(self):43    def __hash__(self):
44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)
4545
46    def __eq__(self, other):46    def __eq__(self, other):
47        if isinstance(other, Tone):47        if isinstance(other, Tone):
48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)
4949
50    def __sub__(self, other):50    def __sub__(self, other):
51        if isinstance(other, Tone):51        if isinstance(other, Tone):
52            if self.get_tone_index() > other.get_tone_index():52            if self.get_tone_index() > other.get_tone_index():
53                return Interval(self.get_tone_index() - other.get_tone_index())53                return Interval(self.get_tone_index() - other.get_tone_index())
54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())
55        elif isinstance(other, Interval):55        elif isinstance(other, Interval):
56            return self + (-other)56            return self + (-other)
5757
58    def __add__(self, other):58    def __add__(self, other):
59        if isinstance(other, Tone):59        if isinstance(other, Tone):
60            return Chord(self, other)60            return Chord(self, other)
61        elif isinstance(other, Interval):61        elif isinstance(other, Interval):
62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT
63            return Tone(INDEX_TO_TONE_STR[index])63            return Tone(INDEX_TO_TONE_STR[index])
6464
65    @property65    @property
66    def tone_str(self):66    def tone_str(self):
67        return self.__tone_str67        return self.__tone_str
6868
69    def get_tone_index(self):69    def get_tone_index(self):
70        return TONE_STR_TO_INDEX[self.__tone_str]70        return TONE_STR_TO_INDEX[self.__tone_str]
7171
7272
73class Interval:73class Interval:
7474
75    def __init__(self, number_of_semitones: int):75    def __init__(self, number_of_semitones: int):
76        self.__number_of_semitones = number_of_semitones % TONES_COUNT76        self.__number_of_semitones = number_of_semitones % TONES_COUNT
7777
78    def __neg__(self):78    def __neg__(self):
79        return Interval(-self.__number_of_semitones)79        return Interval(-self.__number_of_semitones)
8080
81    def __str__(self):81    def __str__(self):
82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]
8383
84    def __add__(self, other):84    def __add__(self, other):
85        if isinstance(other, Interval):85        if isinstance(other, Interval):
86            return Interval(self.number_of_semitones + other.number_of_semitones)86            return Interval(self.number_of_semitones + other.number_of_semitones)
87        elif isinstance(other, Tone):87        elif isinstance(other, Tone):
88            raise TypeError("Invalid operation")88            raise TypeError("Invalid operation")
8989
90    def __sub__(self, other):90    def __sub__(self, other):
91        if isinstance(other, Tone):91        if isinstance(other, Tone):
92            raise TypeError("Invalid operation")92            raise TypeError("Invalid operation")
9393
94    @property94    @property
95    def number_of_semitones(self):95    def number_of_semitones(self):
96        return self.__number_of_semitones96        return self.__number_of_semitones
9797
9898
99class Chord:99class Chord:
100    def __init__(self, root: Tone, *args: [Tone]):100    def __init__(self, root: Tone, *args: [Tone]):
101        self.__root = root101        self.__root = root
102        self.__initialise_tones(args)102        self.__initialise_tones(args)
103103
104    def __str__(self):104    def __str__(self):
105        return "-".join(map(str, [self.__root, *self.__tones]))105        return "-".join(map(str, [self.__root, *self.__tones]))
106106
107    def __sub__(self, other):107    def __sub__(self, other):
108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):
109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")
110110
111        if other.get_tone_index() == self.__root.get_tone_index():111        if other.get_tone_index() == self.__root.get_tone_index():
t112            return Chord(self.__tones[0], self.__tones[1:])t112            return Chord(self.__tones[0], *self.__tones[1:])
113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))
114114
115    def __add__(self, other):115    def __add__(self, other):
116        if isinstance(other, Tone):116        if isinstance(other, Tone):
117            return Chord(self.__root, *self.__tones, other)117            return Chord(self.__root, *self.__tones, other)
118        elif isinstance(other, Chord):118        elif isinstance(other, Chord):
119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)
120120
121    def __initialise_tones(self, new_tones: [Tone]):121    def __initialise_tones(self, new_tones: [Tone]):
122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))
123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered
124124
125        if len(new_tones) == 0:125        if len(new_tones) == 0:
126            raise TypeError("Cannot have a chord made of only 1 unique tone")126            raise TypeError("Cannot have a chord made of only 1 unique tone")
127127
128        pivot = self.__root.get_tone_index()128        pivot = self.__root.get_tone_index()
129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))
130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))
131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))
132        self.__tones = [*upper_bound, *lower_bound]132        self.__tones = [*upper_bound, *lower_bound]
133133
134    def is_minor(self) -> bool:134    def is_minor(self) -> bool:
135        return self.__seek_for_interval(MINOR_THIRD_INDEX)135        return self.__seek_for_interval(MINOR_THIRD_INDEX)
136136
137    def is_major(self) -> bool:137    def is_major(self) -> bool:
138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)
139139
140    def is_power_chord(self) -> bool:140    def is_power_chord(self) -> bool:
141        return not self.is_major() and not self.is_minor()141        return not self.is_major() and not self.is_minor()
142142
143    def __seek_for_interval(self, number_of_semitones: int) -> bool:143    def __seek_for_interval(self, number_of_semitones: int) -> bool:
144        for tone in self.__tones:144        for tone in self.__tones:
145            current_interval = tone - self.__root145            current_interval = tone - self.__root
146            if current_interval.number_of_semitones == number_of_semitones:146            if current_interval.number_of_semitones == number_of_semitones:
147                return True147                return True
148        return False148        return False
149149
150    def transposed(self, interval: Interval):150    def transposed(self, interval: Interval):
151        new_root = self.__root + interval151        new_root = self.__root + interval
152        new_tones = [tone + interval for tone in self.__tones]152        new_tones = [tone + interval for tone in self.__tones]
153        return Chord(new_root, *new_tones)153        return Chord(new_root, *new_tones)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1NUMBER_OF_SEMITONES_TO_STR = {f1NUMBER_OF_SEMITONES_TO_STR = {
2    0: "unison",2    0: "unison",
3    1: "minor 2nd",3    1: "minor 2nd",
4    2: "major 2nd",4    2: "major 2nd",
5    3: "minor 3rd",5    3: "minor 3rd",
6    4: "major 3rd",6    4: "major 3rd",
7    5: "perfect 4th",7    5: "perfect 4th",
8    6: "diminished 5th",8    6: "diminished 5th",
9    7: "perfect 5th",9    7: "perfect 5th",
10    8: "minor 6th",10    8: "minor 6th",
11    9: "major 6th",11    9: "major 6th",
12    10: "minor 7th",12    10: "minor 7th",
13    11: "major 7th"13    11: "major 7th"
14}14}
15INDEX_TO_TONE_STR = {15INDEX_TO_TONE_STR = {
16    0: "C",16    0: "C",
17    1: "C#",17    1: "C#",
18    2: "D",18    2: "D",
19    3: "D#",19    3: "D#",
20    4: "E",20    4: "E",
21    5: "F",21    5: "F",
22    6: "F#",22    6: "F#",
23    7: "G",23    7: "G",
24    8: "G#",24    8: "G#",
25    9: "A",25    9: "A",
26    10: "A#",26    10: "A#",
27    11: "B",27    11: "B",
28}28}
29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}
30TONES_COUNT = 1230TONES_COUNT = 12
31MINOR_THIRD_INDEX = 331MINOR_THIRD_INDEX = 3
32MAJOR_THIRD_INDEX = 432MAJOR_THIRD_INDEX = 4
3333
3434
35class Tone:35class Tone:
3636
37    def __init__(self, tone_str: str):37    def __init__(self, tone_str: str):
38        self.__tone_str = tone_str38        self.__tone_str = tone_str
3939
40    def __str__(self):40    def __str__(self):
41        return self.__tone_str41        return self.__tone_str
4242
43    def __hash__(self):43    def __hash__(self):
44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)
4545
46    def __eq__(self, other):46    def __eq__(self, other):
47        if isinstance(other, Tone):47        if isinstance(other, Tone):
48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)
4949
50    def __sub__(self, other):50    def __sub__(self, other):
51        if isinstance(other, Tone):51        if isinstance(other, Tone):
52            if self.get_tone_index() > other.get_tone_index():52            if self.get_tone_index() > other.get_tone_index():
53                return Interval(self.get_tone_index() - other.get_tone_index())53                return Interval(self.get_tone_index() - other.get_tone_index())
54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())
55        elif isinstance(other, Interval):55        elif isinstance(other, Interval):
56            return self + (-other)56            return self + (-other)
5757
58    def __add__(self, other):58    def __add__(self, other):
59        if isinstance(other, Tone):59        if isinstance(other, Tone):
60            return Chord(self, other)60            return Chord(self, other)
61        elif isinstance(other, Interval):61        elif isinstance(other, Interval):
62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT
63            return Tone(INDEX_TO_TONE_STR[index])63            return Tone(INDEX_TO_TONE_STR[index])
6464
65    @property65    @property
66    def tone_str(self):66    def tone_str(self):
67        return self.__tone_str67        return self.__tone_str
6868
69    def get_tone_index(self):69    def get_tone_index(self):
70        return TONE_STR_TO_INDEX[self.__tone_str]70        return TONE_STR_TO_INDEX[self.__tone_str]
7171
7272
73class Interval:73class Interval:
7474
75    def __init__(self, number_of_semitones: int):75    def __init__(self, number_of_semitones: int):
76        self.__number_of_semitones = number_of_semitones % TONES_COUNT76        self.__number_of_semitones = number_of_semitones % TONES_COUNT
7777
78    def __neg__(self):78    def __neg__(self):
79        return Interval(-self.__number_of_semitones)79        return Interval(-self.__number_of_semitones)
8080
81    def __str__(self):81    def __str__(self):
82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]
8383
84    def __add__(self, other):84    def __add__(self, other):
85        if isinstance(other, Interval):85        if isinstance(other, Interval):
86            return Interval(self.number_of_semitones + other.number_of_semitones)86            return Interval(self.number_of_semitones + other.number_of_semitones)
87        elif isinstance(other, Tone):87        elif isinstance(other, Tone):
88            raise TypeError("Invalid operation")88            raise TypeError("Invalid operation")
8989
90    def __sub__(self, other):90    def __sub__(self, other):
91        if isinstance(other, Tone):91        if isinstance(other, Tone):
92            raise TypeError("Invalid operation")92            raise TypeError("Invalid operation")
9393
94    @property94    @property
95    def number_of_semitones(self):95    def number_of_semitones(self):
96        return self.__number_of_semitones96        return self.__number_of_semitones
9797
9898
99class Chord:99class Chord:
100    def __init__(self, root: Tone, *args: [Tone]):100    def __init__(self, root: Tone, *args: [Tone]):
101        self.__root = root101        self.__root = root
102        self.__initialise_tones(args)102        self.__initialise_tones(args)
103103
104    def __str__(self):104    def __str__(self):
105        return "-".join(map(str, [self.__root, *self.__tones]))105        return "-".join(map(str, [self.__root, *self.__tones]))
106106
107    def __sub__(self, other):107    def __sub__(self, other):
108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):
109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")
110110
111        if other.get_tone_index() == self.__root.get_tone_index():111        if other.get_tone_index() == self.__root.get_tone_index():
112            return Chord(self.__tones[0], self.__tones[1:])112            return Chord(self.__tones[0], self.__tones[1:])
113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))
114114
115    def __add__(self, other):115    def __add__(self, other):
116        if isinstance(other, Tone):116        if isinstance(other, Tone):
117            return Chord(self.__root, *self.__tones, other)117            return Chord(self.__root, *self.__tones, other)
118        elif isinstance(other, Chord):118        elif isinstance(other, Chord):
119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)
120120
121    def __initialise_tones(self, new_tones: [Tone]):121    def __initialise_tones(self, new_tones: [Tone]):
122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))
123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered
124124
125        if len(new_tones) == 0:125        if len(new_tones) == 0:
t126            raise ValueError("Cannot have a chord made of only 1 unique tone")t126            raise TypeError("Cannot have a chord made of only 1 unique tone")
127127
128        pivot = self.__root.get_tone_index()128        pivot = self.__root.get_tone_index()
129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))
130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))
131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))
132        self.__tones = [*upper_bound, *lower_bound]132        self.__tones = [*upper_bound, *lower_bound]
133133
134    def is_minor(self) -> bool:134    def is_minor(self) -> bool:
135        return self.__seek_for_interval(MINOR_THIRD_INDEX)135        return self.__seek_for_interval(MINOR_THIRD_INDEX)
136136
137    def is_major(self) -> bool:137    def is_major(self) -> bool:
138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)
139139
140    def is_power_chord(self) -> bool:140    def is_power_chord(self) -> bool:
141        return not self.is_major() and not self.is_minor()141        return not self.is_major() and not self.is_minor()
142142
143    def __seek_for_interval(self, number_of_semitones: int) -> bool:143    def __seek_for_interval(self, number_of_semitones: int) -> bool:
144        for tone in self.__tones:144        for tone in self.__tones:
145            current_interval = tone - self.__root145            current_interval = tone - self.__root
146            if current_interval.number_of_semitones == number_of_semitones:146            if current_interval.number_of_semitones == number_of_semitones:
147                return True147                return True
148        return False148        return False
149149
150    def transposed(self, interval: Interval):150    def transposed(self, interval: Interval):
151        new_root = self.__root + interval151        new_root = self.__root + interval
152        new_tones = [tone + interval for tone in self.__tones]152        new_tones = [tone + interval for tone in self.__tones]
153        return Chord(new_root, *new_tones)153        return Chord(new_root, *new_tones)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1NUMBER_OF_SEMITONES_TO_STR = {f1NUMBER_OF_SEMITONES_TO_STR = {
2    0: "unison",2    0: "unison",
3    1: "minor 2nd",3    1: "minor 2nd",
4    2: "major 2nd",4    2: "major 2nd",
5    3: "minor 3rd",5    3: "minor 3rd",
6    4: "major 3rd",6    4: "major 3rd",
7    5: "perfect 4th",7    5: "perfect 4th",
8    6: "diminished 5th",8    6: "diminished 5th",
9    7: "perfect 5th",9    7: "perfect 5th",
10    8: "minor 6th",10    8: "minor 6th",
11    9: "major 6th",11    9: "major 6th",
12    10: "minor 7th",12    10: "minor 7th",
13    11: "major 7th"13    11: "major 7th"
14}14}
15INDEX_TO_TONE_STR = {15INDEX_TO_TONE_STR = {
16    0: "C",16    0: "C",
17    1: "C#",17    1: "C#",
18    2: "D",18    2: "D",
19    3: "D#",19    3: "D#",
20    4: "E",20    4: "E",
21    5: "F",21    5: "F",
22    6: "F#",22    6: "F#",
23    7: "G",23    7: "G",
24    8: "G#",24    8: "G#",
25    9: "A",25    9: "A",
26    10: "A#",26    10: "A#",
27    11: "B",27    11: "B",
28}28}
29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}
30TONES_COUNT = 1230TONES_COUNT = 12
31MINOR_THIRD_INDEX = 331MINOR_THIRD_INDEX = 3
32MAJOR_THIRD_INDEX = 432MAJOR_THIRD_INDEX = 4
3333
3434
35class Tone:35class Tone:
3636
37    def __init__(self, tone_str: str):37    def __init__(self, tone_str: str):
38        self.__tone_str = tone_str38        self.__tone_str = tone_str
3939
40    def __str__(self):40    def __str__(self):
41        return self.__tone_str41        return self.__tone_str
4242
43    def __hash__(self):43    def __hash__(self):
44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)
4545
46    def __eq__(self, other):46    def __eq__(self, other):
47        if isinstance(other, Tone):47        if isinstance(other, Tone):
48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)
4949
50    def __sub__(self, other):50    def __sub__(self, other):
51        if isinstance(other, Tone):51        if isinstance(other, Tone):
52            if self.get_tone_index() > other.get_tone_index():52            if self.get_tone_index() > other.get_tone_index():
53                return Interval(self.get_tone_index() - other.get_tone_index())53                return Interval(self.get_tone_index() - other.get_tone_index())
54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())
55        elif isinstance(other, Interval):55        elif isinstance(other, Interval):
56            return self + (-other)56            return self + (-other)
5757
58    def __add__(self, other):58    def __add__(self, other):
59        if isinstance(other, Tone):59        if isinstance(other, Tone):
60            return Chord(self, other)60            return Chord(self, other)
61        elif isinstance(other, Interval):61        elif isinstance(other, Interval):
62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT
63            return Tone(INDEX_TO_TONE_STR[index])63            return Tone(INDEX_TO_TONE_STR[index])
6464
65    @property65    @property
66    def tone_str(self):66    def tone_str(self):
67        return self.__tone_str67        return self.__tone_str
6868
69    def get_tone_index(self):69    def get_tone_index(self):
70        return TONE_STR_TO_INDEX[self.__tone_str]70        return TONE_STR_TO_INDEX[self.__tone_str]
7171
7272
73class Interval:73class Interval:
7474
75    def __init__(self, number_of_semitones: int):75    def __init__(self, number_of_semitones: int):
76        self.__number_of_semitones = number_of_semitones % TONES_COUNT76        self.__number_of_semitones = number_of_semitones % TONES_COUNT
7777
78    def __neg__(self):78    def __neg__(self):
79        return Interval(-self.__number_of_semitones)79        return Interval(-self.__number_of_semitones)
8080
81    def __str__(self):81    def __str__(self):
82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]
8383
84    def __add__(self, other):84    def __add__(self, other):
85        if isinstance(other, Interval):85        if isinstance(other, Interval):
86            return Interval(self.number_of_semitones + other.number_of_semitones)86            return Interval(self.number_of_semitones + other.number_of_semitones)
87        elif isinstance(other, Tone):87        elif isinstance(other, Tone):
88            raise TypeError("Invalid operation")88            raise TypeError("Invalid operation")
8989
90    def __sub__(self, other):90    def __sub__(self, other):
91        if isinstance(other, Tone):91        if isinstance(other, Tone):
92            raise TypeError("Invalid operation")92            raise TypeError("Invalid operation")
9393
94    @property94    @property
95    def number_of_semitones(self):95    def number_of_semitones(self):
96        return self.__number_of_semitones96        return self.__number_of_semitones
9797
9898
99class Chord:99class Chord:
100    def __init__(self, root: Tone, *args: [Tone]):100    def __init__(self, root: Tone, *args: [Tone]):
101        self.__root = root101        self.__root = root
102        self.__initialise_tones(args)102        self.__initialise_tones(args)
103103
104    def __str__(self):104    def __str__(self):
n105        return "-".join(map(str, [self.root, *self.tones]))n105        return "-".join(map(str, [self.__root, *self.__tones]))
106106
107    def __sub__(self, other):107    def __sub__(self, other):
n108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.tones] + [self.root.get_tone_index()]):n108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.__tones] + [self.__root.get_tone_index()]):
109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")
110110
n111        if other.get_tone_index() == self.root.get_tone_index():n111        if other.get_tone_index() == self.__root.get_tone_index():
112            return Chord(self.tones[0], self.tones[1:])112            return Chord(self.__tones[0], self.__tones[1:])
113        return Chord(self.root, *list(filter(lambda cur: str(cur) != str(other), self.tones)))113        return Chord(self.__root, *list(filter(lambda cur: str(cur) != str(other), self.__tones)))
114114
115    def __add__(self, other):115    def __add__(self, other):
116        if isinstance(other, Tone):116        if isinstance(other, Tone):
n117            return Chord(self.root, *self.tones, other)n117            return Chord(self.__root, *self.__tones, other)
118        elif isinstance(other, Chord):118        elif isinstance(other, Chord):
n119            return Chord(self.root, *self.tones, other.root, *other.tones)n119            return Chord(self.__root, *self.__tones, other.__root, *other.__tones)
120 
121    @property
122    def tones(self):
123        return self.__tones.copy()
124 
125    @property
126    def root(self):
127        return self.__root
128120
129    def __initialise_tones(self, new_tones: [Tone]):121    def __initialise_tones(self, new_tones: [Tone]):
130        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))122        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))
131        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered123        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered
132124
n133        if len(new_tones) == 0 or (len(new_tones) == 1 and str(new_tones[0]) == self.__root):n125        if len(new_tones) == 0:
134            raise ValueError("Cannot have a chord made of only 1 unique tone")126            raise ValueError("Cannot have a chord made of only 1 unique tone")
135127
136        pivot = self.__root.get_tone_index()128        pivot = self.__root.get_tone_index()
137        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))129        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))
138        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))130        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))
139        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))131        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))
140        self.__tones = [*upper_bound, *lower_bound]132        self.__tones = [*upper_bound, *lower_bound]
141133
142    def is_minor(self) -> bool:134    def is_minor(self) -> bool:
143        return self.__seek_for_interval(MINOR_THIRD_INDEX)135        return self.__seek_for_interval(MINOR_THIRD_INDEX)
144136
145    def is_major(self) -> bool:137    def is_major(self) -> bool:
146        return self.__seek_for_interval(MAJOR_THIRD_INDEX)138        return self.__seek_for_interval(MAJOR_THIRD_INDEX)
147139
148    def is_power_chord(self) -> bool:140    def is_power_chord(self) -> bool:
149        return not self.is_major() and not self.is_minor()141        return not self.is_major() and not self.is_minor()
150142
151    def __seek_for_interval(self, number_of_semitones: int) -> bool:143    def __seek_for_interval(self, number_of_semitones: int) -> bool:
n152        for tone in self.tones:n144        for tone in self.__tones:
153            current_interval = tone - self.__root145            current_interval = tone - self.__root
154            if current_interval.number_of_semitones == number_of_semitones:146            if current_interval.number_of_semitones == number_of_semitones:
155                return True147                return True
156        return False148        return False
157149
158    def transposed(self, interval: Interval):150    def transposed(self, interval: Interval):
159        new_root = self.__root + interval151        new_root = self.__root + interval
n160        new_tones = [tone + interval for tone in self.tones]n152        new_tones = [tone + interval for tone in self.__tones]
161        return Chord(new_root, *new_tones)153        return Chord(new_root, *new_tones)
t162 t
163 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1NUMBER_OF_SEMITONES_TO_STR = {f1NUMBER_OF_SEMITONES_TO_STR = {
2    0: "unison",2    0: "unison",
3    1: "minor 2nd",3    1: "minor 2nd",
4    2: "major 2nd",4    2: "major 2nd",
5    3: "minor 3rd",5    3: "minor 3rd",
6    4: "major 3rd",6    4: "major 3rd",
7    5: "perfect 4th",7    5: "perfect 4th",
8    6: "diminished 5th",8    6: "diminished 5th",
9    7: "perfect 5th",9    7: "perfect 5th",
10    8: "minor 6th",10    8: "minor 6th",
11    9: "major 6th",11    9: "major 6th",
12    10: "minor 7th",12    10: "minor 7th",
13    11: "major 7th"13    11: "major 7th"
14}14}
15INDEX_TO_TONE_STR = {15INDEX_TO_TONE_STR = {
16    0: "C",16    0: "C",
17    1: "C#",17    1: "C#",
18    2: "D",18    2: "D",
19    3: "D#",19    3: "D#",
20    4: "E",20    4: "E",
21    5: "F",21    5: "F",
22    6: "F#",22    6: "F#",
23    7: "G",23    7: "G",
24    8: "G#",24    8: "G#",
25    9: "A",25    9: "A",
26    10: "A#",26    10: "A#",
27    11: "B",27    11: "B",
28}28}
29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}29TONE_STR_TO_INDEX = {item[1]: item[0] for item in INDEX_TO_TONE_STR.items()}
30TONES_COUNT = 1230TONES_COUNT = 12
31MINOR_THIRD_INDEX = 331MINOR_THIRD_INDEX = 3
32MAJOR_THIRD_INDEX = 432MAJOR_THIRD_INDEX = 4
3333
3434
35class Tone:35class Tone:
3636
37    def __init__(self, tone_str: str):37    def __init__(self, tone_str: str):
38        self.__tone_str = tone_str38        self.__tone_str = tone_str
3939
40    def __str__(self):40    def __str__(self):
41        return self.__tone_str41        return self.__tone_str
4242
43    def __hash__(self):43    def __hash__(self):
44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)44        return hash(self.__tone_str)  # това го правя, за да кажа dict.fromkeys(tones)
4545
46    def __eq__(self, other):46    def __eq__(self, other):
47        if isinstance(other, Tone):47        if isinstance(other, Tone):
48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)48            return self.__tone_str == other.tone_str  # това го правя, за да кажа dict.fromkeys(tones)
4949
50    def __sub__(self, other):50    def __sub__(self, other):
51        if isinstance(other, Tone):51        if isinstance(other, Tone):
52            if self.get_tone_index() > other.get_tone_index():52            if self.get_tone_index() > other.get_tone_index():
53                return Interval(self.get_tone_index() - other.get_tone_index())53                return Interval(self.get_tone_index() - other.get_tone_index())
54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())54            return Interval(TONES_COUNT - other.get_tone_index() - self.get_tone_index())
55        elif isinstance(other, Interval):55        elif isinstance(other, Interval):
56            return self + (-other)56            return self + (-other)
5757
58    def __add__(self, other):58    def __add__(self, other):
59        if isinstance(other, Tone):59        if isinstance(other, Tone):
60            return Chord(self, other)60            return Chord(self, other)
61        elif isinstance(other, Interval):61        elif isinstance(other, Interval):
62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT62            index = (self.get_tone_index() + other.number_of_semitones) % TONES_COUNT
63            return Tone(INDEX_TO_TONE_STR[index])63            return Tone(INDEX_TO_TONE_STR[index])
6464
65    @property65    @property
66    def tone_str(self):66    def tone_str(self):
67        return self.__tone_str67        return self.__tone_str
6868
69    def get_tone_index(self):69    def get_tone_index(self):
70        return TONE_STR_TO_INDEX[self.__tone_str]70        return TONE_STR_TO_INDEX[self.__tone_str]
7171
7272
73class Interval:73class Interval:
7474
75    def __init__(self, number_of_semitones: int):75    def __init__(self, number_of_semitones: int):
76        self.__number_of_semitones = number_of_semitones % TONES_COUNT76        self.__number_of_semitones = number_of_semitones % TONES_COUNT
7777
78    def __neg__(self):78    def __neg__(self):
79        return Interval(-self.__number_of_semitones)79        return Interval(-self.__number_of_semitones)
8080
81    def __str__(self):81    def __str__(self):
82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]82        return NUMBER_OF_SEMITONES_TO_STR[self.number_of_semitones]
8383
84    def __add__(self, other):84    def __add__(self, other):
85        if isinstance(other, Interval):85        if isinstance(other, Interval):
86            return Interval(self.number_of_semitones + other.number_of_semitones)86            return Interval(self.number_of_semitones + other.number_of_semitones)
87        elif isinstance(other, Tone):87        elif isinstance(other, Tone):
88            raise TypeError("Invalid operation")88            raise TypeError("Invalid operation")
8989
90    def __sub__(self, other):90    def __sub__(self, other):
91        if isinstance(other, Tone):91        if isinstance(other, Tone):
92            raise TypeError("Invalid operation")92            raise TypeError("Invalid operation")
9393
94    @property94    @property
95    def number_of_semitones(self):95    def number_of_semitones(self):
96        return self.__number_of_semitones96        return self.__number_of_semitones
9797
9898
99class Chord:99class Chord:
100    def __init__(self, root: Tone, *args: [Tone]):100    def __init__(self, root: Tone, *args: [Tone]):
101        self.__root = root101        self.__root = root
102        self.__initialise_tones(args)102        self.__initialise_tones(args)
103103
104    def __str__(self):104    def __str__(self):
105        return "-".join(map(str, [self.root, *self.tones]))105        return "-".join(map(str, [self.root, *self.tones]))
106106
107    def __sub__(self, other):107    def __sub__(self, other):
108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.tones] + [self.root.get_tone_index()]):108        if not other.get_tone_index() in ([t.get_tone_index() for t in self.tones] + [self.root.get_tone_index()]):
109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")109            raise TypeError(f"Cannot remove tone {str(other)} from chord {self.__str__()}")
110110
111        if other.get_tone_index() == self.root.get_tone_index():111        if other.get_tone_index() == self.root.get_tone_index():
112            return Chord(self.tones[0], self.tones[1:])112            return Chord(self.tones[0], self.tones[1:])
113        return Chord(self.root, *list(filter(lambda cur: str(cur) != str(other), self.tones)))113        return Chord(self.root, *list(filter(lambda cur: str(cur) != str(other), self.tones)))
114114
115    def __add__(self, other):115    def __add__(self, other):
116        if isinstance(other, Tone):116        if isinstance(other, Tone):
117            return Chord(self.root, *self.tones, other)117            return Chord(self.root, *self.tones, other)
118        elif isinstance(other, Chord):118        elif isinstance(other, Chord):
119            return Chord(self.root, *self.tones, other.root, *other.tones)119            return Chord(self.root, *self.tones, other.root, *other.tones)
120120
121    @property121    @property
122    def tones(self):122    def tones(self):
n123        return self.__tonesn123        return self.__tones.copy()
124124
125    @property125    @property
126    def root(self):126    def root(self):
127        return self.__root127        return self.__root
128128
129    def __initialise_tones(self, new_tones: [Tone]):129    def __initialise_tones(self, new_tones: [Tone]):
130        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))130        new_tones = list(dict.fromkeys(filter(lambda cur: str(cur) != str(self.__root), new_tones)))
131        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered131        # това ми прави все едно set ,защото пак ползва hash ,но пази реда ,защото dict след python 3.7 e ordered
132132
133        if len(new_tones) == 0 or (len(new_tones) == 1 and str(new_tones[0]) == self.__root):133        if len(new_tones) == 0 or (len(new_tones) == 1 and str(new_tones[0]) == self.__root):
134            raise ValueError("Cannot have a chord made of only 1 unique tone")134            raise ValueError("Cannot have a chord made of only 1 unique tone")
135135
136        pivot = self.__root.get_tone_index()136        pivot = self.__root.get_tone_index()
137        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))137        ordered_tones = list(sorted(new_tones, key=lambda cur: cur.get_tone_index()))
138        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))138        upper_bound = list(filter(lambda cur: cur.get_tone_index() > pivot, ordered_tones))
139        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))139        lower_bound = list(filter(lambda cur: cur.get_tone_index() < pivot, ordered_tones))
140        self.__tones = [*upper_bound, *lower_bound]140        self.__tones = [*upper_bound, *lower_bound]
141141
142    def is_minor(self) -> bool:142    def is_minor(self) -> bool:
143        return self.__seek_for_interval(MINOR_THIRD_INDEX)143        return self.__seek_for_interval(MINOR_THIRD_INDEX)
144144
145    def is_major(self) -> bool:145    def is_major(self) -> bool:
146        return self.__seek_for_interval(MAJOR_THIRD_INDEX)146        return self.__seek_for_interval(MAJOR_THIRD_INDEX)
147147
148    def is_power_chord(self) -> bool:148    def is_power_chord(self) -> bool:
149        return not self.is_major() and not self.is_minor()149        return not self.is_major() and not self.is_minor()
150150
151    def __seek_for_interval(self, number_of_semitones: int) -> bool:151    def __seek_for_interval(self, number_of_semitones: int) -> bool:
152        for tone in self.tones:152        for tone in self.tones:
153            current_interval = tone - self.__root153            current_interval = tone - self.__root
154            if current_interval.number_of_semitones == number_of_semitones:154            if current_interval.number_of_semitones == number_of_semitones:
155                return True155                return True
156        return False156        return False
157157
158    def transposed(self, interval: Interval):158    def transposed(self, interval: Interval):
159        new_root = self.__root + interval159        new_root = self.__root + interval
160        new_tones = [tone + interval for tone in self.tones]160        new_tones = [tone + interval for tone in self.tones]
161        return Chord(new_root, *new_tones)161        return Chord(new_root, *new_tones)
tt162 
163 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op