Reputation: 69
I'm working on a project that analyses MIDI files and calculates the scale but i've hit a wall.
I can find all the notes of a single track song (i.e only one instrument is playing) but i get a weird number with multi-track MIDIs.
I made a MIDI with: 88 C notes, 32 C#, 16 D, 68 G and 36 E. When i put that MIDI file through my analyser i get: 2 C notes, 2 C# and 1 G
Here's how the MIDI file looks like when i put it into ableton: https://i.sstatic.net/wRGPX.jpg
And here's my code in it's entirety (sorry if its really ugly / bad i'm fairly new): http://pastebin.com/r7YkgqMB
It's really hard to find information about how the MIDI files are build but here are my main two sources (Maybe it's them that are wrong?): Source 1, Source 2
Relevant bit:
for i in range(0, len(midi_bytes) - 3): # iterates through the midi (without head chunk)
# Looks for start of track chunk (MTrk)
if midi_bytes[i][1:3] + \
midi_bytes[i + 1][1:3] + \
midi_bytes[i + 2][1:3] + \
midi_bytes[i + 3][1:3] == "4D54726B":
# Found a track chunk
# How long is the chunk?
len_of_chunk = int(midi_bytes[i + 4][1:3] +
midi_bytes[i + 5][1:3] +
midi_bytes[i + 6][1:3] +
midi_bytes[i + 7][1:3], 16)
# iterates through that chunk (from 8 bytes after chunk start to length of chunk + 8 (from the 8 after))
for j in range(9, len_of_chunk + 8):
# Looks for keys
bit = int(midi_bytes[j][1:3], 16)
if midi_bytes[j - 1][1] == "8" and bit <= 127:
Then it checks what the byte following the 8 (which should be the stop note command) mod 12 is (if = 0 then its a c, = 1 is c# etc.)
Upvotes: 2
Views: 799
Reputation: 8730
I had to deal with MIDI a time ago, in a very basic level : header reading and metadata extraction, standardized events recognition, unrecognized events handling ...
I wrote a really simple JS library midi-parser-js to accomplish it, and i have to say, it was fast and fun, thanks to this useful document: https://github.com/colxi/midi-parser-js/wiki/MIDI-File-Format-Specifications
I hope it helps you in the way helped me.
Fast consideration: I don't know witch are your special requisites, but, in my particular scenario, and after some research, I choose to pre-process the .mid file binary RAW data, and store it parsed, into more 'handy & usable' data structures : Objects with properties to hold the metadata -bpm, active effects, activeinstrument...- , and properties (arrays) with the Midi Events Lists )... This way It allowed me, to simply push events inside an array, and the musical-clock module, just had to analyze and schedule the "events array items"...
Upvotes: 1
Reputation: 180210
You cannot simply search for bytes with 8
in the upper nibble. A note-off message can be encoded as a note-on message with a velocity of zero, and status bytes can be omitted in certain circumstances (running status). Furthermore, bytes that encode delta times also can have such a value.
You have to correctly parse the MIDI file. (And read the official Standard MIDI Files (SMF) Specification.)
Upvotes: 3