def test_shape_name_is_not_added_if_short_name_is_none(self): positions = [ FretPosition(0, 6), FretPosition(2, 5), ] shapes = [ GuitarShape(category='chord', name='E5 Power Chord', positions=positions) ] result = make_sequence(shapes, pick_pattern=pickpatterns.strum, tab_labels=True, rhythm=[Beat(4)]) expected = [ Note(position=positions[0], duration=Beat(4), elapsed_beats=Beat(1, 1), order=0), Note(position=positions[1], duration=Beat(4), elapsed_beats=Beat(1, 1), order=0), ] self.assertEqual(expected, result.notes)
def test_chords_can_have_bends(self): duration = Beat(1, 4) notes = [ Note(order=0, position=FretPosition(12, 5), duration=duration, elapsed_beats=Beat(1, 4)), Note(order=0, position=FretPosition(12, 4), duration=duration, elapsed_beats=Beat(1, 4)), Note(order=1, position=FretPosition(14, 5), duration=duration, elapsed_beats=Beat(2, 4), slur=BEND), Note(order=1, position=FretPosition(14, 4), duration=duration, elapsed_beats=Beat(2, 4), slur=BEND), ] shapes = [GuitarShape(name='shape1', positions=[], category='scale')] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :q (12/5.12/4) :q b(14/5.14/4) =:|') self.assertEqual(expected, vextab)
def test_can_handle_multiple_rests_in_sequence(self): rhythm = [ Beat(duration=1), Beat(duration=1, rest=True), Beat(duration=1, rest=True), Beat(duration=1), ] pattern = make_single_position_pattern(length=2) notes = apply_rhythm(pattern, rhythm) self.assertEqual(4, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1), order=0, elapsed_beats=Beat(1)), notes[0]) self.assertEqual( Note(position=None, duration=Beat(1, rest=True), order=1, elapsed_beats=Beat(2)), notes[1]) self.assertEqual( Note(position=None, duration=Beat(1, rest=True), order=2, elapsed_beats=Beat(3)), notes[2]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1), order=3, elapsed_beats=Beat(4)), notes[3])
def test_can_apply_rhythm_to_chords_and_individual_notes(self): pattern = [ [ FretPosition(string=6, fret=1), FretPosition(string=5, fret=3), ], [FretPosition(string=6, fret=0)], ] rhythm = [ Beat(duration=1), Beat(duration=1), ] notes = apply_rhythm(pattern, rhythm) self.assertEqual(3, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1), order=0, elapsed_beats=Beat(1)), notes[0]) self.assertEqual( Note(position=pattern[0][1], duration=Beat(1), order=0, elapsed_beats=Beat(1)), notes[1]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1), order=1, elapsed_beats=Beat(2)), notes[2])
def test_rhythm_is_repeated_when_shorter_than_pattern(self): rhythm = [ Beat(duration=1), ] pattern = make_single_position_pattern(length=4) notes = apply_rhythm(pattern, rhythm) self.assertEqual(4, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1), order=0, elapsed_beats=Beat(1)), notes[0]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1), order=1, elapsed_beats=Beat(2)), notes[1]) self.assertEqual( Note(position=pattern[2][0], duration=Beat(1), order=2, elapsed_beats=Beat(3)), notes[2]) self.assertEqual( Note(position=pattern[3][0], duration=Beat(1), order=3, elapsed_beats=Beat(4)), notes[3])
def test_can_apply_half_beats(self): rhythm = [ Beat(duration=1, division=2), Beat(duration=1), Beat(duration=1, division=2), Beat(duration=1), ] pattern = make_single_position_pattern(length=4) notes = apply_rhythm(pattern, rhythm) self.assertEqual(4, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1, 2), order=0, elapsed_beats=Beat(1, 2)), notes[0]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1), order=1, elapsed_beats=Beat(3, 4)), notes[1]) self.assertEqual( Note(position=pattern[2][0], duration=Beat(1, 2), order=2, elapsed_beats=Beat(5, 4)), notes[2]) self.assertEqual( Note(position=pattern[3][0], duration=Beat(1), order=3, elapsed_beats=Beat(6, 4)), notes[3])
def test_rest_beats_are_added_to_sequence_and_ignored_by_pick_pattern( self): rhythm = [ Beat(duration=1), Beat(duration=1, rest=True), Beat(duration=1), ] pattern = make_single_position_pattern(length=2) notes = apply_rhythm(pattern, rhythm) self.assertEqual(3, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1), order=0, elapsed_beats=Beat(1)), notes[0]) self.assertEqual( Note(position=None, duration=Beat(1, rest=True), order=1, elapsed_beats=Beat(2)), notes[1]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1), order=2, elapsed_beats=Beat(3)), notes[2])
def test_hammer_on_tie_is_kept_on_first_note(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=position, duration=Beat(3), elapsed_beats=Beat(3), slur=constants.HAMMER_ON), Note(order=1, position=position, duration=Beat(1), elapsed_beats=Beat(4)), ] result = normalise_note_durations(notes) expected = [ Note(order=0, position=position, duration=Beat(1, 2), elapsed_beats=Beat(1, 2), slur=constants.HAMMER_ON), Note(order=1, position=position, duration=Beat(1, 4, tie=True), elapsed_beats=Beat(3, 4)), Note(order=2, position=position, duration=Beat(1, 4), elapsed_beats=Beat(1, 1)), ] self.assertEqual(expected, result)
def test_rests_are_added_to_incomplete_bars_at_the_end(self): rhythm = [ Beat(duration=1, division=1), Beat(duration=1, division=4), ] positions = [ FretPosition(string=1, fret=1), FretPosition(string=1, fret=2), ] shape = GuitarShape(name='shape1', positions=positions, category='scale') sequence = make_sequence([shape], rhythm=rhythm) expected_notes = [ Note(order=0, position=positions[0], duration=Beat(1, 1), elapsed_beats=Beat(1, 1)), Note(order=1, position=positions[1], duration=Beat(1, 4), elapsed_beats=Beat(5, 4)), Note(order=2, position=None, duration=Beat(3, 4, rest=True), elapsed_beats=Beat(2, 1)), ] self.assertEqual(expected_notes, sequence.notes) self.assertEqual([shape], sequence.shapes)
def test_split_beats_are_in_ascending_order_if_not_at_start_of_bar(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=position, duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=position, duration=Beat(3), elapsed_beats=Beat(4)), ] result = normalise_note_durations(notes) expected = [ Note(order=0, position=position, duration=Beat(1, 4), elapsed_beats=Beat(1, 4)), Note(order=1, position=position, duration=Beat(1, 4), elapsed_beats=Beat(2, 4)), Note(order=2, position=position, duration=Beat(2, 4, tie=True), elapsed_beats=Beat(1, 1)), ] self.assertEqual(expected, result)
def test_ties_are_not_added_to_rests(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=None, duration=Beat(3, rest=True), elapsed_beats=Beat(3)), Note(order=1, position=position, duration=Beat(1), elapsed_beats=Beat(4)), ] result = normalise_note_durations(notes) expected = [ Note(order=0, position=None, duration=Beat(1, 2, rest=True), elapsed_beats=Beat(1, 2)), Note(order=1, position=None, duration=Beat(1, 4, rest=True), elapsed_beats=Beat(3, 4)), Note(order=2, position=position, duration=Beat(1, 4), elapsed_beats=Beat(1, 1)), ] self.assertEqual(expected, result)
def test_odd_length_quarter_note_is_split(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=position, duration=Beat(3), elapsed_beats=Beat(3)), Note(order=1, position=position, duration=Beat(1), elapsed_beats=Beat(4)), ] result = normalise_note_durations(notes) expected = [ Note(order=0, position=position, duration=Beat(1, 2), elapsed_beats=Beat(1, 2)), Note(order=1, position=position, duration=Beat(1, 4, tie=True), elapsed_beats=Beat(3, 4)), Note(order=2, position=position, duration=Beat(1, 4), elapsed_beats=Beat(1, 1)), ] self.assertEqual(expected, result)
def test_taps_are_added_to_tab(self): position = FretPosition(string=6, fret=5) duration = Beat(1, 8) notes = [ Note(order=0, position=position, duration=duration, elapsed_beats=Beat(1, 4)), Note(order=1, position=position, duration=duration, elapsed_beats=Beat(2, 4), slur=TAP), ] shapes = [ GuitarShape(name='shape1', positions=[position], category='scale') ] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :8 5/6 t:8: 5/6 =:|') self.assertEqual(expected, vextab)
def test_shape_name_is_added_to_annotations(self): positions = [ FretPosition(0, 6), FretPosition(2, 5), ] shapes = [ GuitarShape(category='chord', name='E5 Power Chord', positions=positions, short_name='E5') ] sequence = make_sequence(shapes, pick_pattern=pickpatterns.strum, tab_labels=True, rhythm=[Beat(4)]) expected_notes = [ Note(position=positions[0], duration=Beat(4), elapsed_beats=Beat(1, 1), order=0, annotations=['label:E5']), Note(position=positions[1], duration=Beat(4), elapsed_beats=Beat(1, 1), order=0, annotations=['label:E5']), ] self.assertEqual(expected_notes, sequence.notes) self.assertEqual(shapes, sequence.shapes)
def test_half_notes_have_a_h_duration(self): position = FretPosition(string=6, fret=5) duration = Beat(2, 4) notes = [ Note(order=1, position=position, duration=duration, elapsed_beats=Beat(2, 4)), Note(order=2, position=position, duration=duration, elapsed_beats=Beat(4, 4)), Note(order=3, position=position, duration=duration, elapsed_beats=Beat(6, 4)), Note(order=4, position=position, duration=duration, elapsed_beats=Beat(8, 4)), ] shapes = [ GuitarShape(name='shape1', positions=[position], category='scale') ] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :h 5/6 :h 5/6 | :h 5/6 :h 5/6 =:|') self.assertEqual(expected, vextab)
def test_tab_bars_are_added_every_four_beats(self): positions = [ FretPosition(string=3, fret=1), FretPosition(string=4, fret=2), FretPosition(string=5, fret=3), ] notes = [ Note(order=0, position=positions[0], duration=Beat(2, 4), elapsed_beats=Beat(2, 4)), Note(order=1, position=positions[1], duration=Beat(2, 4), elapsed_beats=Beat(4, 4)), Note(order=2, position=positions[2], duration=Beat(4, 4), elapsed_beats=Beat(2, 1)), ] shapes = [ GuitarShape(name='shape1', positions=positions, category='scale') ] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :h 1/3 :h 2/4 | :w 3/5 =:|') self.assertEqual(expected, vextab)
def test_rests_are_added_to_the_tab(self): position = FretPosition(string=6, fret=5) duration = Beat(1, 4) rest = Beat(1, 4, rest=True) notes = [ Note(order=0, position=position, duration=duration, elapsed_beats=Beat(1, 4)), Note(order=1, position=position, duration=rest, elapsed_beats=Beat(2, 4)), Note(order=2, position=position, duration=duration, elapsed_beats=Beat(3, 4)), Note(order=3, position=position, duration=rest, elapsed_beats=Beat(4, 4)), ] shapes = [ GuitarShape(name='shape1', positions=[position], category='scale') ] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :q 5/6 :q ## :q 5/6 :q ## =:|') self.assertEqual(expected, vextab)
def test_shape_is_converted_into_notes(self): positions = [ FretPosition(string=1, fret=1), FretPosition(string=1, fret=2), FretPosition(string=1, fret=3), FretPosition(string=1, fret=4), ] shape = GuitarShape(name='shape1', positions=positions, category='scale') sequence = make_sequence([shape]) duration = Beat(duration=1) expected_notes = [ Note(order=0, position=positions[0], duration=duration, elapsed_beats=Beat(1)), Note(order=1, position=positions[1], duration=duration, elapsed_beats=Beat(2)), Note(order=2, position=positions[2], duration=duration, elapsed_beats=Beat(3)), Note(order=3, position=positions[3], duration=duration, elapsed_beats=Beat(4)), ] self.assertEqual(expected_notes, sequence.notes) self.assertEqual([shape], sequence.shapes)
def test_can_palm_mute_and_down_pick_on_tabs(self): duration = Beat(1, 4) notes = [ Note(order=0, position=FretPosition(12, 5), duration=duration, elapsed_beats=Beat(1, 4), annotations=[DOWN_PICK, PALM_MUTE]), Note(order=1, position=FretPosition(14, 5), duration=duration, elapsed_beats=Beat(2, 4), annotations=[DOWN_PICK, PALM_MUTE]), ] shapes = [GuitarShape(name='shape1', positions=[], category='scale')] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ( 'tabstave notation=false\n' 'notes =|: :q 12/5 $.am/top.$ $.top.pm$ :q 14/5 $.am/top.$ $.top.pm$ =:|' ) self.assertEqual(expected, vextab)
def test_can_set_rhythm_for_sequence(self): rhythm = [ Beat(duration=1, division=4), Beat(duration=1, division=2), Beat(duration=1, division=4), ] positions = [ FretPosition(string=1, fret=1), FretPosition(string=1, fret=2), FretPosition(string=1, fret=3), ] shape = GuitarShape(name='shape1', positions=positions, category='scale') sequence = make_sequence([shape], rhythm=rhythm) expected_notes = [ Note(order=0, position=positions[0], duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=positions[1], duration=Beat(1, 2), elapsed_beats=Beat(3, 4)), Note(order=2, position=positions[2], duration=Beat(1, 4), elapsed_beats=Beat(4, 4)), ] self.assertEqual(expected_notes, sequence.notes) self.assertEqual([shape], sequence.shapes)
def test_palm_mutes_are_added_to_tab_as_text(self): position = FretPosition(string=6, fret=5) duration = Beat(1, 8) notes = [ Note(order=0, position=position, duration=duration, elapsed_beats=Beat(1, 4), annotations=[PALM_MUTE]), Note(order=1, position=position, duration=duration, elapsed_beats=Beat(2, 4), annotations=[PALM_MUTE]), ] shapes = [ GuitarShape(name='shape1', positions=[position], category='scale') ] sequence = Sequence(notes=notes, shapes=shapes) vextab = to_vextab(sequence) expected = ('tabstave notation=false\n' 'notes =|: :8 5/6 $.top.pm$ :8 5/6 $.top.pm$ =:|') self.assertEqual(expected, vextab)
def test_rests_are_ignored_when_labelling(self): shapes = [ GuitarShape(category='chord', name='E5 Power Chord', short_name='E5', positions=[ FretPosition(0, 6), FretPosition(2, 5), ]), GuitarShape(category='chord', name='F5 Power Chord', short_name='F5', positions=[ FretPosition(1, 6), FretPosition(3, 5), ]), ] rhythm = [Beat(2), Beat(1, rest=True), Beat(1)] result = make_sequence(shapes, pick_pattern=pickpatterns.strum, tab_labels=True, rhythm=rhythm) expected = [ Note(position=shapes[0].positions[0], duration=Beat(2), elapsed_beats=Beat(1, 2), order=0, annotations=['label:E5']), Note(position=shapes[0].positions[1], duration=Beat(2), elapsed_beats=Beat(1, 2), order=0, annotations=['label:E5']), Note(position=None, duration=Beat(1, rest=True), elapsed_beats=Beat(3), order=1), Note(position=shapes[1].positions[0], duration=Beat(1), elapsed_beats=Beat(1, 1), order=2, annotations=['label:F5']), Note(position=shapes[1].positions[1], duration=Beat(1), elapsed_beats=Beat(1, 1), order=2, annotations=['label:F5']), ] self.assertEqual(expected, result.notes)
def test_pull_off_tie_is_not_added_to_asc_positions(self): notes = [ Note(order=0, position=FretPosition(5, 6), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(7, 6), duration=Beat(1), elapsed_beats=Beat(2)), ] result = pull_off_desc(notes, None) expected = [ Note(order=0, position=FretPosition(5, 6), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(7, 6), duration=Beat(1), elapsed_beats=Beat(2)), ] self.assertEqual(expected, result)
def test_hammer_on_tie_is_added_to_asc_positions(self): notes = [ Note(order=0, position=FretPosition(5, 6), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(7, 6), duration=Beat(1), elapsed_beats=Beat(2)), ] result = hammer_on_asc(notes, None) expected = [ Note(order=0, position=FretPosition(5, 6), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(7, 6), duration=Beat(1), elapsed_beats=Beat(2), slur=HAMMER_ON), ] self.assertEqual(expected, result)
def test_hammer_on_is_not_added_after_string_change(self): notes = [ Note(order=0, position=FretPosition(string=6, fret=5), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(string=5, fret=5), duration=Beat(1), elapsed_beats=Beat(2)), ] result = hammer_on_asc(notes, None) expected = [ Note(order=0, position=FretPosition(string=6, fret=5), duration=Beat(1), elapsed_beats=Beat(1)), Note(order=1, position=FretPosition(string=5, fret=5), duration=Beat(1), elapsed_beats=Beat(2)), ] self.assertEqual(expected, result)
def test_chords_are_not_palm_muted(self): notes = [ Note(position=FretPosition(0, 6), duration=Beat(1), elapsed_beats=Beat(1), order=0), Note(position=FretPosition(0, 5), duration=Beat(1), elapsed_beats=Beat(1), order=0), ] result = palm_mute_single(notes, None) expected = [ Note(position=FretPosition(0, 6), duration=Beat(1), elapsed_beats=Beat(1), order=0), Note(position=FretPosition(0, 5), duration=Beat(1), elapsed_beats=Beat(1), order=0), ] self.assertEqual(expected, result)
def lick_ten(): return [ Note(order=0, position=FretPosition(5, 4), duration=Beat(1, 8), elapsed_beats=Beat(1, 8)), Note(order=1, position=FretPosition(7, 4), duration=Beat(1, 8), elapsed_beats=Beat(2, 8)), Note(order=2, position=FretPosition(5, 4), duration=Beat(1, 8), elapsed_beats=Beat(3, 8)), Note(order=3, position=FretPosition(7, 5), duration=Beat(1, 8), elapsed_beats=Beat(4, 8)), Note(order=4, position=FretPosition(5, 5), duration=Beat(1, 8), elapsed_beats=Beat(5, 8)), Note(order=5, position=FretPosition(7, 5), duration=Beat(1, 8), elapsed_beats=Beat(6, 8)), Note(order=6, position=FretPosition(5, 5), duration=Beat(1, 8), elapsed_beats=Beat(7, 8)), Note(order=7, position=FretPosition(8, 6), duration=Beat(1, 8), elapsed_beats=Beat(8, 8)), ]
def lick_eight(): return [ Note(order=0, position=FretPosition(5, 1), duration=Beat(1, 8), elapsed_beats=Beat(1, 8)), Note(order=1, position=FretPosition(8, 1), duration=Beat(1, 8), elapsed_beats=Beat(2, 8)), Note(order=2, position=FretPosition(5, 1), duration=Beat(1, 8), elapsed_beats=Beat(3, 8)), Note(order=3, position=FretPosition(8, 2), duration=Beat(1, 8), elapsed_beats=Beat(4, 8)), Note(order=4, position=FretPosition(5, 2), duration=Beat(1, 8), elapsed_beats=Beat(5, 8)), Note(order=5, position=FretPosition(8, 2), duration=Beat(1, 8), elapsed_beats=Beat(6, 8)), Note(order=6, position=FretPosition(5, 2), duration=Beat(1, 8), elapsed_beats=Beat(7, 8)), Note(order=7, position=FretPosition(5, 3), duration=Beat(1, 8), elapsed_beats=Beat(8, 8)), ]
def lick_thirteen(): return [ Note(order=0, position=None, duration=Beat(1, 8, rest=True), elapsed_beats=Beat(1, 8)), Note(order=1, position=FretPosition(5, 1), duration=Beat(1, 8), elapsed_beats=Beat(2, 8)), Note(order=2, position=FretPosition(8, 2), duration=Beat(1, 8), elapsed_beats=Beat(3, 8)), Note(order=3, position=FretPosition(5, 2), duration=Beat(1, 8), elapsed_beats=Beat(4, 8)), Note(order=4, position=FretPosition(8, 2), duration=Beat(1, 8), elapsed_beats=Beat(5, 8)), Note(order=5, position=FretPosition(5, 2), duration=Beat(1, 8), elapsed_beats=Beat(6, 8)), Note(order=6, position=FretPosition(7, 3), duration=Beat(1, 8), elapsed_beats=Beat(7, 8)), Note(order=7, position=FretPosition(5, 3), duration=Beat(1, 8), elapsed_beats=Beat(8, 8)), ]
def lick_three(): return [ Note(duration=Beat(1, 8, rest=True), elapsed_beats=Beat(1, 8), position=None, order=0), Note(duration=Beat(1, 8), elapsed_beats=Beat(2, 8), position=FretPosition(5, 1), order=1), Note(duration=Beat(1, 8), elapsed_beats=Beat(3, 8), position=FretPosition(8, 2), order=2), Note(duration=Beat(1, 8), elapsed_beats=Beat(4, 8), position=FretPosition(5, 2), order=3), Note(duration=Beat(1, 8), elapsed_beats=Beat(5, 8), position=FretPosition(7, 3), order=4), Note(duration=Beat(1, 8), elapsed_beats=Beat(6, 8), position=FretPosition(5, 3), order=5), Note(duration=Beat(1, 4), elapsed_beats=Beat(7, 8), position=FretPosition(7, 4), order=6), ]