JUCE
JUCE copied to clipboard
CC MIDI sending bug : some CC can't be sent on MacOS Big Sur
Hello, I've come accross a very strange bug that I can't wrap my head around.. I'm working on this software : http://benjamin.kuperberg.fr/chataigne that is able among other things, to send midi control changes.
The software is mature and working well, relying for this part on the JUCE Midi system, and for some reason, only on MacOS Big Sur : sending on any Midi device (tested IAC driver, Midi fighter twister) : CC Channel 5, Number 32, Value 127 doesn't work, but Number 31 will.
So to clarify :
- I'm on a local develop branch that is following the upstream develop branch (I may be few commits late, but I didn't see any Midi related commit between them)
- Sending any CC from Windows (10) is working, sending any CC from MacOS Catalina (VM 10.15 and real laptop 10.12) is working
- Sending most CC from Big Sur is working, except few numbers (any channel) : I have seen number 6, 32 and 38 not working. Maybe higher numbers will have problems too.
- I have tested as well SendMIDI that is based on JUCE 6.0.5 : https://github.com/gbevin/SendMIDI and I have seen the exact same problem.
- I have tested on Max/MSP 8 (which I assume is still based on JUCE) and the problem is not here.
I'm curious to know if anybody on Big Sur has this kind of problem, even from the JUCE demos, couldn't test as we're in a rush at the end of a project. I couldn't debug on the problematic laptop for the same reason.
Thank you !
I don't have a Big Sur machine here for testing, but I tried to test this on Monterey by performing the following steps:
- Install the snoize MIDIMonitor tool. Open it, and check "Act as a destination for other programs".
- Modify the JUCE MIDIDemo app so that the timerCallback calls:
for (const auto faulty : { 6, 38, 98, 99, 100, 101 }) sendToOutputs (MidiMessage::controllerEvent (1, faulty, 64));
When I run the modified MIDIDemo, all the messages seem to get through to the MIDIMonitor instance without problems.
Note that some CC numbers have "special" meanings in MIDI 1.0, and should not be assigned for general-purpose use.
Big Sur is the first version of macOS to support the Universal MIDI Packet format, and deprecates the old bytestream format functions. In the official documentation for Universal MIDI Packets, which specifies translation between MIDI 1.0 and MIDI 2.0 protocol messages, we find this:
Individual use of controllers CC 6, 38, 98, 99, 100, and 101 do not translate to the MIDI 2.0 Protocol, unless they are properly formed RPN/NRPN messages.
My hunch would be that the output is using the MIDI 2.0 protocol for some reason, and that the system is caching these RPN/NRPN components so that it can send a MIDI 2.0 RPN or NRPN packet, instead of individual MIDI 1.0 controller change packets.
Could you try sticking a breakpoint on juce_mac_CoreMidi.mm:91 and stepping into getProtocolForEndpoint to see whether the endpoint is requesting MIDI 1.0 or MIDI 2.0 protocol?
It would also be helpful to know whether MIDIMonitor picks up the problematic controller changes on your Big Sur machine.
Interesting ! High chances this is the cause of the problem. Is there a way to force it in JUCE ? Unfortunately I don't have a lot of time right now to test out more, but I think a lot of MIDI controllers have arbitrary CC mapping, not caring about MIDI 2.0 special stuff, so being able to force use of a specific midi version from JUCE would be very useful do keep things running as they should !
Is there a way to force it in JUCE?
Not at the moment. Currently, JUCE will just try to use whatever protocol is requested by the endpoint.
I think a lot of MIDI controllers have arbitrary CC mapping, not caring about MIDI 2.0 special stuff
These controller numbers had special meanings before the introduction of MIDI 2.0 - their use is documented in the original MIDI 1.0 spec. It's probably a bad idea to allow these controller numbers to be used for a custom purpose - when you do need to adopt MIDI 2.0 support, you'll need to avoid using these controller numbers because they won't translate to MIDI 2.0.
In addition to the RPN/NRPN/data-entry controllers, there are also special 'bank select' controllers, numbered 0 and 32. From the MIDI 1.0 spec:
Control Change numbers 00H and 20H are defined as the Bank Select message. 00H is the MSB and 20H is the LSB for a total of 14 bits. This allows 16,384 banks to be specified. The transmitter must transmit the MSB and LSB as a pair, and the Program Change must be sent immediately after the Bank Select pair.
This might be why you were previously seeing problems with controller 32.
The full set of implementation recommendations for MIDI 1.0/MIDI 2.0 conversion is as follows:
- Devices sending the MIDI 2.0 Protocol should not transmit Control Change messages with indexes of 6, 38, 98, 99, 100, or 101. Instead they should transmit the new Assignable Controller messages and Registered Controller messages (see Section 4.2.7). These new messages are more friendly to send, to receive, and to edit in a sequencer.
- Devices sending the MIDI 2.0 Protocol should not transmit Control Change messages with indexes of 0 and 32. Instead they should transmit the new MIDI 2.0 Program Change message (see Section 4.2.9).
- Devices receiving the MIDI 2.0 Protocol should ignore Control Change messages with indexes of 0, 6, 32, 38, 98, 99, 100, and 101.
the question should be how RPN respective NRPN commands are distinguished from nonRPN/nonNRPN aka 7bit CC. Usually done by analysing LSB and MSB of the stream. If the directly following command does not match the scheme then it is not RPN/NRPN and can be interpreted as CC. Which in turn applies also to all CC that could indicate that some data that belongs to a former RPN/NRPN command are data or just CC commands which is why MIDI 1.0 Protocol has two different values pairs to indicate RPN or NRPN as well as data. Not the other way around! Because if you interpret any CC that just fits partial to some RPN/NRPN scheme then your software will also act strange when you connect some mixer that follows MackieControl protocol and lots of others who make use of NRPN. In other words - when you make use of CC 98, 99, 100, and 101 and also allow RPN/NRPN devices you also have to implement a skipping algorithm for data that could be send following those indicators.
And the encountered behaviour just tells that JUCE does not skip the data accordingly which means with macBigSur where the os is exposing this inconsistency you have that behaviour.
The whole thing specially applies to devices who support both, 7bit CC as well as RPN/NRPN. So just setting those commands faulty or non valid to use is simply, well wrong!
I think this deserves further thought, based on how MIDI is used in computers in the real world.
Various generic MIDI hardware controllers use 7-bit CCs in a generic way with no concern for the suggested purposes noted in the MIDI 1.0 spec. For instance, my QuNexus controller, in factory default setting, uses CC 101 for one of the pad pressures. And I have used that pad's CC 101 to control various software without problem, and I have projects that rely on CC 101 to keep working.
Now all of a sudden, part of my hardware controller stops working if routed through a JUCE app on macOS.
The MIDI 2.0 spec focuses on reverse compatibility with the extraordinarily long-lived MIDI 1.0 spec. It does this by requiring MIDI endpoints to communicate using a 1.0-compatible method and agree to use MIDI 2.0 features before sending 2.0 messages over the wire. So unless all parties agree that they can handle 2.0, everything stays in protocol 1.0.
In this spirit, it is my opinion that JUCE should refuse to negotiate MIDI 2.0 features / force 1.0 mode unless the user of the JUCE API has opted into protocol version 2.0 for that connection. This way all software will continue to function as it has, until such time as developers are ready to start using 2.0 features and deal with the 1.0 incompatibilities (and user bug reports) that arise.
Perhaps in the future, if 2.0 becomes widespread and 1.0 an anachronism, the default could switch to protocol 2.0 and require opt-out to force backward-compatible 1.0.
I am encountering a similar issue on macOS Monterey. I wrote up full details here:
https://forum.juce.com/t/bug-with-midioutput-and-ccs-when-sent-to-iac-driver/55127
In my case this is only affecting IAC Driver MIDI ports. And the full list of missing CCs is: 0, 6, 32, 38, 98 - 101
I completely agree with @gmatters on this! As a developer of an older MIDI 1.0 spec'd project, I would expect the sending of CCs to function as they always have.