Домашни > Pitches love the D > Решения > Решението на Илиана Миладинова

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

10 точки общо

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

  1class Tone:
  2    _NUMBER_OF_TONES = 12
  3
  4    tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
  5 
  6    def __init__(self, name):
  7        if name in self.tones:
  8            self.name = name
  9 
 10    def __str__(self):
 11        return self.name
 12 
 13    def __add__(self, other):
 14        if isinstance(other, Tone):
 15            return Chord(self, other)
 16        elif isinstance(other, Interval):
 17            ind = self.tones.index(self.name)
 18            new_ind = (ind+other.number_of_semitones) % self._NUMBER_OF_TONES
 19            return Tone(self.tones[new_ind])
 20 
 21    def __sub__(self, other):
 22        if isinstance(other, Tone):
 23            number_of_semitones = (Tone.tones.index(self.name)-Tone.tones.index(other.name)) % self._NUMBER_OF_TONES
 24            return Interval(number_of_semitones)
 25        elif isinstance(other, Interval):
 26            ind = self.tones.index(self.name)
 27            new_ind = (ind - other.number_of_semitones) % self._NUMBER_OF_TONES
 28            return Tone(self.tones[new_ind])
 29        
 30
 31class Interval:
 32    _NUMBER_OF_SEMITONES = 12
 33    intervals = {
 34        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd",
 35        4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th",
 36        7: "perfect 5th", 8: "minor 6th", 9: "major 6th",
 37        10: "minor 7th", 11: "major 7th"
 38        }
 39 
 40    def __init__(self, number_of_semitones):
 41        self.number_of_semitones = number_of_semitones % self._NUMBER_OF_SEMITONES
 42 
 43    def __str__(self):
 44        return self.intervals[self.number_of_semitones]
 45 
 46    def __add__(self, other):
 47        if isinstance(other, Tone):
 48            raise TypeError("Invalid operation")
 49        elif isinstance(other, Interval):
 50            new_num_of_semitones = self.number_of_semitones + other.number_of_semitones
 51            return Interval(new_num_of_semitones)
 52 
 53    def __sub__(self, other):
 54        if isinstance(other, Tone):
 55            raise TypeError("Invalid operation")
 56
 57    #used in the transpose function in order to add a negative interval to a tone 
 58    def __neg__(self): 
 59        """Convert an interval to the negative value."""
 60        return Interval(-self.number_of_semitones)
 61    
 62
 63class Chord:
 64    _NUMBER_OF_SEMITONES = 12
 65    _MIN_UNIQUE_TONES_IN_CHORD = 2
 66    _NUMBER_OF_SEMITONES_IN_MINOR = 3
 67    _NUMBER_OF_SEMITONES_IN_MAJOR = 4
 68    
 69    def __init__(self, main_tone, *other_tones):
 70        unique_tone_names = {main_tone.name}
 71        unique_tones = [main_tone]
 72 
 73        for tone in other_tones:
 74            if tone.name not in unique_tone_names:
 75                unique_tone_names.add(tone.name)
 76                unique_tones.append(tone)
 77 
 78        if len(unique_tone_names) < self._MIN_UNIQUE_TONES_IN_CHORD:
 79            raise TypeError("Cannot have a chord made of only 1 unique tone")
 80 
 81        main_tone_ind = Tone.tones.index(main_tone.name)
 82        self.main_tone_ind = main_tone_ind #so I can use it in _get_distance_from_main_tone
 83        tones_left = list()
 84
 85        for tone in unique_tones:
 86            if tone != main_tone:
 87                tones_left.append(tone)
 88
 89        tones_left.sort(key = self._get_distance_from_main_tone)
 90
 91        self.tones = [main_tone]
 92        for tone in tones_left:
 93            self.tones.append(tone)
 94            
 95    def _get_tones_diff(self, tone, main_tone_ind):
 96        """Return the count of semitones between a tone and the main_tone_ind."""
 97        return (Tone.tones.index(tone.name) - main_tone_ind) % self._NUMBER_OF_SEMITONES
 98    
 99    def _get_distance_from_main_tone(self, tone):
100        """Calculate the difference between the current tone and the main tone of the chord in semitones."""
101        return self._get_tones_diff(tone, self.main_tone_ind)
102         
103    def _get_tone_ind(self, tone_name):
104        """Return the index of a tone."""
105        return Tone.tones.index(tone_name)
106 
107    def __str__(self):
108        return f"{'-'.join(str(tone) for tone in self.tones)}"
109 
110    def _is_interval(self, semitones_count):
111        main_tone = self.tones[0]
112        main_tone_ind = self._get_tone_ind(main_tone.name)
113        tones_count = len(self.tones)
114
115        for t in range(1, tones_count):
116            tone = self.tones[t]
117            tone_ind = self._get_tone_ind(tone.name)
118            if((tone_ind - main_tone_ind) % self._NUMBER_OF_SEMITONES == semitones_count):
119                return True
120 
121        return False
122 
123    def is_minor(self):
124        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MINOR)
125 
126    def is_major(self):
127        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MAJOR)
128 
129    def is_power_chord(self):
130        if not self.is_minor() and not self.is_major():
131            return True
132        
133        return False
134    
135    def _create_chord(self, new_tones):
136        """Create a new chord."""
137        new_main_tone = new_tones[0]
138        new_other_tones = new_tones[1:]
139
140        return Chord(new_main_tone, *new_other_tones)
141    
142    def __add__(self, other):
143        tones_in_new_chord = list(self.tones)
144
145        if isinstance(other, Tone):
146            if other not in tones_in_new_chord:
147                tones_in_new_chord.append(other)
148            return self._create_chord(tones_in_new_chord)
149        elif isinstance(other, Chord):
150            for tone in other.tones:
151                if tone not in tones_in_new_chord:
152                    tones_in_new_chord.append(tone)
153
154            return self._create_chord(tones_in_new_chord)
155        
156    def __sub__(self, other):
157        if isinstance(other, Tone):
158            if other.name not in (tone.name for tone in self.tones):
159                raise TypeError(f"Cannot remove tone {other} from chord {self}")
160
161            tones_in_new_chord = list()
162
163            for tone in self.tones:
164                if tone.name != other.name:
165                    tones_in_new_chord.append(tone)
166
167            if len(tones_in_new_chord) < self._MIN_UNIQUE_TONES_IN_CHORD:
168                raise TypeError("Cannot have a chord made of only 1 unique tone")
169
170            return self._create_chord(tones_in_new_chord)
171    
172    def transposed(self, interval):
173        if isinstance(interval, Interval):
174            tones_in_new_chord = list()
175            for tone in self.tones:
176                new_tone = tone + interval
177                tones_in_new_chord.append(new_tone)
178
179            return self._create_chord(tones_in_new_chord)

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

OK

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

f1class Tone:f1class Tone:
2    _NUMBER_OF_TONES = 122    _NUMBER_OF_TONES = 12
33
4    tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")4    tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
5 5 
6    def __init__(self, name):6    def __init__(self, name):
7        if name in self.tones:7        if name in self.tones:
8            self.name = name8            self.name = name
9 9 
10    def __str__(self):10    def __str__(self):
11        return self.name11        return self.name
12 12 
13    def __add__(self, other):13    def __add__(self, other):
14        if isinstance(other, Tone):14        if isinstance(other, Tone):
15            return Chord(self, other)15            return Chord(self, other)
16        elif isinstance(other, Interval):16        elif isinstance(other, Interval):
17            ind = self.tones.index(self.name)17            ind = self.tones.index(self.name)
18            new_ind = (ind+other.number_of_semitones) % self._NUMBER_OF_TONES18            new_ind = (ind+other.number_of_semitones) % self._NUMBER_OF_TONES
19            return Tone(self.tones[new_ind])19            return Tone(self.tones[new_ind])
20 20 
21    def __sub__(self, other):21    def __sub__(self, other):
22        if isinstance(other, Tone):22        if isinstance(other, Tone):
23            number_of_semitones = (Tone.tones.index(self.name)-Tone.tones.index(other.name)) % self._NUMBER_OF_TONES23            number_of_semitones = (Tone.tones.index(self.name)-Tone.tones.index(other.name)) % self._NUMBER_OF_TONES
24            return Interval(number_of_semitones)24            return Interval(number_of_semitones)
n25 n
26        elif isinstance(other, Interval):25        elif isinstance(other, Interval):
27            ind = self.tones.index(self.name)26            ind = self.tones.index(self.name)
28            new_ind = (ind - other.number_of_semitones) % self._NUMBER_OF_TONES27            new_ind = (ind - other.number_of_semitones) % self._NUMBER_OF_TONES
29            return Tone(self.tones[new_ind])28            return Tone(self.tones[new_ind])
30        29        
3130
32class Interval:31class Interval:
33    _NUMBER_OF_SEMITONES = 1232    _NUMBER_OF_SEMITONES = 12
34    intervals = {33    intervals = {
35        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd",34        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd",
36        4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th",35        4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th",
37        7: "perfect 5th", 8: "minor 6th", 9: "major 6th",36        7: "perfect 5th", 8: "minor 6th", 9: "major 6th",
38        10: "minor 7th", 11: "major 7th"37        10: "minor 7th", 11: "major 7th"
39        }38        }
40 39 
41    def __init__(self, number_of_semitones):40    def __init__(self, number_of_semitones):
42        self.number_of_semitones = number_of_semitones % self._NUMBER_OF_SEMITONES41        self.number_of_semitones = number_of_semitones % self._NUMBER_OF_SEMITONES
43 42 
44    def __str__(self):43    def __str__(self):
45        return self.intervals[self.number_of_semitones]44        return self.intervals[self.number_of_semitones]
46 45 
47    def __add__(self, other):46    def __add__(self, other):
48        if isinstance(other, Tone):47        if isinstance(other, Tone):
49            raise TypeError("Invalid operation")48            raise TypeError("Invalid operation")
50        elif isinstance(other, Interval):49        elif isinstance(other, Interval):
51            new_num_of_semitones = self.number_of_semitones + other.number_of_semitones50            new_num_of_semitones = self.number_of_semitones + other.number_of_semitones
52            return Interval(new_num_of_semitones)51            return Interval(new_num_of_semitones)
53 52 
54    def __sub__(self, other):53    def __sub__(self, other):
55        if isinstance(other, Tone):54        if isinstance(other, Tone):
56            raise TypeError("Invalid operation")55            raise TypeError("Invalid operation")
5756
58    #used in the transpose function in order to add a negative interval to a tone 57    #used in the transpose function in order to add a negative interval to a tone 
59    def __neg__(self): 58    def __neg__(self): 
60        """Convert an interval to the negative value."""59        """Convert an interval to the negative value."""
61        return Interval(-self.number_of_semitones)60        return Interval(-self.number_of_semitones)
62    61    
6362
64class Chord:63class Chord:
65    _NUMBER_OF_SEMITONES = 1264    _NUMBER_OF_SEMITONES = 12
66    _MIN_UNIQUE_TONES_IN_CHORD = 265    _MIN_UNIQUE_TONES_IN_CHORD = 2
67    _NUMBER_OF_SEMITONES_IN_MINOR = 366    _NUMBER_OF_SEMITONES_IN_MINOR = 3
68    _NUMBER_OF_SEMITONES_IN_MAJOR = 467    _NUMBER_OF_SEMITONES_IN_MAJOR = 4
69    68    
70    def __init__(self, main_tone, *other_tones):69    def __init__(self, main_tone, *other_tones):
71        unique_tone_names = {main_tone.name}70        unique_tone_names = {main_tone.name}
72        unique_tones = [main_tone]71        unique_tones = [main_tone]
73 72 
74        for tone in other_tones:73        for tone in other_tones:
75            if tone.name not in unique_tone_names:74            if tone.name not in unique_tone_names:
76                unique_tone_names.add(tone.name)75                unique_tone_names.add(tone.name)
77                unique_tones.append(tone)76                unique_tones.append(tone)
78 77 
79        if len(unique_tone_names) < self._MIN_UNIQUE_TONES_IN_CHORD:78        if len(unique_tone_names) < self._MIN_UNIQUE_TONES_IN_CHORD:
80            raise TypeError("Cannot have a chord made of only 1 unique tone")79            raise TypeError("Cannot have a chord made of only 1 unique tone")
81 80 
82        main_tone_ind = Tone.tones.index(main_tone.name)81        main_tone_ind = Tone.tones.index(main_tone.name)
83        self.main_tone_ind = main_tone_ind #so I can use it in _get_distance_from_main_tone82        self.main_tone_ind = main_tone_ind #so I can use it in _get_distance_from_main_tone
84        tones_left = list()83        tones_left = list()
nn84 
85        for tone in unique_tones:85        for tone in unique_tones:
86            if tone != main_tone:86            if tone != main_tone:
87                tones_left.append(tone)87                tones_left.append(tone)
8888
89        tones_left.sort(key = self._get_distance_from_main_tone)89        tones_left.sort(key = self._get_distance_from_main_tone)
9090
91        self.tones = [main_tone]91        self.tones = [main_tone]
92        for tone in tones_left:92        for tone in tones_left:
93            self.tones.append(tone)93            self.tones.append(tone)
94            94            
95    def _get_tones_diff(self, tone, main_tone_ind):95    def _get_tones_diff(self, tone, main_tone_ind):
96        """Return the count of semitones between a tone and the main_tone_ind."""96        """Return the count of semitones between a tone and the main_tone_ind."""
97        return (Tone.tones.index(tone.name) - main_tone_ind) % self._NUMBER_OF_SEMITONES97        return (Tone.tones.index(tone.name) - main_tone_ind) % self._NUMBER_OF_SEMITONES
98    98    
99    def _get_distance_from_main_tone(self, tone):99    def _get_distance_from_main_tone(self, tone):
100        """Calculate the difference between the current tone and the main tone of the chord in semitones."""100        """Calculate the difference between the current tone and the main tone of the chord in semitones."""
101        return self._get_tones_diff(tone, self.main_tone_ind)101        return self._get_tones_diff(tone, self.main_tone_ind)
102         102         
103    def _get_tone_ind(self, tone_name):103    def _get_tone_ind(self, tone_name):
104        """Return the index of a tone."""104        """Return the index of a tone."""
105        return Tone.tones.index(tone_name)105        return Tone.tones.index(tone_name)
106 106 
107    def __str__(self):107    def __str__(self):
108        return f"{'-'.join(str(tone) for tone in self.tones)}"108        return f"{'-'.join(str(tone) for tone in self.tones)}"
109 109 
110    def _is_interval(self, semitones_count):110    def _is_interval(self, semitones_count):
111        main_tone = self.tones[0]111        main_tone = self.tones[0]
112        main_tone_ind = self._get_tone_ind(main_tone.name)112        main_tone_ind = self._get_tone_ind(main_tone.name)
n113 n
114        tones_count = len(self.tones)113        tones_count = len(self.tones)
nn114 
115        for t in range(1, tones_count):115        for t in range(1, tones_count):
116            tone = self.tones[t]116            tone = self.tones[t]
117            tone_ind = self._get_tone_ind(tone.name)117            tone_ind = self._get_tone_ind(tone.name)
118            if((tone_ind - main_tone_ind) % self._NUMBER_OF_SEMITONES == semitones_count):118            if((tone_ind - main_tone_ind) % self._NUMBER_OF_SEMITONES == semitones_count):
119                return True119                return True
120 120 
121        return False121        return False
122 122 
123    def is_minor(self):123    def is_minor(self):
124        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MINOR)124        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MINOR)
125 125 
126    def is_major(self):126    def is_major(self):
127        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MAJOR)127        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MAJOR)
128 128 
129    def is_power_chord(self):129    def is_power_chord(self):
130        if not self.is_minor() and not self.is_major():130        if not self.is_minor() and not self.is_major():
131            return True131            return True
132        132        
133        return False133        return False
134    134    
135    def _create_chord(self, new_tones):135    def _create_chord(self, new_tones):
136        """Create a new chord."""136        """Create a new chord."""
137        new_main_tone = new_tones[0]137        new_main_tone = new_tones[0]
138        new_other_tones = new_tones[1:]138        new_other_tones = new_tones[1:]
nn139 
139        return Chord(new_main_tone, *new_other_tones)140        return Chord(new_main_tone, *new_other_tones)
140    141    
141    def __add__(self, other):142    def __add__(self, other):
142        tones_in_new_chord = list(self.tones)143        tones_in_new_chord = list(self.tones)
nn144 
143        if isinstance(other, Tone):145        if isinstance(other, Tone):
144            if other not in tones_in_new_chord:146            if other not in tones_in_new_chord:
145                tones_in_new_chord.append(other)147                tones_in_new_chord.append(other)
n146 n
147            return self._create_chord(tones_in_new_chord)148            return self._create_chord(tones_in_new_chord)
n148        n
149        elif isinstance(other, Chord):149        elif isinstance(other, Chord):
150            for tone in other.tones:150            for tone in other.tones:
151                if tone not in tones_in_new_chord:151                if tone not in tones_in_new_chord:
152                    tones_in_new_chord.append(tone)152                    tones_in_new_chord.append(tone)
153153
154            return self._create_chord(tones_in_new_chord)154            return self._create_chord(tones_in_new_chord)
155        155        
156    def __sub__(self, other):156    def __sub__(self, other):
157        if isinstance(other, Tone):157        if isinstance(other, Tone):
158            if other.name not in (tone.name for tone in self.tones):158            if other.name not in (tone.name for tone in self.tones):
159                raise TypeError(f"Cannot remove tone {other} from chord {self}")159                raise TypeError(f"Cannot remove tone {other} from chord {self}")
160160
161            tones_in_new_chord = list()161            tones_in_new_chord = list()
tt162 
162            for tone in self.tones:163            for tone in self.tones:
163                if tone.name != other.name:164                if tone.name != other.name:
164                    tones_in_new_chord.append(tone)165                    tones_in_new_chord.append(tone)
165166
166            if len(tones_in_new_chord) < self._MIN_UNIQUE_TONES_IN_CHORD:167            if len(tones_in_new_chord) < self._MIN_UNIQUE_TONES_IN_CHORD:
167                raise TypeError("Cannot have a chord made of only 1 unique tone")168                raise TypeError("Cannot have a chord made of only 1 unique tone")
168169
169            return self._create_chord(tones_in_new_chord)170            return self._create_chord(tones_in_new_chord)
170    171    
171    def transposed(self, interval):172    def transposed(self, interval):
172        if isinstance(interval, Interval):173        if isinstance(interval, Interval):
173            tones_in_new_chord = list()174            tones_in_new_chord = list()
174            for tone in self.tones:175            for tone in self.tones:
175                new_tone = tone + interval176                new_tone = tone + interval
176                tones_in_new_chord.append(new_tone)177                tones_in_new_chord.append(new_tone)
177178
178            return self._create_chord(tones_in_new_chord)179            return self._create_chord(tones_in_new_chord)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class Tone:f1class Tone:
2    _NUMBER_OF_TONES = 122    _NUMBER_OF_TONES = 12
33
4    tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")4    tones = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
5 5 
6    def __init__(self, name):6    def __init__(self, name):
7        if name in self.tones:7        if name in self.tones:
8            self.name = name8            self.name = name
9 9 
10    def __str__(self):10    def __str__(self):
11        return self.name11        return self.name
12 12 
13    def __add__(self, other):13    def __add__(self, other):
14        if isinstance(other, Tone):14        if isinstance(other, Tone):
15            return Chord(self, other)15            return Chord(self, other)
16        elif isinstance(other, Interval):16        elif isinstance(other, Interval):
17            ind = self.tones.index(self.name)17            ind = self.tones.index(self.name)
18            new_ind = (ind+other.number_of_semitones) % self._NUMBER_OF_TONES18            new_ind = (ind+other.number_of_semitones) % self._NUMBER_OF_TONES
19            return Tone(self.tones[new_ind])19            return Tone(self.tones[new_ind])
20 20 
21    def __sub__(self, other):21    def __sub__(self, other):
22        if isinstance(other, Tone):22        if isinstance(other, Tone):
23            number_of_semitones = (Tone.tones.index(self.name)-Tone.tones.index(other.name)) % self._NUMBER_OF_TONES23            number_of_semitones = (Tone.tones.index(self.name)-Tone.tones.index(other.name)) % self._NUMBER_OF_TONES
24            return Interval(number_of_semitones)24            return Interval(number_of_semitones)
25 25 
26        elif isinstance(other, Interval):26        elif isinstance(other, Interval):
27            ind = self.tones.index(self.name)27            ind = self.tones.index(self.name)
28            new_ind = (ind - other.number_of_semitones) % self._NUMBER_OF_TONES28            new_ind = (ind - other.number_of_semitones) % self._NUMBER_OF_TONES
29            return Tone(self.tones[new_ind])29            return Tone(self.tones[new_ind])
30        30        
3131
32class Interval:32class Interval:
33    _NUMBER_OF_SEMITONES = 1233    _NUMBER_OF_SEMITONES = 12
34    intervals = {34    intervals = {
35        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd",35        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd",
36        4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th",36        4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th",
37        7: "perfect 5th", 8: "minor 6th", 9: "major 6th",37        7: "perfect 5th", 8: "minor 6th", 9: "major 6th",
38        10: "minor 7th", 11: "major 7th"38        10: "minor 7th", 11: "major 7th"
39        }39        }
40 40 
41    def __init__(self, number_of_semitones):41    def __init__(self, number_of_semitones):
42        self.number_of_semitones = number_of_semitones % self._NUMBER_OF_SEMITONES42        self.number_of_semitones = number_of_semitones % self._NUMBER_OF_SEMITONES
43 43 
44    def __str__(self):44    def __str__(self):
45        return self.intervals[self.number_of_semitones]45        return self.intervals[self.number_of_semitones]
46 46 
47    def __add__(self, other):47    def __add__(self, other):
48        if isinstance(other, Tone):48        if isinstance(other, Tone):
49            raise TypeError("Invalid operation")49            raise TypeError("Invalid operation")
50        elif isinstance(other, Interval):50        elif isinstance(other, Interval):
51            new_num_of_semitones = self.number_of_semitones + other.number_of_semitones51            new_num_of_semitones = self.number_of_semitones + other.number_of_semitones
52            return Interval(new_num_of_semitones)52            return Interval(new_num_of_semitones)
53 53 
54    def __sub__(self, other):54    def __sub__(self, other):
55        if isinstance(other, Tone):55        if isinstance(other, Tone):
56            raise TypeError("Invalid operation")56            raise TypeError("Invalid operation")
5757
58    #used in the transpose function in order to add a negative interval to a tone 58    #used in the transpose function in order to add a negative interval to a tone 
59    def __neg__(self): 59    def __neg__(self): 
60        """Convert an interval to the negative value."""60        """Convert an interval to the negative value."""
61        return Interval(-self.number_of_semitones)61        return Interval(-self.number_of_semitones)
62    62    
6363
64class Chord:64class Chord:
65    _NUMBER_OF_SEMITONES = 1265    _NUMBER_OF_SEMITONES = 12
66    _MIN_UNIQUE_TONES_IN_CHORD = 266    _MIN_UNIQUE_TONES_IN_CHORD = 2
67    _NUMBER_OF_SEMITONES_IN_MINOR = 367    _NUMBER_OF_SEMITONES_IN_MINOR = 3
68    _NUMBER_OF_SEMITONES_IN_MAJOR = 468    _NUMBER_OF_SEMITONES_IN_MAJOR = 4
69    69    
70    def __init__(self, main_tone, *other_tones):70    def __init__(self, main_tone, *other_tones):
71        unique_tone_names = {main_tone.name}71        unique_tone_names = {main_tone.name}
72        unique_tones = [main_tone]72        unique_tones = [main_tone]
73 73 
74        for tone in other_tones:74        for tone in other_tones:
75            if tone.name not in unique_tone_names:75            if tone.name not in unique_tone_names:
76                unique_tone_names.add(tone.name)76                unique_tone_names.add(tone.name)
77                unique_tones.append(tone)77                unique_tones.append(tone)
78 78 
79        if len(unique_tone_names) < self._MIN_UNIQUE_TONES_IN_CHORD:79        if len(unique_tone_names) < self._MIN_UNIQUE_TONES_IN_CHORD:
80            raise TypeError("Cannot have a chord made of only 1 unique tone")80            raise TypeError("Cannot have a chord made of only 1 unique tone")
81 81 
82        main_tone_ind = Tone.tones.index(main_tone.name)82        main_tone_ind = Tone.tones.index(main_tone.name)
83        self.main_tone_ind = main_tone_ind #so I can use it in _get_distance_from_main_tone83        self.main_tone_ind = main_tone_ind #so I can use it in _get_distance_from_main_tone
84        tones_left = list()84        tones_left = list()
85        for tone in unique_tones:85        for tone in unique_tones:
86            if tone != main_tone:86            if tone != main_tone:
87                tones_left.append(tone)87                tones_left.append(tone)
8888
89        tones_left.sort(key = self._get_distance_from_main_tone)89        tones_left.sort(key = self._get_distance_from_main_tone)
9090
91        self.tones = [main_tone]91        self.tones = [main_tone]
92        for tone in tones_left:92        for tone in tones_left:
93            self.tones.append(tone)93            self.tones.append(tone)
94            94            
95    def _get_tones_diff(self, tone, main_tone_ind):95    def _get_tones_diff(self, tone, main_tone_ind):
96        """Return the count of semitones between a tone and the main_tone_ind."""96        """Return the count of semitones between a tone and the main_tone_ind."""
97        return (Tone.tones.index(tone.name) - main_tone_ind) % self._NUMBER_OF_SEMITONES97        return (Tone.tones.index(tone.name) - main_tone_ind) % self._NUMBER_OF_SEMITONES
98    98    
99    def _get_distance_from_main_tone(self, tone):99    def _get_distance_from_main_tone(self, tone):
100        """Calculate the difference between the current tone and the main tone of the chord in semitones."""100        """Calculate the difference between the current tone and the main tone of the chord in semitones."""
101        return self._get_tones_diff(tone, self.main_tone_ind)101        return self._get_tones_diff(tone, self.main_tone_ind)
102         102         
103    def _get_tone_ind(self, tone_name):103    def _get_tone_ind(self, tone_name):
104        """Return the index of a tone."""104        """Return the index of a tone."""
105        return Tone.tones.index(tone_name)105        return Tone.tones.index(tone_name)
106 106 
107    def __str__(self):107    def __str__(self):
108        return f"{'-'.join(str(tone) for tone in self.tones)}"108        return f"{'-'.join(str(tone) for tone in self.tones)}"
109 109 
110    def _is_interval(self, semitones_count):110    def _is_interval(self, semitones_count):
111        main_tone = self.tones[0]111        main_tone = self.tones[0]
112        main_tone_ind = self._get_tone_ind(main_tone.name)112        main_tone_ind = self._get_tone_ind(main_tone.name)
113 113 
114        tones_count = len(self.tones)114        tones_count = len(self.tones)
115        for t in range(1, tones_count):115        for t in range(1, tones_count):
116            tone = self.tones[t]116            tone = self.tones[t]
117            tone_ind = self._get_tone_ind(tone.name)117            tone_ind = self._get_tone_ind(tone.name)
t118 t
119            if((tone_ind - main_tone_ind) % self._NUMBER_OF_SEMITONES == semitones_count):118            if((tone_ind - main_tone_ind) % self._NUMBER_OF_SEMITONES == semitones_count):
120                return True119                return True
121 120 
122        return False121        return False
123 122 
124    def is_minor(self):123    def is_minor(self):
125        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MINOR)124        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MINOR)
126 125 
127    def is_major(self):126    def is_major(self):
128        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MAJOR)127        return self._is_interval(self._NUMBER_OF_SEMITONES_IN_MAJOR)
129 128 
130    def is_power_chord(self):129    def is_power_chord(self):
131        if not self.is_minor() and not self.is_major():130        if not self.is_minor() and not self.is_major():
132            return True131            return True
133        132        
134        return False133        return False
135    134    
136    def _create_chord(self, new_tones):135    def _create_chord(self, new_tones):
137        """Create a new chord."""136        """Create a new chord."""
138        new_main_tone = new_tones[0]137        new_main_tone = new_tones[0]
139        new_other_tones = new_tones[1:]138        new_other_tones = new_tones[1:]
140        return Chord(new_main_tone, *new_other_tones)139        return Chord(new_main_tone, *new_other_tones)
141    140    
142    def __add__(self, other):141    def __add__(self, other):
143        tones_in_new_chord = list(self.tones)142        tones_in_new_chord = list(self.tones)
144        if isinstance(other, Tone):143        if isinstance(other, Tone):
145            if other not in tones_in_new_chord:144            if other not in tones_in_new_chord:
146                tones_in_new_chord.append(other)145                tones_in_new_chord.append(other)
147146
148            return self._create_chord(tones_in_new_chord)147            return self._create_chord(tones_in_new_chord)
149        148        
150        elif isinstance(other, Chord):149        elif isinstance(other, Chord):
151            for tone in other.tones:150            for tone in other.tones:
152                if tone not in tones_in_new_chord:151                if tone not in tones_in_new_chord:
153                    tones_in_new_chord.append(tone)152                    tones_in_new_chord.append(tone)
154153
155            return self._create_chord(tones_in_new_chord)154            return self._create_chord(tones_in_new_chord)
156        155        
157    def __sub__(self, other):156    def __sub__(self, other):
158        if isinstance(other, Tone):157        if isinstance(other, Tone):
159            if other.name not in (tone.name for tone in self.tones):158            if other.name not in (tone.name for tone in self.tones):
160                raise TypeError(f"Cannot remove tone {other} from chord {self}")159                raise TypeError(f"Cannot remove tone {other} from chord {self}")
161160
162            tones_in_new_chord = list()161            tones_in_new_chord = list()
163            for tone in self.tones:162            for tone in self.tones:
164                if tone.name != other.name:163                if tone.name != other.name:
165                    tones_in_new_chord.append(tone)164                    tones_in_new_chord.append(tone)
166165
167            if len(tones_in_new_chord) < self._MIN_UNIQUE_TONES_IN_CHORD:166            if len(tones_in_new_chord) < self._MIN_UNIQUE_TONES_IN_CHORD:
168                raise TypeError("Cannot have a chord made of only 1 unique tone")167                raise TypeError("Cannot have a chord made of only 1 unique tone")
169168
170            return self._create_chord(tones_in_new_chord)169            return self._create_chord(tones_in_new_chord)
171    170    
172    def transposed(self, interval):171    def transposed(self, interval):
173        if isinstance(interval, Interval):172        if isinstance(interval, Interval):
174            tones_in_new_chord = list()173            tones_in_new_chord = list()
175            for tone in self.tones:174            for tone in self.tones:
176                new_tone = tone + interval175                new_tone = tone + interval
177                tones_in_new_chord.append(new_tone)176                tones_in_new_chord.append(new_tone)
178177
179            return self._create_chord(tones_in_new_chord)178            return self._create_chord(tones_in_new_chord)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op