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

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

8 точки общо

31 успешни теста
6 неуспешни теста
Код

  1INTERVALS = ['unison','minor 2nd', 'major 2nd', 'minor 3rd', 'major 3rd', 'perfect 4th', 'diminished 5th', 'perfect 5th', 'minor 6th', 'major 6th', 'minor 7th', 'major 7th']
  2ORDER = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
  3MINOR_3RD = 3
  4MAJOR_3RD = 4
  5
  6
  7class Tone:
  8    def __init__(self, name):
  9        self.name = name
 10
 11    def __str__(self):
 12        return self.name
 13
 14    def __add__(self, other):
 15        if type(other) is Tone:
 16            return Chord(self, other)
 17        elif type(other) is Interval:
 18            tone_index = other.number_of_semitones
 19            tone_index += ORDER.index(self.name)
 20            tone_index %= 12
 21            return Tone(ORDER[tone_index]) 
 22
 23    def __sub__(self, other):
 24        if type(other) is Interval:
 25            return Tone(ORDER[(ORDER.index(self.name) - other.number_of_semitones) % 12])
 26        elif type(other) is Tone:
 27            return Interval(abs(ORDER.index(self.name) - ORDER.index(other.name)) % 12)
 28
 29    def __eq__(self, other):
 30        return self.name == other.name
 31        
 32
 33class Interval:
 34    def __init__(self, number_of_semitones):
 35        self.number_of_semitones = number_of_semitones 
 36
 37    def __str__(self):
 38        interval = self.number_of_semitones % 12
 39        return INTERVALS[interval]
 40
 41    def __add__(self, other):
 42        if type(other) is Tone:
 43            raise TypeError('Invalid operation')
 44        elif type(other) is Interval:
 45            res = (self.number_of_semitones + other.number_of_semitones) % 12
 46            return Interval(res)
 47
 48    def __neg__(self):
 49         return Interval(-self.number_of_semitones)
 50
 51
 52
 53def sort_tones(root, tones):
 54    # rotating the ORDER list based on the root index
 55    root_index = ORDER.index(root)
 56    rotated_ORDER = ORDER[root_index:] + ORDER[:root_index]
 57    ORDER_index = {char: idx for idx, char in enumerate(rotated_ORDER)}
 58    return sorted(tones, key = lambda x: ORDER_index[x]) # custom sorting func
 59
 60
 61def remove_duplicates(input_list):
 62    seen = set()
 63    return [x for x in input_list if not (x in seen or seen.add(x))]
 64
 65
 66class Chord:
 67    def __init__(self, main_tone, *args):
 68        tones_names_list = []
 69        for el in args:
 70            tones_names_list.append(el.name)
 71        if main_tone.name in tones_names_list:
 72            tones_names_list.remove(main_tone.name)
 73        tones_names = set(tones_names_list)
 74        if len(tones_names) == 0:
 75            raise TypeError('Cannot have a chord made of only 1 unique tone')
 76        self.root = main_tone
 77        self.tones = args
 78
 79    def __str__(self):
 80        res = self.root.name
 81        tones = []
 82        for el in self.tones: tones.append(el.name)
 83        sorted = remove_duplicates(sort_tones(self.root.name, tones))
 84        for el in sorted: 
 85            if el != self.root.name:
 86               res = f'{res}-{el}'
 87        return res
 88
 89    def is_minor(self):
 90        for el in self.tones:
 91            if abs(ORDER.index(self.root.name) - ORDER.index(el.name)) == MINOR_3RD:
 92                return True
 93        return False
 94
 95    def is_major(self):
 96        for el in self.tones:
 97            if abs(ORDER.index(self.root.name) - ORDER.index(el.name)) == MAJOR_3RD:
 98                return True
 99        return False
100
101    def is_power_chord(self):
102        return not self.is_major() and not self.is_minor()
103
104    def __add__(self, other):
105        if type(other) is Tone:
106            return Chord(self.root, *self.tones, other)
107        elif type(other) is Chord:
108            return Chord(self.root, *self.tones, other.root, *other.tones)
109
110    def __sub__(self, other):
111        if type(other) is Tone:
112            tones = []
113            for el in self.tones: tones.append(el.name)
114            sorted = remove_duplicates(sort_tones(self.root.name, tones))
115            if other not in self.tones and other != self.root:
116                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')
117            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:
118                raise TypeError('Cannot have a chord made of only 1 unique tone')
119            if self.root == other:
120                if sorted[0] != self.root:
121                   self.root = Chord(sorted[0])
122                else:
123                   self.root = Chord(sorted[1]) 
124            res = []
125            for el in sorted: 
126                if el != other.name:
127                   res.append(Tone(el)) 
128            return Chord(self.root, *res)
129
130    def transposed(self, interval):
131        tones = []
132        root = self.root
133        for el in self.tones:
134            tones.append(Tone(ORDER[(ORDER.index(el.name) + interval.number_of_semitones) % 12]))
135        root = Tone(ORDER[(ORDER.index(root.name) + interval.number_of_semitones) % 12])
136        return Chord(root, *tones)
137    
138 

F...FFF....................F.......F.
======================================================================
FAIL: test_chord_not_enough_tones (test.TestBasicChordFunctionality.test_chord_not_enough_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 83, in test_chord_not_enough_tones
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised

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

======================================================================
FAIL: test_is_minor (test.TestBasicChordFunctionality.test_is_minor)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 90, in test_is_minor
self.assertTrue(a_minor_chord.is_minor())
AssertionError: False is not true

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

======================================================================
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

======================================================================
FAIL: test_tone_subtraction_inverse (test.TestOperations.test_tone_subtraction_inverse)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 178, in test_tone_subtraction_inverse
self.assertEqual(str(perfect_4th), "perfect 4th")
AssertionError: 'perfect 5th' != 'perfect 4th'
- perfect 5th
? ^
+ perfect 4th
? ^

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

FAILED (failures=6)

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

n1 n
2intervals = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd', 5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th', 9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}1INTERVALS = ['unison','minor 2nd', 'major 2nd', 'minor 3rd', 'major 3rd', 'perfect 4th', 'diminished 5th', 'perfect 5th', 'minor 6th', 'major 6th', 'minor 7th', 'major 7th']
3order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']2ORDER = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
4minor_3rd = 33MINOR_3RD = 3
5major_3rd = 44MAJOR_3RD = 4
65
76
8class Tone:7class Tone:
9    def __init__(self, name):8    def __init__(self, name):
10        self.name = name9        self.name = name
nn10 
11    def __str__(self):11    def __str__(self):
12        return self.name12        return self.name
nn13 
13    def __add__(self, other):14    def __add__(self, other):
14        if type(other) is Tone:15        if type(other) is Tone:
15            return Chord(self, other)16            return Chord(self, other)
16        elif type(other) is Interval:17        elif type(other) is Interval:
n17            res = other.number_of_semitonesn18            tone_index = other.number_of_semitones
18            res += order.index(self.name)19            tone_index += ORDER.index(self.name)
19            res %= 1220            tone_index %= 12
20            return Tone(order[res]) 21            return Tone(ORDER[tone_index]) 
22 
21    def __sub__(self, other):23    def __sub__(self, other):
22        if type(other) is Interval:24        if type(other) is Interval:
n23            return Tone(order[(order.index(self.name) - other.number_of_semitones) % 12])n25            return Tone(ORDER[(ORDER.index(self.name) - other.number_of_semitones) % 12])
24        elif type(other) is Tone:26        elif type(other) is Tone:
n25            return Interval(abs(order.index(self.name) - order.index(other.name)) % 12)n27            return Interval(abs(ORDER.index(self.name) - ORDER.index(other.name)) % 12)
28 
26    def __eq__(self, other):29    def __eq__(self, other):
27        return self.name == other.name30        return self.name == other.name
28        31        
2932
30class Interval:33class Interval:
31    def __init__(self, number_of_semitones):34    def __init__(self, number_of_semitones):
32        self.number_of_semitones = number_of_semitones 35        self.number_of_semitones = number_of_semitones 
nn36 
33    def __str__(self):37    def __str__(self):
34        interval = self.number_of_semitones % 1238        interval = self.number_of_semitones % 12
n35        return intervals[interval]n39        return INTERVALS[interval]
40 
36    def __add__(self, other):41    def __add__(self, other):
37        if type(other) is Tone:42        if type(other) is Tone:
38            raise TypeError('Invalid operation')43            raise TypeError('Invalid operation')
39        elif type(other) is Interval:44        elif type(other) is Interval:
40            res = (self.number_of_semitones + other.number_of_semitones) % 1245            res = (self.number_of_semitones + other.number_of_semitones) % 12
41            return Interval(res)46            return Interval(res)
nn47 
42    def __neg__(self):48    def __neg__(self):
43         return Interval(-self.number_of_semitones)49         return Interval(-self.number_of_semitones)
4450
4551
4652
n47def sortTones(root, tones):n53def sort_tones(root, tones):
48    # rotating the order list based on the root index54    # rotating the ORDER list based on the root index
49    root_index = order.index(root)55    root_index = ORDER.index(root)
50    rotated_order = order[root_index:] + order[:root_index]56    rotated_ORDER = ORDER[root_index:] + ORDER[:root_index]
51    order_index = {char: idx for idx, char in enumerate(rotated_order)}57    ORDER_index = {char: idx for idx, char in enumerate(rotated_ORDER)}
52    return sorted(tones, key = lambda x: order_index[x]) # custom sorting func58    return sorted(tones, key = lambda x: ORDER_index[x]) # custom sorting func
5359
5460
55def remove_duplicates(input_list):61def remove_duplicates(input_list):
56    seen = set()62    seen = set()
57    return [x for x in input_list if not (x in seen or seen.add(x))]63    return [x for x in input_list if not (x in seen or seen.add(x))]
nn64 
65 
58class Chord:66class Chord:
59    def __init__(self, main_tone, *args):67    def __init__(self, main_tone, *args):
60        tones_names_list = []68        tones_names_list = []
nn69        for el in args:
61        for el in args: tones_names_list.append(el.name)70            tones_names_list.append(el.name)
62        if main_tone.name in tones_names_list:71        if main_tone.name in tones_names_list:
63            tones_names_list.remove(main_tone.name)72            tones_names_list.remove(main_tone.name)
64        tones_names = set(tones_names_list)73        tones_names = set(tones_names_list)
65        if len(tones_names) == 0:74        if len(tones_names) == 0:
66            raise TypeError('Cannot have a chord made of only 1 unique tone')75            raise TypeError('Cannot have a chord made of only 1 unique tone')
67        self.root = main_tone76        self.root = main_tone
68        self.tones = args77        self.tones = args
nn78 
69    def __str__(self):79    def __str__(self):
n70        res = f'{self.root.name}'n80        res = self.root.name
71        tones = []81        tones = []
72        for el in self.tones: tones.append(el.name)82        for el in self.tones: tones.append(el.name)
n73        sorted = remove_duplicates(sortTones(self.root.name, tones))n83        sorted = remove_duplicates(sort_tones(self.root.name, tones))
74        for el in sorted: 84        for el in sorted: 
75            if el != self.root.name:85            if el != self.root.name:
n76               res = res + f'-{el}'n86               res = f'{res}-{el}'
77        return res87        return res
nn88 
78    def is_minor(self):89    def is_minor(self):
79        for el in self.tones:90        for el in self.tones:
n80            if abs(order.index(self.root.name) - order.index(el.name)) == minor_3rd:n91            if abs(ORDER.index(self.root.name) - ORDER.index(el.name)) == MINOR_3RD:
81                return True92                return True
82        return False93        return False
nn94 
83    def is_major(self):95    def is_major(self):
84        for el in self.tones:96        for el in self.tones:
n85            if abs(order.index(self.root.name) - order.index(el.name)) == major_3rd:n97            if abs(ORDER.index(self.root.name) - ORDER.index(el.name)) == MAJOR_3RD:
86                return True98                return True
87        return False99        return False
nn100 
88    def is_power_chord(self):101    def is_power_chord(self):
n89        if self.is_major() or self.is_minor():n102        return not self.is_major() and not self.is_minor()
90            return False103 
91        return True
92    def __add__(self, other):104    def __add__(self, other):
93        if type(other) is Tone:105        if type(other) is Tone:
94            return Chord(self.root, *self.tones, other)106            return Chord(self.root, *self.tones, other)
95        elif type(other) is Chord:107        elif type(other) is Chord:
96            return Chord(self.root, *self.tones, other.root, *other.tones)108            return Chord(self.root, *self.tones, other.root, *other.tones)
nn109 
97    def __sub__(self, other):110    def __sub__(self, other):
98        if type(other) is Tone:111        if type(other) is Tone:
99            tones = []112            tones = []
100            for el in self.tones: tones.append(el.name)113            for el in self.tones: tones.append(el.name)
n101            sorted = remove_duplicates(sortTones(self.root.name, tones))n114            sorted = remove_duplicates(sort_tones(self.root.name, tones))
102            if other not in self.tones and other != self.root:115            if other not in self.tones and other != self.root:
103                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')116                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')
104            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:117            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:
105                raise TypeError('Cannot have a chord made of only 1 unique tone')118                raise TypeError('Cannot have a chord made of only 1 unique tone')
106            if self.root == other:119            if self.root == other:
107                if sorted[0] != self.root:120                if sorted[0] != self.root:
108                   self.root = Chord(sorted[0])121                   self.root = Chord(sorted[0])
109                else:122                else:
110                   self.root = Chord(sorted[1]) 123                   self.root = Chord(sorted[1]) 
111            res = []124            res = []
112            for el in sorted: 125            for el in sorted: 
113                if el != other.name:126                if el != other.name:
114                   res.append(Tone(el)) 127                   res.append(Tone(el)) 
115            return Chord(self.root, *res)128            return Chord(self.root, *res)
nn129 
116    def transposed(self, interval):130    def transposed(self, interval):
117        tones = []131        tones = []
118        root = self.root132        root = self.root
119        for el in self.tones:133        for el in self.tones:
t120            tones.append(Tone(order[(order.index(el.name) + interval.number_of_semitones) % 12]))t134            tones.append(Tone(ORDER[(ORDER.index(el.name) + interval.number_of_semitones) % 12]))
121        root = Tone(order[(order.index(root.name) + interval.number_of_semitones) % 12])135        root = Tone(ORDER[(ORDER.index(root.name) + interval.number_of_semitones) % 12])
122        return Chord(root, *tones)136        return Chord(root, *tones)
123    137    
124 138 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

nn1 
2intervals = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd', 5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th', 9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
3order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
4minor_3rd = 3
5major_3rd = 4
6 
7 
1class Tone:8class Tone:
2    def __init__(self, name):9    def __init__(self, name):
3        self.name = name10        self.name = name
4    def __str__(self):11    def __str__(self):
5        return self.name12        return self.name
6    def __add__(self, other):13    def __add__(self, other):
7        if type(other) is Tone:14        if type(other) is Tone:
8            return Chord(self, other)15            return Chord(self, other)
9        elif type(other) is Interval:16        elif type(other) is Interval:
10            res = other.number_of_semitones17            res = other.number_of_semitones
11            res += order.index(self.name)18            res += order.index(self.name)
12            res %= 1219            res %= 12
13            return Tone(order[res]) 20            return Tone(order[res]) 
14    def __sub__(self, other):21    def __sub__(self, other):
15        if type(other) is Interval:22        if type(other) is Interval:
16            return Tone(order[(order.index(self.name) - other.number_of_semitones) % 12])23            return Tone(order[(order.index(self.name) - other.number_of_semitones) % 12])
17        elif type(other) is Tone:24        elif type(other) is Tone:
18            return Interval(abs(order.index(self.name) - order.index(other.name)) % 12)25            return Interval(abs(order.index(self.name) - order.index(other.name)) % 12)
19    def __eq__(self, other):26    def __eq__(self, other):
20        return self.name == other.name27        return self.name == other.name
21        28        
2229
n23intervals = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd', 5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th', 9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}n
24class Interval:30class Interval:
25    def __init__(self, number_of_semitones):31    def __init__(self, number_of_semitones):
26        self.number_of_semitones = number_of_semitones 32        self.number_of_semitones = number_of_semitones 
27    def __str__(self):33    def __str__(self):
28        interval = self.number_of_semitones % 1234        interval = self.number_of_semitones % 12
29        return intervals[interval]35        return intervals[interval]
30    def __add__(self, other):36    def __add__(self, other):
31        if type(other) is Tone:37        if type(other) is Tone:
32            raise TypeError('Invalid operation')38            raise TypeError('Invalid operation')
33        elif type(other) is Interval:39        elif type(other) is Interval:
34            res = (self.number_of_semitones + other.number_of_semitones) % 1240            res = (self.number_of_semitones + other.number_of_semitones) % 12
35            return Interval(res)41            return Interval(res)
36    def __neg__(self):42    def __neg__(self):
37         return Interval(-self.number_of_semitones)43         return Interval(-self.number_of_semitones)
3844
3945
n40order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']n46 
41def sortTones(root, tones):47def sortTones(root, tones):
42    # rotating the order list based on the root index48    # rotating the order list based on the root index
43    root_index = order.index(root)49    root_index = order.index(root)
44    rotated_order = order[root_index:] + order[:root_index]50    rotated_order = order[root_index:] + order[:root_index]
45    order_index = {char: idx for idx, char in enumerate(rotated_order)}51    order_index = {char: idx for idx, char in enumerate(rotated_order)}
46    return sorted(tones, key = lambda x: order_index[x]) # custom sorting func52    return sorted(tones, key = lambda x: order_index[x]) # custom sorting func
4753
t48minor_3rd = 3t54 
49major_3rd = 4
50def remove_duplicates(input_list):55def remove_duplicates(input_list):
51    seen = set()56    seen = set()
52    return [x for x in input_list if not (x in seen or seen.add(x))]57    return [x for x in input_list if not (x in seen or seen.add(x))]
53class Chord:58class Chord:
54    def __init__(self, main_tone, *args):59    def __init__(self, main_tone, *args):
55        tones_names_list = []60        tones_names_list = []
56        for el in args: tones_names_list.append(el.name)61        for el in args: tones_names_list.append(el.name)
57        if main_tone.name in tones_names_list:62        if main_tone.name in tones_names_list:
58            tones_names_list.remove(main_tone.name)63            tones_names_list.remove(main_tone.name)
59        tones_names = set(tones_names_list)64        tones_names = set(tones_names_list)
60        if len(tones_names) == 0:65        if len(tones_names) == 0:
61            raise TypeError('Cannot have a chord made of only 1 unique tone')66            raise TypeError('Cannot have a chord made of only 1 unique tone')
62        self.root = main_tone67        self.root = main_tone
63        self.tones = args68        self.tones = args
64    def __str__(self):69    def __str__(self):
65        res = f'{self.root.name}'70        res = f'{self.root.name}'
66        tones = []71        tones = []
67        for el in self.tones: tones.append(el.name)72        for el in self.tones: tones.append(el.name)
68        sorted = remove_duplicates(sortTones(self.root.name, tones))73        sorted = remove_duplicates(sortTones(self.root.name, tones))
69        for el in sorted: 74        for el in sorted: 
70            if el != self.root.name:75            if el != self.root.name:
71               res = res + f'-{el}'76               res = res + f'-{el}'
72        return res77        return res
73    def is_minor(self):78    def is_minor(self):
74        for el in self.tones:79        for el in self.tones:
75            if abs(order.index(self.root.name) - order.index(el.name)) == minor_3rd:80            if abs(order.index(self.root.name) - order.index(el.name)) == minor_3rd:
76                return True81                return True
77        return False82        return False
78    def is_major(self):83    def is_major(self):
79        for el in self.tones:84        for el in self.tones:
80            if abs(order.index(self.root.name) - order.index(el.name)) == major_3rd:85            if abs(order.index(self.root.name) - order.index(el.name)) == major_3rd:
81                return True86                return True
82        return False87        return False
83    def is_power_chord(self):88    def is_power_chord(self):
84        if self.is_major() or self.is_minor():89        if self.is_major() or self.is_minor():
85            return False90            return False
86        return True91        return True
87    def __add__(self, other):92    def __add__(self, other):
88        if type(other) is Tone:93        if type(other) is Tone:
89            return Chord(self.root, *self.tones, other)94            return Chord(self.root, *self.tones, other)
90        elif type(other) is Chord:95        elif type(other) is Chord:
91            return Chord(self.root, *self.tones, other.root, *other.tones)96            return Chord(self.root, *self.tones, other.root, *other.tones)
92    def __sub__(self, other):97    def __sub__(self, other):
93        if type(other) is Tone:98        if type(other) is Tone:
94            tones = []99            tones = []
95            for el in self.tones: tones.append(el.name)100            for el in self.tones: tones.append(el.name)
96            sorted = remove_duplicates(sortTones(self.root.name, tones))101            sorted = remove_duplicates(sortTones(self.root.name, tones))
97            if other not in self.tones and other != self.root:102            if other not in self.tones and other != self.root:
98                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')103                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')
99            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:104            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:
100                raise TypeError('Cannot have a chord made of only 1 unique tone')105                raise TypeError('Cannot have a chord made of only 1 unique tone')
101            if self.root == other:106            if self.root == other:
102                if sorted[0] != self.root:107                if sorted[0] != self.root:
103                   self.root = Chord(sorted[0])108                   self.root = Chord(sorted[0])
104                else:109                else:
105                   self.root = Chord(sorted[1]) 110                   self.root = Chord(sorted[1]) 
106            res = []111            res = []
107            for el in sorted: 112            for el in sorted: 
108                if el != other.name:113                if el != other.name:
109                   res.append(Tone(el)) 114                   res.append(Tone(el)) 
110            return Chord(self.root, *res)115            return Chord(self.root, *res)
111    def transposed(self, interval):116    def transposed(self, interval):
112        tones = []117        tones = []
113        root = self.root118        root = self.root
114        for el in self.tones:119        for el in self.tones:
115            tones.append(Tone(order[(order.index(el.name) + interval.number_of_semitones) % 12]))120            tones.append(Tone(order[(order.index(el.name) + interval.number_of_semitones) % 12]))
116        root = Tone(order[(order.index(root.name) + interval.number_of_semitones) % 12])121        root = Tone(order[(order.index(root.name) + interval.number_of_semitones) % 12])
117        return Chord(root, *tones)122        return Chord(root, *tones)
118    123    
119 124 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class Tone:f1class Tone:
2    def __init__(self, name):2    def __init__(self, name):
3        self.name = name3        self.name = name
4    def __str__(self):4    def __str__(self):
5        return self.name5        return self.name
6    def __add__(self, other):6    def __add__(self, other):
7        if type(other) is Tone:7        if type(other) is Tone:
8            return Chord(self, other)8            return Chord(self, other)
9        elif type(other) is Interval:9        elif type(other) is Interval:
10            res = other.number_of_semitones10            res = other.number_of_semitones
11            res += order.index(self.name)11            res += order.index(self.name)
12            res %= 1212            res %= 12
13            return Tone(order[res]) 13            return Tone(order[res]) 
14    def __sub__(self, other):14    def __sub__(self, other):
15        if type(other) is Interval:15        if type(other) is Interval:
16            return Tone(order[(order.index(self.name) - other.number_of_semitones) % 12])16            return Tone(order[(order.index(self.name) - other.number_of_semitones) % 12])
17        elif type(other) is Tone:17        elif type(other) is Tone:
18            return Interval(abs(order.index(self.name) - order.index(other.name)) % 12)18            return Interval(abs(order.index(self.name) - order.index(other.name)) % 12)
19    def __eq__(self, other):19    def __eq__(self, other):
20        return self.name == other.name20        return self.name == other.name
21        21        
2222
23intervals = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd', 5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th', 9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}23intervals = {0 : 'unison', 1 : 'minor 2nd', 2 : 'major 2nd', 3 : 'minor 3rd', 4 : 'major 3rd', 5 : 'perfect 4th', 6 : 'diminished 5th', 7 : 'perfect 5th', 8 : 'minor 6th', 9 : 'major 6th', 10 : 'minor 7th', 11 : 'major 7th'}
24class Interval:24class Interval:
25    def __init__(self, number_of_semitones):25    def __init__(self, number_of_semitones):
26        self.number_of_semitones = number_of_semitones 26        self.number_of_semitones = number_of_semitones 
27    def __str__(self):27    def __str__(self):
28        interval = self.number_of_semitones % 1228        interval = self.number_of_semitones % 12
29        return intervals[interval]29        return intervals[interval]
30    def __add__(self, other):30    def __add__(self, other):
31        if type(other) is Tone:31        if type(other) is Tone:
32            raise TypeError('Invalid operation')32            raise TypeError('Invalid operation')
33        elif type(other) is Interval:33        elif type(other) is Interval:
34            res = (self.number_of_semitones + other.number_of_semitones) % 1234            res = (self.number_of_semitones + other.number_of_semitones) % 12
35            return Interval(res)35            return Interval(res)
36    def __neg__(self):36    def __neg__(self):
37         return Interval(-self.number_of_semitones)37         return Interval(-self.number_of_semitones)
3838
3939
40order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']40order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
41def sortTones(root, tones):41def sortTones(root, tones):
42    # rotating the order list based on the root index42    # rotating the order list based on the root index
43    root_index = order.index(root)43    root_index = order.index(root)
44    rotated_order = order[root_index:] + order[:root_index]44    rotated_order = order[root_index:] + order[:root_index]
45    order_index = {char: idx for idx, char in enumerate(rotated_order)}45    order_index = {char: idx for idx, char in enumerate(rotated_order)}
46    return sorted(tones, key = lambda x: order_index[x]) # custom sorting func46    return sorted(tones, key = lambda x: order_index[x]) # custom sorting func
4747
48minor_3rd = 348minor_3rd = 3
49major_3rd = 449major_3rd = 4
50def remove_duplicates(input_list):50def remove_duplicates(input_list):
51    seen = set()51    seen = set()
52    return [x for x in input_list if not (x in seen or seen.add(x))]52    return [x for x in input_list if not (x in seen or seen.add(x))]
53class Chord:53class Chord:
54    def __init__(self, main_tone, *args):54    def __init__(self, main_tone, *args):
55        tones_names_list = []55        tones_names_list = []
56        for el in args: tones_names_list.append(el.name)56        for el in args: tones_names_list.append(el.name)
57        if main_tone.name in tones_names_list:57        if main_tone.name in tones_names_list:
58            tones_names_list.remove(main_tone.name)58            tones_names_list.remove(main_tone.name)
59        tones_names = set(tones_names_list)59        tones_names = set(tones_names_list)
60        if len(tones_names) == 0:60        if len(tones_names) == 0:
61            raise TypeError('Cannot have a chord made of only 1 unique tone')61            raise TypeError('Cannot have a chord made of only 1 unique tone')
62        self.root = main_tone62        self.root = main_tone
63        self.tones = args63        self.tones = args
64    def __str__(self):64    def __str__(self):
65        res = f'{self.root.name}'65        res = f'{self.root.name}'
66        tones = []66        tones = []
67        for el in self.tones: tones.append(el.name)67        for el in self.tones: tones.append(el.name)
68        sorted = remove_duplicates(sortTones(self.root.name, tones))68        sorted = remove_duplicates(sortTones(self.root.name, tones))
69        for el in sorted: 69        for el in sorted: 
70            if el != self.root.name:70            if el != self.root.name:
71               res = res + f'-{el}'71               res = res + f'-{el}'
72        return res72        return res
73    def is_minor(self):73    def is_minor(self):
74        for el in self.tones:74        for el in self.tones:
75            if abs(order.index(self.root.name) - order.index(el.name)) == minor_3rd:75            if abs(order.index(self.root.name) - order.index(el.name)) == minor_3rd:
76                return True76                return True
77        return False77        return False
78    def is_major(self):78    def is_major(self):
79        for el in self.tones:79        for el in self.tones:
80            if abs(order.index(self.root.name) - order.index(el.name)) == major_3rd:80            if abs(order.index(self.root.name) - order.index(el.name)) == major_3rd:
81                return True81                return True
82        return False82        return False
83    def is_power_chord(self):83    def is_power_chord(self):
84        if self.is_major() or self.is_minor():84        if self.is_major() or self.is_minor():
85            return False85            return False
86        return True86        return True
87    def __add__(self, other):87    def __add__(self, other):
88        if type(other) is Tone:88        if type(other) is Tone:
89            return Chord(self.root, *self.tones, other)89            return Chord(self.root, *self.tones, other)
90        elif type(other) is Chord:90        elif type(other) is Chord:
91            return Chord(self.root, *self.tones, other.root, *other.tones)91            return Chord(self.root, *self.tones, other.root, *other.tones)
92    def __sub__(self, other):92    def __sub__(self, other):
93        if type(other) is Tone:93        if type(other) is Tone:
94            tones = []94            tones = []
95            for el in self.tones: tones.append(el.name)95            for el in self.tones: tones.append(el.name)
96            sorted = remove_duplicates(sortTones(self.root.name, tones))96            sorted = remove_duplicates(sortTones(self.root.name, tones))
97            if other not in self.tones and other != self.root:97            if other not in self.tones and other != self.root:
98                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')98                raise TypeError(f'Cannot remove tone {str(other)} from chord {str(self)}')
99            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:99            if self.root.name in sorted and len(sorted) < 3 or len(sorted) + 1 < 3:
100                raise TypeError('Cannot have a chord made of only 1 unique tone')100                raise TypeError('Cannot have a chord made of only 1 unique tone')
101            if self.root == other:101            if self.root == other:
102                if sorted[0] != self.root:102                if sorted[0] != self.root:
103                   self.root = Chord(sorted[0])103                   self.root = Chord(sorted[0])
104                else:104                else:
105                   self.root = Chord(sorted[1]) 105                   self.root = Chord(sorted[1]) 
106            res = []106            res = []
107            for el in sorted: 107            for el in sorted: 
108                if el != other.name:108                if el != other.name:
109                   res.append(Tone(el)) 109                   res.append(Tone(el)) 
110            return Chord(self.root, *res)110            return Chord(self.root, *res)
111    def transposed(self, interval):111    def transposed(self, interval):
112        tones = []112        tones = []
113        root = self.root113        root = self.root
114        for el in self.tones:114        for el in self.tones:
115            tones.append(Tone(order[(order.index(el.name) + interval.number_of_semitones) % 12]))115            tones.append(Tone(order[(order.index(el.name) + interval.number_of_semitones) % 12]))
116        root = Tone(order[(order.index(root.name) + interval.number_of_semitones) % 12])116        root = Tone(order[(order.index(root.name) + interval.number_of_semitones) % 12])
117        return Chord(root, *tones)117        return Chord(root, *tones)
118    118    
t119c = Tone("C")t
120perfect_fifth = Interval(7)
121result_tone = c - perfect_fifth
122print(str(result_tone))#, "F")
123 119 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op