Search code examples
pythontimemidiaudio-player

Convert midi time to bars and beats


I am trying to figure out how to convert from midi time to bars and beats. Here is a sample midi file. If you download that and open the file in a program like GarageBand, you'll see the third track contains four notes in the first bar:

enter image description here

Now if you load the file with mido in Python, you can see the first four notes in the same track:

import mido

midi = mido.MidiFile('1079-02.mid')
list(midi.tracks[2])

If you look at that list of events in the track, you'll see the first four note on/off events from the track:

 <message note_on channel=1 note=60 velocity=100 time=0>,
 <message note_on channel=1 note=60 velocity=0 time=480>,
 <message note_on channel=1 note=63 velocity=100 time=0>,
 <message note_on channel=1 note=63 velocity=0 time=480>,
 <message note_on channel=1 note=67 velocity=100 time=0>,
 <message note_on channel=1 note=67 velocity=0 time=480>,
 <message note_on channel=1 note=68 velocity=100 time=0>,
 <message note_on channel=1 note=68 velocity=0 time=480>,

Here we can see that in this particular file, the time value of 480 is equal to one quarter of a bar. The madmom library uses 480 as the default ticks per beat value in some of their helper functions, though, so perhaps this is a common magic number? In other files, however, the value is different.

My question is: how can I convert from the time values in the midi file to a time value in lengths of bars? For this file, for example, I would want to represent the time attribute in the first four notes of the third track as 0.25, because each one lasts one quarter of a bar. Does anyone know how I can run this conversion?

For reference, the first track in this file contains the following time attributes:

<meta message smpte_offset frame_rate=24 hours=32 minutes=0 seconds=3 frames=15 sub_frames=0 time=0>,
<meta message time_signature numerator=4 denominator=4 clocks_per_click=24 notated_32nd_notes_per_beat=8 time=0>,
<meta message set_tempo tempo=857143 time=0>,

Solution

  • Praise all things good and holy, mido.MidiFile reads the ticks per beat metadata and stores it in mido.MidiFile.ticks_per_beat:

    import mido
    
    midi = mido.MidiFile('1079-02.mid')
    print(midi.ticks_per_beat)
    

    Then you just need to divide each note's duration by that ticks per beat value to represent the note in terms of its duration in beats!