| f | TONE_ORDER = ["C", "C#", "D", "D#", "E", | f | TONE_ORDER = ["C", "C#", "D", "D#", "E", | 
             |               "F", "F#", "G", "G#", "A", "A#", "B"] |  |               "F", "F#", "G", "G#", "A", "A#", "B"] | 
             | TONE_ORDER_MAP = {tone: index for index, tone in enumerate(TONE_ORDER)} |  | TONE_ORDER_MAP = {tone: index for index, tone in enumerate(TONE_ORDER)} | 
             |  |  |  | 
             |  |  |  | 
             | class Tone: |  | class Tone: | 
             |  |  |  | 
             |     def __init__(self, tone): |  |     def __init__(self, tone): | 
             |         self.name = tone |  |         self.name = tone | 
             |  |  |  | 
             |     def __str__(self): |  |     def __str__(self): | 
             |         return self.name |  |         return self.name | 
             |  |  |  | 
             |     def __eq__(self, other): |  |     def __eq__(self, other): | 
             |         return isinstance(other, Tone) and self.name == other.name |  |         return isinstance(other, Tone) and self.name == other.name | 
             |  |  |  | 
             |     def __hash__(self): |  |     def __hash__(self): | 
             |         return hash(self.name) |  |         return hash(self.name) | 
             |  |  |  | 
             |     def __add__(self, other): |  |     def __add__(self, other): | 
             |         if isinstance(other, Tone): |  |         if isinstance(other, Tone): | 
             |             return Chord(self, other) |  |             return Chord(self, other) | 
             |         elif isinstance(other, Interval): |  |         elif isinstance(other, Interval): | 
            | n |             index = (TONE_ORDER_MAP[self.name]+other.number_of_semitones) % 12 | n |             index = (TONE_ORDER_MAP[self.name] + other.number_of_semitones) % 12 | 
             |             return Tone(TONE_ORDER[index]) |  |             return Tone(TONE_ORDER[index]) | 
             |  |  |  | 
             |     def __sub__(self, other): |  |     def __sub__(self, other): | 
             |         if isinstance(other, Tone): |  |         if isinstance(other, Tone): | 
            | n |             return Interval((12 + TONE_ORDER_MAP[self.name]-TONE_ORDER_MAP[other.name]) % 12) | n |             return Interval((12 + TONE_ORDER_MAP[self.name] - TONE_ORDER_MAP[other.name]) % 12) | 
             |         elif isinstance(other, Interval): |  |         elif isinstance(other, Interval): | 
            | n |             index = (12 + TONE_ORDER_MAP[self.name] - | n |             index = (12 + TONE_ORDER_MAP[self.name] - other.number_of_semitones) % 12 | 
             |                      other.number_of_semitones) % 12 |  |  | 
             |             return Tone(TONE_ORDER[index]) |  |             return Tone(TONE_ORDER[index]) | 
             |  |  |  | 
             |  |  |  | 
             | class Interval: |  | class Interval: | 
             |     intervals = {0: 'unison', |  |     intervals = {0: 'unison', | 
             |                  1: 'minor 2nd', |  |                  1: 'minor 2nd', | 
             |                  2: 'major 2nd', |  |                  2: 'major 2nd', | 
             |                  3: 'minor 3rd', |  |                  3: 'minor 3rd', | 
             |                  4: 'major 3rd', |  |                  4: 'major 3rd', | 
             |                  5: 'perfect 4th', |  |                  5: 'perfect 4th', | 
             |                  6: 'diminished 5th', |  |                  6: 'diminished 5th', | 
             |                  7: 'perfect 5th', |  |                  7: 'perfect 5th', | 
             |                  8: 'minor 6th', |  |                  8: 'minor 6th', | 
             |                  9: 'major 6th', |  |                  9: 'major 6th', | 
             |                  10: 'minor 7th', |  |                  10: 'minor 7th', | 
             |                  11: 'major 7th'} |  |                  11: 'major 7th'} | 
             |  |  |  | 
             |     def __init__(self, number): |  |     def __init__(self, number): | 
            | n |         number = number % 12 | n |  | 
             |         self.number_of_semitones = number |  |         self.number_of_semitones = number % 12 | 
             |  |  |  | 
             |     def __str__(self): |  |     def __str__(self): | 
             |         return self.intervals[self.number_of_semitones] |  |         return self.intervals[self.number_of_semitones] | 
             |  |  |  | 
             |     def __add__(self, other): |  |     def __add__(self, other): | 
             |         if isinstance(other, Interval): |  |         if isinstance(other, Interval): | 
             |             return Interval(self.number_of_semitones + other.number_of_semitones) |  |             return Interval(self.number_of_semitones + other.number_of_semitones) | 
             |         elif isinstance(other, Tone): |  |         elif isinstance(other, Tone): | 
             |             raise TypeError("Invalid operation") |  |             raise TypeError("Invalid operation") | 
             |  |  |  | 
             |     def __sub__(self, other): |  |     def __sub__(self, other): | 
             |         if isinstance(other, Tone): |  |         if isinstance(other, Tone): | 
             |             raise TypeError("Invalid operation") |  |             raise TypeError("Invalid operation") | 
             |  |  |  | 
             |     def __neg__(self): |  |     def __neg__(self): | 
             |         return Interval(12 - self.number_of_semitones) |  |         return Interval(12 - self.number_of_semitones) | 
             |  |  |  | 
             |  |  |  | 
             | class Chord: |  | class Chord: | 
             |  |  |  | 
             |     def __init__(self, root, *args): |  |     def __init__(self, root, *args): | 
             |         unique_tones = {root, *args} |  |         unique_tones = {root, *args} | 
             |  |  |  | 
             |         if len(unique_tones) < 2: |  |         if len(unique_tones) < 2: | 
             |             raise TypeError('Cannot have a chord made of only 1 unique tone') |  |             raise TypeError('Cannot have a chord made of only 1 unique tone') | 
             |  |  |  | 
             |         self.main_tone = root |  |         self.main_tone = root | 
             |         self.root_index = TONE_ORDER_MAP[root.name] |  |         self.root_index = TONE_ORDER_MAP[root.name] | 
             |  |  |  | 
             |         self.tones = sorted( |  |         self.tones = sorted( | 
             |             unique_tones, |  |             unique_tones, | 
             |             key=lambda tone: (TONE_ORDER_MAP[tone.name] - self.root_index) % len(TONE_ORDER)) |  |             key=lambda tone: (TONE_ORDER_MAP[tone.name] - self.root_index) % len(TONE_ORDER)) | 
             |  |  |  | 
             |     def __str__(self): |  |     def __str__(self): | 
             |         return "-".join(tone.name for tone in self.tones) |  |         return "-".join(tone.name for tone in self.tones) | 
             |  |  |  | 
             |     def is_minor(self): |  |     def is_minor(self): | 
             |         for tone in self.tones: |  |         for tone in self.tones: | 
            | n |             if (TONE_ORDER_MAP[tone.name]-self.root_index+12) % 12 == 3: | n |             if (TONE_ORDER_MAP[tone.name] - self.root_index + 12) % 12 == 3: | 
             |                 return True |  |                 return True | 
             |         return False |  |         return False | 
             |  |  |  | 
             |     def is_major(self): |  |     def is_major(self): | 
             |         for tone in self.tones: |  |         for tone in self.tones: | 
            | n |             if (TONE_ORDER_MAP[tone.name]-self.root_index+12) % 12 == 4: | n |             if (TONE_ORDER_MAP[tone.name] - self.root_index + 12) % 12 == 4: | 
             |                 return True |  |                 return True | 
             |         return False |  |         return False | 
             |  |  |  | 
             |     def is_power_chord(self): |  |     def is_power_chord(self): | 
             |         return not self.is_major() and not self.is_minor() |  |         return not self.is_major() and not self.is_minor() | 
             |  |  |  | 
             |     def __add__(self, other): |  |     def __add__(self, other): | 
             |         if isinstance(other, Tone): |  |         if isinstance(other, Tone): | 
             |             return Chord(self.main_tone, *self.tones, other) |  |             return Chord(self.main_tone, *self.tones, other) | 
             |         elif isinstance(other, Chord): |  |         elif isinstance(other, Chord): | 
             |             return Chord(self.main_tone, *self.tones, *other.tones) |  |             return Chord(self.main_tone, *self.tones, *other.tones) | 
             |  |  |  | 
             |     def __sub__(self, other): |  |     def __sub__(self, other): | 
             |         if isinstance(other, Tone): |  |         if isinstance(other, Tone): | 
             |             if other in self.tones: |  |             if other in self.tones: | 
             |                 new_tones = [tone for tone in self.tones if tone != other] |  |                 new_tones = [tone for tone in self.tones if tone != other] | 
            | n |                 if other == self.main_tone: | n |                 new_main_tone = self.main_tone if self.main_tone != other else new_tones[0] | 
             |                     self.main_tone = new_tones[0] |  |  | 
             |                 return Chord(self.main_tone, *new_tones) |  |                 return Chord(new_main_tone, *new_tones) | 
             |             else: |  |             else: | 
             |                 raise TypeError( |  |                 raise TypeError( | 
             |                     f'Cannot remove tone {other} from chord {self}') |  |                     f'Cannot remove tone {other} from chord {self}') | 
             |  |  |  | 
             |     def transposed(self, interval): |  |     def transposed(self, interval): | 
            | t |         newRoot = self.main_tone + interval | t |         new_root = self.main_tone + interval | 
             |         newTones = tuple(tone + interval for tone in self.tones) |  |         new_tones = tuple(tone + interval for tone in self.tones) | 
             |         return Chord(newRoot, *newTones) |  |         return Chord(new_root, *new_tones) | 
             |  |  |  | 
             |  |  |  | 
             |  |  |  |