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

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

10 точки общо

37 успешни теста
0 неуспешни теста
Код

  1from operator import truediv
  2
  3CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',
  4                   'E', 'F', 'F#', 'G',
  5                   'G#', 'A', 'A#', 'B']
  6
  7SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',
  8                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',
  9                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
 10
 11INTERVAL_LEN = len(CHROMATIC_SCALE)
 12MINOR_IDX = 3
 13MAJOR_IDX = 4
 14
 15class Tone:
 16    def __init__(self, name):
 17        self.name = name
 18
 19    def __str__(self):
 20        return self.name
 21
 22    def __eq__(self, other):
 23        return self.name == other.name
 24
 25    def __add__(self, other):
 26        if isinstance(other, Interval):
 27            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % INTERVAL_LEN
 28            return Tone(CHROMATIC_SCALE[new_tone_idx])
 29        return Chord(self, other)
 30
 31    def __sub__(self, other):
 32        first_idx = CHROMATIC_SCALE.index(self.name)
 33        if isinstance(other, Interval):
 34            second_idx = other.number_of_semitones
 35            res_idx = (first_idx - second_idx) % INTERVAL_LEN
 36            return Tone(CHROMATIC_SCALE[res_idx])
 37        second_idx = CHROMATIC_SCALE.index(other.name)
 38        res_idx = (first_idx - second_idx) % INTERVAL_LEN
 39        return Interval(res_idx)
 40
 41
 42class Interval:
 43
 44    def __init__(self, number_of_semitones):
 45        self.number_of_semitones = number_of_semitones
 46
 47    def __str__(self):
 48        return SEMITONES_TYPES[self.number_of_semitones % INTERVAL_LEN]
 49
 50    def __add__(self, other):
 51        if isinstance(other, Tone):
 52            raise TypeError('Invalid operation')
 53        else:
 54            semitones = (self.number_of_semitones + other.number_of_semitones) % INTERVAL_LEN
 55            return Interval(semitones)
 56
 57    def __sub__(self, other):
 58        if isinstance(other, Tone):
 59            raise TypeError('Invalid operation')
 60
 61    def __neg__(self):
 62        return Interval(-self.number_of_semitones)
 63
 64
 65class Chord:
 66    def __init__(self, root, *tones):
 67        self.root = root
 68        self.all_tones = [root, *tones]
 69        self.uniques = self._unique_tones(self.all_tones)
 70        if len(self.uniques) < 2:
 71            raise TypeError("Cannot have a chord made of only 1 unique tone")
 72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter
 73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:
 74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))
 75
 76    @staticmethod
 77    def _unique_tones(tones):
 78        unique_list = []
 79        for tone in tones:
 80            if tone not in unique_list:
 81                unique_list.append(tone)
 82        return unique_list
 83
 84    def __str__(self):
 85        return '-'.join(map(str, self.sorted_unique_tones))
 86
 87    def is_minor(self):
 88        return self._minor_major(MINOR_IDX)
 89
 90    def is_major(self):
 91        return self._minor_major(MAJOR_IDX)
 92
 93    def is_power_chord(self):
 94        return not (self.is_minor() or self.is_major())
 95
 96    def _minor_major(self, interval):
 97        index_of_root = CHROMATIC_SCALE.index(self.root.name)
 98        for tone in self.sorted_unique_tones:
 99            curr_tone = CHROMATIC_SCALE.index(tone.name)
100            diff = (curr_tone - index_of_root)
101            if diff == interval:
102                return True
103            elif diff < 0 and (12 + diff == interval):
104                return True
105        return False
106
107    def __add__(self, other):
108        if isinstance(other, Tone):
109            tones = self.all_tones + [other]
110            end_tones = tuple(tones)
111            return Chord(self.root, *end_tones)
112        all_tones = tuple(self.all_tones) + tuple(other.all_tones)
113        return Chord(self.root, *all_tones)
114
115    def __sub__(self, other):
116        if isinstance(other, Tone):
117            if other not in self.uniques:
118                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')
119            elif len(self.uniques) >= 3:
120                tones = []
121                for tone in self.all_tones:
122                    if tone != other:
123                        tones.append(tone)
124                new_root = tones[0]
125                return Chord(new_root, *(tuple(tones)))
126            else:
127                raise TypeError('Cannot have a chord made of only 1 unique tone')
128
129    def transposed(self, interval):
130        interval_num = interval.number_of_semitones
131        tones = []
132        for tone in self.all_tones:
133            curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % INTERVAL_LEN
134            tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
135        new_root = tones[0]
136        return Chord(new_root, *(tuple(tones[1:])))

.....................................
----------------------------------------------------------------------
Ran 37 tests in 0.001s

OK

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

Да, има превъртане.
Елица Павлова
04.11.2024 17:41

При функциите is_minor, is_major има ли превъртане, както при други функции, или този else, който правя във функцията _minor_major, е излишен?
История

nn1from operator import truediv
2 
1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',3CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',
2                   'E', 'F', 'F#', 'G',4                   'E', 'F', 'F#', 'G',
3                   'G#', 'A', 'A#', 'B']5                   'G#', 'A', 'A#', 'B']
46
5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',7SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',
6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',8                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',
7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}9                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
810
9INTERVAL_LEN = len(CHROMATIC_SCALE)11INTERVAL_LEN = len(CHROMATIC_SCALE)
10MINOR_IDX = 312MINOR_IDX = 3
11MAJOR_IDX = 413MAJOR_IDX = 4
1214
13class Tone:15class Tone:
14    def __init__(self, name):16    def __init__(self, name):
15        self.name = name17        self.name = name
1618
17    def __str__(self):19    def __str__(self):
18        return self.name20        return self.name
1921
20    def __eq__(self, other):22    def __eq__(self, other):
21        return self.name == other.name23        return self.name == other.name
2224
23    def __add__(self, other):25    def __add__(self, other):
24        if isinstance(other, Interval):26        if isinstance(other, Interval):
25            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % INTERVAL_LEN27            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % INTERVAL_LEN
26            return Tone(CHROMATIC_SCALE[new_tone_idx])28            return Tone(CHROMATIC_SCALE[new_tone_idx])
27        return Chord(self, other)29        return Chord(self, other)
2830
29    def __sub__(self, other):31    def __sub__(self, other):
30        first_idx = CHROMATIC_SCALE.index(self.name)32        first_idx = CHROMATIC_SCALE.index(self.name)
31        if isinstance(other, Interval):33        if isinstance(other, Interval):
32            second_idx = other.number_of_semitones34            second_idx = other.number_of_semitones
33            res_idx = (first_idx - second_idx) % INTERVAL_LEN35            res_idx = (first_idx - second_idx) % INTERVAL_LEN
34            return Tone(CHROMATIC_SCALE[res_idx])36            return Tone(CHROMATIC_SCALE[res_idx])
35        second_idx = CHROMATIC_SCALE.index(other.name)37        second_idx = CHROMATIC_SCALE.index(other.name)
36        res_idx = (first_idx - second_idx) % INTERVAL_LEN38        res_idx = (first_idx - second_idx) % INTERVAL_LEN
37        return Interval(res_idx)39        return Interval(res_idx)
3840
3941
40class Interval:42class Interval:
4143
42    def __init__(self, number_of_semitones):44    def __init__(self, number_of_semitones):
43        self.number_of_semitones = number_of_semitones45        self.number_of_semitones = number_of_semitones
4446
45    def __str__(self):47    def __str__(self):
46        return SEMITONES_TYPES[self.number_of_semitones % INTERVAL_LEN]48        return SEMITONES_TYPES[self.number_of_semitones % INTERVAL_LEN]
4749
48    def __add__(self, other):50    def __add__(self, other):
49        if isinstance(other, Tone):51        if isinstance(other, Tone):
50            raise TypeError('Invalid operation')52            raise TypeError('Invalid operation')
51        else:53        else:
52            semitones = (self.number_of_semitones + other.number_of_semitones) % INTERVAL_LEN54            semitones = (self.number_of_semitones + other.number_of_semitones) % INTERVAL_LEN
53            return Interval(semitones)55            return Interval(semitones)
5456
55    def __sub__(self, other):57    def __sub__(self, other):
56        if isinstance(other, Tone):58        if isinstance(other, Tone):
57            raise TypeError('Invalid operation')59            raise TypeError('Invalid operation')
5860
59    def __neg__(self):61    def __neg__(self):
60        return Interval(-self.number_of_semitones)62        return Interval(-self.number_of_semitones)
6163
6264
63class Chord:65class Chord:
64    def __init__(self, root, *tones):66    def __init__(self, root, *tones):
65        self.root = root67        self.root = root
66        self.all_tones = [root, *tones]68        self.all_tones = [root, *tones]
67        self.uniques = self._unique_tones(self.all_tones)69        self.uniques = self._unique_tones(self.all_tones)
68        if len(self.uniques) < 2:70        if len(self.uniques) < 2:
69            raise TypeError("Cannot have a chord made of only 1 unique tone")71            raise TypeError("Cannot have a chord made of only 1 unique tone")
70        #calculates how far is every unique tone from the root and sorts(increase) by this parameter72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter
71        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:
72        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))
7375
74    @staticmethod76    @staticmethod
75    def _unique_tones(tones):77    def _unique_tones(tones):
76        unique_list = []78        unique_list = []
77        for tone in tones:79        for tone in tones:
78            if tone not in unique_list:80            if tone not in unique_list:
79                unique_list.append(tone)81                unique_list.append(tone)
80        return unique_list82        return unique_list
8183
82    def __str__(self):84    def __str__(self):
83        return '-'.join(map(str, self.sorted_unique_tones))85        return '-'.join(map(str, self.sorted_unique_tones))
8486
85    def is_minor(self):87    def is_minor(self):
86        return self._minor_major(MINOR_IDX)88        return self._minor_major(MINOR_IDX)
8789
88    def is_major(self):90    def is_major(self):
89        return self._minor_major(MAJOR_IDX)91        return self._minor_major(MAJOR_IDX)
9092
91    def is_power_chord(self):93    def is_power_chord(self):
92        return not (self.is_minor() or self.is_major())94        return not (self.is_minor() or self.is_major())
9395
94    def _minor_major(self, interval):96    def _minor_major(self, interval):
95        index_of_root = CHROMATIC_SCALE.index(self.root.name)97        index_of_root = CHROMATIC_SCALE.index(self.root.name)
96        for tone in self.sorted_unique_tones:98        for tone in self.sorted_unique_tones:
97            curr_tone = CHROMATIC_SCALE.index(tone.name)99            curr_tone = CHROMATIC_SCALE.index(tone.name)
n98            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:n100            diff = (curr_tone - index_of_root)
101            if diff == interval:
99                return True102                return True
n100            elif (INTERVAL_LEN - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:n103            elif diff < 0 and (12 + diff == interval):
101                return True104                return True
102        return False105        return False
103106
104    def __add__(self, other):107    def __add__(self, other):
105        if isinstance(other, Tone):108        if isinstance(other, Tone):
106            tones = self.all_tones + [other]109            tones = self.all_tones + [other]
107            end_tones = tuple(tones)110            end_tones = tuple(tones)
108            return Chord(self.root, *end_tones)111            return Chord(self.root, *end_tones)
109        all_tones = tuple(self.all_tones) + tuple(other.all_tones)112        all_tones = tuple(self.all_tones) + tuple(other.all_tones)
110        return Chord(self.root, *all_tones)113        return Chord(self.root, *all_tones)
111114
112    def __sub__(self, other):115    def __sub__(self, other):
113        if isinstance(other, Tone):116        if isinstance(other, Tone):
114            if other not in self.uniques:117            if other not in self.uniques:
115                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')118                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')
116            elif len(self.uniques) >= 3:119            elif len(self.uniques) >= 3:
117                tones = []120                tones = []
118                for tone in self.all_tones:121                for tone in self.all_tones:
119                    if tone != other:122                    if tone != other:
120                        tones.append(tone)123                        tones.append(tone)
121                new_root = tones[0]124                new_root = tones[0]
122                return Chord(new_root, *(tuple(tones)))125                return Chord(new_root, *(tuple(tones)))
123            else:126            else:
124                raise TypeError('Cannot have a chord made of only 1 unique tone')127                raise TypeError('Cannot have a chord made of only 1 unique tone')
125128
126    def transposed(self, interval):129    def transposed(self, interval):
127        interval_num = interval.number_of_semitones130        interval_num = interval.number_of_semitones
128        tones = []131        tones = []
129        for tone in self.all_tones:132        for tone in self.all_tones:
130            curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % INTERVAL_LEN133            curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % INTERVAL_LEN
131            tones.append(Tone(CHROMATIC_SCALE[curr_idx]))134            tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
132        new_root = tones[0]135        new_root = tones[0]
133        return Chord(new_root, *(tuple(tones[1:])))136        return Chord(new_root, *(tuple(tones[1:])))
134137
135138
t136 t
137 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',
n2                       'E', 'F', 'F#', 'G',n2                   'E', 'F', 'F#', 'G',
3                       'G#', 'A', 'A#', 'B']3                   'G#', 'A', 'A#', 'B']
44
5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',
6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',
7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
nn8 
9INTERVAL_LEN = len(CHROMATIC_SCALE)
10MINOR_IDX = 3
11MAJOR_IDX = 4
812
9class Tone:13class Tone:
10    def __init__(self, name):14    def __init__(self, name):
11        self.name = name15        self.name = name
1216
13    def __str__(self):17    def __str__(self):
n14        return f'{self.name}'n18        return self.name
1519
16    def __eq__(self, other):20    def __eq__(self, other):
17        return self.name == other.name21        return self.name == other.name
1822
19    def __add__(self, other):23    def __add__(self, other):
20        if isinstance(other, Interval):24        if isinstance(other, Interval):
n21            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % 12n25            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % INTERVAL_LEN
22            return Tone(CHROMATIC_SCALE[new_tone_idx])26            return Tone(CHROMATIC_SCALE[new_tone_idx])
23        return Chord(self, other)27        return Chord(self, other)
2428
25    def __sub__(self, other):29    def __sub__(self, other):
26        first_idx = CHROMATIC_SCALE.index(self.name)30        first_idx = CHROMATIC_SCALE.index(self.name)
27        if isinstance(other, Interval):31        if isinstance(other, Interval):
28            second_idx = other.number_of_semitones32            second_idx = other.number_of_semitones
n29            if first_idx >= second_idx:n
30                res_idx = first_idx - second_idx33            res_idx = (first_idx - second_idx) % INTERVAL_LEN
31            else:
32                res_idx = 12 - abs(first_idx - second_idx)
33            return Tone(CHROMATIC_SCALE[res_idx])34            return Tone(CHROMATIC_SCALE[res_idx])
34        second_idx = CHROMATIC_SCALE.index(other.name)35        second_idx = CHROMATIC_SCALE.index(other.name)
n35        if first_idx >= second_idx:n
36            res_idx = first_idx - second_idx36        res_idx = (first_idx - second_idx) % INTERVAL_LEN
37        else:
38            res_idx = 12 - abs(first_idx - second_idx)
39        return Interval(res_idx)37        return Interval(res_idx)
4038
4139
42class Interval:40class Interval:
4341
44    def __init__(self, number_of_semitones):42    def __init__(self, number_of_semitones):
45        self.number_of_semitones = number_of_semitones43        self.number_of_semitones = number_of_semitones
4644
47    def __str__(self):45    def __str__(self):
n48        return f'{SEMITONES_TYPES[self.number_of_semitones % 12]}'n46        return SEMITONES_TYPES[self.number_of_semitones % INTERVAL_LEN]
4947
50    def __add__(self, other):48    def __add__(self, other):
51        if isinstance(other, Tone):49        if isinstance(other, Tone):
52            raise TypeError('Invalid operation')50            raise TypeError('Invalid operation')
53        else:51        else:
n54            semitones = (self.number_of_semitones + other.number_of_semitones) % 12n52            semitones = (self.number_of_semitones + other.number_of_semitones) % INTERVAL_LEN
55            return Interval(semitones)53            return Interval(semitones)
5654
57    def __sub__(self, other):55    def __sub__(self, other):
58        if isinstance(other, Tone):56        if isinstance(other, Tone):
59            raise TypeError('Invalid operation')57            raise TypeError('Invalid operation')
6058
61    def __neg__(self):59    def __neg__(self):
62        return Interval(-self.number_of_semitones)60        return Interval(-self.number_of_semitones)
6361
6462
65class Chord:63class Chord:
66    def __init__(self, root, *tones):64    def __init__(self, root, *tones):
67        self.root = root65        self.root = root
68        self.all_tones = [root, *tones]66        self.all_tones = [root, *tones]
69        self.uniques = self._unique_tones(self.all_tones)67        self.uniques = self._unique_tones(self.all_tones)
70        if len(self.uniques) < 2:68        if len(self.uniques) < 2:
71            raise TypeError("Cannot have a chord made of only 1 unique tone")69            raise TypeError("Cannot have a chord made of only 1 unique tone")
72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter70        #calculates how far is every unique tone from the root and sorts(increase) by this parameter
73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:71        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:
74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))72        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))
7573
76    @staticmethod74    @staticmethod
77    def _unique_tones(tones):75    def _unique_tones(tones):
78        unique_list = []76        unique_list = []
79        for tone in tones:77        for tone in tones:
80            if tone not in unique_list:78            if tone not in unique_list:
81                unique_list.append(tone)79                unique_list.append(tone)
82        return unique_list80        return unique_list
8381
84    def __str__(self):82    def __str__(self):
n85        self.tones_to_print = '-'.join(str(unique) for unique in self.sorted_unique_tones)n83        return '-'.join(map(str, self.sorted_unique_tones))
86        return self.tones_to_print
8784
88    def is_minor(self):85    def is_minor(self):
n89        return self._minor_major(3)n86        return self._minor_major(MINOR_IDX)
9087
91    def is_major(self):88    def is_major(self):
n92        return self._minor_major(4)n89        return self._minor_major(MAJOR_IDX)
9390
94    def is_power_chord(self):91    def is_power_chord(self):
95        return not (self.is_minor() or self.is_major())92        return not (self.is_minor() or self.is_major())
9693
97    def _minor_major(self, interval):94    def _minor_major(self, interval):
98        index_of_root = CHROMATIC_SCALE.index(self.root.name)95        index_of_root = CHROMATIC_SCALE.index(self.root.name)
99        for tone in self.sorted_unique_tones:96        for tone in self.sorted_unique_tones:
100            curr_tone = CHROMATIC_SCALE.index(tone.name)97            curr_tone = CHROMATIC_SCALE.index(tone.name)
101            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:98            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:
102                return True99                return True
n103            elif (12 - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:n100            elif (INTERVAL_LEN - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:
104                return True101                return True
105        return False102        return False
106103
107    def __add__(self, other):104    def __add__(self, other):
108        if isinstance(other, Tone):105        if isinstance(other, Tone):
n109            tones = []n106            tones = self.all_tones + [other]
110            for tone in self.all_tones:
111                tones.append(tone)
112            tones.append(other)
113            end_tones = tuple(tones)107            end_tones = tuple(tones)
114            return Chord(self.root, *end_tones)108            return Chord(self.root, *end_tones)
115        all_tones = tuple(self.all_tones) + tuple(other.all_tones)109        all_tones = tuple(self.all_tones) + tuple(other.all_tones)
116        return Chord(self.root, *all_tones)110        return Chord(self.root, *all_tones)
117111
118    def __sub__(self, other):112    def __sub__(self, other):
119        if isinstance(other, Tone):113        if isinstance(other, Tone):
120            if other not in self.uniques:114            if other not in self.uniques:
121                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')115                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')
122            elif len(self.uniques) >= 3:116            elif len(self.uniques) >= 3:
123                tones = []117                tones = []
124                for tone in self.all_tones:118                for tone in self.all_tones:
n125                    if not tone == other:n119                    if tone != other:
126                        tones.append(tone)120                        tones.append(tone)
127                new_root = tones[0]121                new_root = tones[0]
128                return Chord(new_root, *(tuple(tones)))122                return Chord(new_root, *(tuple(tones)))
129            else:123            else:
130                raise TypeError('Cannot have a chord made of only 1 unique tone')124                raise TypeError('Cannot have a chord made of only 1 unique tone')
131125
132    def transposed(self, interval):126    def transposed(self, interval):
133        interval_num = interval.number_of_semitones127        interval_num = interval.number_of_semitones
134        tones = []128        tones = []
n135        if interval_num > 0:n
136            for tone in self.all_tones:129        for tone in self.all_tones:
137                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12130            curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % INTERVAL_LEN
138                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))131            tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
139        else:
140            for tone in self.all_tones:
141                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12
142                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
143        new_root = tones[0]132        new_root = tones[0]
144        return Chord(new_root, *(tuple(tones[1:])))133        return Chord(new_root, *(tuple(tones[1:])))
145134
146135
tt136 
137 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',
2                       'E', 'F', 'F#', 'G',2                       'E', 'F', 'F#', 'G',
3                       'G#', 'A', 'A#', 'B']3                       'G#', 'A', 'A#', 'B']
44
5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',
6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',
7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
88
9class Tone:9class Tone:
10    def __init__(self, name):10    def __init__(self, name):
11        self.name = name11        self.name = name
1212
13    def __str__(self):13    def __str__(self):
14        return f'{self.name}'14        return f'{self.name}'
1515
16    def __eq__(self, other):16    def __eq__(self, other):
17        return self.name == other.name17        return self.name == other.name
1818
19    def __add__(self, other):19    def __add__(self, other):
20        if isinstance(other, Interval):20        if isinstance(other, Interval):
21            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % 1221            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % 12
22            return Tone(CHROMATIC_SCALE[new_tone_idx])22            return Tone(CHROMATIC_SCALE[new_tone_idx])
23        return Chord(self, other)23        return Chord(self, other)
2424
25    def __sub__(self, other):25    def __sub__(self, other):
26        first_idx = CHROMATIC_SCALE.index(self.name)26        first_idx = CHROMATIC_SCALE.index(self.name)
27        if isinstance(other, Interval):27        if isinstance(other, Interval):
28            second_idx = other.number_of_semitones28            second_idx = other.number_of_semitones
29            if first_idx >= second_idx:29            if first_idx >= second_idx:
30                res_idx = first_idx - second_idx30                res_idx = first_idx - second_idx
31            else:31            else:
32                res_idx = 12 - abs(first_idx - second_idx)32                res_idx = 12 - abs(first_idx - second_idx)
33            return Tone(CHROMATIC_SCALE[res_idx])33            return Tone(CHROMATIC_SCALE[res_idx])
34        second_idx = CHROMATIC_SCALE.index(other.name)34        second_idx = CHROMATIC_SCALE.index(other.name)
35        if first_idx >= second_idx:35        if first_idx >= second_idx:
36            res_idx = first_idx - second_idx36            res_idx = first_idx - second_idx
37        else:37        else:
38            res_idx = 12 - abs(first_idx - second_idx)38            res_idx = 12 - abs(first_idx - second_idx)
39        return Interval(res_idx)39        return Interval(res_idx)
4040
4141
42class Interval:42class Interval:
4343
44    def __init__(self, number_of_semitones):44    def __init__(self, number_of_semitones):
45        self.number_of_semitones = number_of_semitones45        self.number_of_semitones = number_of_semitones
4646
47    def __str__(self):47    def __str__(self):
48        return f'{SEMITONES_TYPES[self.number_of_semitones % 12]}'48        return f'{SEMITONES_TYPES[self.number_of_semitones % 12]}'
4949
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        else:53        else:
54            semitones = (self.number_of_semitones + other.number_of_semitones) % 1254            semitones = (self.number_of_semitones + other.number_of_semitones) % 12
55            return Interval(semitones)55            return Interval(semitones)
5656
57    def __sub__(self, other):57    def __sub__(self, other):
58        if isinstance(other, Tone):58        if isinstance(other, Tone):
59            raise TypeError('Invalid operation')59            raise TypeError('Invalid operation')
6060
61    def __neg__(self):61    def __neg__(self):
62        return Interval(-self.number_of_semitones)62        return Interval(-self.number_of_semitones)
6363
6464
65class Chord:65class Chord:
66    def __init__(self, root, *tones):66    def __init__(self, root, *tones):
67        self.root = root67        self.root = root
68        self.all_tones = [root, *tones]68        self.all_tones = [root, *tones]
69        self.uniques = self._unique_tones(self.all_tones)69        self.uniques = self._unique_tones(self.all_tones)
70        if len(self.uniques) < 2:70        if len(self.uniques) < 2:
71            raise TypeError("Cannot have a chord made of only 1 unique tone")71            raise TypeError("Cannot have a chord made of only 1 unique tone")
72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter
73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:
74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))
7575
76    @staticmethod76    @staticmethod
77    def _unique_tones(tones):77    def _unique_tones(tones):
78        unique_list = []78        unique_list = []
79        for tone in tones:79        for tone in tones:
80            if tone not in unique_list:80            if tone not in unique_list:
81                unique_list.append(tone)81                unique_list.append(tone)
82        return unique_list82        return unique_list
8383
84    def __str__(self):84    def __str__(self):
85        self.tones_to_print = '-'.join(str(unique) for unique in self.sorted_unique_tones)85        self.tones_to_print = '-'.join(str(unique) for unique in self.sorted_unique_tones)
86        return self.tones_to_print86        return self.tones_to_print
8787
88    def is_minor(self):88    def is_minor(self):
89        return self._minor_major(3)89        return self._minor_major(3)
9090
91    def is_major(self):91    def is_major(self):
92        return self._minor_major(4)92        return self._minor_major(4)
9393
94    def is_power_chord(self):94    def is_power_chord(self):
95        return not (self.is_minor() or self.is_major())95        return not (self.is_minor() or self.is_major())
9696
97    def _minor_major(self, interval):97    def _minor_major(self, interval):
98        index_of_root = CHROMATIC_SCALE.index(self.root.name)98        index_of_root = CHROMATIC_SCALE.index(self.root.name)
99        for tone in self.sorted_unique_tones:99        for tone in self.sorted_unique_tones:
100            curr_tone = CHROMATIC_SCALE.index(tone.name)100            curr_tone = CHROMATIC_SCALE.index(tone.name)
101            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:101            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:
102                return True102                return True
103            elif (12 - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:103            elif (12 - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:
104                return True104                return True
105        return False105        return False
106106
107    def __add__(self, other):107    def __add__(self, other):
108        if isinstance(other, Tone):108        if isinstance(other, Tone):
109            tones = []109            tones = []
110            for tone in self.all_tones:110            for tone in self.all_tones:
111                tones.append(tone)111                tones.append(tone)
112            tones.append(other)112            tones.append(other)
113            end_tones = tuple(tones)113            end_tones = tuple(tones)
114            return Chord(self.root, *end_tones)114            return Chord(self.root, *end_tones)
115        all_tones = tuple(self.all_tones) + tuple(other.all_tones)115        all_tones = tuple(self.all_tones) + tuple(other.all_tones)
116        return Chord(self.root, *all_tones)116        return Chord(self.root, *all_tones)
117117
118    def __sub__(self, other):118    def __sub__(self, other):
119        if isinstance(other, Tone):119        if isinstance(other, Tone):
120            if other not in self.uniques:120            if other not in self.uniques:
121                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')121                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')
122            elif len(self.uniques) >= 3:122            elif len(self.uniques) >= 3:
123                tones = []123                tones = []
124                for tone in self.all_tones:124                for tone in self.all_tones:
125                    if not tone == other:125                    if not tone == other:
126                        tones.append(tone)126                        tones.append(tone)
127                new_root = tones[0]127                new_root = tones[0]
128                return Chord(new_root, *(tuple(tones)))128                return Chord(new_root, *(tuple(tones)))
129            else:129            else:
130                raise TypeError('Cannot have a chord made of only 1 unique tone')130                raise TypeError('Cannot have a chord made of only 1 unique tone')
131131
132    def transposed(self, interval):132    def transposed(self, interval):
133        interval_num = interval.number_of_semitones133        interval_num = interval.number_of_semitones
134        tones = []134        tones = []
135        if interval_num > 0:135        if interval_num > 0:
136            for tone in self.all_tones:136            for tone in self.all_tones:
137                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12137                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12
138                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))138                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
139        else:139        else:
140            for tone in self.all_tones:140            for tone in self.all_tones:
141                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12141                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12
142                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))142                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
143        new_root = tones[0]143        new_root = tones[0]
144        return Chord(new_root, *(tuple(tones[1:])))144        return Chord(new_root, *(tuple(tones[1:])))
145145
146146
t147c_major_chord = Chord(Tone("C"), Tone("E"), Tone("G"))t
148result_chord = c_major_chord - Tone("C")
149print(result_chord)
150# C-G
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',f1CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#',
2                       'E', 'F', 'F#', 'G',2                       'E', 'F', 'F#', 'G',
3                       'G#', 'A', 'A#', 'B']3                       'G#', 'A', 'A#', 'B']
44
5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',5SEMITONES_TYPES = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd',
6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',6                   5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th',
7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}7                   9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
88
9class Tone:9class Tone:
10    def __init__(self, name):10    def __init__(self, name):
11        self.name = name11        self.name = name
1212
13    def __str__(self):13    def __str__(self):
14        return f'{self.name}'14        return f'{self.name}'
1515
16    def __eq__(self, other):16    def __eq__(self, other):
17        return self.name == other.name17        return self.name == other.name
1818
19    def __add__(self, other):19    def __add__(self, other):
20        if isinstance(other, Interval):20        if isinstance(other, Interval):
21            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % 1221            new_tone_idx = (CHROMATIC_SCALE.index(self.name) + other.number_of_semitones) % 12
22            return Tone(CHROMATIC_SCALE[new_tone_idx])22            return Tone(CHROMATIC_SCALE[new_tone_idx])
23        return Chord(self, other)23        return Chord(self, other)
2424
25    def __sub__(self, other):25    def __sub__(self, other):
26        first_idx = CHROMATIC_SCALE.index(self.name)26        first_idx = CHROMATIC_SCALE.index(self.name)
27        if isinstance(other, Interval):27        if isinstance(other, Interval):
28            second_idx = other.number_of_semitones28            second_idx = other.number_of_semitones
29            if first_idx >= second_idx:29            if first_idx >= second_idx:
30                res_idx = first_idx - second_idx30                res_idx = first_idx - second_idx
31            else:31            else:
32                res_idx = 12 - abs(first_idx - second_idx)32                res_idx = 12 - abs(first_idx - second_idx)
33            return Tone(CHROMATIC_SCALE[res_idx])33            return Tone(CHROMATIC_SCALE[res_idx])
34        second_idx = CHROMATIC_SCALE.index(other.name)34        second_idx = CHROMATIC_SCALE.index(other.name)
35        if first_idx >= second_idx:35        if first_idx >= second_idx:
36            res_idx = first_idx - second_idx36            res_idx = first_idx - second_idx
37        else:37        else:
38            res_idx = 12 - abs(first_idx - second_idx)38            res_idx = 12 - abs(first_idx - second_idx)
39        return Interval(res_idx)39        return Interval(res_idx)
4040
4141
42class Interval:42class Interval:
4343
44    def __init__(self, number_of_semitones):44    def __init__(self, number_of_semitones):
45        self.number_of_semitones = number_of_semitones45        self.number_of_semitones = number_of_semitones
4646
47    def __str__(self):47    def __str__(self):
48        return f'{SEMITONES_TYPES[self.number_of_semitones % 12]}'48        return f'{SEMITONES_TYPES[self.number_of_semitones % 12]}'
4949
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        else:53        else:
54            semitones = (self.number_of_semitones + other.number_of_semitones) % 1254            semitones = (self.number_of_semitones + other.number_of_semitones) % 12
55            return Interval(semitones)55            return Interval(semitones)
5656
57    def __sub__(self, other):57    def __sub__(self, other):
58        if isinstance(other, Tone):58        if isinstance(other, Tone):
59            raise TypeError('Invalid operation')59            raise TypeError('Invalid operation')
6060
61    def __neg__(self):61    def __neg__(self):
62        return Interval(-self.number_of_semitones)62        return Interval(-self.number_of_semitones)
6363
6464
65class Chord:65class Chord:
66    def __init__(self, root, *tones):66    def __init__(self, root, *tones):
67        self.root = root67        self.root = root
68        self.all_tones = [root, *tones]68        self.all_tones = [root, *tones]
69        self.uniques = self._unique_tones(self.all_tones)69        self.uniques = self._unique_tones(self.all_tones)
70        if len(self.uniques) < 2:70        if len(self.uniques) < 2:
71            raise TypeError("Cannot have a chord made of only 1 unique tone")71            raise TypeError("Cannot have a chord made of only 1 unique tone")
72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter72        #calculates how far is every unique tone from the root and sorts(increase) by this parameter
73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:73        self.sorted_unique_tones = sorted(self.uniques, key=lambda tone:
74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))74        (CHROMATIC_SCALE.index(tone.name) - CHROMATIC_SCALE.index(root.name)) % len(CHROMATIC_SCALE))
7575
76    @staticmethod76    @staticmethod
77    def _unique_tones(tones):77    def _unique_tones(tones):
78        unique_list = []78        unique_list = []
79        for tone in tones:79        for tone in tones:
80            if tone not in unique_list:80            if tone not in unique_list:
81                unique_list.append(tone)81                unique_list.append(tone)
82        return unique_list82        return unique_list
8383
84    def __str__(self):84    def __str__(self):
85        self.tones_to_print = '-'.join(str(unique) for unique in self.sorted_unique_tones)85        self.tones_to_print = '-'.join(str(unique) for unique in self.sorted_unique_tones)
86        return self.tones_to_print86        return self.tones_to_print
8787
88    def is_minor(self):88    def is_minor(self):
89        return self._minor_major(3)89        return self._minor_major(3)
9090
91    def is_major(self):91    def is_major(self):
92        return self._minor_major(4)92        return self._minor_major(4)
9393
94    def is_power_chord(self):94    def is_power_chord(self):
95        return not (self.is_minor() or self.is_major())95        return not (self.is_minor() or self.is_major())
9696
97    def _minor_major(self, interval):97    def _minor_major(self, interval):
98        index_of_root = CHROMATIC_SCALE.index(self.root.name)98        index_of_root = CHROMATIC_SCALE.index(self.root.name)
99        for tone in self.sorted_unique_tones:99        for tone in self.sorted_unique_tones:
100            curr_tone = CHROMATIC_SCALE.index(tone.name)100            curr_tone = CHROMATIC_SCALE.index(tone.name)
101            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:101            if abs(curr_tone - index_of_root) % len(CHROMATIC_SCALE) == interval:
102                return True102                return True
103            elif (12 - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:103            elif (12 - abs(curr_tone - index_of_root)) % len(CHROMATIC_SCALE) == interval:
104                return True104                return True
105        return False105        return False
106106
107    def __add__(self, other):107    def __add__(self, other):
108        if isinstance(other, Tone):108        if isinstance(other, Tone):
109            tones = []109            tones = []
110            for tone in self.all_tones:110            for tone in self.all_tones:
111                tones.append(tone)111                tones.append(tone)
112            tones.append(other)112            tones.append(other)
113            end_tones = tuple(tones)113            end_tones = tuple(tones)
114            return Chord(self.root, *end_tones)114            return Chord(self.root, *end_tones)
115        all_tones = tuple(self.all_tones) + tuple(other.all_tones)115        all_tones = tuple(self.all_tones) + tuple(other.all_tones)
116        return Chord(self.root, *all_tones)116        return Chord(self.root, *all_tones)
117117
118    def __sub__(self, other):118    def __sub__(self, other):
119        if isinstance(other, Tone):119        if isinstance(other, Tone):
120            if other not in self.uniques:120            if other not in self.uniques:
121                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')121                raise TypeError(f'Cannot remove tone {other.name} from chord {str(self)}')
122            elif len(self.uniques) >= 3:122            elif len(self.uniques) >= 3:
123                tones = []123                tones = []
124                for tone in self.all_tones:124                for tone in self.all_tones:
125                    if not tone == other:125                    if not tone == other:
126                        tones.append(tone)126                        tones.append(tone)
nn127                new_root = tones[0]
127                return Chord(self.root, *(tuple(tones)))128                return Chord(new_root, *(tuple(tones)))
128            else:129            else:
129                raise TypeError('Cannot have a chord made of only 1 unique tone')130                raise TypeError('Cannot have a chord made of only 1 unique tone')
130131
131    def transposed(self, interval):132    def transposed(self, interval):
132        interval_num = interval.number_of_semitones133        interval_num = interval.number_of_semitones
133        tones = []134        tones = []
134        if interval_num > 0:135        if interval_num > 0:
135            for tone in self.all_tones:136            for tone in self.all_tones:
136                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12137                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12
137                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))138                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
138        else:139        else:
139            for tone in self.all_tones:140            for tone in self.all_tones:
140                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12141                curr_idx = (CHROMATIC_SCALE.index(tone.name) + interval_num) % 12
141                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))142                tones.append(Tone(CHROMATIC_SCALE[curr_idx]))
142        new_root = tones[0]143        new_root = tones[0]
143        return Chord(new_root, *(tuple(tones[1:])))144        return Chord(new_root, *(tuple(tones[1:])))
144145
145146
tt147c_major_chord = Chord(Tone("C"), Tone("E"), Tone("G"))
148result_chord = c_major_chord - Tone("C")
149print(result_chord)
150# C-G
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op