Esempio n. 1
0
    def from_name(cls, name: str, octave: int = 4) -> "ChordWithRoot":
        """Creates a ChordWithRoot from a name.

        `semitones_to_chord_name_options` is used to guess a good name for the chord.
        """
        root = None

        for letter in LETTERS:
            if name.startswith(letter):
                root_no_accidental = letter
                break
        else:
            raise InvalidChord(name)

        # Very special case: major chord with no accidentals
        if len(name) == len(root_no_accidental):
            return cls(name, Note(root_no_accidental, octave),
                       Chord.from_name("major"))

        possibly_accidental = name[len(root_no_accidental)]
        if possibly_accidental in ACCIDENTALS:
            root = Note(root_no_accidental + possibly_accidental, octave)
        else:
            root = Note(root_no_accidental, octave)

        name_without_root = name[len(root.name):]
        has_slash = "/" in name_without_root

        if has_slash:
            name_without_root, bass = name_without_root.split("/")
            chord = cls(name, root, Chord.from_name(name_without_root))
            chord.chord.add_semitone(-note_diff(bass, root.name))
            return chord
        else:
            return cls(name, root, Chord.from_name(name_without_root))
Esempio n. 2
0
    def from_name(cls, name: str) -> "Chord":
        # First determine the octave
        octave, name = _separate_octave(name)
        if octave is None:
            octave = 4

        root = None

        for letter in LETTERS:
            if name.startswith(letter):
                root_no_accidental = letter
                break
        else:
            raise InvalidChord(name)

        # Very special case: major chord with no accidentals
        if len(name) == len(root_no_accidental):
            return cls(name, Note(root_no_accidental, octave), Intervals.from_name(""))

        possibly_accidental = name[len(root_no_accidental)]
        if possibly_accidental in ACCIDENTALS:
            root = Note(root_no_accidental + possibly_accidental, octave)
        else:
            root = Note(root_no_accidental, octave)

        name_without_root = name[len(root.name) :]
        has_slash = "/" in name_without_root

        if has_slash:
            name_without_root, bass = name_without_root.split("/")
            chord = cls(name, root, Intervals.from_name(name_without_root))
            chord.intervals = chord.intervals.add_semitone(-note_diff(bass, root.name))
            return chord
        else:
            return cls(name, root, Intervals.from_name(name_without_root))
Esempio n. 3
0
def test_github_issue_8_sloppy_midi():
    prog = ChordProgression.from_midi_file(
        os.path.join(os.path.dirname(__file__), "test_data", "issue_8.mid"))
    assert prog == ChordProgression([
        Chord(
            name="A#min",
            root=Note("A#", 3),
            intervals=Intervals(name="min", semitones=[0, 3, 7]),
        ),
        Chord(
            name="D#",
            root=Note("D#", 4),
            intervals=Intervals(name="", semitones=[0, 4, 7]),
        ),
        Chord(
            name="D#min",
            root=Note("D#", 4),
            intervals=Intervals(name="min", semitones=[0, 3, 7]),
        ),
        Chord(
            name="A#min/G#",
            root=Note("G#", 3),
            intervals=Intervals(name="min/b7", semitones=[0, 5, 9, 14]),
        ),
    ])
Esempio n. 4
0
def test_github_issue_61_slash_chord_with_octave():
    """https://github.com/jonathangjertsen/jchord/issues/61#issuecomment-777625321"""
    chord = Chord.from_name("5C/E")
    assert chord == Chord(
        name="C/E",
        root=Note("C", 5),
        intervals=Intervals(name="major", semitones=[-8, 0, 4, 7]),
    )
    assert chord.bass == Note("E", 4)
Esempio n. 5
0
 def from_root_and_semitones(cls, root: Note, semitones: List[int]) -> "Chord":
     chord = Intervals.from_semitones(semitones)
     if "/" in chord.name:
         chord_name, bass_degree = chord.name.split("/")
         new_root = (
             Note(root.name, 0).transpose(12 - degree_to_semitone(bass_degree)).name
         )
         name = f"{new_root}{chord_name}/{root.name}"
     else:
         name = root.name + chord.name
     return cls(name, root, chord)
Esempio n. 6
0
def test_github_issue_61_progression():
    """https://github.com/jonathangjertsen/jchord/issues/61#issuecomment-777575298"""
    prog = ChordProgression.from_string("4F -- 3Am -- 4Dm7 -- 4F --")
    assert prog == ChordProgression([
        Chord(
            name="F",
            root=Note("F", 4),
            intervals=Intervals(name="major", semitones=[0, 4, 7]),
        ),
        Chord(
            name="F",
            root=Note("F", 4),
            intervals=Intervals(name="major", semitones=[0, 4, 7]),
        ),
        Chord(
            name="Am",
            root=Note("A", 3),
            intervals=Intervals(name="m", semitones=[0, 3, 7]),
        ),
        Chord(
            name="Am",
            root=Note("A", 3),
            intervals=Intervals(name="m", semitones=[0, 3, 7]),
        ),
        Chord(
            name="Dm7",
            root=Note("D", 4),
            intervals=Intervals(name="m7", semitones=[0, 3, 7, 10]),
        ),
        Chord(
            name="Dm7",
            root=Note("D", 4),
            intervals=Intervals(name="m7", semitones=[0, 3, 7, 10]),
        ),
        Chord(
            name="F",
            root=Note("F", 4),
            intervals=Intervals(name="major", semitones=[0, 4, 7]),
        ),
        Chord(
            name="F",
            root=Note("F", 4),
            intervals=Intervals(name="major", semitones=[0, 4, 7]),
        ),
    ])
Esempio n. 7
0
    def from_root_and_semitones(cls, root: Note,
                                semitones: List[int]) -> "ChordWithRoot":
        """Creates a ChordWithRoot from a root `Note` and a list of semitones from the root.

        `semitones_to_chord_name_options` is used to guess a good name for the chord.
        """
        chord = Chord.from_semitones(None, semitones)
        if "/" in chord.name:
            chord_name, bass_degree = chord.name.split("/")
            new_root = (Note(
                root.name,
                0).transpose(12 - degree_to_semitone(bass_degree)).name)
            name = "{}{}/{}".format(new_root, chord_name, root.name)
        else:
            name = root.name + chord.name
        return cls(name, root, chord)
Esempio n. 8
0
def midi_to_note(midi: int) -> Note:
    """Returns the `Note` corresponding to the given MIDI note value."""
    return Note(CHROMATIC[midi % 12], (midi - 12) // 12)
Esempio n. 9
0
def test_note_pitch(name, octave, pitch):
    assert Note(name, octave).pitch() == pytest.approx(pitch)
Esempio n. 10
0
def test_transpose_degree(note_in, octave_in, shift, note_out, octave_out):
    assert Note(note_in,
                octave_in).transpose_degree(shift) == (note_out, octave_out)
Esempio n. 11
0
def test_note_neq(note, octave, other):
    assert Note(note, octave) != other
Esempio n. 12
0
def test_note_to_midi(note, octave, midi):
    assert note_to_midi(Note(note, octave)) == midi
    assert midi_to_note(midi) == Note(note, octave)
Esempio n. 13
0
def test_note_repr(name, octave, the_repr):
    assert repr(Note(name, octave)) == the_repr
    assert Note(name, octave) == eval(the_repr)
Esempio n. 14
0
def test_chord_from_root_and_semitone(root, semitones, name):
    assert Chord.from_root_and_semitones(Note(root, 4), semitones).name == name
Esempio n. 15
0
def test_chord_add_root(name_in, octave):
    name_then_root = Intervals.from_name(name_in).with_root(Note("A#", octave))
    name_and_root = Chord.from_name(f"{octave}A#{name_in}")
    assert name_then_root == name_and_root
Esempio n. 16
0
def test_chord_add_root(name_in, octave):
    name_then_root = Chord.from_name(name_in).with_root(Note("A#", octave))
    name_and_root = ChordWithRoot.from_name("A#" + name_in, octave=octave)
    print(name_and_root._keys())
    assert name_then_root == name_and_root
Esempio n. 17
0
 def __init__(self, scale, degrees, root):
     self.scale = scale
     self.degrees = degrees
     self.root = Note(root, octave=4)
     assert scale[0] == 0
     assert all(degree >= 1 for degree in degrees)
Esempio n. 18
0
def test_note_eq(sharp, flat, octave):
    assert Note(sharp, octave) == Note(flat, octave)
    assert Note(flat, octave) == Note(sharp, octave)
Esempio n. 19
0
def test_note_to_midi_invalid_note():
    with pytest.raises(InvalidNote):
        note_to_midi(Note("bA", 0))
Esempio n. 20
0
def test_note_eq_tuple(note, octave):
    assert Note(note, octave) == (note, octave)