I am working on a script in Python to parse MIDI files (yes I know MIDI parsing libraries exist for Python but for my use case it's easiest if i make it from scratch).
The one thing I'm having a problem with is the time division. the last two bytes of the header specifies the time division, but I'm having trouble determining if a file's time division is noted in ticks per beat or frames per second. After doing some reading, it seems that the top bit of the top byte indicates which of the two the time division is noted in. What I am confused about is if the top bit of a byte is the first bit of a byte or the last bit of a byte, as well as how to read the MIDI time division entirely.
EDIT: for example, a header of a MIDI file I have is the following:
4d54 6864 0000 0006 0000 0001 0078
0078 are the two bytes that denote the time sig, but I am confused as how to interpret it.
Edit 2:
def openmidi(file):
tmbr = []
f = open(file, "rb")#opening the midi in binary mode
loopfile = True
while loopfile == True:
cb = f.read(1)
if cb != b'':#checking if there are still bytes left to read
tmbr.append(cb)
else:
loopfile = False
return tmbr
def byteread(num):#will read and return the specified number of bytes
global bytecounter
bytehold = b''
for i in range(0, num):#reads specified number of bytes
bytehold+=midibytearray[i+bytecounter]#number of increment plus the read position
bytecounter+=num#after reading is done read position is incremented by the number of bytes read.
return bytehold#after looping is done the specified bytes are returned.
def timetype(deltatimebytes):#used to determine if the time division is in ticks per beat or frames per second.
if str(deltatimebytes).replace("b'","").replace("'","")[0:2] == "00":
return True#if true the time division is in ticks per beat.
else:
return False#the time division is in frames per second.
global bytecounter
bytecounter = 0 #keeps track of what position in the file is being read.
midibytearray = openmidi("C:\\Users\\gabep\\Desktop\\Electrorchestrion\\Midis\\BONEY M.Rasputin K.mid") #array that the bytes will be stored in.
header = byteread(4)
chunklength = byteread(4)
formattype = byteread(2)
numofmtrkchunks = byteread(2)
deltatime = byteread(2)#if no tempo is assigned, 120bpm is assumed.
print(deltatime)
print("Header: "+str(header.decode("utf-8")))
print("MThd chunk length: "+str(int(chunklength.hex(), 16)))
print("Midi Format Type: "+str(int(formattype.hex(), 16)))
print("Number of MTrk chunks (number of tracks): "+str(int(numofmtrkchunks.hex(), 16)))
print("Delta time: "+str(int(deltatime.hex(), 16)))
if timetype(deltatime.hex()) == True:
print("Time signature is in ticks per beat")
else:
print("Time signature is in frames per second")