From dirk@diaspar.fb10.TU-Berlin.DEMon Feb 27 20:22:36 1995 Date: Mon, 27 Feb 95 16:43:59 +0100 From: Dirk Schwarzhans Reply to: dirk@kalium.physik.TU-Berlin.DE To: sean@cnct.com Subject: Re: MIDI TIME DATA Hello, in alt.binaries.sounds.midi you asked for info about MIDI timing. I had the same problems too some time ago. Here is the solution: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX deltaRealtime = tempo * deltaTime / division gives you the difference between two midi events (which are separated by the deltaTime value specified in the file) in micro seconds. "division" is from the midi file header. But you CANNOT use this formula because of accumulating errors, even if you use double precision floating points calculations. The way to prevent this is: --------------------------- 1) You calculate a quantity called "midiTime" for every event by adding the deltaTimes of the previous events. 2) Then you use this times for merging the events from different tracks. 3) Then you calculate the realTime of every event like this: -initialize the following variables: long midiOffset = 0; long realOffset = 0; long division; /* = from file header */ long tempo = 5000000; /* default value from midi file spec. */ -for every event do: realTime = realOffset + (long)((double)(midiTime - midiOffset) * (double)tempo / (double)division); -for every tempo change do: tempo = newTempo; /* newTempo specified in SET TEMPO command */ realOffset = realtime; /* calculated above */ midiOffset = midiTime; -------------------------------- Now rounding errors only accumulate on tempo changes which don't occure as often as midi events. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX For the case of negative division in the file header someone sent me the following text: If "division" is negative then its high byte is minus the number of frames per second, and its low byte is the number of ticks per frame. So if you multiply the two bytes together and negate the result, you have the number of ticks per second (1000 is a typical value - gives millisecond timing). Then, divide each Delta-Time by this number to get the length in seconds between each two events. This will give non-integer results!! so be sure to use real number division. If ticks per second=1000 then the conversion of Delta-Times is unnecessary - they're already in units of milliseconds, which is useful enough. The purpose of a tempo change in this environment is not to alter the rate at which the music plays, but to change the rate at which it is represented as quarter notes, eighth notes, etc. You can also use it to derive a value for the number of ticks per quarter note = (Tempo change value) * (ticks per second) / 1000000, because the tempo change value is in microseconds per quarter note. There is another factor that (rarely) affects timing: at the end of a time signature meta-event (FF 58 04 nn dd cc bb) the bb is the number of notated 32nd notes in every MIDI quarter note. I have never seen this be anything other than 8, but if it's different, a program which deals with measures, beats, or notation has to convert the MIDI timing info to useful notation info. The way to do that would be to get a new value for the number of ticks per quarter note: new value = 8 * (old value) / (bb) This new value should then be used to recalculate the relevant timing data: either the number of microseconds per tick if "division" is positive or the number of ticks per second if "division" is negative. Hope this helps, Dirk Schwarzhans