Delta times in MIDI files

After dealings with ym2149 and external midi module communication, came about right time to face delta times which are crucial to replaying midi files. As a small remainder I would like to mention that it’s a relative time from last event occurence in midi sequence. Having this value we know in what time period the adequate events have to be sent e.g. from sequencer to midi device (note on, note off, instrument change etc..). I will not write anything about MIDI files structure, because there is alot of good articles on the web.

After the lecture of MIDI file format specification [0,1,2 type] one question arises – how long time takes one delta time and how to implement sending midi data and tempo change? Ok, firstly we have to see what’s interesting connected with tempo can be found in our MID file. There are two things:

1) time division in “MThd” chunk (0x4D546864), indicates number of ticks of our internal clock in one quaternote (PPQN – pulses per quaternote). And it’s plainly resolution in which the pulses are counted in one quaternote, which one has finite period (more about it later). So if we have time division equal to 96 PPQN, then it means that 96 of these ticks indicate end of one quaternote duration. Musicians for example are measuring tempo in number of quaternotes per minute (simply speaking amount of triggered notes per minute), in computers and electronic devices time tracking has to be done in another way. Time division can be coded also in SMPTE format, but it’s rare in midi files and I will not describe it here..

2) Set tempo value which contains an amount of microseconds per one quaternote. It can be found in tracks meta event “MTrk” chunk (0x4D54726B)

If we have these two informations we can calculate frequency with which one clock tick has to occur :

MSPM – microseconds per minute = 60 000 000
BPM – beats per minute
MPQN – microseconds per quaternote
BPM = MSPM / MPQN 
MPQN = MSPM / BPM

So if we have 120 BPM (standard, default tempo) then one quaternote period is:

MPQN=60 000 000/120 BPM = 500 000 microseconds

Next step is calculation of the one clock tick frequency, when we have one quaternote period the rest is easy:

1 tick=MPQN/1000000/PPQN=500 000/1000000/96 PPQN = ~0,005208333333 Hz…

With those two things from above we program tick counting with ~0,005208333333 Hz frequency, e.g. for resolution 96PPQN there is 96 ticks that give us gives one full quaternote duration  (96 * 1 tick = 96 * 0,005208333333 Hz = 500 000 microseconds = 0,5s).

Now, we can solve an issue how to translate delta times to real time. Below there are three example tempo values:

Tempo 1 Tempo 2 Tempo 3
BPM 120 130 130
PPQN 120 120 96
MPQN 500000 461538 461538
QLS 0,5 0,4615 0,46
TDPS 0,0041666667 0,0038461500 0,0048076875

BPM – it’s a beats per minute 60 000 000/MPQN
PPQN – Pulses per quater note, resolution found in MIDI file
MPQN – microseconds per quaternote or quaternote duration, range is 0-8355711 microseconds (according to MIDI file specification)
QLS – seconds per quaternote (MPQN/1000000)
TDPS – seconds per tick (QLS/PPQN)

And here’s how we translate each delta value to real time for those three different tempos. All the events are triggered relative to the last event. So first events will be fired with 0 delta, after that there have to be 15 ticks to fire the next event, and after that 45 ticks has to pass (in relation to the last event) before event is triggered. As you can see accumulated delta represents the absolute timeline of events.

So to receive the specific real time at which event has to be launched we multiply given tempo TDPS*accumulated delta. Results are presented in three columns below for each tempo.

If you want to see how will look other tempos I’ve prepared simple sheet in OpenOffice Calc, so you can alter values and see how they change.

Tempo 1 Tempo 2 Tempo 3
lp accumulated delta delta delta [s] delta [s] delta [s]
1 0 0 0,00 0,00 0,00
2 15 15 0,06 0,06 0,07
3 60 45 0,25 0,23 0,29
4 70 10 0,29 0,27 0,34
5 90 20 0,38 0,35 0,43
6 100 10 0,42 0,38 0,48
7 120 20 0,50 0,46 0,58
8 135 15 0,56 0,52 0,65
9 180 45 0,75 0,69 0,87
10 195 15 0,81 0,75 0,94
11 240 45 1,00 0,92 1,15
12 250 10 1,04 0,96 1,20
13 270 20 1,13 1,04 1,30
14 280 10 1,17 1,08 1,35
15 300 20 1,25 1,15 1,44
16 315 15 1,31 1,21 1,51
17 360 45 1,50 1,38 1,73
18 480 120 2,00 1,85 2,31
19 555 75 2,31 2,13 2,67
20 570 15 2,38 2,19 2,74
21 615 45 2,56 2,37 2,96
22 630 15 2,63 2,42 3,03
23 675 45 2,81 2,60 3,25
24 735 60 3,06 2,83 3,53
25 765 30 3,19 2,94 3,68
26 780 15 3,25 3,00 3,75
27 795 15 3,31 3,06 3,82
28 810 15 3,38 3,12 3,89
29 855 45 3,56 3,29 4,11
30 955 100 3,98 3,67 4,59
31 975 20 4,06 3,75 4,69
32 990 15 4,13 3,81 4,76
33 1005 15 4,19 3,87 4,83
34 1020 15 4,25 3,92 4,90
35 1035 15 4,31 3,98 4,98
36 1155 120 4,81 4,44 5,55

So, basically for MIDI 0 type replay (only one track, to keep it simple) we increase our delta in TDPS periods. We check current event in sequence delta time. If event delta is equal to counted ticks we fire up event, reset tick counter and go to the following event event. Otherwise we increase tick counter and check current event delta once again.
For multi track replay we have to maintain one tick counter per individual track and iterate through events on all tracks.

Second option would be triggering events at precalculated real time timeline (based on accumulated delta), but handling this would be complicated with multitrack files.



Gallery

Gayle 4
Skarsnik with Gobbla
sauron_coolmini.png
DSCF3401.png
Savage Orc 7
DSCF3388.png
DSCF3731.JPG
2006_0522highelf0006
Plague Marine Standard bearer