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.