def testSimpleSequenceToPrettyMidi_DropEventsAfterLastNote(self): source_midi = pretty_midi.PrettyMIDI(self.midi_simple_filename) multi_tempo_sequence_proto = midi_io.midi_to_sequence_proto( source_midi) # Add a final tempo long after the last note. multi_tempo_sequence_proto.tempos.add(time=600.0, qpm=120) # Translate without dropping. translated_midi = midi_io.sequence_proto_to_pretty_midi( multi_tempo_sequence_proto) self.CheckPrettyMidiAndSequence(translated_midi, multi_tempo_sequence_proto) # Translate dropping anything after the last note. translated_midi = midi_io.sequence_proto_to_pretty_midi( multi_tempo_sequence_proto, drop_events_n_seconds_after_last_note=0) # The added tempo should have been dropped. del multi_tempo_sequence_proto.tempos[-1] self.CheckPrettyMidiAndSequence(translated_midi, multi_tempo_sequence_proto) # Add a final tempo 15 seconds after the last note. last_note_time = max( [n.end_time for n in multi_tempo_sequence_proto.notes]) multi_tempo_sequence_proto.tempos.add(time=last_note_time + 15, qpm=120) # Translate dropping anything 30 seconds after the last note, which should # preserve the added tempo. translated_midi = midi_io.sequence_proto_to_pretty_midi( multi_tempo_sequence_proto, drop_events_n_seconds_after_last_note=30) self.CheckPrettyMidiAndSequence(translated_midi, multi_tempo_sequence_proto)
def convert_midi(root_dir, sub_dir, full_file_path): """Converts a midi 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 = midi_io.midi_to_sequence_proto( tf.gfile.GFile(full_file_path, 'rb').read()) except midi_io.MIDIConversionError as e: tf.logging.warning( 'Could not parse MIDI 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 = generate_note_sequence_id( sequence.filename, sequence.collection_name, 'midi') tf.logging.info('Converted MIDI file %s.', full_file_path) return sequence
def CheckReadWriteMidi(self, filename): """Test writing to a MIDI file and comparing it to the original Sequence.""" # TODO(deck): The input MIDI file is opened in pretty-midi and # re-written to a temp file, sanitizing the MIDI data (reordering # note ons, etc). Issue 85 in the pretty-midi GitHub # (http://github.com/craffel/pretty-midi/issues/85) requests that # this sanitization be available outside of the context of a file # write. If that is implemented, this rewrite code should be # modified or deleted. # When writing to the temp file, use the file object itself instead of # file.name to avoid the permission error on Windows. with tempfile.NamedTemporaryFile(prefix='MidiIoTest') as rewrite_file: original_midi = pretty_midi.PrettyMIDI(filename) original_midi.write(rewrite_file) # Use file object # Back the file position to top to reload the rewrite_file rewrite_file.seek(0) source_midi = pretty_midi.PrettyMIDI( rewrite_file) # Use file object sequence_proto = midi_io.midi_to_sequence_proto(source_midi) # Translate the NoteSequence to MIDI and write to a file. with tempfile.NamedTemporaryFile(prefix='MidiIoTest') as temp_file: midi_io.sequence_proto_to_midi_file(sequence_proto, temp_file.name) # Read it back in and compare to source. created_midi = pretty_midi.PrettyMIDI(temp_file) # Use file object self.CheckPrettyMidiAndSequence(created_midi, sequence_proto)
def testSimpleSequenceToPrettyMidi_MultipleTempos(self): source_midi = pretty_midi.PrettyMIDI(self.midi_simple_filename) multi_tempo_sequence_proto = midi_io.midi_to_sequence_proto(source_midi) multi_tempo_sequence_proto.tempos.add(time=1.0, qpm=60) multi_tempo_sequence_proto.tempos.add(time=2.0, qpm=120) translated_midi = midi_io.sequence_proto_to_pretty_midi( multi_tempo_sequence_proto) self.CheckPrettyMidiAndSequence(translated_midi, multi_tempo_sequence_proto)
def testSimpleSequenceToPrettyMidi_DefaultTicksAndTempo(self): source_midi = pretty_midi.PrettyMIDI(self.midi_simple_filename) stripped_sequence_proto = midi_io.midi_to_sequence_proto(source_midi) del stripped_sequence_proto.tempos[:] stripped_sequence_proto.ClearField('ticks_per_quarter') expected_sequence_proto = music_pb2.NoteSequence() expected_sequence_proto.CopyFrom(stripped_sequence_proto) expected_sequence_proto.tempos.add( qpm=constants.DEFAULT_QUARTERS_PER_MINUTE) expected_sequence_proto.ticks_per_quarter = constants.STANDARD_PPQ translated_midi = midi_io.sequence_proto_to_pretty_midi( stripped_sequence_proto) self.CheckPrettyMidiAndSequence(translated_midi, expected_sequence_proto)
def testSimpleSequenceToPrettyMidi_FirstTempoNotAtZero(self): source_midi = pretty_midi.PrettyMIDI(self.midi_simple_filename) multi_tempo_sequence_proto = midi_io.midi_to_sequence_proto(source_midi) del multi_tempo_sequence_proto.tempos[:] multi_tempo_sequence_proto.tempos.add(time=1.0, qpm=60) multi_tempo_sequence_proto.tempos.add(time=2.0, qpm=120) translated_midi = midi_io.sequence_proto_to_pretty_midi( multi_tempo_sequence_proto) # Translating to MIDI adds an implicit DEFAULT_QUARTERS_PER_MINUTE tempo # at time 0, so recreate the list with that in place. del multi_tempo_sequence_proto.tempos[:] multi_tempo_sequence_proto.tempos.add( time=0.0, qpm=constants.DEFAULT_QUARTERS_PER_MINUTE) multi_tempo_sequence_proto.tempos.add(time=1.0, qpm=60) multi_tempo_sequence_proto.tempos.add(time=2.0, qpm=120) self.CheckPrettyMidiAndSequence(translated_midi, multi_tempo_sequence_proto)
def CheckSequenceToPrettyMidi(self, filename): """Test the translation from Sequence proto to PrettyMIDI.""" source_midi = pretty_midi.PrettyMIDI(filename) sequence_proto = midi_io.midi_to_sequence_proto(source_midi) translated_midi = midi_io.sequence_proto_to_pretty_midi(sequence_proto) self.CheckPrettyMidiAndSequence(translated_midi, sequence_proto)
def CheckMidiToSequence(self, filename): """Test the translation from PrettyMIDI to Sequence proto.""" source_midi = pretty_midi.PrettyMIDI(filename) sequence_proto = midi_io.midi_to_sequence_proto(source_midi) self.CheckPrettyMidiAndSequence(source_midi, sequence_proto)