MIDI CC messages in VST3?

Sure!

In JuceVST3EditController, I modified getMidiControllerAssignment like this:

    tresult PLUGIN_API getMidiControllerAssignment (Steinberg::int32 busIndex, Steinberg::int16 channel,
                                                Vst::CtrlNumber midiControllerNumber, Vst::ParamID& resultID) override
{
		AudioProcessor* pProcessor = audioProcessor->get();
		int id;
		if (pProcessor->getMidiControllerAssignment(busIndex, channel, midiControllerNumber, id))
			resultID = id;

    return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments
}

And I added this function:

		virtual void informHostOfMIDICCMappingChanges() override
	{
		if (auto* handler = getComponentHandler())
			handler->restartComponent(Vst::kMidiCCAssignmentChanged);
	}

Then, in the AudioProcessor class, I added this (in the header):

		virtual bool getMidiControllerAssignment(int busIndex, int channel,
		int midiControllerNumber, int& resultID) {
		return false;
	}

…which I override in my own processor class using the same code I had previously used in my VST3 plugin (pre-JUCE), which assigns the appropriate value to resultID for the given midiControllerNumber (assuming the channel is one I was interested in).

Then, to inform the host I needed to first add this function to the AudioProcessorListener class (header):

		virtual void informHostOfMIDICCMappingChanges() {}

…and overrode that in the JuceVST3EditController class like this:

		virtual void informHostOfMIDICCMappingChanges() override
	{
		if (auto* handler = getComponentHandler())
			handler->restartComponent(Vst::kMidiCCAssignmentChanged);
	}

To get to that function from my plugin, I added a function of the same name to the AudioProcessor class like this:

void AudioProcessor::informHostOfMIDICCMappingChanges() {
for (int i = listeners.size(); --i >= 0;)
	if (auto* l = getListenerLocked(i))
		l->informHostOfMIDICCMappingChanges(); }

…which I then can call from my plugin’s processor class.

But since the editor is the class that needs to inform the host of the changes, I forward a similar call from my editor to my processor at two points: at the end of the editor’s constructor (because I may have read in user preferences that set those mappings) and after the user edits those mapping using a component I made for that. I also set a flag in my processor after loading session data, so that the message thread can make that call in a timer callback (since it needs to be done from the message thread, not the process thread).

I think that covers the changes! Let me know if you need more info.

5 Likes