def test_odd_length_quarter_note_chord_is_split(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=FretPosition(string=3, fret=1), duration=Beat(3, 4), elapsed_beats=Beat(3)), Note(order=0, position=FretPosition(string=2, fret=1), duration=Beat(3, 4), 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=FretPosition(string=3, fret=1), duration=Beat(1, 2), elapsed_beats=Beat(1, 2)), Note(order=0, position=FretPosition(string=2, fret=1), duration=Beat(1, 2), elapsed_beats=Beat(1, 2)), Note(order=1, position=FretPosition(string=3, fret=1), duration=Beat(1, 4, tie=True), elapsed_beats=Beat(3, 4)), Note(order=1, position=FretPosition(string=2, fret=1), 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_less_than_or_equal_for_same_beats(self): self.assertLessEqual(Beat(1, 1), Beat(1, 1))
def test_new_bar_returns_true_when_division_is_not_end_beat(self): self.assertFalse(Beat(2, 4).is_new_bar())
def test_bigger_beats_are_not_lesser_than_smaller_beats(self): result = Beat(1, 1) < Beat(1, 2) self.assertFalse(result)
def test_bigger_beats_are_not_lesser_or_equal_to_smaller_beats(self): result = Beat(1, 1) <= Beat(1, 2) self.assertFalse(result)
def test_smaller_beats_are_not_greater_than_larger_beats(self): result = Beat(1, 2) > Beat(1, 1) self.assertFalse(result)
def test_smaller_beats_are_not_greater_or_equal_to_larger_beats(self): result = Beat(1, 2) >= Beat(1, 1) self.assertFalse(result)
def test_can_apply_sixteenth_notes(self): rhythm = [ Beat(duration=1, division=16), Beat(duration=1, division=16), Beat(duration=1, division=16), Beat(duration=1, division=16), Beat(duration=1), ] pattern = make_single_position_pattern(length=5) notes = apply_rhythm(pattern, rhythm) self.assertEqual(5, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1, 16), order=0, elapsed_beats=Beat(1, 16)), notes[0]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1, 16), order=1, elapsed_beats=Beat(2, 16)), notes[1]) self.assertEqual( Note(position=pattern[2][0], duration=Beat(1, 16), order=2, elapsed_beats=Beat(3, 16)), notes[2]) self.assertEqual( Note(position=pattern[3][0], duration=Beat(1, 16), order=3, elapsed_beats=Beat(4, 16)), notes[3]) self.assertEqual( Note(position=pattern[4][0], duration=Beat(1), order=4, elapsed_beats=Beat(2, 4)), notes[4])
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_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_can_apply_triplets(self): rhythm = [ Beat(duration=1, division=12), Beat(duration=1, division=12), Beat(duration=1, division=12), Beat(duration=1), Beat(duration=1, division=12), Beat(duration=2, division=12), Beat(duration=1), ] pattern = make_single_position_pattern(length=7) notes = apply_rhythm(pattern, rhythm) self.assertEqual(7, len(notes)) self.assertEqual( Note(position=pattern[0][0], duration=Beat(1, 12), order=0, elapsed_beats=Beat(1, 12)), notes[0]) self.assertEqual( Note(position=pattern[1][0], duration=Beat(1, 12), order=1, elapsed_beats=Beat(2, 12)), notes[1]) self.assertEqual( Note(position=pattern[2][0], duration=Beat(1, 12), order=2, elapsed_beats=Beat(3, 12)), notes[2]) self.assertEqual( Note(position=pattern[3][0], duration=Beat(1), order=3, elapsed_beats=Beat(2, 4)), notes[3]) self.assertEqual( Note(position=pattern[4][0], duration=Beat(1, 12), order=4, elapsed_beats=Beat(7, 12)), notes[4]) self.assertEqual( Note(position=pattern[5][0], duration=Beat(2, 12), order=5, elapsed_beats=Beat(3, 4)), notes[5]) self.assertEqual( Note(position=pattern[6][0], duration=Beat(1), order=6, elapsed_beats=Beat(4)), notes[6])
def test_order_increases_based_on_rhythm(self): rhythm = [ Beat(duration=1), Beat(duration=1), Beat(duration=1), 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 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)
def test_normalise_note_durations_keeps_existing_ties(self): position = FretPosition(string=3, fret=1) notes = [ Note(order=0, position=position, duration=Beat(1, 12), elapsed_beats=Beat(1, 12)), Note(order=1, position=position, duration=Beat(1, 12, tie=True), elapsed_beats=Beat(2, 12)), Note(order=2, position=position, duration=Beat(1, 12), elapsed_beats=Beat(3, 12)), ] result = normalise_note_durations(notes) expected = [ Note(order=0, position=position, duration=Beat(1, 12), elapsed_beats=Beat(1, 12)), Note(order=1, position=position, duration=Beat(1, 12, tie=True), elapsed_beats=Beat(2, 12)), Note(order=2, position=position, duration=Beat(1, 12), elapsed_beats=Beat(3, 12)), ] self.assertEqual(expected, result)
def test_next_bar_rounds_beat_up_to_the_nearest_whole_beat(self): calculations = [ [Beat(duration=1, division=1), Beat(duration=1, division=1)], [Beat(duration=1, division=2), Beat(duration=1, division=1)], [Beat(duration=3, division=4), Beat(duration=1, division=1)], [Beat(duration=5, division=8), Beat(duration=1, division=1)], [Beat(duration=8, division=16), Beat(duration=1, division=1)], [Beat(duration=31, division=32), Beat(duration=1, division=1)], [Beat(duration=2, division=1), Beat(duration=2, division=1)], [Beat(duration=5, division=2), Beat(duration=3, division=1)], [Beat(duration=12, division=4), Beat(duration=3, division=1)], [Beat(duration=48, division=8), Beat(duration=6, division=1)], [Beat(duration=160, division=16), Beat(duration=10, division=1)], [Beat(duration=900, division=32), Beat(duration=29, division=1)], ] for calculation in calculations: result = calculation[0].next_bar() self.assertEqual(calculation[1], result)
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_larger_beats_are_greater_than_smaller_beats(self): self.assertGreater(Beat(1, 1), Beat(1, 2))
def test_down_pick_annotation_is_added_to_evey_other_beat(self): notes = [ Note(order=0, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(1, 8)), Note(order=1, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(2, 8)), Note(order=2, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(3, 8)), Note(order=3, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(4, 8)), Note(order=4, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(5, 8)), Note(order=5, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(6, 8)), Note(order=6, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(7, 8)), Note(order=7, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(8, 8)), Note(order=8, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(9, 8)), ] result = down_pick_alternating_beats(notes, None) expected = [ Note(order=0, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(1, 8), annotations=[DOWN_PICK]), Note(order=1, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(2, 8)), Note(order=2, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(3, 8)), Note(order=3, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(4, 8)), Note(order=4, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(5, 8), annotations=[DOWN_PICK]), Note(order=5, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(6, 8)), Note(order=6, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(7, 8)), Note(order=7, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(8, 8)), Note(order=8, position=FretPosition(string=5, fret=5), duration=Beat(1, 8), elapsed_beats=Beat(9, 8), annotations=[DOWN_PICK]), ] self.assertEqual(expected, result)
def test_larger_beats_are_greater_or_equal_to_smaller_beats(self): self.assertGreaterEqual(Beat(1, 1), Beat(1, 2))
def test_open_strings_are_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(2), order=1), Note(position=FretPosition(0, 4), duration=Beat(1), elapsed_beats=Beat(3), order=2), Note(position=FretPosition(0, 3), duration=Beat(1), elapsed_beats=Beat(4), order=3), Note(position=FretPosition(0, 2), duration=Beat(1), elapsed_beats=Beat(5), order=4), Note(position=FretPosition(0, 1), duration=Beat(1), elapsed_beats=Beat(6), order=5), ] result = palm_mute_open(notes, None) expected = [ Note(position=FretPosition(0, 6), duration=Beat(1), elapsed_beats=Beat(1), order=0, annotations=[PALM_MUTE]), Note(position=FretPosition(0, 5), duration=Beat(1), elapsed_beats=Beat(2), order=1, annotations=[PALM_MUTE]), Note(position=FretPosition(0, 4), duration=Beat(1), elapsed_beats=Beat(3), order=2, annotations=[PALM_MUTE]), Note(position=FretPosition(0, 3), duration=Beat(1), elapsed_beats=Beat(4), order=3, annotations=[PALM_MUTE]), Note(position=FretPosition(0, 2), duration=Beat(1), elapsed_beats=Beat(5), order=4, annotations=[PALM_MUTE]), Note(position=FretPosition(0, 1), duration=Beat(1), elapsed_beats=Beat(6), order=5, annotations=[PALM_MUTE]), ] self.assertEqual(expected, result)
def test_smaller_beats_are_lesser_than_bigger_beats(self): self.assertLess(Beat(1, 2), Beat(1, 1))
def test_single_notes_are_palm_muted(self): notes = [ Note(position=FretPosition(1, 6), duration=Beat(1), elapsed_beats=Beat(1), order=0), Note(position=FretPosition(2, 5), duration=Beat(1), elapsed_beats=Beat(2), order=1), Note(position=FretPosition(3, 4), duration=Beat(1), elapsed_beats=Beat(3), order=2), Note(position=FretPosition(4, 3), duration=Beat(1), elapsed_beats=Beat(4), order=3), Note(position=FretPosition(5, 2), duration=Beat(1), elapsed_beats=Beat(5), order=4), Note(position=FretPosition(6, 1), duration=Beat(1), elapsed_beats=Beat(6), order=5), ] result = palm_mute_single(notes, None) expected = [ Note(position=FretPosition(1, 6), duration=Beat(1), elapsed_beats=Beat(1), order=0, annotations=[PALM_MUTE]), Note(position=FretPosition(2, 5), duration=Beat(1), elapsed_beats=Beat(2), order=1, annotations=[PALM_MUTE]), Note(position=FretPosition(3, 4), duration=Beat(1), elapsed_beats=Beat(3), order=2, annotations=[PALM_MUTE]), Note(position=FretPosition(4, 3), duration=Beat(1), elapsed_beats=Beat(4), order=3, annotations=[PALM_MUTE]), Note(position=FretPosition(5, 2), duration=Beat(1), elapsed_beats=Beat(5), order=4, annotations=[PALM_MUTE]), Note(position=FretPosition(6, 1), duration=Beat(1), elapsed_beats=Beat(6), order=5, annotations=[PALM_MUTE]), ] self.assertEqual(expected, result)
def test_smaller_beats_are_lesser_or_equal_to_bigger_beats(self): self.assertLessEqual(Beat(1, 2), Beat(1, 1))
def test_subtracting_the_same_beat_returns_zero_beat(self): result = Beat(1, 1) - Beat(1, 1) self.assertEqual(Beat(0, 1), result)
def test_greater_than_or_equal_for_same_beats(self): self.assertGreaterEqual(Beat(1, 1), Beat(1, 1))
def test_result_of_subtracting_notes_cannot_be_negative(self): with self.assertRaises(ValueError): Beat(duration=1, division=4) - Beat(duration=1, division=1)
def test_new_bar_returns_true_when_division_is_1(self): self.assertTrue(Beat(2, 1).is_new_bar())
def test_subtraction_retains_rest(self): result = Beat(2, 4, rest=True) - Beat(1, 4) self.assertEqual(Beat(1, 4, rest=True), result)
def test_new_bar_returns_true_when_division_is_end_beat(self): self.assertTrue(Beat(4, 4).is_new_bar())
def level_two(): combos = [ { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': [ 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'n', 'n', 'n', 'n', 'n', 'n', 'n', 'n' ], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['c', 'c', 'c', 'c', 'n', 'n', 'n', 'n'], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['n', 'n', 'n', 'n', 'c', 'c', 'c', 'c'], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': [ 'n', 'n', 'n', 'n', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'n', 'n', 'n', 'n' ], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['n', 'c'], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['c', 'n'], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['c', 'c', 'n', 'n'], }, { 'preset_patterns': picked_metal_patterns(length=8), 'length': 16, 'chug_pattern': ['n', 'n', 'c', 'c'], }, { 'preset_patterns': picked_metal_patterns(length=7), 'length': 14, 'chug_pattern': [ 'c', 'c', 'n', 'c', 'n', 'c', 'n', 'c', 'n', 'c', 'n', 'c', 'n', 'n' ], 'rhythm': [ Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 8), Beat(1, 4), Beat(1, 4), ] }, ] return build_sequence_from_combo(combos)