Домашни > Pitches love the D > Решения > Решението на Камелия Тодорова

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

9 точки общо

35 успешни теста
2 неуспешни теста
Код

  1class Tone:
  2    def __init__(self, tone_name):
  3        self.tone_name = tone_name
  4    
  5    def __str__(self):
  6        return str(self.tone_name)
  7    
  8    @property
  9    def name(self):
 10        return self.tone_name
 11    
 12    def __add__(self, other):
 13        if isinstance(other, Tone):
 14            return Chord(self, other)
 15        elif isinstance(other, Interval):
 16            tone_index = Chord.index_of_tone(self)
 17            dist = other.number_of_semitones
 18            result_index = (tone_index + dist) % 12
 19            return Tone(Chord.get_tone_by_index(result_index))
 20    
 21    def __sub__(self, other):
 22        if isinstance(other, Tone):
 23            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))
 24        elif isinstance(other, Interval):
 25            tone_index = Chord.index_of_tone(self)
 26            dist = other.number_of_semitones
 27            res_index = (tone_index - dist) % 12
 28            return Tone(Chord.get_tone_by_index(res_index))
 29
 30
 31class Interval:
 32    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
 33                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
 34                       "major 6th", "minor 7th", "major 7th")
 35     
 36    def __init__(self, number_of_semitones):
 37        self.number_of_semitones = number_of_semitones % 12
 38    
 39    def __str__(self):
 40        return self.NAMED_INTERVALS[self.number_of_semitones]
 41    
 42    def get_index(self):
 43        return self.NAMED_INTERVALS.index(str(self))
 44    
 45    def __add__(self, other):
 46        return Interval(self.get_index() + other.get_index())
 47    
 48    def __neg__(self):
 49        return Interval(-self.number_of_semitones)
 50    
 51
 52class Chord:
 53    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
 54    
 55    def __init__(self, root, *tones):
 56        self.root = root
 57        tones_names = [curr_tone_name.name for curr_tone_name in tones]
 58        tones_names = set(tones_names)
 59        self.unique_tones_names = {root.name} | tones_names
 60        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]
 61        if len(self.tones_unique) == 1:
 62            raise TypeError("Cannot have a chord made of only 1 unique tone")
 63        self.create_right_orderd_list()
 64
 65    def create_right_orderd_list(self):
 66        root_index = self.ALL_TONES.index(self.root.name)
 67        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]
 68        self.tones_unique = [Tone(tone) for tone in right_order_seq if tone in self.unique_tones_names]
 69        self.unique_tones_names = [str(tone) for tone in self.tones_unique]
 70    
 71    def __str__(self):
 72        return "-".join(str(tone) for tone in self.tones_unique)
 73
 74    @classmethod
 75    def index_of_tone(cls, tone):
 76        return cls.ALL_TONES.index(tone.name)
 77    
 78    @classmethod
 79    def get_tone_by_index(cls, index):
 80        return cls.ALL_TONES[index]
 81    
 82    def is_major(self):
 83        MAJOR_STRING = "major 3rd"
 84
 85        for curr_tone in self.tones_unique:
 86            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
 87            if str(Interval(curr_dist)) == MAJOR_STRING:
 88                return True
 89        return False
 90    
 91    def is_minor(self):
 92        MINOR_STRING = "minor 3rd"
 93
 94        for curr_tone in self.tones_unique:
 95            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
 96            if str(Interval(curr_dist)) == MINOR_STRING:
 97                return True
 98        return False
 99    
100    def is_power_chord(self):
101        return not self.is_minor() and not self.is_major()
102
103    def __add__(self, other):
104        if isinstance(other, Tone):
105            return Chord(self.root, *(self.tones_unique + [other]))
106        elif isinstance(other, Chord):
107            return Chord(self.root, *(self.tones_unique + other.tones_unique))
108
109    def __sub__(self, other):
110         if isinstance(other, Tone):
111            if other.name not in self.unique_tones_names:
112                raise TypeError(f"Cannot remove tone {other} from chord {self}")
113            chord_tones = tuple(tone for tone in self.tones_unique if tone.name != other.name)
114            return Chord(self.root, *chord_tones)
115            
116    def transposed(self, interval):
117        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]
118        return Chord(*transposed_chord)
119    

..................E........F.........
======================================================================
ERROR: test_add_interval_to_tone_left_side_error (test.TestOperations.test_add_interval_to_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 210, in test_add_interval_to_tone_left_side_error
Interval(2) + g
~~~~~~~~~~~~^~~
File "/tmp/solution.py", line 46, in __add__
return Interval(self.get_index() + other.get_index())
^^^^^^^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'get_index'

======================================================================
FAIL: test_subtract_interval_from_tone_left_side_error (test.TestOperations.test_subtract_interval_from_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 235, in test_subtract_interval_from_tone_left_side_error
self.assertEqual(str(err.exception), INVALID_OPERATION)
AssertionError: "unsupported operand type(s) for -: 'Interval' and 'Tone'" != 'Invalid operation'
- unsupported operand type(s) for -: 'Interval' and 'Tone'
+ Invalid operation

----------------------------------------------------------------------
Ran 37 tests in 0.003s

FAILED (failures=1, errors=1)

Дискусия
История

f1class Tone:f1class Tone:
2    def __init__(self, tone_name):2    def __init__(self, tone_name):
3        self.tone_name = tone_name3        self.tone_name = tone_name
4    4    
5    def __str__(self):5    def __str__(self):
6        return str(self.tone_name)6        return str(self.tone_name)
7    7    
8    @property8    @property
9    def name(self):9    def name(self):
10        return self.tone_name10        return self.tone_name
11    11    
12    def __add__(self, other):12    def __add__(self, other):
13        if isinstance(other, Tone):13        if isinstance(other, Tone):
14            return Chord(self, other)14            return Chord(self, other)
15        elif isinstance(other, Interval):15        elif isinstance(other, Interval):
16            tone_index = Chord.index_of_tone(self)16            tone_index = Chord.index_of_tone(self)
17            dist = other.number_of_semitones17            dist = other.number_of_semitones
18            result_index = (tone_index + dist) % 1218            result_index = (tone_index + dist) % 12
19            return Tone(Chord.get_tone_by_index(result_index))19            return Tone(Chord.get_tone_by_index(result_index))
20    20    
21    def __sub__(self, other):21    def __sub__(self, other):
22        if isinstance(other, Tone):22        if isinstance(other, Tone):
23            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))23            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))
24        elif isinstance(other, Interval):24        elif isinstance(other, Interval):
25            tone_index = Chord.index_of_tone(self)25            tone_index = Chord.index_of_tone(self)
26            dist = other.number_of_semitones26            dist = other.number_of_semitones
27            res_index = (tone_index - dist) % 1227            res_index = (tone_index - dist) % 12
28            return Tone(Chord.get_tone_by_index(res_index))28            return Tone(Chord.get_tone_by_index(res_index))
2929
3030
31class Interval:31class Interval:
32    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",32    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
33                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",33                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
34                       "major 6th", "minor 7th", "major 7th")34                       "major 6th", "minor 7th", "major 7th")
35     35     
36    def __init__(self, number_of_semitones):36    def __init__(self, number_of_semitones):
37        self.number_of_semitones = number_of_semitones % 1237        self.number_of_semitones = number_of_semitones % 12
38    38    
39    def __str__(self):39    def __str__(self):
40        return self.NAMED_INTERVALS[self.number_of_semitones]40        return self.NAMED_INTERVALS[self.number_of_semitones]
41    41    
42    def get_index(self):42    def get_index(self):
43        return self.NAMED_INTERVALS.index(str(self))43        return self.NAMED_INTERVALS.index(str(self))
44    44    
45    def __add__(self, other):45    def __add__(self, other):
46        return Interval(self.get_index() + other.get_index())46        return Interval(self.get_index() + other.get_index())
nn47    
48    def __neg__(self):
49        return Interval(-self.number_of_semitones)
47    50    
4851
49class Chord:52class Chord:
50    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")53    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
51    54    
52    def __init__(self, root, *tones):55    def __init__(self, root, *tones):
53        self.root = root56        self.root = root
54        tones_names = [curr_tone_name.name for curr_tone_name in tones]57        tones_names = [curr_tone_name.name for curr_tone_name in tones]
55        tones_names = set(tones_names)58        tones_names = set(tones_names)
56        self.unique_tones_names = {root.name} | tones_names59        self.unique_tones_names = {root.name} | tones_names
57        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]60        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]
58        if len(self.tones_unique) == 1:61        if len(self.tones_unique) == 1:
59            raise TypeError("Cannot have a chord made of only 1 unique tone")62            raise TypeError("Cannot have a chord made of only 1 unique tone")
60        self.create_right_orderd_list()63        self.create_right_orderd_list()
6164
62    def create_right_orderd_list(self):65    def create_right_orderd_list(self):
63        root_index = self.ALL_TONES.index(self.root.name)66        root_index = self.ALL_TONES.index(self.root.name)
64        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]67        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]
65        self.tones_unique = [Tone(tone) for tone in right_order_seq if tone in self.unique_tones_names]68        self.tones_unique = [Tone(tone) for tone in right_order_seq if tone in self.unique_tones_names]
66        self.unique_tones_names = [str(tone) for tone in self.tones_unique]69        self.unique_tones_names = [str(tone) for tone in self.tones_unique]
67    70    
68    def __str__(self):71    def __str__(self):
69        return "-".join(str(tone) for tone in self.tones_unique)72        return "-".join(str(tone) for tone in self.tones_unique)
7073
71    @classmethod74    @classmethod
72    def index_of_tone(cls, tone):75    def index_of_tone(cls, tone):
73        return cls.ALL_TONES.index(tone.name)76        return cls.ALL_TONES.index(tone.name)
74    77    
75    @classmethod78    @classmethod
76    def get_tone_by_index(cls, index):79    def get_tone_by_index(cls, index):
77        return cls.ALL_TONES[index]80        return cls.ALL_TONES[index]
78    81    
79    def is_major(self):82    def is_major(self):
80        MAJOR_STRING = "major 3rd"83        MAJOR_STRING = "major 3rd"
8184
82        for curr_tone in self.tones_unique:85        for curr_tone in self.tones_unique:
83            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)86            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
84            if str(Interval(curr_dist)) == MAJOR_STRING:87            if str(Interval(curr_dist)) == MAJOR_STRING:
85                return True88                return True
86        return False89        return False
87    90    
88    def is_minor(self):91    def is_minor(self):
89        MINOR_STRING = "minor 3rd"92        MINOR_STRING = "minor 3rd"
9093
91        for curr_tone in self.tones_unique:94        for curr_tone in self.tones_unique:
92            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)95            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
93            if str(Interval(curr_dist)) == MINOR_STRING:96            if str(Interval(curr_dist)) == MINOR_STRING:
94                return True97                return True
95        return False98        return False
96    99    
97    def is_power_chord(self):100    def is_power_chord(self):
98        return not self.is_minor() and not self.is_major()101        return not self.is_minor() and not self.is_major()
99102
100    def __add__(self, other):103    def __add__(self, other):
101        if isinstance(other, Tone):104        if isinstance(other, Tone):
102            return Chord(self.root, *(self.tones_unique + [other]))105            return Chord(self.root, *(self.tones_unique + [other]))
103        elif isinstance(other, Chord):106        elif isinstance(other, Chord):
104            return Chord(self.root, *(self.tones_unique + other.tones_unique))107            return Chord(self.root, *(self.tones_unique + other.tones_unique))
105108
106    def __sub__(self, other):109    def __sub__(self, other):
107         if isinstance(other, Tone):110         if isinstance(other, Tone):
108            if other.name not in self.unique_tones_names:111            if other.name not in self.unique_tones_names:
109                raise TypeError(f"Cannot remove tone {other} from chord {self}")112                raise TypeError(f"Cannot remove tone {other} from chord {self}")
110            chord_tones = tuple(tone for tone in self.tones_unique if tone.name != other.name)113            chord_tones = tuple(tone for tone in self.tones_unique if tone.name != other.name)
111            return Chord(self.root, *chord_tones)114            return Chord(self.root, *chord_tones)
112            115            
113    def transposed(self, interval):116    def transposed(self, interval):
114        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]117        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]
115        return Chord(*transposed_chord)118        return Chord(*transposed_chord)
t116 t119    
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class Tone:f1class Tone:
2    def __init__(self, tone_name):2    def __init__(self, tone_name):
3        self.tone_name = tone_name3        self.tone_name = tone_name
4    4    
5    def __str__(self):5    def __str__(self):
6        return str(self.tone_name)6        return str(self.tone_name)
7    7    
nn8    @property
8    def get_name(self):9    def name(self):
9        return self.tone_name10        return self.tone_name
10    11    
11    def __add__(self, other):12    def __add__(self, other):
12        if isinstance(other, Tone):13        if isinstance(other, Tone):
13            return Chord(self, other)14            return Chord(self, other)
14        elif isinstance(other, Interval):15        elif isinstance(other, Interval):
15            tone_index = Chord.index_of_tone(self)16            tone_index = Chord.index_of_tone(self)
16            dist = other.number_of_semitones17            dist = other.number_of_semitones
17            result_index = (tone_index + dist) % 1218            result_index = (tone_index + dist) % 12
18            return Tone(Chord.get_tone_by_index(result_index))19            return Tone(Chord.get_tone_by_index(result_index))
19    20    
20    def __sub__(self, other):21    def __sub__(self, other):
21        if isinstance(other, Tone):22        if isinstance(other, Tone):
22            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))23            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))
23        elif isinstance(other, Interval):24        elif isinstance(other, Interval):
24            tone_index = Chord.index_of_tone(self)25            tone_index = Chord.index_of_tone(self)
25            dist = other.number_of_semitones26            dist = other.number_of_semitones
26            res_index = (tone_index - dist) % 1227            res_index = (tone_index - dist) % 12
27            return Tone(Chord.get_tone_by_index(res_index))28            return Tone(Chord.get_tone_by_index(res_index))
2829
2930
30class Interval:31class Interval:
31    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",32    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
32                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",33                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
33                       "major 6th", "minor 7th", "major 7th")34                       "major 6th", "minor 7th", "major 7th")
34     35     
35    def __init__(self, number_of_semitones):36    def __init__(self, number_of_semitones):
36        self.number_of_semitones = number_of_semitones % 1237        self.number_of_semitones = number_of_semitones % 12
37    38    
38    def __str__(self):39    def __str__(self):
39        return self.NAMED_INTERVALS[self.number_of_semitones]40        return self.NAMED_INTERVALS[self.number_of_semitones]
40    41    
41    def get_index(self):42    def get_index(self):
42        return self.NAMED_INTERVALS.index(str(self))43        return self.NAMED_INTERVALS.index(str(self))
43    44    
44    def __add__(self, other):45    def __add__(self, other):
45        return Interval(self.get_index() + other.get_index())46        return Interval(self.get_index() + other.get_index())
46    47    
nn48 
47class Chord:49class Chord:
48    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")50    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
49    51    
50    def __init__(self, root, *tones):52    def __init__(self, root, *tones):
51        self.root = root53        self.root = root
n52        tones_names = [curr_tone_name.get_name() for curr_tone_name in tones]n54        tones_names = [curr_tone_name.name for curr_tone_name in tones]
53        tones_names = set(tones_names)55        tones_names = set(tones_names)
n54        self.unique_tones_names = {root.get_name()} | tones_namesn56        self.unique_tones_names = {root.name} | tones_names
55        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]57        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]
56        if len(self.tones_unique) == 1:58        if len(self.tones_unique) == 1:
57            raise TypeError("Cannot have a chord made of only 1 unique tone")59            raise TypeError("Cannot have a chord made of only 1 unique tone")
58        self.create_right_orderd_list()60        self.create_right_orderd_list()
5961
60    def create_right_orderd_list(self):62    def create_right_orderd_list(self):
n61        root_index = self.ALL_TONES.index(self.root.get_name())n63        root_index = self.ALL_TONES.index(self.root.name)
62        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]64        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]
n63        final_order_of_tones = []n65        self.tones_unique = [Tone(tone) for tone in right_order_seq if tone in self.unique_tones_names]
64        for curr_tone in right_order_seq:
65            if curr_tone in self.unique_tones_names:
66                final_order_of_tones.append(Tone(curr_tone))
67        self.tones_unique = final_order_of_tones
68        self.unique_tones_names = [str(tone) for tone in self.tones_unique]66        self.unique_tones_names = [str(tone) for tone in self.tones_unique]
69    67    
70    def __str__(self):68    def __str__(self):
n71        to_print = "-".join(str(tone) for tone in self.tones_unique)n69        return "-".join(str(tone) for tone in self.tones_unique)
72        return f"{to_print}"
7370
74    @classmethod71    @classmethod
n75    def index_of_tone(self, tone):n72    def index_of_tone(cls, tone):
76        return self.ALL_TONES.index(tone.get_name())73        return cls.ALL_TONES.index(tone.name)
77    74    
78    @classmethod75    @classmethod
n79    def get_tone_by_index(self, index):n76    def get_tone_by_index(cls, index):
80        return self.ALL_TONES[index]77        return cls.ALL_TONES[index]
81    78    
82    def is_major(self):79    def is_major(self):
83        MAJOR_STRING = "major 3rd"80        MAJOR_STRING = "major 3rd"
8481
85        for curr_tone in self.tones_unique:82        for curr_tone in self.tones_unique:
86            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)83            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
87            if str(Interval(curr_dist)) == MAJOR_STRING:84            if str(Interval(curr_dist)) == MAJOR_STRING:
88                return True85                return True
89        return False86        return False
90    87    
91    def is_minor(self):88    def is_minor(self):
92        MINOR_STRING = "minor 3rd"89        MINOR_STRING = "minor 3rd"
n93        n90 
94        for curr_tone in self.tones_unique:91        for curr_tone in self.tones_unique:
95            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)92            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
96            if str(Interval(curr_dist)) == MINOR_STRING:93            if str(Interval(curr_dist)) == MINOR_STRING:
97                return True94                return True
98        return False95        return False
99    96    
100    def is_power_chord(self):97    def is_power_chord(self):
101        return not self.is_minor() and not self.is_major()98        return not self.is_minor() and not self.is_major()
10299
103    def __add__(self, other):100    def __add__(self, other):
104        if isinstance(other, Tone):101        if isinstance(other, Tone):
105            return Chord(self.root, *(self.tones_unique + [other]))102            return Chord(self.root, *(self.tones_unique + [other]))
106        elif isinstance(other, Chord):103        elif isinstance(other, Chord):
107            return Chord(self.root, *(self.tones_unique + other.tones_unique))104            return Chord(self.root, *(self.tones_unique + other.tones_unique))
108105
109    def __sub__(self, other):106    def __sub__(self, other):
110         if isinstance(other, Tone):107         if isinstance(other, Tone):
n111            if other.get_name() not in self.unique_tones_names:n108            if other.name not in self.unique_tones_names:
112                raise TypeError(f"Cannot remove tone {other} from chord {self}")109                raise TypeError(f"Cannot remove tone {other} from chord {self}")
n113            chord_tones = tuple(tone for tone in self.tones_unique if tone.get_name() != other.get_name())n110            chord_tones = tuple(tone for tone in self.tones_unique if tone.name != other.name)
114            return Chord(self.root, *chord_tones)111            return Chord(self.root, *chord_tones)
115            112            
116    def transposed(self, interval):113    def transposed(self, interval):
117        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]114        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]
t118        return Chord(transposed_chord[0], *transposed_chord[1:])t115        return Chord(*transposed_chord)
116 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class Tone:f1class Tone:
2    def __init__(self, tone_name):2    def __init__(self, tone_name):
3        self.tone_name = tone_name3        self.tone_name = tone_name
4    4    
5    def __str__(self):5    def __str__(self):
6        return str(self.tone_name)6        return str(self.tone_name)
7    7    
8    def get_name(self):8    def get_name(self):
9        return self.tone_name9        return self.tone_name
10    10    
11    def __add__(self, other):11    def __add__(self, other):
12        if isinstance(other, Tone):12        if isinstance(other, Tone):
13            return Chord(self, other)13            return Chord(self, other)
14        elif isinstance(other, Interval):14        elif isinstance(other, Interval):
15            tone_index = Chord.index_of_tone(self)15            tone_index = Chord.index_of_tone(self)
16            dist = other.number_of_semitones16            dist = other.number_of_semitones
17            result_index = (tone_index + dist) % 1217            result_index = (tone_index + dist) % 12
18            return Tone(Chord.get_tone_by_index(result_index))18            return Tone(Chord.get_tone_by_index(result_index))
19    19    
20    def __sub__(self, other):20    def __sub__(self, other):
21        if isinstance(other, Tone):21        if isinstance(other, Tone):
22            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))22            return Interval(Chord.index_of_tone(self) - Chord.index_of_tone(other))
23        elif isinstance(other, Interval):23        elif isinstance(other, Interval):
24            tone_index = Chord.index_of_tone(self)24            tone_index = Chord.index_of_tone(self)
25            dist = other.number_of_semitones25            dist = other.number_of_semitones
26            res_index = (tone_index - dist) % 1226            res_index = (tone_index - dist) % 12
27            return Tone(Chord.get_tone_by_index(res_index))27            return Tone(Chord.get_tone_by_index(res_index))
2828
2929
30class Interval:30class Interval:
31    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",31    NAMED_INTERVALS = ("unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
32                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",32                       "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
33                       "major 6th", "minor 7th", "major 7th")33                       "major 6th", "minor 7th", "major 7th")
34     34     
35    def __init__(self, number_of_semitones):35    def __init__(self, number_of_semitones):
36        self.number_of_semitones = number_of_semitones % 1236        self.number_of_semitones = number_of_semitones % 12
37    37    
38    def __str__(self):38    def __str__(self):
39        return self.NAMED_INTERVALS[self.number_of_semitones]39        return self.NAMED_INTERVALS[self.number_of_semitones]
40    40    
41    def get_index(self):41    def get_index(self):
42        return self.NAMED_INTERVALS.index(str(self))42        return self.NAMED_INTERVALS.index(str(self))
43    43    
44    def __add__(self, other):44    def __add__(self, other):
45        return Interval(self.get_index() + other.get_index())45        return Interval(self.get_index() + other.get_index())
46    46    
47class Chord:47class Chord:
48    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")48    ALL_TONES = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
49    49    
50    def __init__(self, root, *tones):50    def __init__(self, root, *tones):
51        self.root = root51        self.root = root
52        tones_names = [curr_tone_name.get_name() for curr_tone_name in tones]52        tones_names = [curr_tone_name.get_name() for curr_tone_name in tones]
53        tones_names = set(tones_names)53        tones_names = set(tones_names)
54        self.unique_tones_names = {root.get_name()} | tones_names54        self.unique_tones_names = {root.get_name()} | tones_names
55        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]55        self.tones_unique = [Tone(tone_name) for tone_name in self.unique_tones_names]
56        if len(self.tones_unique) == 1:56        if len(self.tones_unique) == 1:
57            raise TypeError("Cannot have a chord made of only 1 unique tone")57            raise TypeError("Cannot have a chord made of only 1 unique tone")
58        self.create_right_orderd_list()58        self.create_right_orderd_list()
5959
60    def create_right_orderd_list(self):60    def create_right_orderd_list(self):
61        root_index = self.ALL_TONES.index(self.root.get_name())61        root_index = self.ALL_TONES.index(self.root.get_name())
62        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]62        right_order_seq = self.ALL_TONES[root_index:] + self.ALL_TONES[:root_index]
63        final_order_of_tones = []63        final_order_of_tones = []
64        for curr_tone in right_order_seq:64        for curr_tone in right_order_seq:
65            if curr_tone in self.unique_tones_names:65            if curr_tone in self.unique_tones_names:
66                final_order_of_tones.append(Tone(curr_tone))66                final_order_of_tones.append(Tone(curr_tone))
67        self.tones_unique = final_order_of_tones67        self.tones_unique = final_order_of_tones
68        self.unique_tones_names = [str(tone) for tone in self.tones_unique]68        self.unique_tones_names = [str(tone) for tone in self.tones_unique]
69    69    
70    def __str__(self):70    def __str__(self):
71        to_print = "-".join(str(tone) for tone in self.tones_unique)71        to_print = "-".join(str(tone) for tone in self.tones_unique)
72        return f"{to_print}"72        return f"{to_print}"
7373
74    @classmethod74    @classmethod
75    def index_of_tone(self, tone):75    def index_of_tone(self, tone):
76        return self.ALL_TONES.index(tone.get_name())76        return self.ALL_TONES.index(tone.get_name())
77    77    
78    @classmethod78    @classmethod
79    def get_tone_by_index(self, index):79    def get_tone_by_index(self, index):
80        return self.ALL_TONES[index]80        return self.ALL_TONES[index]
81    81    
82    def is_major(self):82    def is_major(self):
n83        major_string = "major 3rd"n83        MAJOR_STRING = "major 3rd"
84 
84        for curr_tone in self.tones_unique:85        for curr_tone in self.tones_unique:
85            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)86            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
n86            if str(Interval(curr_dist)) == major_string:n87            if str(Interval(curr_dist)) == MAJOR_STRING:
87                return True88                return True
88        return False89        return False
89    90    
90    def is_minor(self):91    def is_minor(self):
n91        minor_string = "minor 3rd"n92        MINOR_STRING = "minor 3rd"
93        
92        for curr_tone in self.tones_unique:94        for curr_tone in self.tones_unique:
93            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)95            curr_dist = self.index_of_tone(curr_tone) - self.index_of_tone(self.root)
t94            if str(Interval(curr_dist)) == minor_string:t96            if str(Interval(curr_dist)) == MINOR_STRING:
95                return True97                return True
96        return False98        return False
97    99    
98    def is_power_chord(self):100    def is_power_chord(self):
99        return not self.is_minor() and not self.is_major()101        return not self.is_minor() and not self.is_major()
100102
101    def __add__(self, other):103    def __add__(self, other):
102        if isinstance(other, Tone):104        if isinstance(other, Tone):
103            return Chord(self.root, *(self.tones_unique + [other]))105            return Chord(self.root, *(self.tones_unique + [other]))
104        elif isinstance(other, Chord):106        elif isinstance(other, Chord):
105            return Chord(self.root, *(self.tones_unique + other.tones_unique))107            return Chord(self.root, *(self.tones_unique + other.tones_unique))
106108
107    def __sub__(self, other):109    def __sub__(self, other):
108         if isinstance(other, Tone):110         if isinstance(other, Tone):
109            if other.get_name() not in self.unique_tones_names:111            if other.get_name() not in self.unique_tones_names:
110                raise TypeError(f"Cannot remove tone {other} from chord {self}")112                raise TypeError(f"Cannot remove tone {other} from chord {self}")
111            chord_tones = tuple(tone for tone in self.tones_unique if tone.get_name() != other.get_name())113            chord_tones = tuple(tone for tone in self.tones_unique if tone.get_name() != other.get_name())
112            return Chord(self.root, *chord_tones)114            return Chord(self.root, *chord_tones)
113            115            
114    def transposed(self, interval):116    def transposed(self, interval):
115        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]117        transposed_chord = [curr_tone + interval for curr_tone in self.tones_unique]
116        return Chord(transposed_chord[0], *transposed_chord[1:])118        return Chord(transposed_chord[0], *transposed_chord[1:])
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op