Yes. I am aware of this bug and have several ideas on how to fix it (see below). I also didn’t want to fix this on a tagged release.
I’d also like to discuss the nature of the bug with you guys before I push this on a develop branch. Maybe you have a better solution. It’s also good if people here get an understanding on how the VST2 wrapper works, as many of you have a lot of experience on how different DAWs handle VST2 plug-ins.
See here’s the general problem with a multi-aux synth plug-in in Cubase:
Most DAWs call getSpeakerArrangement
before calling any processing methods. However, Cubase will only call this method after an ioChange
callback AND only if the plug-in is a synth. As far as I can tell, Cubase 8 will always mute all outputs no matter which speaker arrangement JUCE returns from the getSpeakerArrangement
callback. The only solution is to return false
to indicate that you do not support the getSpeakerArrangement
callback. This will work fine with the MultiSynth plug-in, for example.
I can see some logic in this: essentially getSpeakerArrangement
was obviously not really meant for multi-bus plug-ins (in fact all of VST2 wasn’t really designed with multibus plug-ins in mind) and there is no authoritative documentation on what getSpeakerArrangement
should do in a multibus setting. It should essentially return the speaker arrangement (or AudioChannelSet in JUCE speak) of the only existing bus - but the plug-in has several buses - so what to do?. It sort of makes sense to indicate that the plug-in does not support getSpeakerArrangement
by returning false if the plug-in has more than one bus.
One solution could be that JUCE always returns false
if the plug-in has sidechains or aux buses. However, this breaks the use of sidechain effect plug-ins in both Cubase and many other DAWs. The problem is that Cubase doesn’t really support multibus VST2 effect plug-ins at all. The workaround is to create a quadrophonic group fx track - for example - and use the the surround channels as sidechain channels.
When you load the effect plug-in onto the quadrophonic track, Cubase 8 will call setSpeakerArrangement
/getSpeakerArrangement
to change the layout of the plug-in to quadrophonic.
For getSpeakerArrangement
to be consistent, JUCE will simply return a canonical layout with the same number of channels as the combined total of number of channels of all input/output buses together - if, and only if, the plug-in is a multi-bus plug-in. If it only has a main bus the setSpeakerArrangment
/getSpeakerArrangement
simply passes through the arrangement to the plug-in’s setPreferredBusArrangement call.
A related problem, is that a JUCE plug-in can support an infinite combination of layouts on it’s buses - this is really hard to get working correctly with VST2. Take, for example a NoiseGate plug-in. Let’s say that the developer of this plug-in wants the sidechain to always only be mono, but the main bus, could really be any layout - for the sake of argument, let’s say mono, stereo and LCR. I now need to find a unique mapping between the layout supplied by setSpeakerArrangment
to the set of layouts on each bus.
For example, the combined total number of input channels for the above mentioned NoiseGate plug-in is anything between 2 and 4. If the plug-in gets a setSpeakerArrangement
callback with a quadrophonic input layout, then I know that the only possible bus configuration of the plug-in must be “main-bus: LCR + sidechain: mono = 4 (quadraphonic)”. If the arrangement supplied to setSpeakerArrangement
is LCR, then the only possible bus configuration of the plug-in is “main-bus: stereo + sidechain: mono = 3 (LCR)”.
As a result, JUCE’s VST-2 implementation requires that multibus plug-ins mustn’t allow two bus configurations that have the same combined total number of channels on all buses. In fact, JUCE will assert if this is the case.
I personally see three options to solve the Cubase 8/VST2/muting problem:
-
Always return false if getSpeakerArrangement
is called in a synth with more than one output bus.
This would probably work for Cubase, but I feel this is a bit ugly and might not work in other DAWs.
-
Return false from a getSpeakerArrangement
call if setSpeakerArrangement
was never called before AND the plug-in has aux and/or sidechains. If the DAW never called setSpeakerArrangement
arrangement then the plug-in will have the maximum number of total channels enabled by default (this is a VST2 requirement). Therefore, the plug-in will have all aux outputs enabled. If setSpeakerArrangement
is called then we have to return the same layout from a getSpeakerArrangement
to be consistent.
-
Reject both the getSpeakerArrangement
/setSpeakerArrangement
calls in all plug-ins which have aux and/or sidechains. This would get rid of a lot of complexity of the current VST2 wrapper. However, it would mean that VST2 plug-ins with aux and/or sidechains could not change their bus layouts, i.e the layouts on each bus would be static, as there is no way for the DAW to switch between layouts. With this, we would need to limit the above NoiseGate example to a single configuration: mono sidechain and stereo main bus, for example. Effect plug-ins with a single main in/out bus would not be affected and could have multiple layouts.
I prefer either 2 or 3 where 3 would probably remove much of the complex, potentially buggy code. However, it does come with a big down side: sidechain/aux plug-ins can only support a single bus configuration. Any ideas? Comments?