VST3 Layout Validation Problem with Acoustica7 and Pyramix 14

I’m currently tracking down a bug related to the channel config of our VST3 plugin in Acoustica 7 on Windows. Our side-chain enabled plugin is muting the track, since the VST3 wrapper reports an invalid channel layout, which results in a blank input buffer.

When I load the VST3 plugin into Acoustica on a mono track, I can see that the plugin is prepared with one mono input-bus as well as one inactive mono side-chain bus.
When processing the Steinberg::Vst::ProcessData::inputs array contains two elements.
The first element is the expected input-bus with one channel. The second element however corresponding to the disabled side-chain bus is present, but with 0 channels.

I’ve tracked the changes to the recent commit here: VST3 Client: Allow host to enable/disable buses at will · juce-framework/JUCE@0e85fec · GitHub

In the situation described above the newly introduced validateLayouts method reports an invalid configuration, since the plugin was prepared with a mono side-chain bus, while it actually received an empty one while processing.

The check is the following:

auto** busPtr = getAudioBusPointer (detail::Tag<FloatType>{}, *it);
const auto anyChannelIsNull = std::any_of (busPtr, busPtr + it->numChannels, [] (auto* ptr) { return ptr == nullptr; });

 // Null channels are allowed if the bus is inactive
 if ((mapIterator->isHostActive() && anyChannelIsNull) || ((int) mapIterator->size() != it->numChannels))
     return false;

with a configuration of:

busPtr == nullptr
it->numChannels == 0
anyChannelIsNull == false (since the std::any_of is executed from nullptr to nullptr)
mapIterator->size() == 1

So, is it really the desired behaviour to mute the input in these situations?

@reuk Sorry to bother you, but do you have any insights on this?
I would have assumed that an invalid channel layout would be ignored, if the bus is ignored anyways, e.g. that the check looks something like

 // Null channels are allowed if the bus is inactive
 if (mapIterator->isHostActive() && (anyChannelIsNull || mapIterator->size() != it->numChannels))
     return false;

I’m on holiday this week, so I can’t look too closely.

However, based on the details you’ve provided, this sounds like a bug in Acoustica7.

According to the VST3 docs (VST 3 Interfaces: AudioBusBuffers Struct Reference), “the number of channels (numChannels) [in the buffer passed to process] must always match the current bus arrangement.” This appears to be the case whether the bus is active or inactive.

Perhaps the VST3 wrapper could attempt to continue processing in the case that the host breaks this contract, but ideally the host wouldn’t break the contract in the first place. I’d recommend filing a bug report with Acoustica7 if you haven’t already done so.

Oh dear, this is obviously not important enough to disturb you in your holiday- sorry!

Thanks for your insight. We’ve received similar bug reports for Pyramix 14 in the meantime, and there I was noticing the following situation:

The plugin is prepared with two buses, one active mono input bus, and one inactive side-chain bus, e.g.

processor.getBus (true, 0)->layout.size() == 2
processor.getBus (true, 0)->isEnabled() == true
processor.getBus (true, 0)->getLastEnabledLayout().size() == 2

processor.getBus (true, 1)->layout.size() == 0
processor.getBus (true, 1)->isEnabled() == false
processor.getBus (true, 1)->getLastEnabledLayout().size() == 1

During the construction of the ClientBufferMapper::inputMap the two buses are asked for the getLastEnabledLayout, this means that after the prepare the plugin is initialized for one active stereo-bus and one inactive mono-bus.

During the subsequent calls to process, the DAW provides two input buffers in its Steinberg::Vst::ProcessData struct, the first with two channels, the second one with 0 channels, as was announced initially. However, now the validateLayouts will fail.

I missed it the first time, but this is also exactly the same behaviour as Acoustica 7, it also prepares with a disabled empty side-chain bus, while the plugin, accessing the last enabled layout for that bus is prepared with a mono bus, which also triggers exactly the same error.

Looking at this situation I think that the DAWs are actually abiding by the VST3 requirements and that this is a bug in the way the VST3 wrapper handles this particular situation!

Is this a problem that is likely to be fixed in JUCE upstream, or is this some configuration error I’m not aware of? I’m just asking since our customers are still reporting this problem and I’d like to give them a timeline!

Sorry, I haven’t managed to investigate this yet - I’m a bit buried in OpenGL debugging at the moment. It sounds like there could be a bug in the JUCE VST3 wrapper, and I’ve added it to my backlog, but I can’t say when I’ll be able to take a look.

Sure thing, thanks for the heads-up!

Thanks for reporting the issue. I’ve investigated it a bit, and I think the change you suggested is the correct fix. That is, the issue you were seeing is on the plug-in side.

While testing, I also noticed that the host was occasionally calling activateBus and setBusArrangement after the plugin was already prepared. This is not allowed by the VST3 spec. It looks like Acoustica 7 is a JUCE host, and I think I’ve found the cause of that problem too. To improve conformance with the VST3 spec, Acoustica 7 will need to be updated once I’ve merged the fix.

Thats great, thank you for looking into the issue! I’ll contact Acon Digital once the fix is merged to make them aware of the issue.

Thanks for reporting these issues.

The host-side change is here:

The client-side fix is here:


Thanks for reporting and fixing this! We’ll try to get this fix into Acoustica as soon as possible.