Files
Work/midiseq/DOCS/MIDITIME
2024-08-07 09:16:27 -04:00

96 lines
3.6 KiB
Plaintext

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 <dirk@diaspar.fb10.TU-Berlin.DE>
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