4.1. setPreferredBusArrangement() mono-stereo or same Ins/Outs

I'm really trying to understand how things work, but i can't! Its confusing!

setPreferredBusArrangement() only asks for a single configuration of a single bus, but shoudn't it ask for all I/O busses in conjunction?

I  need the a behavior to support the same number of input & output channels, and mono->stereo configuration

Like the old {1,1},{1,2},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},{8,8}, but the old makro is just not working as expected.

Because i'm now switching to 4.1. i change a lot code inside my library, and a way back to 4.0 would be painful!

 

OK, to be honest I'm just guessing here because the multibus stuff isn't my code, but reading the documentation of setPreferredBusArrangement():

You may override it and return false if you want to make your plugin smarter about refusing certain layouts that you don't want to support. Your plug-in may also respond to this call by changing the channel layout of other buses, for example, if your plug-in requires the same number of input and output channels.

To do that for all buses, you could let your override set the same number of input and output channels regardless of what busIndex gets passed in from the host.

That being said, the old macro—albeit deprecated—should still work as well, what's broken there?

Hi, thank you for coming back to this topic.

I'm not interested how things should theoretically work, they should work ;-)

There are several threads on this forum who are discussing issues. The macro is not working, as in previews versions.

But this is really important (really!) , because it will break current plugin-projects and forces me to stay on juce 4.0

Even the smallest changes have a big impact. 

To be honest, i just don't have the time to test any host, but i fear i have to do it, because i don't like buggy or undefined behavior.

 

At least there has to be a few configurations which should be tested along all different major hosts.

- Plugin which is using the same number of I/O channels (default stereo)

- Plugin which is using the same number of I/O channels, and mono to stereo (default stereo)

- Plugin which is using the same number of I/O channels, and mono/stereo to surround, mono to stereo (default stereo)

This configurations must be tested in Cubase, Logic, Reaper, Wavelab, Tracktion, Mainstage, Ableton Live, Pro Tools, Bitwig etc...... on 

- Mono Channels

- Stereo Channels

- Surround Channels

 

Also, the new functionality, IMHO is a little confusing. I have the slight suspicion that it can't work, but thats speculation.

I tried to understand what's going http://www.juce.com/forum/topic/plugin-channel-configurations-juce-41-workaround-not-working-expected-cubase#comment-318967

 

The old macro doesn't work as it should. When you have {1, 1}, {2, 2} in the IntroJucer and load the plugin as Stereo on a Stereo track, the AU version (in Logic X) works fine but the VST (in Live 9) loads as mono {1, 1} on a stereo track. I suspect that AAX has the same problem.

Leaving the channel configuration field empty, fixes the problem, but I can't seem to find a way to properly have {1, 1}, {1, 2}, {2, 2} (mono, mono->stereo, stereo) ONLY.

Using this:

if (numChannels > 2) return false;

in setPreferredBusArrangement leads to {1, 1}, {1, 2}, {2, 1}, {2, 2}. So there's Stereo->Mono which I don't want, how can I get rid of it?
(By the way Stereo->Mono is only showing in Pro Tools, I think).

I understand that NAMM is/was in the way, but if you decide to deprecate something at least, please, test in major hosts the main configurations.

For what is worth, I find the new channel thing very confusing and messy. The examples aren't very clear either and probably not enough to cover the main configurations.

Hi all,

there was a bug in the VST 2.x plug-in wrapper which messed up plug-ins using the legacy layout macro. This is now fixed on the latest tip.

Also, the new functionality, IMHO is a little confusing. I have the slight suspicion that it can't work, but thats speculation.

I think people are confusing somethings here as the API is actually rather simple, so allow me to add some comments to the new API.

  1. I think some people are confusing the busArrangment arrays with an array of all possible bus layouts - however, the buses in the busArrangement array are the actual buses. In the constructor you add buses to your plugin. For example, an effects plug-in (with no side-chain or aux channels) would add a single input and a single output bus  (however see Note 3 below!!). The AudioChannelSet parameter in the AudioProcessorBus's constructor (second parameter) is simply the default layout for that bus. But this can be changed via the setPreferredBusArrangement callback
  2. You restrict the possible layouts that your plug-in supports by returning false in setPreferredBusArrangement to a layout which your plug-in does not support (for example quadrophonic in the example below). You can choose to accept this format by calling through to the base class' version of setPreferredBusArrangement OR decline the format change by returning false. Additionally, if you accept the format change (and only if), you can also adjust the formats of the other buses before calling the base class version of setPreferredBusArrangement. For instance you may change the format of the bus in the opposite direction to align with the format of the bus that is being changed (as is done below). But it is undefined behaviour to change the layout of the bus for which the setPreferredBusArranangement was triggered (for example, if IsInput=true and busIdx=0 then you may NOT change the layout of that bus). setPreferredBusArrangement will be called hundreds of times for the plug-in wrapper to understand the layout logic of your plug-in. There may be obscure cases we have missed but I doubt it. The code snippet below is an example of a plug-in which only supports mono and stereo layouts and where the input must have the same layout as the ouput.
  3. One thing is admittedly slightly confusing: for backward compatibility, the AudioProcessor's base class constructor already adds  one input and one output bus if your plug-in is an effects plug-in (the default layout is stereo). Therefore, your constructor should only add additional buses (such as aux and sidechain buses). If this too confusing then you can also clear the buses that JUCE automatically created for you, by simply clearing the busArrangement arrays in the constructor (busArrangement.inputBuses .clear(); busArrangement.outputBuses .clear();) and then adding your own buses.
  4. There are certain layout restrictions depending on the plug-in type. This is a restriction of the plug-in format and not JUCE's fault. For example, AAX only supports a single sidechannel. There are other restrictions with other formats as well. 
bool setPreferredBusArrangement (bool isInputBus, int busIndex,
                                const AudioChannelSet& preferred) override
{
    const int numChannels = preferred.size();
    
    // we do not allow disabling any buses
    if (preferred == AudioChannelSet::disabled())
        return false;

    // only mono and stereo please
    if (numChannels > 2)
        return false;
    
     // always have the same channel layout on both input and output on the main bus
     if (! AudioProcessor::setPreferredBusArrangement (! isInputBus, busIndex, preferred))
         return false;

     // when accepting the layout we must fall through to the base class!
     return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
}

 

Hi Fabian, 

thanks for clarification! Regarding the new method (not the legacy functionality), TBH i still haven't realized how the VST2-Wrapper can check the input/output configuration in conjunction to each other.

Maybe i just don't found the missing link in my head.

The wrapper calls in setSpeakerArrangement, setPreferredBusArrangement first for the input configuration, how does the plugin now what the suggested output configuration is at the same time. (Theoretical example my plugin only accepts 1 input-channel (mono) and only stereo OR surround as output configuration) The call to the setPreferredBusArrangement-base function, will always return true, as long the bus index is positive.

It would be a pleasure if you could enlighten me.
 

Thanks Fabian, but I'm still very confused.

What should I do to get [1, 1]  [1, 2]  [2, 2]  (mono, mono->stereo, stereo) only? If I use 

    if (numChannels > 2)
        return false;

I also get [2, 1], Stereo->Mono, and I don't want that.

Hi Fabian,

Thanks very much, with every post this construct becomes clearer. However where do you collect knowledge like:

For example, AAX only supports a single sidechannel. There are other restrictions with other formats as well. 

Could you add a page or maybe a wiki to the documentation about wrapper specific differences? I know you guys prefer to write demos, but I spend a lot of time reading to understand how thinks are meant to work instead of trying out. It makes me more happy and produces better code. But it's a matter of taste I think.

And another question, is there a certain sequence how the wrapper probes the ChannelSets? Like input first then output, so that lapsang could do e.g.

if (!isInput) {
    if (busArrangement.inputBuses.size() > busIndex) {
        if (numChannels < busArrangement.inputBuses.getUnchecked (busIndex).size()) {
            return false;
        }
    }
}

?

Thanks

Nice hint, Daniel. I tried this and tested in PT12:

bool JuceDemoPluginAudioProcessor::setPreferredBusArrangement (bool isInputBus, int busIndex, const AudioChannelSet& preferred)
{
    const int numChannels = preferred.size();
    
    const bool isMainBus = (busIndex == 0);
    
    if(numChannels > 2)
        return false;
    
    // do not allow disabling the main output bus
    if (isMainBus && preferred.isDisabled()) return false;
    
    // do not allow when inputs > outputs
    if(! isInputBus)
    {
        int numInputChan = busArrangement.inputBuses.getUnchecked(busIndex).channels.size();
        DBG("Input Ch: " << numInputChan << " || Output Ch: " << numChannels);
        
        if(numInputChan > numChannels)
            return false;
    }

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

I get mono->stereo and stereo only. no mono->mono.

What I get in the debugger is:

Input Ch: 2 || Output Ch: 1
Input Ch: 2 || Output Ch: 1
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 1 || Output Ch: 2

Funny thing is.. if I remove the last comparison (the one that should block the unwanted sets), then I get this:

Input Ch: 2 || Output Ch: 1
Input Ch: 2 || Output Ch: 1
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 2 || Output Ch: 2
Input Ch: 1 || Output Ch: 2
Input Ch: 1 || Output Ch: 1

And here, unfortunately, I got the same issue as lapsang.. stereo->mono included in the available channel configurations.
I tried several things before posting and watched all the code provided in the examples, but looks like something that used to be really simple has been turned into something... well, not very much so simple.. at least to achieve the same results as before.

What are we missing?

Cheers.

What should I do to get [1, 1]  [1, 2]  [2, 2]  (mono, mono->stereo, stereo) only? 

 

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

    // we do not allow disabling any buses
    if (preferred == AudioChannelSet::disabled())
         return false;

    if (numChannels > 2)
        return false;

    if ( (isInputBus  && numChannels == 2)  // if the input is stereo then the output must be stereo
   || ((! isInputBus) && numChannels == 1)) // if the output is mono then the input must be mono
    {
         if (! AudioProcessor::setPreferredBusArrangement (! isInputBus, 0, preferred))
              return false;
    }

    // when accepting the layout we must fall through to the base class!
    return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
}

nope.. in this way you only get the plugin to work on mono tracks, since you are not allowing stereo inputs.

Let's forget for a moment the deprecated method of expliciting the channel configuration in IntroJucer... the "newbie" question will be:

What should I do to allow the following channel configurations in my effect plugin?

1) Mono -> Mono

2) Mono -> Stereo

3) Stereo -> Stereo

 

By using numChannels > 2 return false, you also get a Stereo -> Mono which is undesired.

Cheers.

Sorry, I didn't read the post properly. I've edited my post above.

I'm sorry Fabian, but with the code above now I only get mono OR stereo.... Mono -> Stereo is not showing up.

Yep, it doesn't work.

Using the deprecated code works.

Fabian, I appreciate your work and help, but I really think this should be much easier to do at least for common configurations. Alternatevly, I think JUCE should provide a bunch of macros for newbies or people who can't spend days/weeks on something like that.

Which host is this and which plug-in type?

Hi Fabian,

host is ProTools 12.3, AAX plugin type.

Cheers.

I'm using Logic X instead, and I get this in the AU Manager:

Reported Channel Capabilities (explicit):
      [1, 1]  [2, 2]  
 

I don't want to repeat myself, but without knowing which configuration the opposite bus has, IMHO it simply can't work.

Take a look: http://www.juce.com/forum/topic/41-setpreferredbusarrangement-mono-stereo-or-same-ins/outs#comment-319228

(and the way the vst-wrapper works, it wouldn't also working by accessing the busArrangement)

Arrgh! OK I got the sample code wrong again. Obviously I also need to check the case where the output bus is set to mono (then the input must also be set to mono as stereo->mono is not supported).

This is now the correct and tested (AU) version:


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

    // we do not allow disabling any buses
    if (preferred == AudioChannelSet::disabled())
         return false;

    if (numChannels > 2)
        return false;

    if ( (isInputBus  && numChannels == 2)  // if the input is stereo then the output must be stereo
   || ((! isInputBus) && numChannels == 1)) // if the output is mono then the input must be mono
    {
         if (! AudioProcessor::setPreferredBusArrangement (! isInputBus, 0, preferred))
              return false;
    }

    // when accepting the layout we must fall through to the base class!
    return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
}

P.S: I'll also be preparing a sticky note on the subject.

Awesome! This works.

Yes a sticky would be useful, thanks.