f | class Tone: | f | class Tone: |
| CHROMATIC_SCALE = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") | | CHROMATIC_SCALE = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") |
| | | |
| def __init__(self, name): | | def __init__(self, name): |
| self.name = name | | self.name = name |
| self.index = self.CHROMATIC_SCALE.index(name) | | self.index = self.CHROMATIC_SCALE.index(name) |
| | | |
| def __str__(self): | | def __str__(self): |
| return self.name | | return self.name |
| | | |
| def __eq__(self, other): | | def __eq__(self, other): |
| return self.name == other.name | | return 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): |
n | | n | """Add Tone and Tone or Tone and Interval""" |
| if isinstance(other, Tone): | | if isinstance(other, Tone): |
| return Chord(self, other) | | return Chord(self, other) |
| if isinstance(other, Interval): | | if isinstance(other, Interval): |
| return Tone(self.CHROMATIC_SCALE[(self.index + other.semitones) % 12]) | | return Tone(self.CHROMATIC_SCALE[(self.index + other.semitones) % 12]) |
| | | |
| def __sub__(self, other): | | def __sub__(self, other): |
n | | n | """Substract Tone from Tone or Tone from Interval""" |
| if isinstance(other, Tone): | | if isinstance(other, Tone): |
| return Interval((self.index - other.index) % 12) | | return Interval((self.index - other.index) % 12) |
| if isinstance(other, Interval): | | if isinstance(other, Interval): |
| return Tone(self.CHROMATIC_SCALE[(self.index - other.semitones) % 12]) | | return Tone(self.CHROMATIC_SCALE[(self.index - other.semitones) % 12]) |
| | | |
| | | |
| | | |
| class Interval: | | class Interval: |
| INTERVAL_NAMES = ( | | INTERVAL_NAMES = ( |
| "unison", | | "unison", |
| "minor 2nd", | | "minor 2nd", |
| "major 2nd", | | "major 2nd", |
| "minor 3rd", | | "minor 3rd", |
| "major 3rd", | | "major 3rd", |
| "perfect 4th", | | "perfect 4th", |
| "diminished 5th", | | "diminished 5th", |
| "perfect 5th", | | "perfect 5th", |
| "minor 6th", | | "minor 6th", |
| "major 6th", | | "major 6th", |
| "minor 7th", | | "minor 7th", |
| "major 7th" | | "major 7th" |
| ) | | ) |
| | | |
| def __init__(self, semitones): | | def __init__(self, semitones): |
| self.semitones = semitones % 12 | | self.semitones = semitones % 12 |
| | | |
| def __str__(self): | | def __str__(self): |
| return self.INTERVAL_NAMES[self.semitones % 12] | | return self.INTERVAL_NAMES[self.semitones % 12] |
| | | |
| def __add__(self, other): | | def __add__(self, other): |
n | | n | """Throw err when adding Interval and Tone; Add Interval and Interval""" |
| if isinstance(other, Tone): | | if isinstance(other, Tone): |
| raise TypeError("Invalid operation") | | raise TypeError("Invalid operation") |
| if isinstance(other, Interval): | | if isinstance(other, Interval): |
| return Interval((self.semitones + other.semitones) % 12) | | return Interval((self.semitones + other.semitones) % 12) |
| | | |
| def __sub__(self, other): | | def __sub__(self, other): |
n | | n | """Throw err when substracting Tone from Interval""" |
| if isinstance(other, Tone): | | if isinstance(other, Tone): |
| raise TypeError("Invalid operation") | | raise TypeError("Invalid operation") |
| | | |
| def __neg__(self): | | def __neg__(self): |
| return Interval(-self.semitones) | | return Interval(-self.semitones) |
| | | |
| | | |
| class Chord: | | class Chord: |
| def __init__(self, root, *tones): | | def __init__(self, root, *tones): |
| unique_tones = {root, *tones} | | unique_tones = {root, *tones} |
| 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.root = root | | self.root = root |
| self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) | | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - root.index) % 12) |
| | | |
| def __str__(self): | | def __str__(self): |
| return "-".join(str(t) for t in self.tones) | | return "-".join(str(t) for t in self.tones) |
| | | |
| def is_minor(self): | | def is_minor(self): |
n | | n | """Has minor 3rd""" |
| return any((t.index - self.root.index) % 12 == 3 for t in self.tones) | | return any((t.index - self.root.index) % 12 == 3 for t in self.tones) |
| | | |
| def is_major(self): | | def is_major(self): |
n | | n | """Has major 3rd""" |
| return any((t.index - self.root.index) % 12 == 4 for t in self.tones) | | return any((t.index - self.root.index) % 12 == 4 for t in self.tones) |
| | | |
| def is_power_chord(self): | | def is_power_chord(self): |
n | | n | """Is not minor and major""" |
| return not (self.is_minor() or self.is_major()) | | return not (self.is_minor() or self.is_major()) |
| | | |
| def __sub__(self, other): | | def __sub__(self, other): |
n | | n | """Substract Tone from Chord""" |
| if isinstance(other, Tone): | | if isinstance(other, Tone): |
| if other not in self.tones: | | if other not in self.tones: |
| raise TypeError(f"Cannot remove tone {other} from chord {self}") | | raise TypeError(f"Cannot remove tone {other} from chord {self}") |
| new_tones = [tone for tone in self.tones if tone != other] | | new_tones = [tone for tone in self.tones if tone != other] |
| if len(new_tones) < 2: | | if len(new_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") |
| if other == self.root: | | if other == self.root: |
| new_root = new_tones[0] | | new_root = new_tones[0] |
| return Chord(new_root, *new_tones) | | return Chord(new_root, *new_tones) |
| return Chord(self.root, *new_tones) | | return Chord(self.root, *new_tones) |
| | | |
| def __add__(self, other): | | def __add__(self, other): |
n | | n | """Add Chord and Tone or Chord and Chord""" |
| | | if isinstance(other, Tone): |
| | | self.tones.append(other) |
| | | unique_tones = {self.root, *self.tones} |
| | | self.tones = sorted(unique_tones, key=lambda tone: (tone.index - self.root.index) % 12) |
| | | return Chord(self.root, *self.tones) |
| if isinstance(other, Chord): | | if isinstance(other, Chord): |
| tones_sum = {self.root, *self.tones, *other.tones} | | tones_sum = {self.root, *self.tones, *other.tones} |
| return Chord(self.root, *tones_sum) | | return Chord(self.root, *tones_sum) |
| | | |
| def transposed(self, interval): | | def transposed(self, interval): |
n | | n | """Move with interval positions each tone in the chord""" |
| transposed_tones = [tone + interval for tone in self.tones] | | transposed_tones = [tone + interval for tone in self.tones] |
| return Chord(transposed_tones[0], *transposed_tones) | | return Chord(transposed_tones[0], *transposed_tones) |
t | | t | |
07.11.2024 09:20
07.11.2024 09:21
07.11.2024 09:22