starnges that an destructor calls initialize
saw you have a dump mode (but it is a cooked dump not a raw dump)
not handling all values between 0xf1 ... 0xff:
x not used
syntactically wrong as you should use the boolean && not the bitwise &and it can be faster
many loops use int i; you could check if uint8_t is enough ?
So many #if 's makes me wonder if you could not better
not handling all values between 0xf1 ... 0xff:Yes, correct. These values are real time valuies that appear in a MIDI live stream as control messages but are not valid in a file - 0xf1 is undefined, 0xf2 is Start a sequence, 0xf3 is Continue sequence. 0xf4 is Stop sequence, 0xf5 is undefined, 0xf6 is Active Sense (like a watchdog timer), 0xff is Reset System. All others in this range should be processed.
I take your point, but they are actually not allowed to exist in the stream according to the Standard MIDI File documentation.