Pos_To_Time() Function. (Midi)

I’m stuck. :( Based on the above, so far I got: i[/i]

function export_pos_to_time(pos, delay, bpm, lpb)  
 local duration = 60 / (bpm * lpb)  
 local timestamp = pos * duration  
 local timestamp = timestamp + (delay * (duration / 256))  
 return timestamp   

Is this right?

Fuck, this is frustrating. MIDI time is retarded. Look at this garbage:


Quote of the day: “Remember that musicians always think in terms of a beat, not the passage of seconds, minutes, etc.”


Staring at a text editor for hours trying to convert line position to time would be hella easy if time = time, not whatever MIDI thinks it is. Math wizards, help a whiner out?

What I don’t want: More english.

I had the same fist clenching in my Notes Randomizer thread. Pages upon pages of undecipherable garbage trying to explain keys, when the answer was simply to rotate a Lua table.

What I do want: Lua.

Preferably generic enough so that in the future, when I refer to past threads, it’s actually useful and not barely info, weeks pass, skip to undecipherable and implemented code.


Loneliness of the long distance threader.

Reverse engineering the PHP script.

BPM 120, LPB 4, 1 note on each line, Where division is set to 96 with Midi:setTimebase() outputs:

MFile 1 2 96  
0 Tempo 500000  
24 Off ch=1 n=60 v=0  
24 On ch=1 n=60 v=127  
48 Off ch=1 n=60 v=0  
48 On ch=1 n=60 v=127  
72 Off ch=1 n=60 v=0  
72 On ch=1 n=60 v=127  
96 Off ch=1 n=60 v=0  
96 On ch=1 n=60 v=127  

Repeat with BPM 176, the only thing that changes is:

0 Tempo 340909  

Repeat with BPM 120, LPB 5:

19.2 Off ch=1 n=60 v=0  
19.2 On ch=1 n=60 v=127  
38.4 Off ch=1 n=60 v=0  
38.4 On ch=1 n=60 v=127  
57.6 Off ch=1 n=60 v=0  
57.6 On ch=1 n=60 v=127  
76.8 Off ch=1 n=60 v=0  
76.8 On ch=1 n=60 v=127  

All midi files play back accurately. So it appears that:

time = pos * (division/lpb)  

Getting somewhere!


function export_pos_to_time(pos, delay, division, lpb)  
 return ((pos - 1) + (delay * 100 / 255 * 0.01)) * (division/lpb)  

Isn’t 100/255 * 0.01 = 255?

Pos-1 is correct, as line0 is Pos=1 in LUA I believe.

Delay/256 is all you need for delay fraction calculation. Delay 80h = 128. 128/256 equals half a line, correct. And it’s 256 values, 0-255, so use 256 not 255.

That will give you how many lines through a Song(? - I Assume Pos must count lines from beginning on Song, not start of Pattern) to a delay value fraction of a line.

Divide by LPB will give you how many beats into the song you are.

60/BPM will give you length of a single beat in Seconds.

SMPTE is in Frames though (related to video) did you work out if you want SMPTE or mS for smallest division? If SMPTE what format? 24, 25, 29.97 or 30 Frames per second? User selectable?

So let’s try and combine this:

(((pos - 1) + (Delay / 256)) / LPB) * (60 / BPM) {I think this should give times in Seconds.}

I feel I have missed a point or two of yours though. Espeically as you started talking about PPQN. You do know that not all MIDI systems have to use 96PPQN, 24PPQN is used in MIDI Beat Clock, 192, 240, 384, 480 and more can be found if you query the specification of MIDI sequencing equipment.

But it’s: (delay * 100 / 255 * 0.01))

Mathematical order of operations will do (delay * 100) first. So if delay is 75, then it’s (7500 / 255 * 0.01)

To make a long story short, it works. Thanks for your help, though.

Divide and multiple are done at the same unless you have brackets in place time so with no brackets in place the *100 and 0.01 still cancel out to a 1. Unless you mean it to be 2550.01 on the bottom of the divisor, then you will need a bracket around the term. At least for it to be correct mathematically, although maybe LUA works through the process due to routines it uses…

Trust me all you need is Delay/256. Think about it! This will give you the decimal representation of the fraction of a line at delay value X, which you are then adding to how many lines through you are.

No, divide and multiply are in the same group, done from left to right.

Trust me, the code does’t lie (nor does it give the same when you do what you propose). :)

Here’s a more detailed explination.

The space between two tracker lines can be expressed as a percentage. Each tracker line has 255 equal “delay” slices between them. This translates to:

 X 70  
--- = ---  
100 255  

Where 70 is delay. So, gradeschool math says:

X = 70 * 100 / 255  

Now that I have X expressed as a percentage, I want to express it as 0.X, so that I can add it to pos. This is why I multiply it by 0.01. So, with my function I get something like 1.274509803921569 for a note on pos 1, with a delay of 70 (decimal). Then with this number, I multiply it by (division/lpb) to give me the MF2T timestamp.


Multiple and divide are opposite sides of the same coin! The are exactly the same operator!! X*10 = X/0.1!!! Dividing is the same as multiplying by the inverse and the two can not be seperated further than making it easy for kids by teaching them rhymes such as Betty Makes The Doughnuts Always Salty (or whatever rude version you may of learnt at school.)

26315/2/6/3/2 = 2/26/63/31/25 whichever way you punch in into calculator AND CAN SEE EVERY OPERAND IS PERFORMED INSTANTLY!

AS Stated my equation will give the answer in Seconds. You failed to answer what yours is giving it in and how/why you are using this Division parameter you never really explained where it suddenly appeared from (starting to thing from your rambling posts you actual want incremental counts of MIDI ticks since start of song assuming a PPQN of 96 but you haven’t made it clear.)

You know what? I’m an idiot and you are right.

Delay/255 is the same thing.

Doh, and thanks!

256 positions! 0 is a position too, as stated more than one.

Why have you gone percentage and back again?

70/256 = 0.2734375 OF A LINE! Exactly what you want, no?

Yes, I was wrong. I stand corrected.


No worries.

Sorry about the excessive use of exclamation marks ;)

Re: 255 vs 256.

If you have a Delay = 255. With your method of using 255 you will get a +1, exactly onto next line which is obviously wrong, rather than +0.996…

Although these differences are probably so small to not be worth working about.

Alright, thanks again. I have modified the function:

function pos_to_time(pos, delay, division, lpb)  
 local time = ((pos - 1) + delay / 256) * (division / lpb)  
 return math.floor(time + .5) --Round  

For the sake of this discussion division = PPQN. Although it wasn’t me who brought it up.

Basically, I have a Lua Midi class which I ported from PHP. This Midi class “works.” I did the work of “translation” and tested it with a bunch of different MIDI files which proved that the PHP to Lua translation was done correctly. The concept of Midi, however, is still strange to me. As you figured out math isn’t my strong point. Haha. I’m better at finding patterns in existing data, regular expressions, clever foreach loops, and just plain hacking code.

Division in the class (which I didn’t write, just ported) means “MIDI clicks per quarter note”, and “quarter note” is just another way of saying “beat” (@see: Tempo)

Suffice to say, I will commit the changes to the Midi Export script later today. Woot!

This pos_to_time is just a small part of the script. It’s been the most frustrating to date, though. Looking at the PHP version I don’t think we had it exacyly right

I think this function, Bantai’s idea of “Whenever you encounter a BPM command, just write it to the MIDI tempo track,” and the fact that changing the BPM doesn’t change the timestamp (see my reverse engineering post, as well as the quoted spec) we have something solid now.

Good times.

Glad you’re getting towards something that is working and moving forwards with your challenge.

So Time is a count of PPQNs so far. Assuming the math.floor removes the fractional component, leaving just the integer.

((pos - 1) + delay / 256) = Lines
/ LPB = Beats, or Quarter Notes.

  • Division = PPQN (Quarter Notes so far times by how many part per quarter note are used.)

Replace Division with 60/BPM would give you result in Seconds but don’t think that is of use to you.

Still don’t quite understand what this is in reference to MIDI though. MIDI (Beat) Clock is just a syncing pulse and runs at PPQN of 24. MIDI Time Code actually transmits full SMPTE.

Song Position Pointer (location in Song) seems likely to be closest. Usually only used to cue before playback, then Play command, then the MIDI Clock pulses would keep in time rather than updates via SPP:

“This 14-bit value is the MIDI Beat upon which to start the song. Songs are always assumed to start on a MIDI Beat of 0. Each MIDI Beat spans 6 MIDI Clocks. In other words, each MIDI Beat is a 16th note”

IE it has the equivalent of a PPQN=4.

But you say a Division value of 96 is giving correct results, yeah?

http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html#Seq may be of interest.

Also not trying to tell you what to do, just trying to understand what you are doing and why.

This is just confusion of terms.

I’m not looking for time, rather a “MF2T Timestamp”

Edit: Which, at first, I thought was time so the first half of the thread is me getting it wrong. It turns out a MF2T Timestamp, when using a positive integer for division, is more like “pos”.

ping kazakore, and other math whizzz’s

-- Tick to delay  
function export_tick_to_delay(tick, tpl)  
 if tick > tpl then return false end  
 local delay = tick * 256 / tpl  
 delay = delay * 100 / 256 * .01  
 return math.max(0, math.min(delay, 256))  

I get the result I want with the above equation, can it be simplified? Specifically

 local delay = tick * 256 / tpl  
 delay = delay * 100 / 256 * .01  

It converts a tick to a 0.XX value, normalized against the delay column.


Well we’ve already covered this one:

 delay = delay * 100 / 256 * .01  

The *100 and *0.01 cancel each other out so just delay/256 is needed.

And I assume the other part is converting a Tick value into a Delay value, correct? If so your “local delay = tick*256/TPL” looks correct to me.


I see both these above give you an answer in difference formats. The first will turn a Delay into a “Fraction of Line” and the second one converts Ticks in Renoise Delay value. I guess you are then going to convert this into Fraction of Line, as with the original Delay value. Correct?

If so that is again a simple divide by 256 BUT you are adding extra work by going to Delay value then Fraction of Line value. If you only want the final Fraction very simply Tick/TPL.


For this do just use Tick/TPL.

Normalised as in quantised to Delay column? OK…

-- Tick to delay  
function export_tick_to_delay(tick, tpl)  
 if tick > tpl then return false end  
 delay = tick * 256 / tpl  
 return math.floor(delay + .5) --Round** - This rounds up and leaves the integer yeah?  
 local delay = delay / 256 -- This will give you 0.xx value.  
 ??return math.max(0, math.min(local delay, 256))?? --What is purpose of this line?  

May have the command wrong as have copied it from a section of earlier code you posted I assume does this but if you want quantised to the Delay column you are going to have to convert to the Delay (as you did) then Round Off, removing decimal places, then do the covert to fraction from that. Hopefully you get what I am trying to do with the addition above even if I’ve got the code wrong as have to admit haven’t even looked properly at the API. Also changed a couple of your constant labels around. Delay used for when it is the same as a Delay value inported direct from Renoise, Local Delay for the 0.xx fractional value you want at the end.

Hope I’m making sense and not just rambling like a madman!

Cheers. I think I got it.