vishnubob / python-midi

Python MIDI library
MIT License
1.51k stars 370 forks source link

closed formula to calculate real time after tempo event #156

Open yoniwe1 opened 6 years ago

yoniwe1 commented 6 years ago

Hello!

Thank you for the explenation about real time calculation after tempo event: [https://github.com/vishnubob/python-midi#Side_Note_What_is_a_MIDI_Tick]

Something still does not line up for me in my calculations for the case of a multiple tempo event midi file.

Say I have this midi event sequence (taken out of naudio c# output) inside a midi file:

5384 NoteOn Ch: 10 Ride Bell Vel:0 (Note Off) 5387 NoteOn Ch: 10 Mute Triangle Vel:0 (Note Off) 5388 SetTempo 116bpm (512821) 5390 NoteOn Ch: 2 D#4 Vel:0 (Note Off) 5391 NoteOn Ch: 2 A#4 Vel:0 (Note Off)

which sets a new tempo.

The first tempo event was:

0 SetTempo 120bpm (500000)

and the resolution is:

Delta Ticks Per Quarter Note 192

How do I calculate the real time of the next events after the tempo change? I need to somehow add it to the accumulated time using the new tempo event scaling factor.

I would be happy to get some closed formula for this. The purpose is to have the actual time that would be played with a sound player when playing the midi file.

I tried this formula with no success:

60000 / ( (Resolution Tempo) 1000 )

Thank you very much in advance!

MaurizioB commented 6 years ago

For some time I was thinking about this, and tonight I decided to give it a try. I've tested with a few files but didn't have time to test it further with complex tempo maps, anyway it seems ok right now.

midi_timings.py

There are two main functions. getEventTime() takes a midi.Pattern, a track number and event number in the track sequence as arguments, and it returns the timing for that event in seconds. getTrackTimings() takes the pattern and track number and returns a list of event, time tuples including NoteOnEvents (and NoteOffEvents if optional noteOff argument is True). I'm not completely sure about the behavior of the latter if there are tracks with few events and lots of tempo changes, specifically when there are more than one tempo change between two events in a single track.

Of course there's plenty of room for optimization, but I tried to be as much comprehensive and exhaustive as possible here.