How to use restartComponent and which flags are the right one, when changing all characteristics parameters except size

Hi,

This is Erez from Waves Audio, a SW plugins engineer.
We would like to consult about an issue we couldn’t find enough documentation in the SDK.
We see very different behaviors under different hosts.

The Issue:
We have a plugin with a special feature that need to make change in almost all of its controls/parameters (ex, flags, value, title …)
When the user triggers specific action, we do the following:

  1. Change all parameters value, title and flags in the plugin.
  2. Calling on each parameter that changed to EditController::beginEdit, EditController::setParamNormalized, EditController::performEdit; and EditController::endEdit;
  3. Calling to restartComponent(Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged);
    Important Note! This flow shouldn’t affect on the number of the parameters, meaning the number of parameters we declared in the instantiate, remain the same.
    While doing this we came across issue in a good and popular host. In this host after this flow we received from the host different values to parameters than we declared and changed in the previous steps .
    After a session and debugging on their side, they asked us to do the follow steps, since our flow is not correct and in this stage he doesn’t recognize our parameters.
    They suggested flow:
    Call restartComponent(Steinberg::Vst:: kReloadComponent); and when the host calling to setActive() with false only then we need to load our preset and change all our parameters.

This suggested flow causes each host react differently (Some will crash, some will do nothing and obviously the host that suggested this works…).

After this little prolog, I guess my questions are:

  1. What is the right way to support our feature, how to notify the host about many parameters that changed, title, flag(automated), value etc’.
  2. When and what are the right flags to use in restartComponent. Is this function can be called any time from any thread or there are rules for that? And is it enough to call with Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged or we need the Steinberg::Vst:: kReloadComponent flag

Thanks

Some related threads:
https://sdk.steinberg.net/viewtopic.php?f=4&t=642
https://sdk.steinberg.net/viewtopic.php?f=4&t=641

Hi

  1. When you plug-in changes all or partially the titles or units and its values of its parameters you should call:

restartComponent (Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged);

See for meaning of the flags: https://steinbergmedia.github.io/vst3_doc/vstinterfaces/namespaceSteinberg_1_1Vst.html#a17867782006f9fdb2b72c16b0420bed5
and https://developer.steinberg.help/display/VST/Parameters+and+Automation

  1. restartComponent should be called in the UI Thread.

  2. Steinberg::Vst::kReloadComponent (if supported by the host) will unload totally the plug-in and reload it…

Yes reload component should not be necessary, restartComponent (Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged) already implies that the plugin will be deactivated and re-activated right?
Then the plugin should load the new preset and expose the new parameters after setActive(false). Is that correct?

I think it is pretty much obvious because if the new preset implies loading files from disk, allocating memory, initializing and computing structures etc… this can’t happen while the plugin is processing.

Hi Yvan,
Thanks for your quick response,

I do have few more questions about it:

  1. What should I expect from the host after calling restartComponent (Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged)
    After this stage the host can continue calling to the process and automation?
  2. What function should I expect from the host after those stages, will setActive (false) will be called and only then we need to change our value,
    or before calling restartComponent?
  3. When and how do the host know about our new titles/values/flags ?

Thanks

Hi,
a call to componentHandler::restartComponent(kParamTitlesChanged| kParamValuesChanged) will only trigger the host to invalidate its caches for the parameter titles and values. It will not send parameter changes to the processor in its process function and it will not deactivate and activate the processor.

One question for Erez:
What do you expect to happen in the host when the user of your plug-in triggers the action and the host is in write automation mode for your plug-in?

Cheers,
Arne

Erez, in your case not only the parameter title/value/flags changes, but also the parameters count and parameter index/id mapping as well right?

Yvan and Arne, if I understand correctly kParamTitlesChanged| kParamValuesChanged is only for cosmetics and does not require to activate/deactivate? So if the number of parameters or the parameter index to id mapping change a reload component would be necessary right?

Hi Alexander,
No in our case, we are not changing our parameters count only the values, titles and flags. (Its in title of this post)
But when we call to kParamTitlesChanged| kParamValuesChanged and during changing all value, titles and flags, we don’t want that the host will call us with previous value, meaning before the change.

Hi Arne,
This case is handled in our side, we are ignore all value (since those are not valid any more) until we finished our routing and after we change all parameters and call to kParamTitlesChanged| kParamValuesChanged only then we refer to the automation events again (we know and our users know that if they write automation and after it load a preset that might change those parameters, the automation they written are not valid any more)

Arne,
So if I understand it right we need to change all those value, titles and flags before calling kParamTitlesChanged| kParamValuesChanged ?
What will be the right way to do it for many parameters ?
Currently we are calling for each parameter with
EditController::beginEdit,
EditController::setParamNormalized,
EditController::performEdit and then EditController::endEdit.

Only after we finished this routing for each parameter that we want to change only then we are calling restartComponent(Steinberg::Vst::kParamTitlesChanged | Steinberg::Vst::kParamValuesChanged);

Is it the right way?

In your case the latency might change right?

Yes it might changed latter this flow, and in case it changed we are calling to
restartComponent(Steinberg::Vst::kLatencyChanged | Steinberg::Vst::kParamValuesChanged);

Hi Erez,
you don’t need to call for every parameter beginEdit, performEdit, endEdit. If you do this, then the parameter values are already known in the host and you don’t need to call restartComponent with kParamValuesChanged. If you do this only to tell your processor to use these new values, you can also send your processor a custom message with all the new values and set them yourself in the processor.
You just have to make sure that before you make a call to restartComponent with kParamTitlesChanged|kParamValuesChanged, that your controller will return the correct information afterwards.

Hi Arne,
By saying “custom message” what do you mean ?

Here is a partial code that we do before calling restartComponent with kParamTitlesChanged|kParamValuesChanged
Without this code the automation list remain the same and also the value in the host doesn’t change
Is that your meaning (only without the calling of beginEdit, performEdit, endEdit)?

EditController::setParamNormalized(hostIndex, NEW_VALUE);

Steinberg::Vst::Parameter* param = getParameterObject(hostIndex);
Steinberg::Vst::ParameterInfo& info = param->getInfo();

Steinberg::UString(info.title, tStrBufferSize(Steinberg::Vst::String128)).assign(USTRING(“NEW_NAME”));
info.stepCount = NEW_NUM_STEP;
info.defaultNormalizedValue = NEW_VALUE;
info.flags = NEW_AUTOMATION_FLAG;

If you now call restartComponent with kParamTitlesChanged|kParamValuesChanged, the host should have the new parameter names, flags and values. The host will not send the values to your processor in the process call this way.
So if you need them there, but without going thru the beginEdit, performEdit, endEdit methods, you could allocate an IMessage with IHostApplication::createInstance() fill it with the necessary information and send it via IConnectionPoint::notify to your processor.

Why shouldn’t the host sends the new parameter values to the processor after kParamValuesChanged?

I think the question is: Why should it. As far as I can tell this is by design, restartComponent with kParamValuesChanged is a message from the plugin to the host, notifying the latter that its parameters have changed internally.

When the GUI changes a parameter it calls performEdit() which then sends the param update to the processor. So the host is responsible for keeping the processor and UI in sync.

A plug-in calls restartComponent (kParamValuesChanged) to let the host know about an internal change of its parameter values.
If you want to communicate changes from the controller to the processor via the host, then you have to use beginEdit, performEdit, endEdit.
So the host wont transfer changes when restartComponent (kParamValuesChanged) is called.

Cheers,
Arne