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_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 test_show_shape_labels_sets_shape_labels_to_true(self): positions = [FretPosition(fret=0, string=6)] shape = GuitarShape('open string', 'note', positions=positions) sequence = make_sequence(shapes=[shape], shape_labels=True) self.assertTrue(sequence.shape_labels)
def level_one(): chords = random.sample(c_major_scale_triad_chords(), 2) pick_pattern = partial(strum, length=4) return make_sequence( shapes=chords, pick_pattern=pick_pattern, shape_labels=True, tab_labels=True, )
def test_shapes_are_not_duplicated(self): positions = [FretPosition(fret=0, string=6)] shape_1 = GuitarShape('open string', 'note', positions=positions) shape_2 = GuitarShape('open string', 'note', positions=positions) sequence = make_sequence(shapes=[shape_1, shape_2]) self.assertEqual(len(sequence.shapes), 1) self.assertEqual(sequence.shapes[0], shape_1) self.assertEqual(sequence.shapes[0], shape_2)
def level_one() -> Sequence: shape = generate_single_string_shape(1) repeater = partial(repeat_each_position, repeats=16) rhythm = [Beat(duration=1, division=16)] return make_sequence( shapes=[shape], rhythm=rhythm, pick_pattern=repeater, )
def level_three_variation_one(): preset_pattern = random.choice(level_three_fixed_patterns()) chords = random.sample(c_major_scale_triad_chords(), 2) pick_pattern = partial(pickpatterns.fixed_string_pattern, pattern=preset_pattern) return make_sequence( shapes=chords, pick_pattern=pick_pattern, shape_labels=True, )
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 level_two(): chords = random.choice([ level_two_chords_variation_one(), level_two_chords_variation_two(), ]) order = random.choice([bass_and_strum, strum, strum, strum]) pick_pattern = partial(order, length=4) return make_sequence(shapes=chords, pick_pattern=pick_pattern, shape_labels=True, annotators=[shape_name])
def assorted_rhythm(rhythm_options, beat_count): position = FretPosition(0, 6) shape = GuitarShape('Open String', 'scale', positions=[position]) rhythm_choices = [random.choice(rhythm_options) for _ in range(beat_count)] rhythm = list(chain.from_iterable(rhythm_choices)) picked_notes = [beat for beat in rhythm if not beat.rest] repeater = partial(repeat_each_position, repeats=len(picked_notes)) return make_sequence( shapes=[shape], rhythm=rhythm, pick_pattern=repeater, )
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 major_scale() -> Sequence: shape = random.choice(c_major_modes()) pattern = random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.asc_and_desc, partial(pickpatterns.alternating_bass_and_asc, length=14) ]) rhythm = [Beat(duration=1, division=8)] lowest_fret = random.randrange(1, 13) return make_sequence( shapes=[shape], rhythm=rhythm, pick_pattern=pattern, shape_shifters=[partial(shift_vertically, lowest_fret=lowest_fret)], shape_labels=True, )
def level_one(): order_choices = [ pickpatterns.asc, pickpatterns.asc_and_desc, ] order = random.choice(order_choices) notes_per_arpeggio = random.choice([4, 6, 8]) chords = random.sample(c_major_scale_triad_chords(), 2) pick_pattern = partial(order, length=notes_per_arpeggio) return make_sequence( shapes=chords, pick_pattern=pick_pattern, shape_labels=True, tab_labels=True, )
def build_sequence_from_combo(combos): combo = random.choice(combos) rhythm = [] shapes = [] for _ in range(combo.get('repeats', 4)): position = random.choice(combo.get('choices')) rhythm.extend(position['rhythm']) shapes.extend(position['shapes']) return make_sequence( shapes=shapes, rhythm=rhythm, pick_pattern=chug, annotators=[palm_mute_single] )
def test_repeated_shapes_are_not_labeled(self): positions = [ FretPosition(0, 6), FretPosition(2, 5), ] shapes = [ GuitarShape(category='chord', name='E5 Power Chord', positions=positions, short_name='E5'), GuitarShape(category='chord', name='E5 Power Chord', positions=positions, short_name='E5'), ] result = make_sequence(shapes, pick_pattern=pickpatterns.strum, tab_labels=True, rhythm=[Beat(2)]) expected = [ Note(position=positions[0], duration=Beat(2), elapsed_beats=Beat(1, 2), order=0, annotations=['label:E5']), Note(position=positions[1], duration=Beat(2), elapsed_beats=Beat(1, 2), order=0, annotations=['label:E5']), Note(position=positions[0], duration=Beat(2), elapsed_beats=Beat(1, 1), order=1), Note(position=positions[1], duration=Beat(2), elapsed_beats=Beat(1, 1), order=1), ] self.assertEqual(expected, result.notes)
def test_can_label_arpeggios(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), ]), ] result = make_sequence(shapes, tab_labels=True, rhythm=[Beat(1)]) expected = [ Note(position=shapes[0].positions[0], duration=Beat(1), elapsed_beats=Beat(1), order=0, annotations=['label:E5']), Note(position=shapes[0].positions[1], duration=Beat(1), elapsed_beats=Beat(1, 2), order=1), Note(position=shapes[1].positions[0], duration=Beat(1), elapsed_beats=Beat(3), order=2, annotations=['label:F5']), Note(position=shapes[1].positions[1], duration=Beat(1), elapsed_beats=Beat(1, 1), order=3), ] self.assertEqual(expected, result.notes)
def test_multiple_shapes_are_combined_into_a_sequence(self): positions_1 = [ FretPosition(string=1, fret=1), FretPosition(string=1, fret=2), ] shape_1 = GuitarShape(name='shape1', positions=positions_1, category='scale') positions_2 = [ FretPosition(string=2, fret=1), FretPosition(string=2, fret=2), ] shape_2 = GuitarShape(name='shape2', positions=positions_2, category='scale') sequence = make_sequence([shape_1, shape_2]) duration = Beat(duration=1) expected_notes = [ Note(order=0, position=positions_1[0], duration=duration, elapsed_beats=Beat(1)), Note(order=1, position=positions_1[1], duration=duration, elapsed_beats=Beat(2)), Note(order=2, position=positions_2[0], duration=duration, elapsed_beats=Beat(3)), Note(order=3, position=positions_2[1], duration=duration, elapsed_beats=Beat(4)), ] self.assertEqual(expected_notes, sequence.notes) self.assertEqual([shape_1, shape_2], sequence.shapes)
def level_two() -> Sequence: combos = [ { 'shapes': [generate_single_string_shape(4)], 'pick_pattern': partial(repeat_each_position, repeats=16, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.randomly ])), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [generate_single_string_shape(2)], 'pick_pattern': partial(repeat_each_position, repeats=8, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.randomly ])), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [positions_on_adjacent_strings()], 'pick_pattern': partial(repeat_each_position, repeats=16, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.randomly ])), 'rhythm': [Beat(duration=1, division=16)], }, ] combo = random.choice(combos) return make_sequence(**combo)
def build_sequence_from_combo(combos): shape_choices = [ *scale_collections.c_major_modes(), *scale_collections.c_major_pentatonic_modes(), chromatic_shapes.chromatic_4_notes_per_string(), chromatic_shapes.chromatic_5_notes_per_string(), single_string_scales.chromatic_string_6(), single_string_scales.major_pentatonic_string_6(), single_string_scales.major_string_6(), single_string_scales.mixolydian_string_6(), single_string_scales.lydian_string_6(), single_string_scales.phrygian_dominant_string_6(), single_string_scales.minor_pentatonic_string_6(), single_string_scales.minor_blues_string_6(), single_string_scales.natural_minor_string_6(), single_string_scales.harmonic_minor_string_6(), single_string_scales.melodic_minor_string_6(), single_string_scales.dorian_string_6(), single_string_scales.chromatic_string_5(), single_string_scales.major_pentatonic_string_5(), single_string_scales.major_string_5(), single_string_scales.mixolydian_string_5(), single_string_scales.lydian_string_5(), single_string_scales.phrygian_dominant_string_5(), single_string_scales.minor_pentatonic_string_5(), single_string_scales.minor_blues_string_5(), single_string_scales.natural_minor_string_5(), single_string_scales.harmonic_minor_string_5(), single_string_scales.melodic_minor_string_5(), single_string_scales.dorian_string_5(), ] shape = random.choice(shape_choices) combo = random.choice(combos) preset_pattern = random.choice(combo['preset_patterns']) pick_pattern = partial(fixed_order_pattern, pattern=preset_pattern) chug_pattern = partial(fixed_chug_pattern, length=combo['length'], note_order=pick_pattern, pattern=combo['chug_pattern']) if combo.get('rhythm'): rhythm = combo.get('rhythm') else: rhythm = [Beat(1, 8)] if max([position.fret for position in shape.positions]) > 10: highest_min_fret = 5 else: highest_min_fret = 7 shape_shifter = partial(shift_vertically, lowest_fret=random.randrange(1, highest_min_fret)) return make_sequence( [shape], pick_pattern=chug_pattern, rhythm=rhythm, annotators=[palm_mute_open], shape_shifters=[shape_shifter], recalculate_shape=True, )
def level_three() -> Sequence: combos = [ { 'shapes': [random.choice(c_major_modes())], 'pick_pattern': partial(repeat_each_position, repeats=4, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.asc_and_desc ])), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [random.choice(c_major_pentatonic_modes())], 'pick_pattern': partial(repeat_each_position, repeats=4, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.asc_and_desc ])), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [single_string_chromatic_pattern()], 'pick_pattern': partial(repeat_each_position, repeats=4, order=random.choice([ pickpatterns.asc, pickpatterns.desc, pickpatterns.randomly ])), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [single_string_chromatic_pattern()], 'pick_pattern': partial(repeat_each_position, repeats=2, length=16, order=pickpatterns.alternating_bass_asc_and_desc), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [generate_single_string_shape(2)], 'pick_pattern': partial(fixed_order_pattern, pattern=random.choice(sixteenth_note_patterns())), 'rhythm': [Beat(duration=1, division=16)], }, { 'shapes': [positions_on_adjacent_strings()], 'pick_pattern': partial(fixed_order_pattern, pattern=random.choice(sixteenth_note_patterns())), 'rhythm': [Beat(duration=1, division=16)], }, ] combo = random.choice(combos) return make_sequence(**combo)