def test_empty_doc(self): """Verify that an empty doc can be parsed.""" xml = br"""<?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 = 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 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 = 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 setUp(self): self.note_sequence = music_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ tempos: { qpm: 60 } ticks_per_quarter: 220 """)
def setUp(self): super(PianorollPipelineTest, self).setUp() self.note_sequence = music_testing_lib.parse_test_proto( music_pb2.NoteSequence, """ tempos: { qpm: 60 } ticks_per_quarter: 220 """)
def check_fmajor_scale(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 = 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 = testing_lib.parse_test_proto( music_pb2.NoteSequence, """ tempos: { qpm: 60 } ticks_per_quarter: 220 """)
def setUp(self): self.steps_per_quarter = 4 self.note_sequence = music_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_abc_tunebook("""X:1 T:Test CC,',C,C'c """) self.assertEqual(1, len(tunes)) self.assertEqual(0, len(exceptions)) expected_ns1 = 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 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 = 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 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 = 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 testFluteScale(self): """Verify properties of the flute scale.""" ns = musicxml_reader.musicxml_file_to_sequence_proto( self.flute_scale_filename) expected_ns = 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 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 = 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 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.VariantEndingError)) self.assertTrue(isinstance(exceptions[1], abc_parser.PartError)) expected_metadata1 = 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 = 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.compare_to_abc2midi_and_metadata('testdata/english1.mid', expected_metadata1, expected_expanded_metadata1, tunes[1])
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 = 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 test_meter(self): """Test that meters are encoded properly. Musical meters are expressed as a ratio of beats to divisions. The MusicXML parser uses this ratio in lowest terms for timing purposes. However, the meters should be in the actual terms when appearing in a NoteSequence. """ ns = musicxml_reader.musicxml_file_to_sequence_proto( self.meter_test_filename) expected_ns = testing_lib.parse_test_proto( music_pb2.NoteSequence, """ ticks_per_quarter: 220 time_signatures { numerator: 1 denominator: 4 } time_signatures { time: 0.5 numerator: 2 denominator: 4 } time_signatures { time: 1.5 numerator: 3 denominator: 4 } time_signatures { time: 3.0 numerator: 4 denominator: 4 } time_signatures { time: 5.0 numerator: 5 denominator: 4 } time_signatures { time: 7.5 numerator: 6 denominator: 4 } time_signatures { time: 10.5 numerator: 7 denominator: 4 } time_signatures { time: 14.0 numerator: 1 denominator: 8 } time_signatures { time: 14.25 numerator: 2 denominator: 8 } time_signatures { time: 14.75 numerator: 3 denominator: 8 } time_signatures { time: 15.5 numerator: 4 denominator: 8 } time_signatures { time: 16.5 numerator: 5 denominator: 8 } time_signatures { time: 17.75 numerator: 6 denominator: 8 } time_signatures { time: 19.25 numerator: 7 denominator: 8 } time_signatures { time: 21.0 numerator: 8 denominator: 8 } time_signatures { time: 23.0 numerator: 9 denominator: 8 } time_signatures { time: 25.25 numerator: 10 denominator: 8 } time_signatures { time: 27.75 numerator: 11 denominator: 8 } time_signatures { time: 30.5 numerator: 12 denominator: 8 } time_signatures { time: 33.5 numerator: 2 denominator: 2 } time_signatures { time: 35.5 numerator: 3 denominator: 2 } time_signatures { time: 38.5 numerator: 4 denominator: 2 } time_signatures { time: 42.5 numerator: 4 denominator: 4 } time_signatures { time: 44.5 numerator: 2 denominator: 2 } key_signatures { } tempos { qpm: 120 } notes { pitch: 72 velocity: 64 end_time: 0.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 0.5 end_time: 1.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 1.5 end_time: 3.0 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 3.0 end_time: 5.0 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 5.0 end_time: 6.5 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 6.5 end_time: 7.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 7.5 end_time: 9.0 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 9.0 end_time: 10.5 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 10.5 end_time: 12.0 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 12.0 end_time: 13.5 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 13.5 end_time: 14.0 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 14.0 end_time: 14.25 numerator: 1 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 14.25 end_time: 14.75 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 14.75 end_time: 15.5 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 15.5 end_time: 16.0 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 16.0 end_time: 16.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 16.5 end_time: 17.0 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 17.0 end_time: 17.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 17.5 end_time: 17.75 numerator: 1 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 17.75 end_time: 18.5 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 18.5 end_time: 19.25 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 19.25 end_time: 20.0 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 20.0 end_time: 20.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 20.5 end_time: 21.0 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 21.0 end_time: 21.75 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 21.75 end_time: 22.5 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 22.5 end_time: 23.0 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 23.0 end_time: 24.5 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 24.5 end_time: 25.25 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 25.25 end_time: 26.75 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 26.75 end_time: 27.25 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 27.25 end_time: 27.75 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 27.75 end_time: 29.25 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 29.25 end_time: 30.0 numerator: 3 denominator: 8 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 30.0 end_time: 30.5 numerator: 1 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 30.5 end_time: 32.0 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 32.0 end_time: 33.5 numerator: 3 denominator: 4 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 33.5 end_time: 34.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 34.5 end_time: 35.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 35.5 end_time: 36.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 36.5 end_time: 37.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 37.5 end_time: 38.5 numerator: 1 denominator: 2 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 38.5 end_time: 40.5 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 40.5 end_time: 42.5 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 42.5 end_time: 44.5 numerator: 1 denominator: 1 voice: 1 } notes { pitch: 72 velocity: 64 start_time: 44.5 end_time: 46.5 numerator: 1 denominator: 1 voice: 1 } total_time: 46.5 part_infos { name: "Flute" } source_info { source_type: SCORE_BASED encoding_type: MUSIC_XML parser: MAGENTA_MUSIC_XML } """) self.assertProtoEquals(expected_ns, ns)
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 = 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)
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 = 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: 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: 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 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.RepeatParseError)) self.assertTrue(isinstance(exceptions[1], abc_parser.RepeatParseError)) self.assertTrue(isinstance(exceptions[2], abc_parser.RepeatParseError)) expected_ns1 = 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 = 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 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 = 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 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 = 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)