JUCE MPE Mode Configuration implementation issue

Hi there,

I’ve come across some issue when 2 different sources are emitting RPN/NRPN messages and how those are being handled in JUCE. The issue occurs when a piece of hardware sends an NRPN message and takes advantage of the Running Status feature. In this specific case, it emits the Parameter Number (on CC99 and 98) and the Param Value on CC6 (MSB) initially. It will then subsequently only send the Param Value’s MSB on CC6 (to limit the amount of data sent).

In JUCE the MidiRPNDetector class allows for the running status implementation. It buffers the Parameter Number portion of the message, and accepts subsequent Param Value changes without the Param Number needing to be resent. An issue occurs when another source is sending stripped version of RPN/NRPN version - i.e. just CC6 messages - but associated with another parameter number. This results in the wrong parameter being updated at the receiver end.

The JUCE MPE Mode Configuration implementation uses a MidiRPNDetector object to read in MPE layout config changes (RPN 6). Currently, once a config message has been read - the MidiRPNDetector object remains active and ready to receive any further Param Value (CC6) changes or increments. The MPE layout can then be erroneously updated if a CC6 message arrives from another source.

Is there any objection to me raising a PR to update the MPEZoneLayout class, to reset the MidiRPNDetector object once the RPN message has been successfully processed? Thus closing the door on any further erroneous param value changes.

Laurent

This sounds like an important fix to me. I have NRPN on the horizon for some of my projects so I’m quite interested in your experience with this - and the subsequent fix you propose. I’d suggest pushing a PR and letting your finding make its way into main.

The MIDI 1.0 spec says the following:

After the reception of Non-Registered (or Registered) Parameter Numbers has been enabled, the receiver should wait until it receives both the LSB and MSB for a parameter number…
The receiver should be able to respond accordingly if the transmitter sends only an LSB or MSB to change the parameter number.

I interpret this as meaning that, if we send Bn 64 06 Bn 65 00 to select the MPE Configuration parameter, then we should remember the MSB and LSB of this parameter number. If we then send a parameter number LSB message, Bn 64 00, then this should select the master pitch bend range parameter, with no need to send the parameter number MSB again.

Resetting the MidiRPNDetector detector would cause it to forget the LSB and MSB of the selected parameter number, so this use-case would fail.

The spec also says:

It is recommended that the LSB and MSB be sent each time a new parameter number is selected

It sounds like the problem is caused by combining two MIDI streams, where each stream attempts to modify a different registered parameter without selecting the intended RPN each time.

How are the MIDI input streams combined? Are you relying on the OS to combine the streams, or do you combine them yourself? If you’re doing this yourself, then I think the correct way to implement this is for the combiner to maintain a separate RPN state for each of the input streams, and also for the output stream. Whenever a data-entry, data-increment, or data-decrement message is encountered on either input stream, if the selected RPN on that input differs from the selected RPN on the output, then insert additional messages in the output stream to select the correct RPN.

I agree that the Midi 1.0 spec with regards to RPN and NRPN messages should allow for receiving individual MSB and LSB messages after the Parameter value portion of the message has been received. This is the general use case of RPN/NRPN messages. However in the specific case of MPE MCM config message, the specification states that for MCM config message the LSB is ignored:

The MPE Configuration message (AMEI/MMA CA-034) is defined as Registered Parameter Number “00 06”. The MSB of Data Entry represents the number of MIDI Channels assigned, as explained below. The LSB of Data Entry is not used.

So once the MSB data entry (CC6) portion of the RPN message has been received, there is no need to wait for an LSB message - as it is not used as part of the MPE configuration.

I think the correct way to implement this is for the combiner to maintain a separate RPN state for each of the input streams

I had initially hoped to handle it this way, but the Midi streams are being combined at the DAW level (in this case Ableton) before being received by our plugin - so there’s no way to differentiate between streams and handle RPN states for different sources from within our plugin.

As an alternative, adding a member function to the MPEZoneLayout class to reset the MidiRPNDetector object would be another (and safer) approach perhaps?