Search code examples
midimido

Convert time/tick in Python MIDI MIDO read/save file


The following program uses MIDO to read 'g1.mid' then save it to 'g1_new.mid'. My question is that: in reading the file, 'msg.time' is a float value, but in saving the file, 'time in Message' is an integer in tick. How do we convert 'msg.time' to 'tick in message' in this case?

from mido import MidiFile 
from mido import Message, MidiTrack

mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)

for msg in MidiFile('g1.mid'):
    if (not msg.is_meta):
        if (msg.type == 'note_on'):
            # how to convert msg.time to tick to fill in '?'
            track.append(Message('note_on', note=msg.note, velocity=msg.velocity, time=?))
        elif (msg.type == 'note_off'):
            # how to convert msg.time to tick to fill in '?'
            track.append(Message('note_off', note=msg.note, velocity=msg.velocity, time=?))
        elif (msg.type == 'program_change'):
            track.append(Message('program_change', program=msg.program, channel=msg.channel))

mid.save('g1_new.mid')

Note: This piece of code is in a project about music generation.


Solution

  • When you iterate over the MidiFile object itself, the time stamps are explicitly converted:

    class MidiFile(object):
        ...
        def __iter__(self):
            ...
            tempo = DEFAULT_TEMPO
            for msg in merge_tracks(self.tracks):
                # Convert message time from absolute time
                # in ticks to relative time in seconds.
                if msg.time > 0:
                    delta = tick2second(msg.time, self.ticks_per_beat, tempo)
                else:
                    delta = 0
    
                yield msg.copy(time=delta)
    
                if msg.type == 'set_tempo':
                    tempo = msg.tempo
    

    So just iterate over mid.tracks (or over the merged tracks) directly.