Muted VST2 outputs in Cubase after ioChanged() call

We have a problem with JUCE 4.2-based VST2 plugin not making any sound in Cubase (tested on both 8.5.0 and 8.5.15 on Windows and OS X) after the setLatencySamples() is called.

Thing is, if we call the setLatencySamples() from the constructor of our AudioProcessor, it works fine. But our plugin doesn’t know the real latency until later. So it is reported by the message thread a couple of seconds after plugin startup. But after this call, there’s no longer any audio output!

This is easy to reproduce in the MultiOutSynth plugin example. If I do this:

MultiOutSynth()
{
    // The base class constructor will already add a main stereo output bus
    // If you want to add your own main channel then simply call clear the
    // output buses (busArrangement.outputBuses.clear()) and then add your own

    // Add additional output buses but disable these by default
    for (int busNr = 1; busNr < maxMidiChannel; ++busNr)
        busArrangement.outputBuses.add (AudioProcessorBus (String ("Output #") += String (busNr + 1), AudioChannelSet::disabled()));

    // initialize other stuff (not related to buses)
    formatManager.registerBasicFormats();

    for (int midiChannel = 0; midiChannel < maxMidiChannel; ++midiChannel)
    {
        synth.add (new Synthesiser());

        for (int i = 0; i < maxNumberOfVoices; ++i)
            synth[midiChannel]->addVoice (new SamplerVoice());
    }

    loadNewSample (BinaryData::singing_ogg, BinaryData::singing_oggSize);
    
    startTimer(3000); // <-- ADDED
}

void timerCallback() override
{
    setLatencySamples(1000); // <-- now the plugin no longer produced sound in Cubase
    stopTimer();
}

longer any audio output!

No audio output of Cubase, or of the plugin?

Is this with every cubase project, or only sometimes? Does older JUCE releases work?

I had once an issue with cubase - similar behavior. The fix was to use triggerAsyncUpdate(); to call ioChanged(); in the VST2 Wrapper, which fixed the behavior in most cases (Just checked the wrapper, it still uses the approach)

Seems like audio output is muted by cubase for some reason. The plugin generates audio, and the output bus layout looks correct when debugging the processBlock() call.

The setLatencySamples() function indeed already does a triggerAsyncUpdate() in the VST wrapper, so it does get to the ioChanged() right after latency has been set. It seems like it is the ioChanged() call that causes the output to become silent in Cubase.

It reminds me about his issue

from Reporting a changed latency in VST plug-ins - #12 by ckk

One, in particular, was quite annoying: when loading a session in Cubase where the plug-in state implied a latency different from the one of the plug-in in its “just inserted” state, the whole session didn’t output any sound when played even if the meters in the GUI moved as if playing was actually happening.

If its this issue, it looks like a bug in Cubase, somebody should contact Steinberg.

But anyway, i would recommend to set the latency as early as possible (in prepareToPlay or setStateInformation() your plugin should at least know its latency?) or later when the user changes the latency setting from the plugin-GUI.

BTW: could be of course some other issue too

So, if I skip adding the individual output buses in my synth, this problem no longer occurs. Main output stays audible also after the setLatencySamples() call.

Could indeed be a Cubase problem. Hopefully I can find time later to create an isolated example of this and report it to Steinberg.

i also experience this in cubase 8, in setProgram of my plugin i call updateHostDisplay and this in turn will call the vst wrapper audioProcessorChanged which will triggerAsyncUpdate the ioChanged call, and then the synth is muted. i need to deactivate and reactivate the output busses in order to hear again the sound. here is my setPreferredBusArrangement:

const int numChannels = preferredLayout.size();

// do not allow the host to disable any buses
if (preferredLayout == AudioChannelSet::disabled())
	return false;

// we only accept stereo channels
if (isInputBus || numChannels != 2)
	return false;

// when accepting a layout, always fall through to the base class
return AudioProcessor::setPreferredBusArrangement(isInputBus, busIndex, preferredLayout);

i forgot to say that i have the main stereo output bus and 4 individual auxiliary stereo output busses

Same problem exists also if setLatencySamples() is called from prepareToPlay(). Only when called from the constructor, it seems to work. But in this case, we don’t seem to end up in ioChanged() at all. Perhaps the VST wrapper has not yet registered itself as an AudioProcessor listener.

Can you also confirm that it works OK as soon as you remove the individual output buses?

In which case you may however be required to add a sidechain input in order to avoid a crash.

edit: doh.

additonal busses works ok with VST3 in cubase8, but they do not with VST2.4. still trying to find a way to delete the plugin cache in cubase cause it’s still instantiating it with 10 outputs even if i recompiled with only 2 outputs (tried deleting the plugin from the folders of course).

Same results here. Guess our VST2 users will have to live with this limitation for now.

yeah. really annoying

This is my last run of a multi output synth (on mac):

  • AU2 working in renoise / reaper / logic
  • VST2 working in renoise / bitwig / reaper
  • VST3 working in cubase8
  • Standalone working
  • AU3 / AAX / RTAS not tested

Things done:

_ Cleared the preferred channel layout in projucer

_ Added this setup in the plugin constructor:

busArrangement.inputBuses.clear();
busArrangement.outputBuses.clear();
busArrangement.outputBuses.add(AudioProcessorBus("Master", AudioChannelSet::stereo()));
busArrangement.outputBuses.add(AudioProcessorBus("Out A", AudioChannelSet::stereo()));
busArrangement.outputBuses.add(AudioProcessorBus("Out B", AudioChannelSet::stereo()));
busArrangement.outputBuses.add(AudioProcessorBus("Out C", AudioChannelSet::stereo()));
busArrangement.outputBuses.add(AudioProcessorBus("Out D", AudioChannelSet::stereo()));
if (PluginHostType().isLogic()) {
    busArrangement.inputBuses.add(AudioProcessorBus("Input", AudioChannelSet::stereo()));
    busArrangement.outputBuses.add(AudioProcessorBus("", AudioChannelSet::disabled()));
    busArrangement.outputBuses.add(AudioProcessorBus("", AudioChannelSet::disabled()));
    busArrangement.outputBuses.add(AudioProcessorBus("", AudioChannelSet::disabled()));
}

_ This is the setPreferredBusArrangement method implementation

bool setPreferredBusArrangement(bool isInputBus, int busIndex, const AudioChannelSet& preferredLayout)
{
    const int numChannels = preferredLayout.size();

    // do not allow the host to disable any busses
    if (preferredLayout == AudioChannelSet::disabled())
            return false;

    // we only accept stereo busses
    if (isInputBus || numChannels != 2)
            return false;

    // when accepting a layout, always fall through to the base class
    return AudioProcessor::setPreferredBusArrangement(isInputBus, busIndex, preferredLayout);
}

Issues:

_ VST2 in Cubase8 after switching program (calling ioChanged via AudioProcessor::updateHostDisplay) the outputs are muted (but still reported as active, so i need to forcibly deactivate them and reactivate again to hear sound again).

_ VST 2 In Cubase8 the bus names are wrong. Master bus is named Master L.

_ VST 2 in Reaper, the single channels names receive a L R, some other times 0 1. So in my case i get sometimes Out A L and Out A R and some other times Out A 0 and Out A 1.

_ The additional stereo busses are present in the host but they are switched off (may not be a juce problem), i’m still trying to understand what’s the point of having them created as AudioChannelSet::disabled() (btw if i don’t disable them for logic, i will get in the outputs dropdown a 16outputs layout instead of a stereo5 which is the one i want.

I’m wondering the same. How should one reason about this? Is it supposed to be a way of telling the host what your preferred default configuration is? I can confirm that it has an important effect on how the plugin is presented (in terms of output count) in Logic.

yeah, Logic always wants to open my plugs as single stereo (totally ok) or 16 outputs (why?) even if i’m reporting up to 5 busses (5 stereo channels): in the multibus guide, this side effect is not documented (that you have to explicitly disable channels up to X to avoid strange things with hosts that want to open the plug with more busses than the ones specified in the constructor).

other thing is, when you add a disabled bus with AudioChannelSet::disabled() in the constructor, and eventually enable it in setPreferredBusArrangement, there is no way to make it stereo afterwards. or i’m missing something ?

You should be able to force it to stereo (or disabled) in the setPreferredBusArrangement by only allowing 0 or 2 channels?

yeah i see. but i still don’t understand why i have to do this in logic only, and will break other hosts (like cubase8, but that’s even more broken).

So in my opinion, this issue still exists in JUCE 4.2.2. Any ideas about workarounds or ways to fix?

I can also confirm that the fix proposed by @kraken here fixes the problem:

Wondering if this fix could make it into JUCE?

Yes this is in the pipeline although I prefer the fix where JUCE simply doesn’t allow dynamic channel formats on aux and sidechains buses (only if the plugin has vst 2 and aux buses and only for vst 2 plugins). This gets rid of a lot of complexity in the vst 2 wrapper and is something many DAWs don’t support anyway.

Any news yet regarding this fix? Are there any uncertainties left that this community could perhaps help figuring out, or does it simply need more time from you guys?

Humble question really, just wondering because the current state of the development branch is actually pretty stable except for this very problem.