VST3 Host - mapping MIDI CC to params

Hello,

As you know, VST3 plugins don’t receive MIDI directly. They receive events (such as kNoteOnEvent events), and these events cannot and do not include MIDI CC messages, like sustain pedal messages.

In the VST3 spec, you’re supposed to query for an IMidiMapping interface, and then use this interface to map MIDI CC messages to VST3 parameters, and then automate those parameters. It seems simple enough, but JUCE doesn’t seem to provide the IMidiMapping interface, and it also doesn’t seem to provide the IPluginFactory required to search for the IMidiMapping interface.

I’ve tried using getPlatformSpecificData() to get an IComponent* and querying for IMidiMapping_iid and IPluginFactory_iid, and that didn’t work. Looking at the code, queryInterface() only returns the various interfaces that the “component” member might support.

Is there any way to do this? It seems like MIDI controller support is so fundamental to hosting a VST3, there must be a way I’m overlooking. I’d appreciate your help. Thanks!

Dan

Of course we support MIDI controller events and the IMidiMapping interface. It’s well tested and works. See this line in the code.

Forgive me, but I don’t see any way to get an IEditController (or JuceVST3EditController) from a VST3PluginInstance object. I can see that the VST3PluginInstance has an IEditController, but I can’t get it via queryInterface() on the IComponent* returned by getPlatformSpecificData(). Is there another way that my VST3 hosting application can get the JuceVST3EditController object?

Thanks,
Dan

In addition, even if I “brute force” this and retrieve the IMidiMapping interface from the VST3’s factory outside of JUCE, the IMidiMapping::getMidiControllerAssignment() function returns a Vst::ParamID value, and I can’t seem to find a way in JUCE to map a ParamID to a parameter index, which is what JUCE’s automation functions seem to take.

JUCE’s plug-in host example project doesn’t seem to send MIDI CC to VST3 plug-ins. For example, I can’t press a sustain pedal when using a VST3 instrument in the host example. But I’m certain you must have exposed the getMidiControllerAssignment() functionality in JUCE’s VST3 hosting code. I just can’t seem to find it anywhere.

(To be completely clear, I’m writing a VST3 host in JUCE, not a plug-in.)

I think you may want to read up on how VST3 works. You use the IComponent’s getControllerClassId method to get the uuid of the edit controller class. You then use the class factory and iterate through the classes until you find a class that matches that uuid.

Hi Fabian,

I’m aware of that as well. But the VST3PluginInstance doesn’t seem to expose the class factory. It sounds like there must be some way to get at it, though, from what you’re saying. Right now I’m having to call GetModuleHandle() to query the DLL for the factory function.

Also, as I mentioned, there doesn’t seem to be a way to map VST3 param IDs to param indexes, which would also be required to use getMidiControllerAssignment().

Thanks again,
Dan

Fabian,

I’ve gone ahead and modified juce_VST3PluginFormat in the following ways:

  1. It now queries for an IMidiMapping interface in grabInformationObjects().

  2. I added an additional function, setParameterAtTime(), which adds an automation parameter at a given sample position. The current setParameter() function adds all events at sample 0.

  3. I added a mapMidiControllers() function that gets called by processAudio(). This function iterates through all the MIDI messages and maps these messages to VST3 parameter messages at the correct sample time.

    The end result is that MIDI messages are now automatically mapped to VST3 parameters. It’s tested and works properly.

    Modifying JUCE’s code to achieve this functionality was the only real way to do it, the AudioPluginInstance interface just doesn’t provide functions to get the IEditController or to do sample-accurate parameter mapping. At least, I couldn’t figure out a way to do these things.

    I’ve attached my code, in case you’d like to review it and possibly integrate it into JUCE. My code is from JUCE 4.2.

juce_VST3PluginFormat.cpp (94.7 KB)

I hope this is helpful.

All the best,
Dan

Hi Dan, this is very helpful as Cubase 9 is promoting VST3 more often. Can you share a test case to demonstrate how to call these functions in pluginprocessor? Thanks.

Hi 200gaga,

The code I added is automatic – you don’t need to call anything. The test case is very simple – just load any VST3 instrument into a Juce host, such as their demo host application. You’ll find that the stock code will not let you use your pitch bend wheel to control the instrument’s pitch, but with my modification, pitch bend will work. The same holds true for the mod wheel, aftertouch, and other non-note events.

Best of luck,
Dan

1 Like

This stuff seems to be broken again – I tried loading the U-He Repro 5 VST3 into the latest version of the JUCE Audio Plugin Host and aftertouch does not work.
Any idea how to fix this