So I have gotten myself in to a small pickle. In removing a SYSEX event from a MIDI file, I need to combine the pre- and post-SYSEX delta times in to a new single delta time and write that/those byte(s) in place of the original delta times. I know how to read a delta time going forward in a file. If the byte is greater than 127, keep reading until the byte is less than 127, combine values appropriately. However, if I do this going backwards, the"first" byte will always be less than 127, so how would I know how far back to go before stopping? Is this even possible? I think maybe not. For example, two SYSEX commands one after another. F0 ... F7 12 F0 ... F7 12 ... would give me two delta times of 12, adding to 24, but if I tried to read backwards I'd have F7 12, which is obviously no good.
I thought of a workaround while typing this, in that I could store the pre- and post-SYSEX delta times in their own variables as I am reading the file in, but I feel like there might be a better solution. Or am I doomed because MIDI is a linear "forward" format?
Yes, you've got a problem. A midi file makes sense ONLY when processed forwards, byte-by-byte. It may be possible to process it backwards, but it will be massively more complicated.
I take it that you're wanting to 'fix' the file without rebuilding the whole thing? Most progs that 'play' a midi file will turn the incremental delta times into absolute delta times, this is essential as the playing software will need to merge tracks. If this data is then saved back to a midi file then it's no problem to adjust for the removal of indiv events.
If you cannot do any of that, and the maths causes problems, then you might try a way to leave the existing delta time alone, in situ, and replace the actual command (SysEx or whatever, with some sort of dummy that does nothing. I suppose this depends on how many bytes the SysEx is. One of the variable length text Meta commands might be most useful, as this would have no effect on the piece playing?
Geoff
I thought about leaving the SYSEX and just dummying it, as you say, maybe by replacing the "innards" with all zeros? So the XG reset would turn in to
F0 08 43 (10) 4C 00 00 7E 00 F7
F0 08 00 00 00 00 00 00 00 F7
but I figured it would be be better to do it right and remove it altogether 😉
I am only concerned with SYSEX resets/system ONs (GM, XG, GS reset/system ON), and no other SYSEX events.
So, I've added variables to store the delta times around the SYSEX resets. So now I request assistance in reverse-engineering my delta time code :p I've been mostly decoding MIDI data up to this point, and haven't had to really encode anything. Most of what I've been doing has involved one-to-one data replacement (writing fixed MSB/LSB bank select data, fixed program change data).
[code type=markup]
d_time = 0;
process_byte = buffer_read(global.edit_buffer, buffer_u8);
if ( process_byte & 0x80 )
{
process_byte = process_byte & 0x7F;
do
{
next_char = buffer_read(global.edit_buffer, buffer_u8);
process_byte = (process_byte << 7) + (next_char & 0x7F);
}
until (!(next_char & 0x80));
}
d_time = process_byte;
[/code]
"&" is bitwise AND.
"process_byte" is the currently read-in byte, and "next_char" is the next read-in byte as long as required.
The code reads a series of delta time bytes until the read-in byte is less than 0x80, with the final result being the decoded delta time "d_time".
Having trouble wrapping my brain around doing it in reverse to encode the delta time to write the correct new bytes.
In theory, if "new delta time" > 127, save end byte to write later. Then figure out potential first byte or more if the delta time is particularly large.