Problem with high TPQN value in MidiFile


#1

Hi all !

A little question about the juce's MidiFile class and about the TPQN value.

The common oldest value of TPQN used in some hardware was a little 96 TPQN, i say oldest because a classic value used today is something like 960 TPQN. There's no specifications in the Genearal Midi level 1.0 (or 2.0) about the limitations (maximum) of this value. The recent MIDI sequencers allow to use highest value and each company use is own value.

This value is not without interest. First, because a good software need to allow the user to specify is own particular value, allowing the compatibility with oldest hardware (the famous 96 TPQN), and second, because this is all the mathematic subdivision of the code that is impacted.

We can say that in prime approach that the TPQN need to be a multiple of 2 (even number) or if not, at least not a prime number (that always a odd number except for the special case of 2). Why 96 or 960 are used in major hardware or software ?

I think because 960, for example, is a good number because it's abundant number with a good number of divisors : 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 16, 20, 24, 30, 32, 40, 48, 60, 64, 80, 96, 120, 160, 192, 240, 320, 480, 960

A TPQN of 960, as a 32th note's resolution of 120 that's a good resolution and 120 can be subdivided with a good precision. Maybe with some exception with for example a tuplet of 14:8 over a 32th note (always for example) that produce irregular result that need to be rounded.

There's not magic numbers that allow to have integer result on each subdivisions, especially when it comes to tuple. But theorically, 960 is not the "best" value. Some MIDI sequencer adopt the 1680 value that produce more precision in subdivision. This document compare the different TPQN less than 1680. http://www.public.iastate.edu/~ltibbits/downloads/SonarForum/MIDI-tick-time-calculations.pdf

1680 can be divided by : 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 15, 16, 20, 21, 24, 28, 30, 35, 40, 42, 48, 56, 60, 70, 80, 84, 105, 112, 120, 140, 168, 210, 240, 280, 336, 420, 560, 840, 1680

If we look about the divisors of 960 & 1680 less than 16, 1680 allow more simple divisors :

960  - 1 2 3 4 5 6 8 10 12 15 16
where
1680 - 1 2 3 4 5 6 7 8 10 12 14 15 16

So, I've search about a number that allow more dividors less than 16. 

A good number is 2520 that allow the divisors : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 18, 20, 21, 24, 28, 30, 35, 36, 40, 42, 45, 56, 60, 63, 70, 72, 84, 90, 105, 120, 126, 140, 168, 180, 210, 252, 280, 315,360, 420, 504, 630, 840, 1260, 2520

2520 - 1 2 3 4 5 6 7 8 9 10 12 14 15 

we have all the dividors between 1 and 10 but 16 is excluded.

Another good number can be 4320 : 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 27, 30, 32, 36, 40, 45, 48, 54, 60, 72, 80, 90, 96, 108, 120, 135, 144, 160, 180, 216, 240, 270, 288, 360, 432,480, 540, 720, 864, 1080, 1440, 2160, 4320

4320 - 1 2 3 4 5 6 8 9 10 12 15 16

4320 loose the 7 and 14 and win the 16

And now a little study of musical subdivision from theses numbers and others. Just copy/paster this code in your favorite text editor (too large for a forum view)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 24 32 48 64

240 | 120 | 80 | 60 | 48 | 40 | 34.29 | 30 | 26.67 | 24 | 21.82 | 20 | 18.46 | 17.14 | 16 | 15 | 10 | 7.50 | 5 | 3.75
360 | 180 | 120 | 90 | 72 | 60 | 51.43 | 45 | 40 | 36 | 32.73 | 30 | 27.69 | 25.71 | 24 | 22.50 | 15 | 11.25 | 7.50 | 5.63
384 | 192 | 128 | 96 | 76.80 | 64 | 54.86 | 48 | 42.67 | 38.40 | 34.91 | 32 | 29.54 | 27.43 | 25.60 | 24 | 16 | 12 | 8 | 6
840 | 420 | 280 | 210 | 168 | 140 | 120 | 105 | 93.33 | 84 | 76.36 | 70 | 64.62 | 60 | 56 | 52.50 | 35 | 26.25 | 17.50 | 13.13
960 | 480 | 320 | 240 | 192 | 160 | 137.14 | 120 | 106.67 | 96 | 87.27 | 80 | 73.85 | 68.57 | 64 | 60 | 40 | 30 | 20 | 15
1260 | 630 | 420 | 315 | 252 | 210 | 180 | 157.50 | 140 | 126 | 114.55 | 105 | 96.92 | 90 | 84 | 78.75 | 52.50 | 39.38 | 26.25 | 19.69
1680 | 840 | 560 | 420 | 336 | 280 | 240 | 210 | 186.67 | 168 | 152.73 | 140 | 129.23 | 120 | 112 | 105 | 70 | 52.50 | 35 | 26.25
2520 | 1260 | 840 | 630 | 504 | 420 | 360 | 315 | 280 | 252 | 229.09 | 210 | 193.85 | 180 | 168 | 157.50 | 105 | 78.75 | 52.50 | 39.38
4320 | 2160 | 1440 | 1080 | 864 | 720 | 617.14 | 540 | 480 | 432 | 392.73 | 360 | 332.31 | 308.57 | 288 | 270 | 180 | 135 | 90 | 67.50
5040 | 2520 | 1680 | 1260 | 1008 | 840 | 720 | 630 | 560 | 504 | 458.18 | 420 | 387.69 | 360 | 336 | 315 | 210 | 157.50 | 105 | 78.75
7560 | 3780 | 2520 | 1890 | 1512 | 1260 | 1080 | 945 | 840 | 756 | 687.27 | 630 | 581.54 | 540 | 504 | 472.50 | 315 | 236.25 | 157.50 | 118.13
10080 | 5040 | 3360 | 2520 | 2016 | 1680 | 1440 | 1260 | 1120 | 1008 | 916.36 | 840 | 775.38 | 720 | 672 | 630 | 420 | 315 | 210 | 157.50

4th 8th 8th(T) 16th 16th(T) 32th 32th(T) 64th 64th(T) 128th 128th(T) 256th

OK, now this is my question, and my problem about the TPQN.

I have a MidiFile that is converted from a tablature score that use 8 tracks. The start an end timestamp of each tracks computed at 4320 TPQN are :

TRACK 1 - VOCAL       3179232 4388832
TRACK 2 - HARMONICA   3592512 4004352
TRACK 3 - GUITAR LEAD 1546272 5426712
TRACK 4 - GUITAR RYTH  725472 5426712
TRACK 5 - ORGAN LEAD     4032 2950272
TRACK 6 - ORGAN RYTH   565632 5438592
TRACK 7 - BASS        1062432 5438592
TRACK 8 - DRUMS        690912 5442912

4032 is the first concret timestamp (app. 1 second of timelag at the current BPM).

When i save my MIdi File all is ok except that the track 1 and 2 that strangely start directly over the Organ. Seem like the timestamp was modified somewhere. The track 3 (Guitar Solo) start correctly, but the second solo start juste before the first one. You need to know that the track 1, 2, and 3 are blank bars in between.

I looked in my code if I screwed up somewhere, nothing. So I pulled on TPQN and putting a TPQN 960, everything is in order.

So I think it's a limitation of TPQN (undocumented) as the code of the track saving, Jules modifies the timestamp to make it relative (delta time) (in void MidiFile::writeTrack)

 const int tick = roundToInt (mm.getTimeStamp());
 const int delta = jmax (0, tick - lastTick);
 MidiFileHelpers::writeVariableLengthInt (out, (uint32) delta);
 lastTick = tick;

I wonder if the code does not truncate some timestamp too big and how to remedy this problem. At least, determine the maximum value to be adopted for TPQN.

Sorry for the amount of info for so little, but at least it is didactic!

Friendly,

Max


#2

Looking at the code that converts the timestamp to ticks, I can't see anything that could be improved.. It's already a time in ticks, so taking the delta won't lose any accuracy.. Or maybe I'm misunderstanding?


#3

I don't see anything false in your code. It's a strange problem. The problem comes only when i've few tracks that start long time after the song start. In this case and when the TPQN is 4320 then the tracks start at the beginning of the song (over the others tracks so), like the empty bars was removed, but as you can see the timestamp are good and the problem disappears when I go down the TPQN 960, nothing more that.

I will investigate and feedback here.

Thank you Jules !


#4

I too fail to see the problem. You convert the midi timstamps from seconds to ticks using the tpqn of your choosing (anywhere between 1 and 32767, the latter of course giving the best precision) and the current bpm /spqn. Your tpqn will be written to the midifile if you set it with setTicksPerQuarterNote().

If you don't get the result you expect when writing your midisequence back to the file, the problem would most certainly be an arithmetic flaw in your calculations and not to hard to track down in the debugger. Or am I missing something?