I am encountering an issue related to SysEx packetization when sending data from a JUCE application to external hardware.
With JUCE 8.0.12 running on Sequoia 15.3.1, a 21-byte SysEx message is incorrectly packetized. The first two packets (corresponding to the first six bytes of the SysEx message) use the correct 0x04 type byte. The third packet, however, uses a 0x0F type byte and contains only the 9th byte, followed by two zero bytes. The fourth packet then returns to a 0x04 type byte and carries the 10th, 11th, and 12th bytes. This behavior breaks the SysEx message.
The snoize midi monitor display the message correctly.
I do not observe this issue with JUCE 8.0.8. and I have not tested the intermediate versions.
Is this a known issue? Is anyone else experiencing the same problem?
I’ve been fighting what looks like the same problem on macOS, and your description gives it away. A 0x0F packet in the middle of a SysEx is exactly what Apple’s class-compliant USB-MIDI driver does in this case.
USB-MIDI packs SysEx into 3-byte packets (CIN 0x4, then 0x5/0x6/0x7 for the last one). If the driver gets a buffer from CoreMIDI that stops partway through a SysEx and its length isn’t a multiple of 3, it doesn’t hold onto the leftover 1 or 2 bytes until the next buffer arrives. It sends them straight away as single-byte packets (CIN 0xF). A lot of interfaces and synths don’t handle that and drop or garble the message. Others handle it fine, which is why it only shows up with some hardware.
That’s also why MIDI Monitor shows your message as correct. It sees the byte stream at the CoreMIDI level, before the driver breaks it into USB packets, so the data really is correct at that point.
This is an old one. There’s a JUCE thread from 2013 where every 256th byte went missing because JUCE sent SysEx in 256-byte chunks (256 = 3×85 + 1), and changing it to 255 fixed it:
I can’t tell you exactly what changed between 8.0.8 and 8.0.12. The send code in juce_CoreMidi_mac.mm looks basically the same in both. Since 8.0.8 is fine, though, something upstream must now be splitting the SysEx at a point that isn’t a multiple of 3, whether that’s the UMP conversion or how the message gets chunked before it reaches CoreMIDI. On macOS 11+ JUCE sends through MIDISendEventList, so the bytes the driver finally sees also depend on CoreMIDI’s own UMP-to-bytestream conversion. If you can, try the same message on 8.0.8 and 8.0.12 on the same Mac, and send it from SysEx Librarian to the same hardware. That should tell you whether it’s JUCE or the OS.
For what it’s worth, I hit this in Max, which has its own MIDI output code, and fixed it with a small external that calls MIDISend directly with 255-byte buffers. It’s been solid on the interfaces that were failing, so if you need a workaround now, controlling the buffer sizes yourself should work.
Good call on the multiple-of-3 fix. That’s exactly the cause. One catch, though: in current JUCE that 256-byte chunking is only used on macOS 10.x. On macOS 11+ juce_CoreMidi_mac.mm always takes the onlyNew path, which sends UMP through MIDISendEventList, so that line never runs on Sequoia. The 8.0.12 problem must come from how the new path splits SysEx before CoreMIDI converts it back to bytes for the USB driver. I’d still change 256 to 255 for older systems.