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_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_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_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_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_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_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_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 d_minor_seven() -> GuitarShape: positions = [ FretPosition(string=4, fret=0, highlighted=True), FretPosition(string=3, fret=2, finger=2), FretPosition(string=2, fret=1, finger=1), FretPosition(string=1, fret=1, finger=1) ] return GuitarShape('D Minor 7', 'chord', positions, short_name='Dm7')
def b_diminished() -> GuitarShape: positions = [ FretPosition(string=4, fret=0), FretPosition(string=3, fret=4, finger=4, highlighted=True), FretPosition(string=2, fret=0, highlighted=True), FretPosition(string=1, fret=1, finger=1), ] return GuitarShape('B Diminished', 'chord', positions, short_name='Bdim')
def f_major_seven() -> GuitarShape: positions = [ FretPosition(string=4, fret=3, finger=3, highlighted=True), FretPosition(string=3, fret=2, finger=2), FretPosition(string=2, fret=1, finger=1), FretPosition(string=1, fret=0), ] return GuitarShape('F Major 7', 'chord', positions, short_name='Fmaj7')
def power_chord(string=6, fret=None) -> GuitarShape: if fret is None: fret = random.randrange(0, 12) positions = [ FretPosition(string=string, fret=fret), FretPosition(string=string - 1, fret=fret + 2), ] return GuitarShape('Power Chord', 'chord', positions)
def f_major_add_9() -> GuitarShape: positions = [ FretPosition(string=4, fret=3, finger=3, highlighted=True), FretPosition(string=3, fret=2, finger=2), FretPosition(string=2, fret=1, finger=1), FretPosition(string=1, fret=3, finger=4), ] return GuitarShape('F Major add 9', 'chord', positions, short_name='Fadd9')
def a_minor() -> GuitarShape: positions = [ FretPosition(string=5, fret=0, highlighted=True), FretPosition(string=4, fret=2, finger=2), FretPosition(string=3, fret=2, finger=3, highlighted=True), FretPosition(string=2, fret=1, finger=1), FretPosition(string=1, fret=0, highlighted=True) ] return GuitarShape('A Minor', 'chord', positions, short_name='Am')
def c_major() -> GuitarShape: positions = [ FretPosition(string=5, fret=3, finger=3, highlighted=True), FretPosition(string=4, fret=2, finger=2), FretPosition(string=3, fret=0), FretPosition(string=2, fret=1, finger=1, highlighted=True), FretPosition(string=1, fret=0) ] return GuitarShape('C Major', 'chord', positions, short_name='C')
def b_minor_seven_flat_five() -> GuitarShape: positions = [ FretPosition(string=4, fret=0), FretPosition(string=3, fret=2, finger=2), FretPosition(string=2, fret=0, highlighted=True), FretPosition(string=1, fret=1, finger=1), ] return GuitarShape('B Minor 7 Flat 5', 'chord', positions, short_name='Bm7b5')
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 d_minor_add_9() -> GuitarShape: positions = [ FretPosition(string=4, fret=3, finger=2), FretPosition(string=3, fret=2, finger=1), FretPosition(string=2, fret=3, finger=3, highlighted=True), FretPosition(string=1, fret=0) ] return GuitarShape('D Minor add 9', 'chord', positions, short_name='Dmadd9')
def test_setting_lowest_fret_to_lower_number_moves_shape_down(self): positions = [ FretPosition(fret=5, string=6), FretPosition(fret=7, string=5), ] shape = GuitarShape('Power chord', 'chord', positions=positions) result = shift_vertically(shape, 1) expected_positions = [ FretPosition(fret=1, string=6), FretPosition(fret=3, string=5), ] self.assertEqual(expected_positions, result.positions)
def test_setting_lowest_fret_to_same_lowest_fret_does_not_move_shape(self): positions = [ FretPosition(fret=5, string=6), FretPosition(fret=7, string=5), ] shape = GuitarShape('Power chord', 'chord', positions=positions) result = shift_vertically(shape, 5) expected_positions = [ FretPosition(fret=5, string=6), FretPosition(fret=7, string=5), ] self.assertEqual(expected_positions, result.positions)
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 positions_on_adjacent_strings(): base_string = random.randrange(1, 6) other_string = base_string + 1 base_fret = random.randrange(0, 8) other_fret = max(0, base_fret + random.randrange(-3, 3)) positions = [ FretPosition(string=base_string, fret=base_fret), FretPosition(string=other_string, fret=other_fret), ] return GuitarShape('Two notes on adjacent strings', 'scale', positions=positions)
def test_recalculate_shape_only_displays_positions_that_are_used(self): positions = [ FretPosition(fret=0, string=6), FretPosition(fret=1, string=6) ] shape = GuitarShape('two notes', 'note', positions=positions) pick_pattern = partial(pickpatterns.asc, length=1) sequence = make_sequence(shapes=[shape], pick_pattern=pick_pattern, recalculate_shape=True) self.assertEqual(1, len(sequence.shapes[0].positions)) self.assertEqual(positions[0], sequence.shapes[0].positions[0])
def fixed_chug_pattern( shape: GuitarShape, length: int = None, pattern: List[str] = None, note_order: Callable = None) -> List[List[FretPosition]]: if note_order is None: raise ValueError('note_order must be set') if pattern is None: raise ValueError('pattern must be set') if length is None: length = len(pattern) notes_pick_pattern = cycle(note_order(shape)) pattern_cycle = cycle(pattern) pick_pattern = [] while len(pick_pattern) < length: item = next(pattern_cycle) if item == 'c': pick_pattern.append([FretPosition(string=6, fret=0)]) elif item == 'n': pick_pattern.append(next(notes_pick_pattern)) return pick_pattern