Standard Midi File Timestamp For Delta Time

This is just a general post for anyone it may help, as when working on this it was quite hard to get sources on the net.

Basically I have been working on a personal script for some MIDI exporting, and following is some of the work for variable length values I did.

_Anyone looking for a released MIDI export tool please see conner_bws script here:_ [conner_bws MIDI Export](

Firstly thanks to Beatslaughter, who gave me this very useful link a while ago, which breaks down the basics for standard MIDI files:

This Link is not relevant to following code (which is done numerically) but there is a bitwise explanation at this site for variable length values. May be of interest.
Bitwise explanation

Eventually from the java snippet and explanations given on the skytopia website I managed to get variable length conversions working in LUA and therefore my own script. The following code includes a test conversion at the end. Hope this may help any scripters or any random googlers looking for info on this smile.gif

--Lua Code Example:

--Helper to convert dec to hex
function num_to_hex_string(num)

num = tostring(num)
num = string.format("%X",num)

if #num < 2 then
return tostring("0x0"..num)
return tostring("0x"..num) --string

--Convert midi time to decimal number

function midi_dec_time_to_normal_time(n)
local length = #n
local time = 0

for i = 1,(length - 1) do
time = time + (n[i]-128) * math.pow(2,(7 * (length - i )))

--add last byte
time = time + n[length]
return time

--Convert to midi time (reverse of above)

function normal_time_to_midi_time(t)

--if t is too large truncate to largest allowable time.
if t > 268435455 then
print("Time Gap Too Large For MIDI Standard")
return {0xFF,0xFF,0xFF,0x00}

--table to contain bytes (up to 4 allowed for timestamp)
local ts_bytes = {}
local quotient = 0

--Convert decimal to timestamp base 128 starting with last byte first.
--The last byte of a timestamp will always be below 0x80 to signal that timestamps end.
ts_bytes[1] = (t % 128) --remainder
quotient = math.floor(t/128) --quotient

--128 decimal added to each preceeding byte.
--These bytes will all be over 0x80 (0x80 to 0xFF range). Therefore
--showing there are more bytes left to read
while quotient ~= 0 do
table.insert(ts_bytes,1,(quotient % 128) + 128)
quotient = math.floor(quotient/128)

--convert all bytes in table to string
for i = 1, #ts_bytes do
ts_bytes[i] = num_to_hex_string(ts_bytes[i])
--return byte table
return ts_bytes


local test_timestamp = {0xfE,0x80,0x83,0x74}
local dec_time = midi_dec_time_to_normal_time(test_timestamp)
local back_to_hex = normal_time_to_midi_time(dec_time)

print("Decimal Time: \n"..dec_time.."\n")
print("Decimal Time Converted Back To MIDI Time: \n")

-- Number (hex) Representation (hex MIDI)
-- 00000000 00
-- 00000040 40
-- 0000007F 7F
-- 00000080 81 00
-- 00002000 C0 00
-- 00003FFF FF 7F
-- 001FFFFF FF FF 7F
-- 08000000 C0 80 80 00

I just discovered via email that skytopia is the site of forum member Twinbee, so thanks a lot to him!

It`s a small world on the web! :)