Sidechain / BusArrangement AU Bug


#1

Hey Jucers and ROLI. team,

I’ve discovered an issue with sidechain channel configuration when using AU plugins in the Digital Performer 8 DAW – though not widely used, it is a DAW that is used frequently by the customer base that uses the plugins that I have designed with JUCE.

Using the GainPlugin demo, for example, with a sidechain bus existent in the plugin results in the AU not producing any Audio output (bypassed, or not). To allow audio to pass through, the sidechain bus must be selecting some input; any input (Built-in Microphone, for example).

Your attention to this issue is greatly appreciated. Please let me know if I can provide any further information for debugging. The GainPlugin demo was built using the default settings for Xcode in the Projucer project.

Here are the repro steps, using the GainPlugin demo:

Add to GainProcessor() constructor:
// add single side-chain bus busArrangement.inputBuses.add (AudioProcessorBus ("Sidechain In", AudioChannelSet::mono()));

Alter setPreferredBusArrangement():

bool setPreferredBusArrangement (bool isInputBus, int busIdx,
const AudioChannelSet& preferredLayout) override
{

    const bool isMainBus   = (busIdx == 0);
    const bool isSideChain = (busIdx == 1);

    const int numChannels = preferredLayout.size();
    
    // do not allow disabling channels on main bus
    if (numChannels == 0 && isMainBus) return false;
    
    // we only accept mono/stereo/mono->stereo & mono sidechain
    if (!isAAX() && numChannels > 3) return false;
    else if (isAAX() && numChannels > 2) return false;
    
    if(isVST2()){
        // we only do mono sidechain (vst2)
        if (isSideChain && numChannels != 1)
            return false;
    }
    
    // when accepting a layout, always fall through to the base class
    return AudioProcessor::setPreferredBusArrangement (isInputBus, busIdx, preferredLayout);
}

#2

This line doesn’t make sense. The preferredLayout parameter is the layout of the bus referred to by busIdx, isInputBus. It’s not the layout of the entire plug-in. Therefore, your numChannels variable is the number of channels of that specific bus and not the combined total number of channels. Your implementation allows numChannels = 3, but your sidechain/main bus can only ever be mono or stereo.

I think this is what you may want:

bool setPreferredBusArrangement (bool isInputBus, int busIndex, const AudioChannelSet& preferred) override
{
    const bool isMainBus   = (busIndex == 0);
    const bool isSideChain = (busIndex == 1);

    const int numChannels = preferred.size();

    // do not allow disabling channels on main bus
    if (numChannels == 0 && isMainBus) return false;
    
    // AAX/VST2 only supports mono on the sidechannel
    const int maxSidechainChannels = ((isAAX() || isVST2()) ? 1 : 2);
    
    if (isSideChain)
    {
        if (numChannels < 1 || numChannels > maxSidechainChannels)
            return false;
    }

    // VST2 does not natively support sidechains/aux buses.
    // But many DAWs treat the third input of a plug-in
    // as a sidechain. So limit the main bus to stereo!
    if (isVST2())
    {
        if (isMainBus && numChannels != 2) return false;
    }

    // always have the same channel layout on both input and output on the main bus
    if (isMainBus && ! AudioProcessor::setPreferredBusArrangement (! isInputBus, busIndex, preferred))
        return false;

    return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
}

Let me know if this works for you.


#3

Hey Fabian,

Thanks so much for taking the time to reply to this post. After testing out your suggestions in a variety of ways, the issue unfortunately remains. With the channel configuration recommendation above, and ZERO sidechain busses added, Audio-thru works just fine in the GainPlugin example – however after adding the singular mono sidechain input, no audio-thru occurs (bypassed, or not). Attached below is the updated channel configuration.

Do you have any other recommendations, or is this something that I should wait for the JUCE team to examine and address?

bool setPreferredBusArrangement (bool isInputBus, int busIdx,
                                 const AudioChannelSet& preferredLayout) override
{   
    const bool isMainBus   = (busIdx == 0);
    const bool isSideChain = (busIdx == 1);
    
    const int numChannels = preferredLayout.size();
    
    // do not allow disabling channels on main bus
    if (numChannels == 0 && isMainBus) return false;
    
    if (isAAX() && numChannels > 2) return false;
    
    // AAX/VST2 only supports mono on the sidechannel
    const int maxSidechainChannels = ((isAAX() || isVST2()) ? 1 : 2);
    
    if (isSideChain)
    {
        if (numChannels < 1 || numChannels > maxSidechainChannels)
            return false;
    }
    
    if(isVST2()){
        // we only do mono sidechain (vst2)
        if (isSideChain && numChannels != 1)
            return false;
    }
    
    if (isVST2())
    {
        if (isMainBus && numChannels != 2) return false;
    }
    
    // always have the same channel layout on both input and output on the main bus
    if (isMainBus && ! AudioProcessor::setPreferredBusArrangement (! isInputBus, busIdx, preferredLayout))
        return false;
    
    
    // when accepting a layout, always fall through to the base class
    return AudioProcessor::setPreferredBusArrangement (isInputBus, busIdx, preferredLayout);
}

Again, thanks for your time and help in this matter. :slight_smile:

Cheers,
Bruce


#4

Hi Bruce,

I copied your setPreferredBusArrangement and put it into the NoiseGate demo (line NoiseGate.cpp:48). I also commented out lines NoiseGate.cpp:41 and NoiseGate.cpp:42 as your plug-in does not have a sidechain out. I then tested this in DP and everything works as expected. Can you help understand what your plug-in may do differently than the NoiseGate example? Try deriving your plug-in from the NoiseGate example and make the necessary changes one by one to figure out exactly which change breaks support in DP.


#5

I should add that I am not connecting the side-chain bus (as you mentioned in your first post) and setting the threshold parameter to zero. Audio processes as expected.


#6

Hi @fabian, I know the BusArrangement is deprecated but we’re seeing the exact same issue EVEN with newer api.
(JUCE commit: 21c6fc)

  1. It’s deeper than BusArrangement. it’s within the wrapper I guess.
  2. It happens on Digital Performer 8.x, version 9.x works as expected (maybe it’s a DP bug though we have seen similar behaviors in other hosts such as iZotope RX)

I’ve also went ahead and used NoiseGate.
You can set Threshold to minimum (so it’ll always bypass) and it’ll reproduce it.
You can modify the code to simply “pass-thru”

You’ll notice that it won’t work without Side-Chain set by the host, and as suggested above Bypass toggle also won’t work…


#7

I think this is now fixed on the develop branch. Kudos to MOTU who were super helpful in fixing this bug.


#8

Thanks for the update Fabian! Will check this out and verify as soon as I can.

Cheers!


#9

for future reference: