Hosting VST3 with JUCE: getting incorrect parameter reference from specific VST3 plugins

Hi,
we developed a host plugin for VST, AU and VST3. We are using JUCE 6.0.7.
When hosting specific VST3 plugins (and a few AU) the reference to the parameter given from JUCE when trying to a get a specific parameter is not the parameter chosen.
We get the parameter reference by clicking on the hosted plugin’s parameter.
For example, trying to link the Cutoff Freq. it links the LFO rate. Trying to link the Attack, links the Release and so on.

This happens only with all VST3 U-he plugins and a few AU. VST2 is linking correctly. Although, U-he plugins link correctly in all DAWs and other hosts.
We noticed that other hosting plugins/apps made with JUCE have the same issue.

We reached out to U-He and they were kind enough to give us some insights,
“The id you’re looking for is the first member of the Steinberg::Vst::ParameterInfo structure you get via AM_VST3_Processor::getParameterInfo.”

It seems that In VST3 the identifying index is defined by “id” field in the Steinberg::Vst::ParameterInfo structure, which can diverge from the order in which parameters are reported to the host.

Any idea of what may be causing this and any advice on how to solve it?

Thank you very much!
Em

1 Like

I fixed a similar-sounding bug about a month ago:

Could you try testing with the current JUCE develop branch and see whether the issue is resolved?

Thank much, we will try this out and post an update.

YES!!!
that fixed it. We only tested on Windows so far, but will test on Mac tomorrow.
I think some AUs were having the same issue, i am not sure if this change will fix them as well.
Will post the findings soon.
So, from our tests, this fixed the issue with U-He plugins and Fabfilter Pro-Q3 adding a second band (probably because these parameters are added as more bands are added in the plugin)
Thanks much!

Great, glad it seems to solve the issue.

The patch above won’t affect audio unit hosting. If you run into any problems with audio units on the develop branch, please create a new issue and let us know which plugins are broken, and in what way.

We tried to build on mac using the JUCE 6.0.8 4c133c2 develop but we get this error:
JUCE/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm:1304:41: error: no matching constructor for initialization of ‘CFObjectHolder’ (aka ‘CFObjectHolder<const __CFString *>’)
CFObjectHolder contextName { properties.name.toCFString() };

Any ideas on how to fix this one?
Thanks much!

We’ve not seen that on our CI systems. Which version of Xcode are you using? Which C++ language standard are you targeting?

We are using Xcode 12.5, C++ 20 via cmake on Clion.

We added 2 constructors in juce_mac_CFHelpers.h so that we can build.
CFObjectHolder(CFStringRef pString) {

}

CFObjectHolder(CFPropertyListRef pVoid) {

}

We were able to build the plugins and tested the original issue with the wrong linked parameters and the problem is resolved.

A quick update, just to keep in mind in the final release of 6.0.9, we went back to 6.0.7 because some things were not working as expected when using the developer branch of 6.0.8
The problems were:

  1. Our nested menus stopped working, the menu items were showing but did not function on items that had to do with file operations (opening and saving files).
  2. Were getting some random crashes when hosting plugins.

Thanks for the update. These sound like quite serious issues, and I’d like to try tracking them down. Please can you provide some more details about the broken behaviour, and some steps to reproduce it? For item 1, it would be useful to know see the code snippet you are using to launch the file chooser. For item 2, it would help to know which plugins are causing issues when they are hosted, and whether the crashes are reproducible in other JUCE hosts (such as the AudioPluginHost).

We updated to Juce 6.1.0 and this is fixed.
Thanks much!

Although when linking parameters the parameter reference is correct,
AU and VST3 plugins from some vendors (For example, U-He Diva and Arturia Jun-V6) when we change the preset on the hosted plugin, we get a program change notification but the parameter values in the getParameters() array is not updating.
This problem appeared with JUCE 6.1.0, with 6.0.7 we did not have this issue.
Do we need to change something in our code to get the updated list of parameters when a preset changes?

Thanks for reporting, I can reproduce the issue with the VST3 versions of the plugins you mentioned, and I have a potential fix which should be on develop shortly.

I see that parameter values are not updated in the AudioPluginHost when changing presets via the editor in the AU version of Jun-6 V, but I checked with JUCE 6.0.7 and it didn’t work there either. I also tried some other hosts (Reaper, Live, Carla) and those didn’t update their parameter views in response to program changes in the plugin. Logic does seem to update its “smart controls” view when changing programs, but doesn’t update non-automated parameter values displayed in the automation lane.

I’ve spent some time searching and reading the AU documentation, and at the moment it’s not clear how Logic is achieving this. I think I would probably expect changing parameters to trigger an AudioUnitEvent describing the parameter change, but I don’t see this when changing the program in Jun-6 V. If the AU API has an analog to the VST3 kParamValuesChanged I haven’t been able to find it yet (if anyone is aware of such a feature, please let me know!).

2 Likes

You are correct regarding the AU. We just tested with Jun V6 directly in Ableton and it does not update the linked params when changing presets.
In Logic 10.6.3, changing presets on the Jun V6 does not change smart controls.
Also, when moving a smart control does not change the linked parameter, but when moving a linked parameter it does change the smart control.
For the AU this seems like a problem with the Jun-V6 plugin because it does not work properly in any DAW.

U-He Diva AU in Logic and Ableton does work properly with smart controls/linked parameters and also moving smart controls changes the target parameter and the opposite.
In our AU host (JUCE 6.0.7 and 6.1.0) Diva AU also changes parameters when presets change.

The problem of not updating params when changing presets in general seems to be only with hosted VST3 plugins.

In our Host using JUCE 6.1.0, when hosting U-he Diva AU, there is still a problem when linking correctly some parameters (not all). For example, when trying to link the Waveform of osc1 it links the Vibrato parameter. When linking Feedback, it links the FM mod source. When hosting Diva VST3 this issue is fixed in 6.1.0.and all parameters link correctly.

Thanks, I took another look at U-He Diva AU in the AudioPluginHost and I think I can reproduce the problem you’re seeing:

  • Open the AudioPluginHost and load U-He Diva AU
  • Open the plugin’s custom editor, and also the generic parameters view
  • Click on “Modifications” in the editor, then change the “OSC FmModSrc” parameter. The equivalent parameter in the generic display should update, but does not.

I’ve put together a potential fix, which will go on develop shortly after the next bufix release in a week or so.

If this issue is different to the problem that you were seeing, please let me know and provide a set of steps to reproduce the problem, ideally in the AudioPluginHost.

I was able to reproduce it in the J6.1.0 AudioPluginHost. Yes, this is part of the problem but not all of it.

Also, it is easy to see it with the Waveform of the first Oscillator. For instance, preset HS Albert Hall Mini, has the triple VCO, move the Waveform of the first Oscillator, it does not move the Shape1 slider in the generic params view.

Here is an unlisted video to take a look Linking Parameters AU Diva - J6.1.0 - YouTube

Clicking on Feedback and then on the selected rotary encoder is linking them and automatically gets the parameter name. In this case, instead of getting the name Feedback, it gets the name FreqMod2Src. Moving the linked encoder changes the FreqMod2Src instead of the Feedback param. Moving Feedback on Diva moves the linked encoder, but the movement range is not linear as it should be.
There is a second example with Waveform. Linking the Waveform, links Vibrato and the encoder now controls Vibrato. Moving the Waveform on Diva, controls the Vibrato encoder of the host.
This was exactly the problem with VST3 that has been fixed in 6.1.0

I’m running into an issue (now on JUCE 6.1.0) that seems to be related to this commit. I’m trying to validate my plugin using the pluginval tool, and the validation for VST3 is failing whenever the plugin calls updateHostDisplay() (AU validation passes without issue).

From updateHostDisplay(), the VST3 wrapper runs into this code where the program parameter can be updated. The interesting thing here is that programParameterIndex is equal to -1 (not sure why, but it seems like it’s been that way for a long time).

if (auto* programParameter = audioProcessor->getProgramParameter())
{
    const auto programParameterIndex = programParameter->getParameterIndex();
    const auto programParameterId = audioProcessor->getProgramParamID();
    const auto currentProgram = pluginInstance->getCurrentProgram();
    const auto paramValue = roundToInt (EditController::normalizedParamToPlain (programParameterId, EditController::getParamNormalized (programParameterId)));

    if (currentProgram != paramValue)
    {
        beginGesture (programParameterId);
        paramChanged (programParameterIndex, programParameterId, EditController::plainParamToNormalized (programParameterId, currentProgram));
        endGesture (programParameterId);

    flags |= Vst::kParamValuesChanged;
    }
}

However, when the paramChanged() from above get’s called, the parameter index is propagated through to this member function in CachedParamValues, where it gets cast to an unsigned int. So now the -1 becomes a really large. positive number.

void set (Steinberg::int32 index, float value) { floatCache.set ((size_t) index, value); }

And then finally, in FloatCache::set(), the index (which was a negative int, and is now a massive unsigned int) is used to try to index an array, resulting in a crash.

void set (size_t index, float value)
{
    jassert (index < size());
    const auto previous = values[index].exchange (value, std::memory_order_relaxed);
    const auto bit = previous == value ? ((FlagType) 0) : ((FlagType) 1 << (index % numFlagBits));
    flags[index / numFlagBits].fetch_or (bit, std::memory_order_acq_rel);
}

Anyway, I have a pretty limited understanding of the VST3 wrapper code, but I hope this information is enough to understand where the crash is coming from. Please let me know if there’s more information I could provide that would be helpful.

Thanks for reporting this problem. This patch should fix the issue:

Please try this out and let me know if you encounter any further issues.

1 Like

Yes, the issue is now fixed on the latest develop. Thanks much!