Pos_To_Time() Function. (Midi)

I’m looking to create the following function, but I need mathz help.

  
function pos_to_time(pos, delay, bpm, lpb)  
 -- TODO  
 return time  
end  
  

Two problems:

I want to express time in MF2T timestamp format as seen in the PHP version of XRNS to MIDI script, but I totally forget what this is. SMTPE? Microseconds? It’s been a while.

Once that’s established, the above function receives:

  • pos = Line position. I’ve already calculated this so that the 10th line on pattern 3, where each pattern is 64, would be: 138,
  • delay = The delay column, somewhere between 0 and 255 in between two lines
  • bpm = Bpm
  • lpb = Lines per beat

Bonus points: A sane strategy to stack these. For example, if the BPM changes several times in the song. The returned time would be messed up. The PHP code I’m inspiring myself from is a bit of a mess as it also supports ticks (which this new version of the script won’t) and I’m having trouble extracting the concepts I’m looking for because it’s been too long since I looked at it.

Ideas?

Hi Bantai,

I’m looking through the code too. Starting to make sense, but it’s not the greatest joy. Heh.

The parts I want, so far, are:

  • __constructed with setTimebase($this->division) where $this->division is set to 96 and never changed.

  • getTimestamp() which is doing a lot of time travelling. I’d like to simplify it in my Lua version (and maybe add secondary functions to do the rest like check previous bpm). Also, $pos doesn’t mean what I want, I don’t think.

I’ve committed my WIP to SVN.

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   
end  
  

Is this right?

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

http://home.roadrunner.com/~jgglatt/tech/midifile/ppqn.htm

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

:rolleyes:

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.

Argh.

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!

Booya?

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

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.

Cheers.

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.

Thanks!

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  
end  
  

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?

MIDI Specification 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))  
end  
  

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.

Thanks.