VST3, Programs and MIDI Program Changes

Following what I have read here and here, can someone please tell me what callbacks / parameters should I see being called / changed in response to a MIDI Program Change sent from the DAW?

My plug-in is an audio plug-in that also receives MIDI (but does not emit it)

Any repeatable procedure to see it triggered in any of the main DAWs would be greatly helpful.

I have tried creating the default audio plug-in project with Projucer and increased the value returned by getNumPrograms() to 128, added a member variable to hold the current program but none of the program-related callback seem to ever be called, neither in Cubase nor in REAPER (I am developing on macOS mainly).

Has someone been able to make it work somehow? Any pointers in the right direction?

For the JUCE team, is this even possible in VST3

1 Like

I’ve never really gotten this working, but you might want to look at the wrapper code where they create a VST3::Parameter struct that reports kIsProgramChange and responds to VST3 program changes in audioProcessorChanged(). Might try setting a breakpoint there to see if it’s called on program changes?

That said the VST3 spec doesn’t say that hosts should map MIDI program changes to VST3 program changes.

1 Like

Hi everyone,

Did anybody make any progress with this? It’s 2024 but I think that JUCE is still failing at this.

I’m also trying to make JUCE accept MIDI program change messages on different MIDI channels for backwards compatibility with the VST2 of my plugins and because setCurrentProgram(int index) can’t tell between different MIDI channels.

I’ve looked into it and it’s a big mess. I still can’t believe that Steinberg broke MIDI compatibility with VST3 and made it so difficult to deal with something as basic as MIDI channels…

From what I have understood by looking at juce_VST3_Wrapper.cpp:

Control messages have a dedicated method “getMidiControllerAssignment(busIndex,channel,midiControllerNumber,&paramID”
so you can actually assign the paramID (of a Vst::parameter) to a particular control message in a particular channel very easily.

Program changes though are handled separately and are received directly in a Vst::parameter with a ParameterInfo::kIsProgramChange flag.

Apparently the only mechanism to attach a certain Vst::parameter to a certain MIDI channel message is with a unitID, so you have to create a unitID for each MIDI channel and then implement tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex,Steinberg::int32 channel, Vst::UnitID& unitId) so that every channel is assigned to its corresponding unitID (the beauty of this design suggested by steinberg! :expressionless:).

However and this is the most stupid part of it, then all Vst::parameter’s assigned to a MIDI channel must be assigned to the same unitID even if they are totally unrelated (e.g. control messages and program changes).

So adding Vst::parameters of different unitID and assigning them to different channels through JuceAudioProcessor::getUnitByBus() would force us to also assign those unitID to the internal parameters to handle the CC messages, but I don’t know if I’m missing something here and I feel I have already spent too much time with this…

Wouldn’t it be worth to implement this in JUCE?
From what I can read in MIDI Program Change - VST 3 SDK - Steinberg Forums, the Vienna Symphonic Library and Blue Cat Audio got it right but it looks like every other plugin made with JUCE will potentially fail to operate correctly in the VST3 format if it was using program changes previously in different MIDI channels. There are quite a few plugins out there which have their program change support broken in their VST3 version (eg. Kontakt, PIanoteq).

Thanks for reading until here anyway!

P.S. Here’s my patch to juce_VST3_Wrapper.cpp to include program changes as MIDI messages in the plugin processBlock().

To use it make sure that you override previously:

int getNumPrograms() override { return 128; }

1 Like

I know this isn’t super helpful, but the problem isn’t JUCE, but VST3. VST3 does not support MIDI. Converting to/from VST3 event types and MIDI is lossy, and this is an example of it. It took a decade of complaining to get LegacyMidiCCOutEvent to work around parameter based hacks for receiving MIDI CC events correctly.

Well this surely a problem created by VST3 but I think this is at the core of where JUCE is useful, shielding its users from the nonsensical myriad of different plugin formats. If we managed to get this working then we could safely stop thinking about VST3 for a while and wait until it is replaced by more sensible approaches. JUCE can’t certainly do miracles and restore things the MIDI standard allSoundsOff message in VST3 but others seem to have succeeded in making multi channel program changes work, so I think it would be very beneficial.