def testSplitNoteSequenceCoincidentTimeChanges(self): sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} time_signatures: { time: 2.0 numerator: 3 denominator: 4} tempos: { qpm: 60} tempos: { time: 2.0 qpm: 80}""") testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)]) expected_subsequence_1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(expected_subsequence_1, 0, [(12, 100, 0.01, 2.0), (11, 55, 0.22, 0.50)]) testing_lib.add_chords_to_sequence(expected_subsequence_1, [('C', 1.5)]) expected_subsequence_1.total_time = 2.0 expected_subsequence_1.subsequence_info.end_time_offset = 8.0 expected_subsequence_2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 3 denominator: 4} tempos: { qpm: 80}""") testing_lib.add_track_to_sequence(expected_subsequence_2, 0, [(40, 45, 0.50, 1.50), (55, 120, 2.0, 2.01), (52, 99, 2.75, 3.0)]) testing_lib.add_chords_to_sequence(expected_subsequence_2, [('C', 0.0), ('G7', 1.0), ('F', 2.8)]) expected_subsequence_2.total_time = 8.0 expected_subsequence_2.subsequence_info.start_time_offset = 2.0 subsequences = sequences_lib.split_note_sequence_on_time_changes( sequence) self.assertEquals(2, len(subsequences)) self.assertProtoEquals(expected_subsequence_1, subsequences[0]) self.assertProtoEquals(expected_subsequence_2, subsequences[1])
def testSplitNoteSequenceCoincidentTimeChanges(self): sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} time_signatures: { time: 2.0 numerator: 3 denominator: 4} tempos: { qpm: 60} tempos: { time: 2.0 qpm: 80}""") testing_lib.add_track_to_sequence( sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence( sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)]) expected_subsequence_1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( expected_subsequence_1, 0, [(12, 100, 0.01, 2.0), (11, 55, 0.22, 0.50)]) testing_lib.add_chords_to_sequence( expected_subsequence_1, [('C', 1.5)]) expected_subsequence_1.total_time = 2.0 expected_subsequence_1.subsequence_info.end_time_offset = 8.0 expected_subsequence_2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 3 denominator: 4} tempos: { qpm: 80}""") testing_lib.add_track_to_sequence( expected_subsequence_2, 0, [(40, 45, 0.50, 1.50), (55, 120, 2.0, 2.01), (52, 99, 2.75, 3.0)]) testing_lib.add_chords_to_sequence( expected_subsequence_2, [('C', 0.0), ('G7', 1.0), ('F', 2.8)]) expected_subsequence_2.total_time = 3.0 expected_subsequence_2.subsequence_info.start_time_offset = 2.0 expected_subsequence_2.subsequence_info.end_time_offset = 5.0 subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence) self.assertEquals(2, len(subsequences)) self.assertProtoEquals(expected_subsequence_1, subsequences[0]) self.assertProtoEquals(expected_subsequence_2, subsequences[1])
def testSplitNoteSequenceSkipSplitsInsideNotes(self): # Tests splitting a NoteSequence at regular hop size, skipping splits that # would have occurred inside a note. sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( sequence, 0, [(12, 100, 0.01, 3.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence( sequence, [('C', 0.0), ('G7', 3.0), ('F', 4.5)]) expected_subsequence_1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( expected_subsequence_1, 0, [(12, 100, 0.01, 3.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50)]) testing_lib.add_chords_to_sequence( expected_subsequence_1, [('C', 0.0), ('G7', 3.0)]) expected_subsequence_1.total_time = 3.50 expected_subsequence_1.subsequence_info.end_time_offset = 1.5 expected_subsequence_2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( expected_subsequence_2, 0, [(55, 120, 0.0, 0.01), (52, 99, 0.75, 1.0)]) testing_lib.add_chords_to_sequence( expected_subsequence_2, [('G7', 0.0), ('F', 0.5)]) expected_subsequence_2.total_time = 1.0 expected_subsequence_2.subsequence_info.start_time_offset = 4.0 subsequences = sequences_lib.split_note_sequence( sequence, hop_size_seconds=2.0, skip_splits_inside_notes=True) self.assertEquals(2, len(subsequences)) self.assertProtoEquals(expected_subsequence_1, subsequences[0]) self.assertProtoEquals(expected_subsequence_2, subsequences[1])
def testSplitNoteSequenceDuplicateTimeChanges(self): # Tests splitting a NoteSequence on time changes for a NoteSequence that has # duplicate time changes. sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} time_signatures: { time: 2.0 numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence( sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)]) expected_subsequence = music_pb2.NoteSequence() expected_subsequence.CopyFrom(sequence) expected_subsequence.subsequence_info.start_time_offset = 0.0 expected_subsequence.subsequence_info.end_time_offset = 0.0 subsequences = sequences_lib.split_note_sequence_on_time_changes(sequence) self.assertEquals(1, len(subsequences)) self.assertProtoEquals(expected_subsequence, subsequences[0])
def testMelodyExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7)]) testing_lib.add_track_to_sequence(note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_events = [[ NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11 ], [ NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT ]] expected_melodies = [] for events_list in expected_events: melody = melodies_lib.Melody(events_list, steps_per_quarter=1, steps_per_bar=4) expected_melodies.append(melody) unit = melody_pipelines.MelodyExtractor(min_bars=1, min_unique_pitches=1, gap_bars=1) self._unit_transform_test(unit, quantized_sequence, expected_melodies)
def testTranspositionPipeline(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") tp = note_sequence_pipelines.TranspositionPipeline(range(0, 2)) testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 1.0, 4.0)]) testing_lib.add_track_to_sequence( note_sequence, 1, [(36, 100, 2.0, 2.01)], is_drum=True) transposed = tp.transform(note_sequence) self.assertEqual(2, len(transposed)) self.assertEqual(2, len(transposed[0].notes)) self.assertEqual(2, len(transposed[1].notes)) self.assertEqual(12, transposed[0].notes[0].pitch) self.assertEqual(13, transposed[1].notes[0].pitch) self.assertEqual(36, transposed[0].notes[1].pitch) self.assertEqual(36, transposed[1].notes[1].pitch)
def testTranspositionPipelineIgnoreOutOfRangeNotes(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") tp = note_sequence_pipelines.TranspositionPipeline( range(-1, 2), ignore_out_of_range_notes=True, min_pitch=0, max_pitch=12) testing_lib.add_track_to_sequence( note_sequence, 0, [(10, 100, 1.0, 2.0), (12, 100, 2.0, 4.0), (13, 100, 4.0, 5.0)]) transposed = tp.transform(note_sequence) self.assertEqual(3, len(transposed)) self.assertEqual(3, len(transposed[0].notes)) self.assertEqual(2, len(transposed[1].notes)) self.assertEqual(1, len(transposed[2].notes)) self.assertEqual(9, transposed[0].notes[0].pitch) self.assertEqual(10, transposed[1].notes[0].pitch) self.assertEqual(11, transposed[2].notes[0].pitch) self.assertEqual(11, transposed[0].notes[1].pitch) self.assertEqual(12, transposed[1].notes[1].pitch) self.assertEqual(12, transposed[0].notes[2].pitch)
def testQuantizer(self): steps_per_quarter = 4 note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(note_sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) expected_quantized_sequence = sequences_lib.QuantizedSequence() expected_quantized_sequence.qpm = 60.0 expected_quantized_sequence.steps_per_quarter = steps_per_quarter testing_lib.add_quantized_track_to_sequence( expected_quantized_sequence, 0, [(12, 100, 0, 40), (11, 55, 1, 2), (40, 45, 10, 14), (55, 120, 16, 17), (52, 99, 19, 20)]) unit = pipelines_common.Quantizer(steps_per_quarter) self._unit_transform_test(unit, note_sequence, [expected_quantized_sequence])
def testQuantizer(self): steps_per_quarter = 4 note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) expected_quantized_sequence = sequences_lib.QuantizedSequence() expected_quantized_sequence.qpm = 60.0 expected_quantized_sequence.steps_per_quarter = steps_per_quarter testing_lib.add_quantized_track_to_sequence( expected_quantized_sequence, 0, [(12, 100, 0, 40), (11, 55, 1, 2), (40, 45, 10, 14), (55, 120, 16, 17), (52, 99, 19, 20)]) unit = pipelines_common.Quantizer(steps_per_quarter) self._unit_transform_test(unit, note_sequence, [expected_quantized_sequence])
def testSustainPipeline(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(note_sequence, 0, [(11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01)]) testing_lib.add_control_changes_to_sequence(note_sequence, 0, [(0.0, 64, 127), (0.75, 64, 0), (2.0, 64, 127), (3.0, 64, 0), (3.75, 64, 127), (4.5, 64, 127), (4.8, 64, 0), (4.9, 64, 127), (6.0, 64, 0)]) expected_sequence = sequences_lib.apply_sustain_control_changes( note_sequence) unit = note_sequence_pipelines.SustainPipeline() self._unit_transform_test(unit, note_sequence, [expected_sequence])
def testSplitNoteSequenceDuplicateTimeChanges(self): # Tests splitting a NoteSequence on time changes for a NoteSequence that has # duplicate time changes. sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} time_signatures: { time: 2.0 numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)]) expected_subsequence = music_pb2.NoteSequence() expected_subsequence.CopyFrom(sequence) expected_subsequence.subsequence_info.start_time_offset = 0.0 expected_subsequence.subsequence_info.end_time_offset = 0.0 subsequences = sequences_lib.split_note_sequence_on_time_changes( sequence) self.assertEquals(1, len(subsequences)) self.assertProtoEquals(expected_subsequence, subsequences[0])
def test_empty_doc(self): """Verify that an empty doc can be parsed.""" xml = r"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd"> <score-partwise version="3.0"> </score-partwise> """ with tempfile.NamedTemporaryFile() as temp_file: temp_file.write(xml) temp_file.flush() ns = musicxml_reader.musicxml_file_to_sequence_proto( temp_file.name) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } key_signatures { key: C time: 0 } tempos { qpm: 120.0 } total_time: 0.0 """) self.assertProtoEquals(expected_ns, ns)
def testDrumsExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7), (12, 1, 6, 8)], is_drum=True) testing_lib.add_track_to_sequence( note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_events = [ [NO_DRUMS, NO_DRUMS, DRUMS(12), NO_DRUMS, NO_DRUMS, NO_DRUMS, DRUMS(11, 12)]] expected_drum_tracks = [] for events_list in expected_events: drums = drums_lib.DrumTrack( events_list, steps_per_quarter=1, steps_per_bar=4) expected_drum_tracks.append(drums) unit = drum_pipelines.DrumsExtractor(min_bars=1, gap_bars=1) self._unit_transform_test(unit, quantized_sequence, expected_drum_tracks)
def testMelodyRNNPipeline(self): FLAGS.eval_ratio = 0.0 note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 120}""") testing_lib.add_track(note_sequence, 0, [(12, 100, 0.00, 2.0), (11, 55, 2.1, 5.0), (40, 45, 5.1, 8.0), (55, 120, 8.1, 11.0), (53, 99, 11.1, 14.1)]) quantizer = pipelines_common.Quantizer(steps_per_quarter=4) melody_extractor = pipelines_common.MonophonicMelodyExtractor( min_bars=7, min_unique_pitches=5, gap_bars=1.0, ignore_polyphonic_notes=False) one_hot_encoder = melodies_lib.OneHotEncoderDecoder(0, 127, 0) quantized = quantizer.transform(note_sequence)[0] print quantized.tracks melody = melody_extractor.transform(quantized)[0] one_hot = one_hot_encoder.squash_and_encode(melody) print one_hot expected_result = {'training_melodies': [one_hot], 'eval_melodies': []} pipeline_inst = melody_rnn_create_dataset.get_pipeline(one_hot_encoder) result = pipeline_inst.transform(note_sequence) self.assertEqual(expected_result, result)
def testDrumsExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7), (12, 1, 6, 8)], is_drum=True) testing_lib.add_track_to_sequence(note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_events = [[ NO_DRUMS, NO_DRUMS, DRUMS(12), NO_DRUMS, NO_DRUMS, NO_DRUMS, DRUMS(11, 12) ]] expected_drum_tracks = [] for events_list in expected_events: drums = drums_lib.DrumTrack(events_list, steps_per_quarter=1, steps_per_bar=4) expected_drum_tracks.append(drums) unit = drum_pipelines.DrumsExtractor(min_bars=1, gap_bars=1) self._unit_transform_test(unit, quantized_sequence, expected_drum_tracks)
def testMelodyExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7)]) testing_lib.add_track_to_sequence( note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_events = [ [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT]] expected_melodies = [] for events_list in expected_events: melody = melodies_lib.Melody( events_list, steps_per_quarter=1, steps_per_bar=4) expected_melodies.append(melody) unit = melody_pipelines.MelodyExtractor( min_bars=1, min_unique_pitches=1, gap_bars=1) self._unit_transform_test(unit, quantized_sequence, expected_melodies)
def testSlashDuration(self): tunes, exceptions = abc_parser.parse_abc_tunebook("""X:1 Q:1/4=120 L:1/4 T:Test CC/C//C///C//// """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 60 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 60 velocity: 90 start_time: 0.5 end_time: 0.75 } notes { pitch: 60 velocity: 90 start_time: 0.75 end_time: 0.875 } notes { pitch: 60 velocity: 90 start_time: 0.875 end_time: 0.9375 } notes { pitch: 60 velocity: 90 start_time: 0.9375 end_time: 0.96875 } total_time: 0.96875 """) self.assertProtoEquals(expected_ns1, tunes[1])
def testSlashDuration(self): tunes, exceptions = abc_parser.parse_tunebook("""X:1 Q:1/4=120 L:1/4 T:Test CC/C//C///C//// """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 60 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 60 velocity: 90 start_time: 0.5 end_time: 0.75 } notes { pitch: 60 velocity: 90 start_time: 0.75 end_time: 0.875 } notes { pitch: 60 velocity: 90 start_time: 0.875 end_time: 0.9375 } notes { pitch: 60 velocity: 90 start_time: 0.9375 end_time: 0.96875 } total_time: 0.96875 """) self.assertProtoEquals(expected_ns1, tunes[1])
def checkFMajorScale(self, filename, part_name): """Verify MusicXML scale file. Verify that it contains the correct pitches (sounding pitch) and durations. Args: filename: file to test. part_name: name of the part the sequence is expected to contain. """ expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } key_signatures { key: F time: 0 } time_signatures { numerator: 4 denominator: 4 } tempos { qpm: 120.0 } total_time: 4.0 """) part_info = expected_ns.part_infos.add() part_info.name = part_name expected_pitches = [65, 67, 69, 70, 72, 74, 76, 77] time = 0 for pitch in expected_pitches: note = expected_ns.notes.add() note.part = 0 note.voice = 1 note.pitch = pitch note.start_time = time time += .5 note.end_time = time note.velocity = 64 note.numerator = 1 note.denominator = 4 # Convert MusicXML to NoteSequence source_musicxml = musicxml_parser.MusicXMLDocument(filename) sequence_proto = musicxml_reader.musicxml_to_sequence_proto(source_musicxml) # Check equality self.assertProtoEquals(expected_ns, sequence_proto)
def setUp(self): self.maxDiff = None # pylint:disable=invalid-name self.note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ tempos: { qpm: 60 } ticks_per_quarter: 220 """)
def setUp(self): self.maxDiff = None self.steps_per_quarter = 4 self.note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""")
def testParseOctaves(self): tunes, exceptions = abc_parser.parse_tunebook("""X:1 T:Test CC,',C,C'c """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } notes { pitch: 60 velocity: 90 end_time: 0.25 } notes { pitch: 48 velocity: 90 start_time: 0.25 end_time: 0.5 } notes { pitch: 48 velocity: 90 start_time: 0.5 end_time: 0.75 } notes { pitch: 72 velocity: 90 start_time: 0.75 end_time: 1.0 } notes { pitch: 72 velocity: 90 start_time: 1.0 end_time: 1.25 } total_time: 1.25 """) self.assertProtoEquals(expected_ns1, tunes[1])
def setUp(self): self.steps_per_quarter = 4 self.note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") self.expected_quantized_sequence = sequences_lib.QuantizedSequence() self.expected_quantized_sequence.qpm = 60.0 self.expected_quantized_sequence.steps_per_quarter = self.steps_per_quarter
def testParseOctaves(self): tunes, exceptions = abc_parser.parse_abc_tunebook("""X:1 T:Test CC,',C,C'c """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } notes { pitch: 60 velocity: 90 end_time: 0.25 } notes { pitch: 48 velocity: 90 start_time: 0.25 end_time: 0.5 } notes { pitch: 48 velocity: 90 start_time: 0.5 end_time: 0.75 } notes { pitch: 72 velocity: 90 start_time: 0.75 end_time: 1.0 } notes { pitch: 72 velocity: 90 start_time: 1.0 end_time: 1.25 } total_time: 1.25 """) self.assertProtoEquals(expected_ns1, tunes[1])
def testChordAnnotations(self): tunes, exceptions = abc_parser.parse_abc_tunebook(""" X:1 Q:1/4=120 L:1/4 T:Test "G"G % verify that an empty annotation doesn't cause problems. ""D """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 67 velocity: 90 end_time: 0.5 } notes { pitch: 62 velocity: 90 start_time: 0.5 end_time: 1.0 } text_annotations { text: "G" annotation_type: CHORD_SYMBOL } text_annotations { time: 0.5 } total_time: 1.0 """) self.assertProtoEquals(expected_ns1, tunes[1])
def testChordAnnotations(self): tunes, exceptions = abc_parser.parse_tunebook(""" X:1 Q:1/4=120 L:1/4 T:Test "G"G % verify that an empty annotation doesn't cause problems. ""D """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 67 velocity: 90 end_time: 0.5 } notes { pitch: 62 velocity: 90 start_time: 0.5 end_time: 1.0 } text_annotations { text: "G" annotation_type: CHORD_SYMBOL } text_annotations { time: 0.5 } total_time: 1.0 """) self.assertProtoEquals(expected_ns1, tunes[1])
def test_atonal_transposition(self): """Test that transposition works when changing instrument transposition. This can occur within a single part in a score where the score has no key signature / is atonal. Examples include changing from a non-transposing instrument to a transposing one (ex. Flute to Bb Clarinet) or vice versa, or changing among transposing instruments (ex. Bb Clarinet to Eb Alto Saxophone). """ ns = musicxml_reader.musicxml_file_to_sequence_proto( self.atonal_transposition_filename) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures: { numerator: 4 denominator: 4 } tempos: { qpm: 120 } key_signatures: { } part_infos { part: 0 name: "Flute" } source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } total_time: 4.0 """) expected_pitches = [72, 74, 76, 77, 79, 77, 76, 74] time = 0 for pitch in expected_pitches: note = expected_ns.notes.add() note.pitch = pitch note.start_time = time time += .5 note.end_time = time note.velocity = 64 note.numerator = 1 note.denominator = 4 note.voice = 1 self.maxDiff = None self.assertProtoEquals(expected_ns, ns)
def testSplitter(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) expected_sequences = sequences_lib.split_note_sequence(note_sequence, 1.0) unit = note_sequence_pipelines.Splitter(1.0) self._unit_transform_test(unit, note_sequence, expected_sequences)
def testLeadSheetExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") music_testing_lib.add_track_to_sequence(note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7)]) music_testing_lib.add_track_to_sequence(note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) music_testing_lib.add_chords_to_sequence(note_sequence, [('Cm7', 2), ('F9', 4), ('G7b9', 6)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_melody_events = [[ NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11 ], [ NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT ]] expected_chord_events = [[ NO_CHORD, NO_CHORD, 'Cm7', 'Cm7', 'F9', 'F9', 'G7b9' ], [NO_CHORD, NO_CHORD, 'Cm7', 'Cm7', 'F9', 'F9', 'G7b9', 'G7b9']] expected_lead_sheets = [] for melody_events, chord_events in zip(expected_melody_events, expected_chord_events): melody = melodies_lib.Melody(melody_events, steps_per_quarter=1, steps_per_bar=4) chords = chords_lib.ChordProgression(chord_events, steps_per_quarter=1, steps_per_bar=4) lead_sheet = lead_sheets_lib.LeadSheet(melody, chords) expected_lead_sheets.append(lead_sheet) unit = lead_sheet_pipelines.LeadSheetExtractor( min_bars=1, min_unique_pitches=1, gap_bars=1, all_transpositions=False) self._unit_transform_test(unit, quantized_sequence, expected_lead_sheets)
def testFluteScale(self): """Verify properties of the flute scale.""" ns = musicxml_reader.musicxml_file_to_sequence_proto( self.flute_scale_filename) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures: { numerator: 4 denominator: 4 } tempos: { qpm: 120 } key_signatures: { key: F } source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } part_infos { part: 0 name: "Flute" } total_time: 4.0 """) expected_pitches = [65, 67, 69, 70, 72, 74, 76, 77] time = 0 for pitch in expected_pitches: note = expected_ns.notes.add() note.part = 0 note.voice = 1 note.pitch = pitch note.start_time = time time += .5 note.end_time = time note.velocity = 64 note.numerator = 1 note.denominator = 4 self.assertProtoEquals(expected_ns, ns)
def testParseOctaves(self): tunes = abc_parser.parse_tunebook("""X:1 T:Test CC,',C,C'c """) self.assertEqual(1, len(tunes)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } notes { pitch: 60 velocity: 90 } notes { pitch: 48 velocity: 90 } notes { pitch: 48 velocity: 90 } notes { pitch: 72 velocity: 90 } notes { pitch: 72 velocity: 90 } """) # TODO(fjord): add timing self.assertProtoEquals(expected_ns1, tunes[0])
def testTranspositionPipelineOutOfRangeNotes(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") tp = note_sequence_pipelines.TranspositionPipeline( range(-1, 2), min_pitch=0, max_pitch=12) testing_lib.add_track_to_sequence( note_sequence, 0, [(10, 100, 1.0, 2.0), (12, 100, 2.0, 4.0), (13, 100, 4.0, 5.0)]) transposed = tp.transform(note_sequence) self.assertEqual(1, len(transposed)) self.assertEqual(3, len(transposed[0].notes)) self.assertEqual(9, transposed[0].notes[0].pitch) self.assertEqual(11, transposed[0].notes[1].pitch) self.assertEqual(12, transposed[0].notes[2].pitch)
def testSustainPipeline(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01)]) testing_lib.add_control_changes_to_sequence( note_sequence, 0, [(0.0, 64, 127), (0.75, 64, 0), (2.0, 64, 127), (3.0, 64, 0), (3.75, 64, 127), (4.5, 64, 127), (4.8, 64, 0), (4.9, 64, 127), (6.0, 64, 0)]) expected_sequence = sequences_lib.apply_sustain_control_changes( note_sequence) unit = note_sequence_pipelines.SustainPipeline() self._unit_transform_test(unit, note_sequence, [expected_sequence])
def testStretchPipeline(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { time: 1.0 numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01)]) expected_sequences = [ sequences_lib.stretch_note_sequence(note_sequence, 0.5), sequences_lib.stretch_note_sequence(note_sequence, 1.0), sequences_lib.stretch_note_sequence(note_sequence, 1.5)] unit = note_sequence_pipelines.StretchPipeline( stretch_factors=[0.5, 1.0, 1.5]) self._unit_transform_test(unit, note_sequence, expected_sequences)
def testLeadSheetExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence( note_sequence, 0, [(12, 100, 2, 4), (11, 1, 6, 7)]) testing_lib.add_track_to_sequence( note_sequence, 1, [(12, 127, 2, 4), (14, 50, 6, 8)]) testing_lib.add_chords_to_sequence( note_sequence, [('Cm7', 2), ('F9', 4), ('G7b9', 6)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) expected_melody_events = [ [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 11], [NO_EVENT, NO_EVENT, 12, NO_EVENT, NOTE_OFF, NO_EVENT, 14, NO_EVENT]] expected_chord_events = [ [NO_CHORD, NO_CHORD, 'Cm7', 'Cm7', 'F9', 'F9', 'G7b9'], [NO_CHORD, NO_CHORD, 'Cm7', 'Cm7', 'F9', 'F9', 'G7b9', 'G7b9']] expected_lead_sheets = [] for melody_events, chord_events in zip(expected_melody_events, expected_chord_events): melody = melodies_lib.Melody( melody_events, steps_per_quarter=1, steps_per_bar=4) chords = chords_lib.ChordProgression( chord_events, steps_per_quarter=1, steps_per_bar=4) lead_sheet = lead_sheets_lib.LeadSheet(melody, chords) expected_lead_sheets.append(lead_sheet) unit = lead_sheet_pipelines.LeadSheetExtractor( min_bars=1, min_unique_pitches=1, gap_bars=1, all_transpositions=False) self._unit_transform_test(unit, quantized_sequence, expected_lead_sheets)
def testChordsExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_chords_to_sequence( note_sequence, [('C', 2), ('Am', 4), ('F', 5)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) quantized_sequence.total_quantized_steps = 8 expected_events = [[NO_CHORD, NO_CHORD, 'C', 'C', 'Am', 'F', 'F', 'F']] expected_chord_progressions = [] for events_list in expected_events: chords = chords_lib.ChordProgression( events_list, steps_per_quarter=1, steps_per_bar=4) expected_chord_progressions.append(chords) unit = chord_pipelines.ChordsExtractor(all_transpositions=False) self._unit_transform_test(unit, quantized_sequence, expected_chord_progressions)
def testChordsExtractor(self): note_sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_chords_to_sequence(note_sequence, [('C', 2), ('Am', 4), ('F', 5)]) quantized_sequence = sequences_lib.quantize_note_sequence( note_sequence, steps_per_quarter=1) quantized_sequence.total_quantized_steps = 8 expected_events = [[NO_CHORD, NO_CHORD, 'C', 'C', 'Am', 'F', 'F', 'F']] expected_chord_progressions = [] for events_list in expected_events: chords = chords_lib.ChordProgression(events_list, steps_per_quarter=1, steps_per_bar=4) expected_chord_progressions.append(chords) unit = chord_pipelines.ChordsExtractor(all_transpositions=False) self._unit_transform_test(unit, quantized_sequence, expected_chord_progressions)
def testNoteAccidentalsPerBar(self): tunes, exceptions = abc_parser.parse_abc_tunebook(""" X:1 Q:1/4=120 L:1/4 T:Test GF^GGg|Gg """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 67 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 65 velocity: 90 start_time: 0.5 end_time: 1.0 } notes { pitch: 68 velocity: 90 start_time: 1.0 end_time: 1.5 } notes { pitch: 68 velocity: 90 start_time: 1.5 end_time: 2.0 } notes { pitch: 80 velocity: 90 start_time: 2.0 end_time: 2.5 } notes { pitch: 67 velocity: 90 start_time: 2.5 end_time: 3.0 } notes { pitch: 79 velocity: 90 start_time: 3.0 end_time: 3.5 } total_time: 3.5 """) self.assertProtoEquals(expected_ns1, tunes[1])
def testParseEnglishAbc(self): tunes = abc_parser.parse_tunebook(ENGLISH_ABC) self.assertEqual(3, len(tunes)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Dusty Miller, The; Binny's Jig" artist: "Trad." composers: "Trad." } time_signatures { numerator: 3 denominator: 4 } key_signatures { key: G } """) # TODO(fjord): add notes del tunes[0].notes[:] self.assertProtoEquals(expected_ns1, tunes[0]) expected_ns2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 2 sequence_metadata { title: "Old Sir Simon the King" artist: "Trad." composers: "Trad." } time_signatures { numerator: 9 denominator: 8 } time_signatures { numerator: 12 denominator: 8 } time_signatures { numerator: 9 denominator: 8 } key_signatures { key: G } """) # TODO(fjord): add notes and times. del tunes[1].notes[:] self.assertProtoEquals(expected_ns2, tunes[1]) expected_ns3 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 3 sequence_metadata { title: "William and Nancy; New Mown Hay; Legacy, The" artist: "Trad." composers: "Trad." } time_signatures { numerator: 6 denominator: 8 } key_signatures { key: G } """) # TODO(fjord): add notes and times. del tunes[2].notes[:] del tunes[2].text_annotations[:] self.assertProtoEquals(expected_ns3, tunes[2])
def testOneSidedRepeat(self): tunes, exceptions = abc_parser.parse_abc_tunebook(""" X:1 Q:1/4=120 L:1/4 T:Test Bcd :| Bcd """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 71 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 72 velocity: 90 start_time: 0.5 end_time: 1.0 } notes { pitch: 74 velocity: 90 start_time: 1.0 end_time: 1.5 } notes { pitch: 71 velocity: 90 start_time: 1.5 end_time: 2.0 } notes { pitch: 72 velocity: 90 start_time: 2.0 end_time: 2.5 } notes { pitch: 74 velocity: 90 start_time: 2.5 end_time: 3.0 } section_annotations { time: 0 section_id: 0 } section_annotations { time: 1.5 section_id: 1 } section_groups { sections { section_id: 0 } num_times: 2 } section_groups { sections { section_id: 1 } num_times: 1 } total_time: 3.0 """) self.assertProtoEquals(expected_ns1, tunes[1])
def testRepeats(self): # Several equivalent versions of the same tune. tunes, exceptions = abc_parser.parse_abc_tunebook(""" X:1 Q:1/4=120 L:1/4 T:Test Bcd ::[]|[]:: Bcd ::| X:2 Q:1/4=120 L:1/4 T:Test Bcd :::: Bcd ::| X:3 Q:1/4=120 L:1/4 T:Test |::Bcd ::|:: Bcd ::| % This version contains mismatched repeat symbols. X:4 Q:1/4=120 L:1/4 T:Test |::Bcd ::|: Bcd ::| % This version is missing a repeat symbol at the end. X:5 Q:1/4=120 L:1/4 T:Test |:: Bcd ::|: Bcd | % Ambiguous repeat that should go to the last repeat symbol. X:6 Q:1/4=120 L:1/4 T:Test |:: Bcd ::| Bcd :| % Ambiguous repeat that should go to the last double bar. X:7 Q:1/4=120 L:1/4 T:Test |:: Bcd ::| Bcd || Bcd :| % Ambiguous repeat that should go to the last double bar. X:8 Q:1/4=120 L:1/4 T:Test || Bcd ::| Bcd || Bcd :| % Ensure double bar doesn't confuse declared repeat. X:9 Q:1/4=120 L:1/4 T:Test |:: B || cd ::| Bcd || |: Bcd :| % Mismatched repeat at the very beginning. X:10 Q:1/4=120 L:1/4 T:Test :| Bcd |:: Bcd ::| """) self.assertEqual(7, len(tunes)) self.assertEqual(3, len(exceptions)) self.assertTrue(isinstance(exceptions[0], abc_parser.RepeatParseException)) self.assertTrue(isinstance(exceptions[1], abc_parser.RepeatParseException)) self.assertTrue(isinstance(exceptions[2], abc_parser.RepeatParseException)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 71 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 72 velocity: 90 start_time: 0.5 end_time: 1.0 } notes { pitch: 74 velocity: 90 start_time: 1.0 end_time: 1.5 } notes { pitch: 71 velocity: 90 start_time: 1.5 end_time: 2.0 } notes { pitch: 72 velocity: 90 start_time: 2.0 end_time: 2.5 } notes { pitch: 74 velocity: 90 start_time: 2.5 end_time: 3.0 } section_annotations { time: 0 section_id: 0 } section_annotations { time: 1.5 section_id: 1 } section_groups { sections { section_id: 0 } num_times: 3 } section_groups { sections { section_id: 1 } num_times: 3 } total_time: 3.0 """) self.assertProtoEquals(expected_ns1, tunes[1]) # Other versions are identical except for the reference number. expected_ns2 = copy.deepcopy(expected_ns1) expected_ns2.reference_number = 2 self.assertProtoEquals(expected_ns2, tunes[2]) expected_ns3 = copy.deepcopy(expected_ns1) expected_ns3.reference_number = 3 self.assertProtoEquals(expected_ns3, tunes[3]) # Also identical, except the last section is played only twice. expected_ns6 = copy.deepcopy(expected_ns1) expected_ns6.reference_number = 6 expected_ns6.section_groups[-1].num_times = 2 self.assertProtoEquals(expected_ns6, tunes[6]) expected_ns7 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 7 sequence_metadata { title: "Test" } tempos { qpm: 120 } notes { pitch: 71 velocity: 90 start_time: 0.0 end_time: 0.5 } notes { pitch: 72 velocity: 90 start_time: 0.5 end_time: 1.0 } notes { pitch: 74 velocity: 90 start_time: 1.0 end_time: 1.5 } notes { pitch: 71 velocity: 90 start_time: 1.5 end_time: 2.0 } notes { pitch: 72 velocity: 90 start_time: 2.0 end_time: 2.5 } notes { pitch: 74 velocity: 90 start_time: 2.5 end_time: 3.0 } notes { pitch: 71 velocity: 90 start_time: 3.0 end_time: 3.5 } notes { pitch: 72 velocity: 90 start_time: 3.5 end_time: 4.0 } notes { pitch: 74 velocity: 90 start_time: 4.0 end_time: 4.5 } section_annotations { time: 0 section_id: 0 } section_annotations { time: 1.5 section_id: 1 } section_annotations { time: 3.0 section_id: 2 } section_groups { sections { section_id: 0 } num_times: 3 } section_groups { sections { section_id: 1 } num_times: 1 } section_groups { sections { section_id: 2 } num_times: 2 } total_time: 4.5 """) self.assertProtoEquals(expected_ns7, tunes[7]) expected_ns8 = copy.deepcopy(expected_ns7) expected_ns8.reference_number = 8 self.assertProtoEquals(expected_ns8, tunes[8]) expected_ns9 = copy.deepcopy(expected_ns7) expected_ns9.reference_number = 9 self.assertProtoEquals(expected_ns9, tunes[9])
def testParseBrokenRhythm(self): # These tunes should be equivalent. tunes, exceptions = abc_parser.parse_abc_tunebook(""" X:1 Q:1/4=120 L:1/4 M:3/4 T:Test B>cd B<cd X:2 Q:1/4=120 L:1/4 M:3/4 T:Test B3/2c/2d B/2c3/2d X:3 Q:1/4=120 L:1/4 M:3/4 T:Test B3/c/d B/c3/d """) self.assertEqual(3, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Test" } time_signatures { numerator: 3 denominator: 4 } tempos { qpm: 120 } notes { pitch: 71 velocity: 90 start_time: 0.0 end_time: 0.75 } notes { pitch: 72 velocity: 90 start_time: 0.75 end_time: 1.0 } notes { pitch: 74 velocity: 90 start_time: 1.0 end_time: 1.5 } notes { pitch: 71 velocity: 90 start_time: 1.5 end_time: 1.75 } notes { pitch: 72 velocity: 90 start_time: 1.75 end_time: 2.5 } notes { pitch: 74 velocity: 90 start_time: 2.5 end_time: 3.0 } total_time: 3.0 """) self.assertProtoEquals(expected_ns1, tunes[1]) expected_ns2 = copy.deepcopy(expected_ns1) expected_ns2.reference_number = 2 self.assertProtoEquals(expected_ns2, tunes[2]) expected_ns2.reference_number = 3 self.assertProtoEquals(expected_ns2, tunes[3])
def test_unmetered_music(self): """Test that time signatures are inserted for music without time signatures. MusicXML does not require the use of time signatures. Music without time signatures occur in medieval chant, cadenzas, and contemporary music. """ ns = musicxml_reader.musicxml_file_to_sequence_proto( self.unmetered_filename) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures: { numerator: 11 denominator: 8 } tempos: { qpm: 120 } key_signatures: { } notes { pitch: 72 velocity: 64 end_time: 0.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 74 velocity: 64 start_time: 0.5 end_time: 0.75 numerator: 1 denominator: 8 voice: 1 } notes { pitch: 76 velocity: 64 start_time: 0.75 end_time: 1.25 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 77 velocity: 64 start_time: 1.25 end_time: 1.75 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 79 velocity: 64 start_time: 1.75 end_time: 2.75 numerator: 1 denominator: 2 voice: 1 } part_infos { name: "Flute" } source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } total_time: 2.75 """) self.maxDiff = None self.assertProtoEquals(expected_ns, ns)
def test_st_anne(self): """Verify properties of the St. Anne file. The file contains 2 parts and 4 voices. """ ns = musicxml_reader.musicxml_file_to_sequence_proto( self.st_anne_filename) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures { numerator: 1 denominator: 4 } time_signatures { time: 0.5 numerator: 4 denominator: 4 } time_signatures { time: 2.5 numerator: 4 denominator: 4 } time_signatures { time: 4.5 numerator: 4 denominator: 4 } time_signatures { time: 6.5 numerator: 3 denominator: 4 } time_signatures { time: 8.0 numerator: 1 denominator: 4 } time_signatures { time: 8.5 numerator: 4 denominator: 4 } time_signatures { time: 10.5 numerator: 4 denominator: 4 } time_signatures { time: 12.5 numerator: 4 denominator: 4 } time_signatures { time: 14.5 numerator: 3 denominator: 4 } tempos: { qpm: 120 } key_signatures: { key: C } source_info: { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } part_infos { part: 0 name: "Harpsichord" } part_infos { part: 1 name: "Piano" } total_time: 16.0 """) pitches_0_1 = [ (67, .5), (64, .5), (69, .5), (67, .5), (72, .5), (72, .5), (71, .5), (72, .5), (67, .5), (72, .5), (67, .5), (69, .5), (66, .5), (67, 1.5), (71, .5), (72, .5), (69, .5), (74, .5), (71, .5), (72, .5), (69, .5), (71, .5), (67, .5), (69, .5), (72, .5), (74, .5), (71, .5), (72, 1.5), ] pitches_0_2 = [ (60, .5), (60, .5), (60, .5), (60, .5), (64, .5), (62, .5), (62, .5), (64, .5), (64, .5), (64, .5), (64, .5), (64, .5), (62, .5), (62, 1.5), (62, .5), (64, .5), (60, .5), (65, .5), (62, .5), (64, .75), (62, .25), (59, .5), (60, .5), (65, .5), (64, .5), (62, .5), (62, .5), (64, 1.5), ] pitches_1_1 = [ (52, .5), (55, .5), (57, .5), (60, .5), (60, .5), (57, .5), (55, .5), (55, .5), (60, .5), (60, .5), (59, .5), (57, .5), (57, .5), (59, 1.5), (55, .5), (55, .5), (57, .5), (57, .5), (55, .5), (55, .5), (57, .5), (56, .5), (55, .5), (53, .5), (55, .5), (57, .5), (55, .5), (55, 1.5), ] pitches_1_2 = [ (48, .5), (48, .5), (53, .5), (52, .5), (57, .5), (53, .5), (55, .5), (48, .5), (48, .5), (45, .5), (52, .5), (48, .5), (50, .5), (43, 1.5), (55, .5), (48, .5), (53, .5), (50, .5), (55, .5), (48, .5), (53, .5), (52, .5), (52, .5), (50, .5), (48, .5), (53, .5), (55, .5), (48, 1.5), ] part_voice_instrument_program_pitches = [ (0, 1, 1, 7, pitches_0_1), (0, 2, 1, 7, pitches_0_2), (1, 1, 2, 1, pitches_1_1), (1, 2, 2, 1, pitches_1_2), ] for part, voice, instrument, program, pitches in ( part_voice_instrument_program_pitches): time = 0 for pitch, duration in pitches: note = expected_ns.notes.add() note.part = part note.voice = voice note.pitch = pitch note.start_time = time time += duration note.end_time = time note.velocity = 64 note.instrument = instrument note.program = program if duration == .5: note.numerator = 1 note.denominator = 4 if duration == .25: note.numerator = 1 note.denominator = 8 if duration == .75: note.numerator = 3 note.denominator = 8 if duration == 1.5: note.numerator = 3 note.denominator = 4 expected_ns.notes.sort( key=lambda note: (note.part, note.voice, note.start_time)) ns.notes.sort( key=lambda note: (note.part, note.voice, note.start_time)) self.assertProtoEquals(expected_ns, ns)
def testSplitNoteSequence(self): # Tests splitting a NoteSequence at regular hop size, truncating notes. sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 8.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence(sequence, [('C', 1.0), ('G7', 2.0), ('F', 4.0)]) expected_subsequence_1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(expected_subsequence_1, 0, [(12, 100, 0.01, 3.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.0)]) testing_lib.add_chords_to_sequence(expected_subsequence_1, [('C', 1.0), ('G7', 2.0)]) expected_subsequence_1.total_time = 3.0 expected_subsequence_1.subsequence_info.end_time_offset = 5.0 expected_subsequence_2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(expected_subsequence_2, 0, [(55, 120, 1.0, 1.01), (52, 99, 1.75, 2.0)]) testing_lib.add_chords_to_sequence(expected_subsequence_2, [('G7', 0.0), ('F', 1.0)]) expected_subsequence_2.total_time = 2.0 expected_subsequence_2.subsequence_info.start_time_offset = 3.0 expected_subsequence_2.subsequence_info.end_time_offset = 3.0 expected_subsequence_3 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_chords_to_sequence(expected_subsequence_3, [('F', 0.0)]) expected_subsequence_3.total_time = 0.0 expected_subsequence_3.subsequence_info.start_time_offset = 6.0 expected_subsequence_3.subsequence_info.end_time_offset = 2.0 subsequences = sequences_lib.split_note_sequence(sequence, hop_size_seconds=3.0) self.assertEquals(3, len(subsequences)) self.assertProtoEquals(expected_subsequence_1, subsequences[0]) self.assertProtoEquals(expected_subsequence_2, subsequences[1]) self.assertProtoEquals(expected_subsequence_3, subsequences[2])
def testSplitNoteSequenceMultipleTimeChanges(self): # Tests splitting a NoteSequence on time changes, truncating notes on splits # that occur inside notes. sequence = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} time_signatures: { time: 2.0 numerator: 3 denominator: 4} tempos: { qpm: 60} tempos: { time: 4.25 qpm: 80}""") testing_lib.add_track_to_sequence(sequence, 0, [(12, 100, 0.01, 10.0), (11, 55, 0.22, 0.50), (40, 45, 2.50, 3.50), (55, 120, 4.0, 4.01), (52, 99, 4.75, 5.0)]) testing_lib.add_chords_to_sequence(sequence, [('C', 1.5), ('G7', 3.0), ('F', 4.8)]) expected_subsequence_1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 4 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(expected_subsequence_1, 0, [(12, 100, 0.01, 2.0), (11, 55, 0.22, 0.50)]) testing_lib.add_chords_to_sequence(expected_subsequence_1, [('C', 1.5)]) expected_subsequence_1.total_time = 2.0 expected_subsequence_1.subsequence_info.end_time_offset = 8.0 expected_subsequence_2 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 3 denominator: 4} tempos: { qpm: 60}""") testing_lib.add_track_to_sequence(expected_subsequence_2, 0, [(40, 45, 0.50, 1.50), (55, 120, 2.0, 2.01)]) testing_lib.add_chords_to_sequence(expected_subsequence_2, [('C', 0.0), ('G7', 1.0)]) expected_subsequence_2.total_time = 2.01 expected_subsequence_2.subsequence_info.start_time_offset = 2.0 expected_subsequence_2.subsequence_info.end_time_offset = 5.99 expected_subsequence_3 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ time_signatures: { numerator: 3 denominator: 4} tempos: { qpm: 80}""") testing_lib.add_track_to_sequence(expected_subsequence_3, 0, [(52, 99, 0.5, 0.75)]) testing_lib.add_chords_to_sequence(expected_subsequence_3, [('G7', 0.0), ('F', 0.55)]) expected_subsequence_3.total_time = 0.75 expected_subsequence_3.subsequence_info.start_time_offset = 4.25 expected_subsequence_3.subsequence_info.end_time_offset = 5.0 subsequences = sequences_lib.split_note_sequence_on_time_changes( sequence) self.assertEquals(3, len(subsequences)) self.assertProtoEquals(expected_subsequence_1, subsequences[0]) self.assertProtoEquals(expected_subsequence_2, subsequences[1]) self.assertProtoEquals(expected_subsequence_3, subsequences[2])
def testParseEnglishAbc(self): tunes, exceptions = abc_parser.parse_abc_tunebook_file( os.path.join(tf.resource_loader.get_data_files_path(), 'testdata/english.abc')) self.assertEqual(1, len(tunes)) self.assertEqual(2, len(exceptions)) self.assertTrue(isinstance(exceptions[0], abc_parser.VariantEndingException)) self.assertTrue(isinstance(exceptions[1], abc_parser.PartException)) expected_metadata1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Dusty Miller, The; Binny's Jig" artist: "Trad." composers: "Trad." } key_signatures { key: G } section_annotations { time: 0.0 section_id: 0 } section_annotations { time: 6.0 section_id: 1 } section_annotations { time: 12.0 section_id: 2 } section_groups { sections { section_id: 0 } num_times: 2 } section_groups { sections { section_id: 1 } num_times: 2 } section_groups { sections { section_id: 2 } num_times: 2 } """) expected_expanded_metadata1 = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 source_info: { source_type: SCORE_BASED encoding_type: ABC parser: MAGENTA_ABC } reference_number: 1 sequence_metadata { title: "Dusty Miller, The; Binny's Jig" artist: "Trad." composers: "Trad." } key_signatures { key: G } section_annotations { time: 0.0 section_id: 0 } section_annotations { time: 6.0 section_id: 0 } section_annotations { time: 12.0 section_id: 1 } section_annotations { time: 18.0 section_id: 1 } section_annotations { time: 24.0 section_id: 2 } section_annotations { time: 30.0 section_id: 2 } """) self.compareToAbc2midiAndMetadata( 'testdata/english1.mid', expected_metadata1, expected_expanded_metadata1, tunes[1])
def test_whole_measure_rest_forward(self): """Test that a whole measure rest can be encoded using <forward>. A whole measure rest is usually encoded as a <note> with a duration equal to that of a whole measure. An alternative encoding is to use the <forward> element to advance the time cursor to a duration equal to that of a whole measure. This implies a whole measure rest when there are no <note> elements in this measure. """ ns = musicxml_reader.musicxml_file_to_sequence_proto( self.whole_measure_rest_forward_filename) expected_ns = common_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures { numerator: 4 denominator: 4 } time_signatures { time: 6.0 numerator: 2 denominator: 4 } key_signatures { } tempos { qpm: 120 } notes { pitch: 72 velocity: 64 end_time: 2.0 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 4.0 end_time: 6.0 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 60 velocity: 64 start_time: 6.0 end_time: 7.0 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 60 velocity: 64 start_time: 8.0 end_time: 9.0 numerator: 1 denominator: 2 voice: 1 } total_time: 9.0 part_infos { name: "Flute" } source_info { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } """) self.assertProtoEquals(expected_ns, ns)