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