JUCE Problem with MPE Legacy Mode

There appears to be a problem with the way the MPE Synthesiser is handling pitchwheel bends. This is evident even in the included JUCE tutorial project “MPEDemo”.

In Legacy Mode, the pitchwheel bends should be applied globally to all notes. However, it is only actually applied to the most recent active note.

Eg. If you play a C4 and G4 together with a regular MIDI keyboard, hold them down, and then do a bend, only the most recently pressed of the two will bend.

This is obviously not the intended function of the legacy mode, is it? Shouldn’t both notes bend simultaneously?

The sustain pedal function is being properly applied to all notes, but not the pitchwheel bend.

Is there any fix?

There are more than one legacies :wink:

The LegacyMode is not MPE off, but the older MPE mode. There was an update, which allows split keyboards. Some Information is given in MPEZoneLayout:

An MPE device can have up to two zones: a lower zone with master channel 1 and allocated MIDI channels increasing from channel 2, and an upper zone with master channel 16 and allocated MIDI channels decreasing from channel 15. MPE mode is enabled on a device when one of these zones is active and disabled when both are inactive.

To turn off, use MPEZoneLayout::clearAllZones() (if I read that correctly)

1 Like

Thanks daniel. So the legacyMode is not what I want then to disable MPE on an MPE synth (ie. for using with an old style MIDI keyboard).

I tried the suggestion to clearAllZones as well as to set the MPE synthesiser to a default MPEZoneLayout, but neither actually seems to work. The synth does not output audio of any kind from a regular keyboard in this case.

Here’s what I have in my pluginProcessor.cpp for switching the MPE mode from a button:

void AudioPlugInAudioProcessor::updateMpeMode()
         	MPEZoneLayout zoneLayout;
    } else {
        MPEZoneLayout zoneLayout;
        zoneLayout.setLowerZone(15, pitchBendChannel, pitchBendGlobal);

Only by using the line mMpeSynth.enableLegacyMode(pitchBendGlobal); can I get any audio from a regular MIDI keyboard.

Am I missing something? Should an MPE Synthesiser with no zones (ie. “MPE disabled”) still make sound or behave like a non-MPE synthesiser? Or should it just be dead?

I’m sorry, that’s what I would have done as well.
I hope someone from the ROLI people can shed some light here…
Good luck

Yeah thanks. Currently the only way I can get a synthesiser to be properly switchable between MPE and non-MPE mode is by building an MPESynthesiser and a regular Synthesiser and then switching them in the pluginProcessor.cpp like this:

void AudioPlugInAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
    ScopedNoDenormals noDenormals;
	if (mpeOff) {
		mySynth.renderNextBlockCustom(buffer, midiMessages, 0, buffer.getNumSamples());
	else {
		myMpeSynth.renderNextBlockCustom(buffer, midiMessages, 0, buffer.getNumSamples());

But I don’t know if that’s the way we’re supposed to build backwards compatible MPE synths. It’s obviously pretty redundant.

Any JUCE folks that can clarify?


When using legacy mode with the MPEInstrument, you’ll want to enable the MPEInstrument::allNotesOnChannel tracking mode for pitchbend (and probably pressure tracking and timbre, too) like so -

instrument.setPressureTrackingMode  (MPEInstrument::allNotesOnChannel);
instrument.setPitchbendTrackingMode (MPEInstrument::allNotesOnChannel);
instrument.setTimbreTrackingMode    (MPEInstrument::allNotesOnChannel);

This should enable the behaviour that you want.

1 Like

Thanks ed! That gets me a lot closer. However, there is still one remaining problem with that. The global pitch bend this is adding will only apply to notes that have already been started before the bend occurs.

ie. If I play two notes, then bend up as much as possible, then play a third note, the third note will have no bend applied to it.

The bend in this case should be applied to all notes, as it is with a global bend in true MPE mode.

Here is my basic code for the bends in my MPE Synth Voice:

void notePitchbendChanged() override {
		currentNotePitchBendAmount = currentlyPlayingNote.totalPitchbendInSemitones; 

This function is also run at note start:

void noteStarted() override

The variable currentNotePitchBendAmount is then used to calculate the output frequency of the synth. It works fine in MPE mode. So I’m not sure why the bend is not being applied properly in Legacy mode.

ie. In Legacy, bends only seem to be transmitted to voices if they occur while those voices have actively playing notes.

Is there any fix? Thanks again.

Just want to bump this and report that I’m hitting the same issue with new notes not catching the current pitch bend value until it changes. This is in Legacy Mode.

hmm … still an issue?