 <p>One complexity of MIDI files is <a href="http://dogsbodynet.com/fileformats/midi.html#RUNSTATUS" rel="nofollow">Running Status</a>. If there's sequence of messages of the same type and channel (eg all controllers or all notes) then MIDI can save a number of bytes by omitting the status byte. If this didn't use running status then the bytes you would see are:</p> <pre><code>00 B0 79 00 - controller 121: controller reset 00 B0 5B 00 - controller 91: reverb 00 B0 40 00 - controller 64: sustain 00 B0 07 64 - controller 7: volume 00 B0 0A 10 - controller 10: pan 00 90 3E 47 - note message </code></pre> <p>Because all the controller messages are contiguous and are for the same channel, the status byte can be omitted. As soon as there's a change of message type, the status byte has to be added again.</p> <p>If you're trying to make sense of MIDI files then I would recommend using a separate tool such as <a href="https://github.com/vishnubob/python-midi" rel="nofollow">Python-MIDI</a> or <a href="http://www.gnmidi.com/" rel="nofollow">GNMidi</a> as a sanity checker whenever there's a MIDI event you can't make sense of. These can show it as text so you can mimic what it's doing.</p> <p>EDIT: Another gotcha to be aware of is that any MIDI messages that take a length or duration parameter (eg the time in PPQN between events in a MIDI file, or the length of sysex messages or meta events) uses a variable length, so don't assume all the length fields are always a fixed length.</p> <p>Disclaimer: I wrote the MIDI export code in Sibelius 6...</p>