Esempio n. 1
0
    def test_empty_archive(self):
        with tempfile.NamedTemporaryFile(suffix='.mxl') as temp_file:
            z = zipfile.ZipFile(temp_file.name, 'w')
            z.close()

            with self.assertRaises(musicxml_reader.MusicXMLConversionError):
                musicxml_reader.musicxml_file_to_sequence_proto(temp_file.name)
Esempio n. 2
0
 def test_unpitched_notes(self):
   with self.assertRaises(musicxml_parser.UnpitchedNoteError):
     musicxml_parser.MusicXMLDocument(os.path.join(
         testing_lib.get_testdata_dir(), 'unpitched.xml'))
   with self.assertRaises(musicxml_reader.MusicXMLConversionError):
     musicxml_reader.musicxml_file_to_sequence_proto(os.path.join(
         testing_lib.get_testdata_dir(), 'unpitched.xml'))
Esempio n. 3
0
  def test_empty_archive(self):
    with tempfile.NamedTemporaryFile(suffix='.mxl') as temp_file:
      z = zipfile.ZipFile(temp_file.name, 'w')
      z.close()

      with self.assertRaises(musicxml_reader.MusicXMLConversionError):
        musicxml_reader.musicxml_file_to_sequence_proto(
            temp_file.name)
 def test_unpitched_notes(self):
   with self.assertRaises(musicxml_parser.UnpitchedNoteException):
     musicxml_parser.MusicXMLDocument(os.path.join(
         tf.resource_loader.get_data_files_path(),
         'testdata/unpitched.xml'))
   with self.assertRaises(musicxml_reader.MusicXMLConversionError):
     musicxml_reader.musicxml_file_to_sequence_proto(os.path.join(
         tf.resource_loader.get_data_files_path(),
         'testdata/unpitched.xml'))
Esempio n. 5
0
  def testcompressedmxlunicodefilename(self):
    """Test an MXL file containing a unicode filename within its zip archive."""

    unicode_filename = os.path.join(
        testing_lib.get_testdata_dir(), 'unicode_filename.mxl')
    sequence = musicxml_reader.musicxml_file_to_sequence_proto(unicode_filename)
    self.assertLen(sequence.notes, 8)
  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)
Esempio n. 7
0
    def _xml_to_seq_proto(self, full_xml_path, seq_collection_name):
        """Converts an individual .xml file to a NoteSequence proto. 
        Args:
            full_xml_path: the full path to the file to convert.
            collection: name of collection to which to save.
        Returns:
            NoteSequence proto or None if the file could not be converted.
        """

        if (full_xml_path.lower().endswith('.xml')
                or full_xml_path.lower().endswith('.mxl')):

            try:
                sequence = musicxml_reader.musicxml_file_to_sequence_proto(
                    full_xml_path)
            except musicxml_reader.MusicXMLConversionError as e:
                print(
                    'INFO: Could not parse MusicXML file {}. It will be skipped. \
                      Error was: {}'.format(full_xml_path, e))
                return None

            sequence.collection_name = seq_collection_name
            sequence.filename = os.path.basename(full_xml_path)
            sequence.id = os.path.basename(full_xml_path)
            return sequence

        else:
            print('INFO: Unable to find a converter for file {}'.format(
                full_xml_path))
def convert_musicxml(root_dir, sub_dir, full_file_path):
  """Converts a musicxml file to a sequence proto.

  Args:
    root_dir: A string specifying the root directory for the files being
        converted.
    sub_dir: The directory being converted currently.
    full_file_path: the full path to the file to convert.

  Returns:
    Either a NoteSequence proto or None if the file could not be converted.
  """
  try:
    sequence = musicxml_reader.musicxml_file_to_sequence_proto(full_file_path)
  except musicxml_reader.MusicXMLConversionError as e:
    tf.logging.warning(
        'Could not parse MusicXML file %s. It will be skipped. Error was: %s',
        full_file_path, e)
    return None
  sequence.collection_name = os.path.basename(root_dir)
  sequence.filename = os.path.join(sub_dir, os.path.basename(full_file_path))
  sequence.id = note_sequence_io.generate_note_sequence_id(
      sequence.filename, sequence.collection_name, 'musicxml')
  tf.logging.info('Converted MusicXML file %s.', full_file_path)
  return sequence
  def test_chord_symbols(self):
    ns = musicxml_reader.musicxml_file_to_sequence_proto(
        self.chord_symbols_filename)
    chord_symbols = [(annotation.time, annotation.text)
                     for annotation in ns.text_annotations
                     if annotation.annotation_type == CHORD_SYMBOL]
    chord_symbols = list(sorted(chord_symbols, key=operator.itemgetter(0)))

    expected_beats_and_chords = [
        (0.0, 'N.C.'),
        (4.0, 'Cmaj7'),
        (12.0, 'F6(add9)'),
        (16.0, 'F#dim7/A'),
        (20.0, 'Bm7b5'),
        (24.0, 'E7(#9)'),
        (28.0, 'A7(add9)(no3)'),
        (32.0, 'Bbsus2'),
        (36.0, 'Am(maj7)'),
        (38.0, 'D13'),
        (40.0, 'E5'),
        (44.0, 'Caug')
    ]

    # Adjust for 120 QPM.
    expected_times_and_chords = [(beat / 2.0, chord)
                                 for beat, chord in expected_beats_and_chords]
    self.assertEqual(expected_times_and_chords, chord_symbols)
def convert_musicxml(root_dir, sub_dir, full_file_path):
    """Converts a musicxml file to a sequence proto.

  Args:
    root_dir: A string specifying the root directory for the files being
        converted.
    sub_dir: The directory being converted currently.
    full_file_path: the full path to the file to convert.

  Returns:
    Either a NoteSequence proto or None if the file could not be converted.
  """
    try:
        sequence = musicxml_reader.musicxml_file_to_sequence_proto(
            full_file_path)
    except musicxml_reader.MusicXMLConversionError as e:
        tf.logging.warning(
            'Could not parse MusicXML file %s. It will be skipped. Error was: %s',
            full_file_path, e)
        return None
    sequence.collection_name = os.path.basename(root_dir)
    sequence.filename = os.path.join(sub_dir, os.path.basename(full_file_path))
    sequence.id = note_sequence_io.generate_note_sequence_id(
        sequence.filename, sequence.collection_name, 'musicxml')
    tf.logging.info('Converted MusicXML file %s.', full_file_path)
    return sequence
  def testcompressedmxlunicodefilename(self):
    """Test an MXL file containing a unicode filename within its zip archive."""

    unicode_filename = os.path.join(
        tf.resource_loader.get_data_files_path(),
        'testdata/unicode_filename.mxl')
    sequence = musicxml_reader.musicxml_file_to_sequence_proto(unicode_filename)
    self.assertEqual(len(sequence.notes), 8)
Esempio n. 12
0
def convert_directory(root_dir, sub_dir, sequence_writer, recursive=False):
    """Converts MusicXMLs to NoteSequences and writes to `sequence_writer`.

  MusicXML files found in the specified directory specified by the combination
  of `root_dir` and `sub_dir` and converted to NoteSequence protos with the
  basename of `root_dir` as the collection_name, and the relative path to the
  MusicXML file from `root_dir` as the filename. If `recursive` is true,
  recursively converts any subdirectories of the specified directory.

  Args:
    root_dir: A string specifying a root directory.
    sub_dir: A string specifying a path to a directory under `root_dir` in which
        to convert MusicXML contents.
    sequence_writer: A NoteSequenceRecordWriter to write the resulting
        NoteSequence protos to.
    recursive: A boolean specifying whether or not recursively convert
        MusicXMLs contained in subdirectories of the specified directory.

  Returns:
    The number of NoteSequence protos written as an integer.
  """
    dir_to_convert = os.path.join(root_dir, sub_dir)
    tf.logging.info("Converting MusicXML files in '%s'.", dir_to_convert)
    files_in_dir = tf.gfile.ListDirectory(os.path.join(dir_to_convert))
    recurse_sub_dirs = []
    sequences_written = 0
    sequences_skipped = 0
    for file_in_dir in files_in_dir:
        full_file_path = os.path.join(dir_to_convert, file_in_dir)
        if tf.gfile.IsDirectory(full_file_path):
            if recursive:
                recurse_sub_dirs.append(os.path.join(sub_dir, file_in_dir))
            continue
        try:
            sequence = musicxml_reader.musicxml_file_to_sequence_proto(
                full_file_path)
        except musicxml_reader.MusicXMLConversionError as e:
            tf.logging.warning(
                'Could not parse MusicXML file %s. It will be skipped. Error was: %s',
                full_file_path, e)
            sequences_skipped += 1
            continue
        sequence.collection_name = os.path.basename(root_dir)
        sequence.filename = os.path.join(sub_dir, file_in_dir)
        sequence.id = note_sequence_io.generate_note_sequence_id(
            sequence.filename, sequence.collection_name, 'musicxml')
        sequence_writer.write(sequence)
        sequences_written += 1
    tf.logging.info("Converted %d MusicXML files in '%s'.", sequences_written,
                    dir_to_convert)
    tf.logging.info('Could not parse %d MusicXML files.', sequences_skipped)
    for recurse_sub_dir in recurse_sub_dirs:
        sequences_written += convert_directory(root_dir, recurse_sub_dir,
                                               sequence_writer, recursive)
    return sequences_written
Esempio n. 13
0
 def test_transposed_keysig(self):
   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">
       <part-list>
         <score-part id="P1">
           <part-name/>
         </score-part>
       </part-list>
       <part id="P1">
         <measure number="1">
         <attributes>
           <divisions>4</divisions>
           <key>
             <fifths>-3</fifths>
             <mode>major</mode>
           </key>
           <time>
             <beats>4</beats>
             <beat-type>4</beat-type>
           </time>
           <clef>
             <sign>G</sign>
             <line>2</line>
           </clef>
           <transpose>
             <diatonic>-5</diatonic>
             <chromatic>-9</chromatic>
           </transpose>
           </attributes>
           <note>
             <pitch>
               <step>G</step>
               <octave>4</octave>
             </pitch>
             <duration>2</duration>
             <voice>1</voice>
             <type>quarter</type>
           </note>
         </measure>
       </part>
     </score-partwise>
   """
   with tempfile.NamedTemporaryFile() as temp_file:
     temp_file.write(xml)
     temp_file.flush()
     musicxml_parser.MusicXMLDocument(temp_file.name)
     sequence = musicxml_reader.musicxml_file_to_sequence_proto(temp_file.name)
     self.assertLen(sequence.key_signatures, 1)
     self.assertEqual(music_pb2.NoteSequence.KeySignature.G_FLAT,
                      sequence.key_signatures[0].key)
Esempio n. 14
0
 def test_transposed_keysig(self):
   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">
       <part-list>
         <score-part id="P1">
           <part-name/>
         </score-part>
       </part-list>
       <part id="P1">
         <measure number="1">
         <attributes>
           <divisions>4</divisions>
           <key>
             <fifths>-3</fifths>
             <mode>major</mode>
           </key>
           <time>
             <beats>4</beats>
             <beat-type>4</beat-type>
           </time>
           <clef>
             <sign>G</sign>
             <line>2</line>
           </clef>
           <transpose>
             <diatonic>-5</diatonic>
             <chromatic>-9</chromatic>
           </transpose>
           </attributes>
           <note>
             <pitch>
               <step>G</step>
               <octave>4</octave>
             </pitch>
             <duration>2</duration>
             <voice>1</voice>
             <type>quarter</type>
           </note>
         </measure>
       </part>
     </score-partwise>
   """
   with tempfile.NamedTemporaryFile() as temp_file:
     temp_file.write(xml)
     temp_file.flush()
     musicxml_parser.MusicXMLDocument(temp_file.name)
     sequence = musicxml_reader.musicxml_file_to_sequence_proto(temp_file.name)
     self.assertEqual(1, len(sequence.key_signatures))
     self.assertEqual(music_pb2.NoteSequence.KeySignature.G_FLAT,
                      sequence.key_signatures[0].key)
Esempio n. 15
0
def read_from_xml(xml_file):
    """Reads an xml file into a prettyMIDI object.

    Args:
    xml_file : str
        path to a musicxml file

    Returns:
        a prettyMIDI object
    """
    xml_note_sequence = musicxml_reader.musicxml_file_to_sequence_proto(
        xml_file)
    return magenta.music.sequence_proto_to_pretty_midi(xml_note_sequence)
  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 test_incomplete_measures(self):
    """Test that incomplete measures have the correct time signature.

    This can occur in pickup bars or incomplete measures. For example,
    if the time signature in the MusicXML is 4/4, but the measure only
    contains one quarter note, Magenta expects this pickup measure to have
    a time signature of 1/4.
    """
    ns = musicxml_reader.musicxml_file_to_sequence_proto(
        self.time_signature_filename)

    # One time signature per measure
    self.assertEqual(len(ns.time_signatures), 10)
    self.assertEqual(len(ns.key_signatures), 1)
    self.assertEqual(len(ns.notes), 112)
 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)
Esempio n. 19
0
  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)
Esempio n. 20
0
  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)
Esempio n. 21
0
  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_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 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)
Esempio n. 24
0
  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 = 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: 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)