Hosting - Korg VST3s not calling VST3HostContext::restartComponent

So when hosting Korg VST3s VST3HostContext::restartComponent() never seems to be called.

As this it is not called on preset changes then juce will never update the cached parameters. When changing presets (beginEdit(), performEdit(), endEdit(), and setDirty() are also not called here)

Also the initial cacheing of the param values is always cacheing a value of 0.0 as the plugins don’t actually seem to have set any values up at this point.

You can see this quite easily by hosting one of the Korg VST3s in AudioPluginHost.

So I tested the Korg VST3s in various DAWs including Waveform and they seem to be being notified of preset changes also they are not seeing the 0.0 values but correct values.

I have looked through the VST3 interfaces and I’m pretty sure that the only way to be notified is by restartComponent().

So:

  1. Do we think restartComponent() is being called in these DAWs and not in Juce for some reason?
  2. Is there another way of a VST3 plugin notifying the host that the param values have changed?

I have run the Korg plugins through the tests in Steinbergs VSTPluginTestHost and all tests pass.

Anyone any ideas?

Ok, the Korg plugins are sending param changes via processor->process() in ProcessAudio(), these output params are being pushed to the parameterDispatcher.

The timer based flush() in EditControllerParameterDispatcher is not calling controller->setParamNormalized() for any of the parameters.

void flush()
    {
        cache.ifSet ([this] (Steinberg::int32 index, float value)
        {
            controller->setParamNormalized (cache.getParamID (index), value);
        });
    }

Is this maybe a bug in CachedParamValues?

Ok, I think I have it now,

The cache is working fine, I’m guessing the plugins are not.

Having read up a bit on this is seems the plugin is setting the parameters, it should not update the edit controller, these parameters are then handled by the host who updates the edit controller on the main thread, the edit controller should then inform the host of the parameter changes via IComponentHandler. I wonder what they were smoking!

The Korg plugins are directly updating the edit controller, are not calling restartComponent() and are not using IComponentHandler to inform the host. The devs were in another room also smoking something.

Anyone else that is having this or similar problems I hacked the code a bit to get things working, this would never make it into the juce code so here it is:

change ‘EditControllerParameterDispatcher’ to:

class EditControllerParameterDispatcher  : private Timer
{
public:
    ~EditControllerParameterDispatcher() override { stopTimer(); }

    void push (Steinberg::int32 index, float value)
    {
        if (controller == nullptr)
            return;

        if (MessageManager::getInstance()->isThisTheMessageThread())
            controller->setParamNormalized (cache.getParamID (index), value);
        else
            cache.set (index, value);
    }
  
    void start (Vst::IEditController& controllerIn, std::function<void(Steinberg::Vst::ParamID, float)> callbackIn)
    {
        controller = &controllerIn;
        callback = callbackIn;
        cache = CachedParamValues { getAllParamIDs (controllerIn) };
        startTimerHz (60);
    }

    void flush()
    {
        cache.ifSet ([this] (Steinberg::int32 index, float value)
        {
            Steinberg::int32 id = cache.getParamID (index);
            controller->setParamNormalized (id, value);
            callback(id, value);
        });
    }

private:
    void timerCallback() override
    {
        flush();
    }

    CachedParamValues cache;
    Vst::IEditController* controller = nullptr;
    std::function<void(Steinberg::Vst::ParamID, float)> callback = nullptr;
};

in VST3PluginInstance initialise() change the ‘parameterDispatcher.start’ call to:

      parameterDispatcher.start (*editController, [this](Steinberg::Vst::ParamID id, float value)
      {
        if(VST3Parameter* p = getParameterForID(id))
            p->setValueWithoutUpdatingProcessor(value);
      });

Please can you give an example of a specific Korg plugin that is producing unexpected behaviour?

Well any of the VST3 ones really but you could start with MonoPoly.

To be honest though as far as I can see Juce is not doing anything wrong, I am not in anyway an expert on vst3 though :slight_smile:

I’m guessing the hack/workaround is also what other hosters are doing.

It is interesting in that they are working in Waveform though as I thought they were using the Juce hosting code?

Thanks, I tried with the M1 plugin and I see the same behaviour there.

It looks like the plugin is communicating the parameter value changes, but only from the audio processor. The VST3 docs aren’t super clear, but it looks like in this case, the host needs to communicate these values back to the plugin’s edit controller (we’re already doing this) and also update the host-side copy of the parameters (we’re not doing this yet).

It’ll need a bit more testing to make sure that I haven’t broken anything, but hopefully we can get a fix for this merged soon.

Hi @reuk, the code I posted above does that. Possibly not how you would want though :wink:

This change is now on develop, thanks for reporting: