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

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

2 точки общо

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

  1class Tone:
  2    """This is the class for Tones."""
  3    TONES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
  4    
  5    def __init__(self, name):   
  6        if name not in Tone.TONES:
  7            raise ValueError(f"Invalid tone {name}.")
  8        self.name = name 
  9        
 10    def __str__(self):
 11        return self.name
 12    
 13    def __add__(self, interval):
 14        if isinstance(interval, Interval):
 15            index = Tone.TONES.index(self.name)
 16            new_index = ((index + interval.name) % len(Tone.TONES))
 17            return Tone(Tone.TONES[new_index])
 18        else:
 19            raise TypeError("Invalid operation.")
 20        
 21    def __sub__(self, interval):
 22        if isinstance(interval, Interval):
 23            index = Tone. TONES.index(self.name)
 24            index_other = (index - interval.name) % len(Tone.TONE_ORDER)
 25            return Tone(Tone.TONES[index_other])
 26        else:
 27            raise TypeError("Invalid operation.") 
 28    
 29    def __eq__(self, other):
 30       if isinstance(other, Tone):
 31           return self.name == other.name
 32       return False
 33    
 34    def __hash__(self):
 35        return hash(self.note)
 36    
 37    def __lt__(self, other):
 38        if isinstance(other, Tone):
 39            return Tone.TONE_ORDER.index(self.note) < Tone.TONE_ORDER.index(other.note)
 40        return NotImplemented
 41    
 42    
 43class Interval:
 44    """This is the class for intervals."""
 45    INTERVALS = {0:"unison", 1:"minor 2nd", 2:"major 2nd", 3:"minor 3rd", 4:"major 3rd", 5:"perfect 4th", 6:"diminished 5th",
 46                 7:"perfect 5th", 8:"minor 6th", 9:"major 6th", 10:"minor 7th", 11:"major 7th"}
 47    
 48    def __init__(self, name):
 49        if not isinstance(name, int):
 50            raise ValueError("Interval must me an integer.")
 51        self.name = name % 12
 52    
 53    def __str__(self):
 54        return Interval.INTERVALS[self.name]
 55    
 56    def __eq__(self, other):
 57        if isinstance(other, Interval):
 58            return self.name == other.name
 59        return False
 60
 61    def __hash__(self):
 62        return hash(self.name)
 63
 64    
 65class Chord:
 66    """This is the class for chords."""
 67    def __init__(self, root, *tones):
 68        if not isinstance(root, Tone):
 69            raise ValueError("Root must be a Tone instance.")
 70        self.tones = sorted(set([root] + list(tones)))
 71    
 72    def __str__(self):
 73        return "-".join(tone.name for tone in self.tones)
 74    
 75    def is_major(self):
 76        if len(self.tones) != 3:
 77            return False
 78        root, third, fifth = self.tones[0], self.tones[1], self.tones[2]
 79        return (
 80            Tone.TONE_ORDER.index(third.note) - Tone.TONE_ORDER.index(root.note) == 4 and
 81            Tone.TONE_ORDER.index(fifth.note) - Tone.TONE_ORDER.index(third.note) == 3
 82        )
 83
 84    def is_minor(self):
 85        if len(self.tones) != 3:
 86            return False
 87        root, third, fifth = self.tones[0], self.tones[1], self.tones[2]
 88        return (
 89            Tone.TONE_ORDER.index(third.note) - Tone.TONE_ORDER.index(root.note) == 3 and
 90            Tone.TONE_ORDER.index(fifth.note) - Tone.TONE_ORDER.index(third.note) == 4
 91        )
 92    
 93    def is_power_chord(self):
 94        return not self.is_minor() and not self.is_major()
 95    
 96    def __add__(self, tone):
 97        if isinstance(tone, Tone):
 98            self.tones.append(tone)
 99            self.tones = sorted(set(self.tones))
100            return self
101        else:
102            raise TypeError("Invalid operation.")
103    
104    def __sub__(self, tone):
105        if isinstance(tone, Tone):
106            if tone in self.tones:
107                self.tones.remove(tone)
108            else:
109                raise ValueError(f"Cannot remove tone {tone.note} from chord {self}")
110            return self
111        else:
112            raise TypeError("Invalid operation.")
113    
114    def transposed(self, interval):
115        transposed_chord = [self.root + interval] + [tone + interval for tone in self.tones[1:]]
116        return Chord(transposed_chord[0], *transposed_chord[1:])
117    

EEEEEEEEEEEE...EE.F..EEEEEEFEEEEEFEEE
======================================================================
ERROR: test_chord_not_enough_tones (test.TestBasicChordFunctionality.test_chord_not_enough_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 79, in test_chord_not_enough_tones
Chord(a_sharp)
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_chord_ordering (test.TestBasicChordFunctionality.test_chord_ordering)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 64, in test_chord_ordering
f_sixth_ninth_chord = Chord(*f_major_seventh_tones)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_chord_str (test.TestBasicChordFunctionality.test_chord_str)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 59, in test_chord_str
a_major_chord = Chord(*a_major_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_chord_tone_repetition (test.TestBasicChordFunctionality.test_chord_tone_repetition)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 73, in test_chord_tone_repetition
a_minor_chord = Chord(*a_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_is_major (test.TestBasicChordFunctionality.test_is_major)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 102, in test_is_major
a_minor_chord = Chord(*a_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_is_minor (test.TestBasicChordFunctionality.test_is_minor)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 89, in test_is_minor
a_minor_chord = Chord(*a_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_is_power_chord (test.TestBasicChordFunctionality.test_is_power_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 115, in test_is_power_chord
a_minor_chord = Chord(*a_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_transposed (test.TestBasicChordFunctionality.test_transposed)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 128, in test_transposed
d_major_chord = Chord(*d_major_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_transposed_negative (test.TestBasicChordFunctionality.test_transposed_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 135, in test_transposed_negative
e_minor_chord = Chord(*e_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_transposed_negative_overflow (test.TestBasicChordFunctionality.test_transposed_negative_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 149, in test_transposed_negative_overflow
e_minor_chord = Chord(*e_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_transposed_overflow (test.TestBasicChordFunctionality.test_transposed_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 142, in test_transposed_overflow
d_major_chord = Chord(*d_major_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 50, in test_interval_negative
minor_2nd = -major_7th
^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'

======================================================================
ERROR: test_add_chords (test.TestOperations.test_add_chords)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 296, in test_add_chords
c5_chord = Chord(Tone("C"), Tone("G"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_add_chords_repeating_notes (test.TestOperations.test_add_chords_repeating_notes)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 302, in test_add_chords_repeating_notes
c5_chord = Chord(Tone("C"), Tone("G"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_add_tone_to_chord (test.TestOperations.test_add_tone_to_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 251, in test_add_tone_to_chord
f_major_chord = Chord(*f_major_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_add_tone_to_chord_existing_tone (test.TestOperations.test_add_tone_to_chord_existing_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 265, in test_add_tone_to_chord_existing_tone
f_minor_chord = Chord(*f_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_add_tone_to_chord_order (test.TestOperations.test_add_tone_to_chord_order)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 258, in test_add_tone_to_chord_order
f_major_chord = Chord(*f_major_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_interval_addition (test.TestOperations.test_interval_addition)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 239, in test_interval_addition
major_3rd = minor_2nd + minor_3rd
~~~~~~~~~~^~~~~~~~~~~
TypeError: unsupported operand type(s) for +: 'Interval' and 'Interval'

======================================================================
ERROR: test_interval_addition_overflow (test.TestOperations.test_interval_addition_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 245, in test_interval_addition_overflow
unison = perfect_4th + perfect_5th
~~~~~~~~~~~~^~~~~~~~~~~~~
TypeError: unsupported operand type(s) for +: 'Interval' and 'Interval'

======================================================================
ERROR: test_subtract_interval_from_tone (test.TestOperations.test_subtract_interval_from_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 215, in test_subtract_interval_from_tone
f_sharp = g - Interval(1)
~~^~~~~~~~~~~~~
File "/tmp/solution.py", line 24, in __sub__
index_other = (index - interval.name) % len(Tone.TONE_ORDER)
^^^^^^^^^^^^^^^
AttributeError: type object 'Tone' has no attribute 'TONE_ORDER'

======================================================================
ERROR: test_subtract_interval_from_tone_oveflow (test.TestOperations.test_subtract_interval_from_tone_oveflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 227, in test_subtract_interval_from_tone_oveflow
g = c - Interval(5)
~~^~~~~~~~~~~~~
File "/tmp/solution.py", line 24, in __sub__
index_other = (index - interval.name) % len(Tone.TONE_ORDER)
^^^^^^^^^^^^^^^
AttributeError: type object 'Tone' has no attribute 'TONE_ORDER'

======================================================================
ERROR: test_subtract_interval_from_tone_same_tone (test.TestOperations.test_subtract_interval_from_tone_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 221, in test_subtract_interval_from_tone_same_tone
still_g = g - Interval(0)
~~^~~~~~~~~~~~~
File "/tmp/solution.py", line 24, in __sub__
index_other = (index - interval.name) % len(Tone.TONE_ORDER)
^^^^^^^^^^^^^^^
AttributeError: type object 'Tone' has no attribute 'TONE_ORDER'

======================================================================
ERROR: test_subtract_tone_from_chord (test.TestOperations.test_subtract_tone_from_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 274, in test_subtract_tone_from_chord
f_minor_chord = Chord(*f_minor_tones)
^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_subtract_tone_from_chord_error (test.TestOperations.test_subtract_tone_from_chord_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 288, in test_subtract_tone_from_chord_error
c5_chord = Chord(*c5_chord_tones)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 70, in __init__
self.tones = sorted(set([root] + list(tones)))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 35, in __hash__
return hash(self.note)
^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'note'

======================================================================
ERROR: test_tone_addition_different_tones (test.TestOperations.test_tone_addition_different_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 160, in test_tone_addition_different_tones
result_chord = g + f
~~^~~
File "/tmp/solution.py", line 19, in __add__
raise TypeError("Invalid operation.")
TypeError: Invalid operation.

======================================================================
ERROR: test_tone_subtraction (test.TestOperations.test_tone_subtraction)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 172, in test_tone_subtraction
perfect_5th = g - c
~~^~~
File "/tmp/solution.py", line 27, in __sub__
raise TypeError("Invalid operation.")
TypeError: Invalid operation.

======================================================================
ERROR: test_tone_subtraction_inverse (test.TestOperations.test_tone_subtraction_inverse)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 177, in test_tone_subtraction_inverse
perfect_4th = c - g
~~^~~
File "/tmp/solution.py", line 27, in __sub__
raise TypeError("Invalid operation.")
TypeError: Invalid operation.

======================================================================
ERROR: test_tone_subtraction_same_tone (test.TestOperations.test_tone_subtraction_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 182, in test_tone_subtraction_same_tone
unison = c - another_c
~~^~~~~~~~~~~
File "/tmp/solution.py", line 27, in __sub__
raise TypeError("Invalid operation.")
TypeError: Invalid operation.

======================================================================
FAIL: 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 211, in test_add_interval_to_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_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_addition_same_tone (test.TestOperations.test_tone_addition_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 168, in test_tone_addition_same_tone
self.assertEqual(str(err.exception), CANNOT_CHORD_THIS_CHORD)
AssertionError: 'Invalid operation.' != 'Cannot have a chord made of only 1 unique tone'
- Invalid operation.
+ Cannot have a chord made of only 1 unique tone

----------------------------------------------------------------------
Ran 37 tests in 0.007s

FAILED (failures=3, errors=28)

Дискусия
Мина Евтимова
07.11.2024 16:48

Добре, мерси.
Виктор Бечев
07.11.2024 15:34

За мен не дава никаква допълнителна информация. Знаеш, как работи индексирането при списъците - елементът на 1-ва позиция е с индекс 0, на 2ра - с индекс 1 и т.н. Да имаш речник, който описва същото не дава кой знае колко повече информация и изобщо не променя начинът, по който би се използвала въпросната структура. Дори в случая, в който имаш числа от 1 до 12 (например за месеци) - пак не бих използвал речник, тъй като операцията е елементарна - изваждаш едно за да индексираш.
Мина Евтимова
07.11.2024 13:47

Имам въпрос относно ред 45. Така както съм ги написала не е ли по-четимо или по-скоро обърква? Смисъл трябва да ги пиша само, ако ги сменям (например да почва от 1:, не от 0: и да е до 12:, а не до 11:), така ли?
Мина Евтимова
06.11.2024 18:10

Ами аз чак сега получих отговора, така че късно. Все пак ще го погледна и ще се опитам да си ги оправя. Благодаря.
Виктор Бечев
06.11.2024 17:20

Заради 2 дребни глупости ще ти фейлнат 80% от тестовете. Казвам ти го, защото си написала немалко код, който ми изглежда твой и ще е загуба. Имаш 40 минути да ги оправиш. Обратна връзка ще ти върнем по-натам, сега няма за кога.
История

f1class Tone:f1class Tone:
nn2    """This is the class for Tones."""
2    TONES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']3    TONES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
3    4    
4    def __init__(self, name):   5    def __init__(self, name):   
5        if name not in Tone.TONES:6        if name not in Tone.TONES:
6            raise ValueError(f"Invalid tone {name}.")7            raise ValueError(f"Invalid tone {name}.")
7        self.name = name 8        self.name = name 
8        9        
9    def __str__(self):10    def __str__(self):
10        return self.name11        return self.name
11    12    
12    def __add__(self, interval):13    def __add__(self, interval):
13        if isinstance(interval, Interval):14        if isinstance(interval, Interval):
14            index = Tone.TONES.index(self.name)15            index = Tone.TONES.index(self.name)
15            new_index = ((index + interval.name) % len(Tone.TONES))16            new_index = ((index + interval.name) % len(Tone.TONES))
16            return Tone(Tone.TONES[new_index])17            return Tone(Tone.TONES[new_index])
17        else:18        else:
18            raise TypeError("Invalid operation.")19            raise TypeError("Invalid operation.")
19        20        
20    def __sub__(self, interval):21    def __sub__(self, interval):
21        if isinstance(interval, Interval):22        if isinstance(interval, Interval):
22            index = Tone. TONES.index(self.name)23            index = Tone. TONES.index(self.name)
23            index_other = (index - interval.name) % len(Tone.TONE_ORDER)24            index_other = (index - interval.name) % len(Tone.TONE_ORDER)
n24            return Tone(Tone.TONES[index])n25            return Tone(Tone.TONES[index_other])
25        else:26        else:
26            raise TypeError("Invalid operation.") 27            raise TypeError("Invalid operation.") 
27    28    
28    def __eq__(self, other):29    def __eq__(self, other):
29       if isinstance(other, Tone):30       if isinstance(other, Tone):
30           return self.name == other.name31           return self.name == other.name
31       return False32       return False
32    33    
33    def __hash__(self):34    def __hash__(self):
34        return hash(self.note)35        return hash(self.note)
35    36    
nn37    def __lt__(self, other):
38        if isinstance(other, Tone):
39            return Tone.TONE_ORDER.index(self.note) < Tone.TONE_ORDER.index(other.note)
40        return NotImplemented
41    
36    42    
37class Interval:43class Interval:
nn44    """This is the class for intervals."""
38    INTERVALS = {0:"unison", 1:"minor 2nd", 2:"major 2nd", 3:"minor 3rd", 4:"major 3rd", 5:"perfect 4th", 6:"diminished 5th",45    INTERVALS = {0:"unison", 1:"minor 2nd", 2:"major 2nd", 3:"minor 3rd", 4:"major 3rd", 5:"perfect 4th", 6:"diminished 5th",
39                 7:"perfect 5th", 8:"minor 6th", 9:"major 6th", 10:"minor 7th", 11:"major 7th"}46                 7:"perfect 5th", 8:"minor 6th", 9:"major 6th", 10:"minor 7th", 11:"major 7th"}
40    47    
41    def __init__(self, name):48    def __init__(self, name):
n42        self.name = name % 12 if name % 12 != 0 else 12n49        if not isinstance(name, int):
50            raise ValueError("Interval must me an integer.")
51        self.name = name % 12
43    52    
44    def __str__(self):53    def __str__(self):
45        return Interval.INTERVALS[self.name]54        return Interval.INTERVALS[self.name]
46    55    
47    def __eq__(self, other):56    def __eq__(self, other):
48        if isinstance(other, Interval):57        if isinstance(other, Interval):
49            return self.name == other.name58            return self.name == other.name
50        return False59        return False
5160
52    def __hash__(self):61    def __hash__(self):
53        return hash(self.name)62        return hash(self.name)
5463
55    64    
56class Chord:65class Chord:
nn66    """This is the class for chords."""
57    def __init__(self, root, *tones):67    def __init__(self, root, *tones):
n58        if not tones:n68        if not isinstance(root, Tone):
59            raise TypeError("Cannot have chord from only one tone.")69            raise ValueError("Root must be a Tone instance.")
60        self.root = root70        self.tones = sorted(set([root] + list(tones)))
61        self.tones = sorted(set([root] + list(tones)), key=lambda tone: Tone.TONE_ORDER.index(tone.note))
62            
63        if len(self.tones) < 2:
64            raise TypeError("Cannot have chord from only one tone.")
65    71    
66    def __str__(self):72    def __str__(self):
n67        return "-".join(str(tone) for tone in self.tones)n73        return "-".join(tone.name for tone in self.tones)
68    
69    def is_minor(self):
70        minor_third = Interval(3)
71        return any((tone - self.root).name == minor_third.name for tone in self.tones)
72    74    
73    def is_major(self):75    def is_major(self):
n74        major_third = Interval(4)n76        if len(self.tones) != 3:
75        return any((tone - self.root).name == major_third.name for tone in self.tones)77            return False
78        root, third, fifth = self.tones[0], self.tones[1], self.tones[2]
79        return (
80            Tone.TONE_ORDER.index(third.note) - Tone.TONE_ORDER.index(root.note) == 4 and
81            Tone.TONE_ORDER.index(fifth.note) - Tone.TONE_ORDER.index(third.note) == 3
82        )
83 
84    def is_minor(self):
85        if len(self.tones) != 3:
86            return False
87        root, third, fifth = self.tones[0], self.tones[1], self.tones[2]
88        return (
89            Tone.TONE_ORDER.index(third.note) - Tone.TONE_ORDER.index(root.note) == 3 and
90            Tone.TONE_ORDER.index(fifth.note) - Tone.TONE_ORDER.index(third.note) == 4
91        )
76    92    
77    def is_power_chord(self):93    def is_power_chord(self):
78        return not self.is_minor() and not self.is_major()94        return not self.is_minor() and not self.is_major()
79    95    
80    def __add__(self, tone):96    def __add__(self, tone):
81        if isinstance(tone, Tone):97        if isinstance(tone, Tone):
82            self.tones.append(tone)98            self.tones.append(tone)
t83            self.tones = sorted(self.tones, key=lambda tone: Tone.TONE_ORDER.index(tone.note))t99            self.tones = sorted(set(self.tones))
84            return self100            return self
85        else:101        else:
86            raise TypeError("Invalid operation.")102            raise TypeError("Invalid operation.")
87    103    
88    def __sub__(self, tone):104    def __sub__(self, tone):
89        if isinstance(tone, Tone):105        if isinstance(tone, Tone):
90            if tone in self.tones:106            if tone in self.tones:
91                self.tones.remove(tone)107                self.tones.remove(tone)
92            else:108            else:
93                raise ValueError(f"Cannot remove tone {tone.note} from chord {self}")109                raise ValueError(f"Cannot remove tone {tone.note} from chord {self}")
94            return self110            return self
95        else:111        else:
96            raise TypeError("Invalid operation.")112            raise TypeError("Invalid operation.")
97    113    
98    def transposed(self, interval):114    def transposed(self, interval):
99        transposed_chord = [self.root + interval] + [tone + interval for tone in self.tones[1:]]115        transposed_chord = [self.root + interval] + [tone + interval for tone in self.tones[1:]]
100        return Chord(transposed_chord[0], *transposed_chord[1:])116        return Chord(transposed_chord[0], *transposed_chord[1:])
101    117    
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op