Bus layouts


#1

I have few question about bus layouts in JUCE 4.3.1 and later. I’ve just upgraded from 4.2.3 bus system (setPreferredBusArrangement). Sorry for maybe obvious questions, but i am a bit lost, looking for proper functions to do the job.

I have a plugin which should have, with VST2 format, from 4 to 8 channels on main input bus (dynamically set).

Other formats (AAX, AU, VST3) should have from 1-8 channels on main input bus and a sidechain bus added.

I can see, busses are always added in constructor function definition (initializing parent constructor)- is there a way to add them in constructor body ??? I would like to create different bus layout depending on wrapper format. Is this possible, i mean is info about wrapper now available already in constructor?

Another question - how do i dynamically change number of channels of the bus to the fixed value ??

Thx!


#2

Hi,

I suggest you to use a static method to create the preferred buses layout in the constructor and as wrapperType is not yet defined, you should use PluginHostType::getPluginLoadedAs().

Then you should use the method isBusesLayoutSupported() to dynamically accept or reject the buses layouts submitted by the DAW (if I understood well, the plugin can’t ask for a specific buses layout, this is the DAW that submit to the plugin a buses layout and the plugin accept it or reject it).

PS: Dynamic buses and dynamic multichannel are not well supported by most of the DAW. Often, I don’t have the expected functioning…


#3

I understand the purpose of isBusesLayoutSupported(), but i am not sure which static method should i use to define buses layout inside constructor body. All examples use initialization thru parent constructor like …

MyAudioProcessor::MyAudioProcessor() : AudioProcessor (BusesProperties().withInput ("Input", AudioChannelSet::quadraphonic(), true)
    																		   .withInput ("Sidechain", AudioChannelSet::mono(), true)
    								 										   .withOutput ("Output", AudioChannelSet::stereo(), true))

Thx!


#4

wrapperType should be safe as you’re inherething AudioProcessor that was already initialized.

This works here:

    if (wrapperType == YOUR_WRAPPER)
    {
        addBus(true);
        auto sc = getBus(true, 1);
        if (sc != nullptr)
        {
            sc->setCurrentLayoutWithoutEnabling(juce::AudioChannelSet::mono());
        }
    }

Also, setting bus layout by the wrappers would also happen.
Imagine you’ve set

BusesProperties().withInput ("Input", AudioChannelSet::stereo(), true)

And you’re reporting you can handle {1,1}. The wrappers might (for example on AAX) would set your main input bus to mono()…

Only callback that you cannot “update” when doing your additional setup on the constructor is:

// Unfortunately the deprecated getInputSpeakerArrangement/getOutputSpeakerArrangement return
// references to strings. Therefore we need to keep a copy. Once getInputSpeakerArrangement is
// removed, we can also remove this function
void AudioProcessor::updateSpeakerFormatStrings()

But it seems to be for deprecated callbacks?


#5

You should never call one of the set layout methods (i.e. setCurrentLayout, setCurrentLayoutWithoutEnabling, …) from within your plug-in. As a plug-in you cannot set your own layout - the host does. You can only tell the host which layouts you support (via isBusesLayoutSupported) and the number of buses and their default layouts (via your constructor).

To do what you want you should create a static method like this:

static BusesProperties getDefaultLayout()
{
    if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX)
        return BusesProperties().withInput ("Input", AudioChannelSet::quadraphonic(), true)
																		   .withInput ("Sidechain", AudioChannelSet::mono(), true)
								 										   .withOutput ("Output", AudioChannelSet::stereo(), true);
    if (PluginHostType::getPluginLoadedAs() ==  ...)
    ...
}

and then in you call the above method in your constructor:

MyAudioProcessor::MyAudioProcessor() : AudioProcessor (getDefaultLayout())
{
    ...
}

@noahdayan wrote a fantastic tutorial explaining all this in a bit more detail:

https://docs.juce.com/master/tutorial_audio_bus_layouts.html


#6

Thank you !!! I’ve just came to this solution with static method you proposed (Pierre mentioned it few posts above, but i didn’t understand it at first). Things are much clearer now :slight_smile:


#7

That’s a very nice approach. and cleaner. so it is way better.

Just from a technical discussion, if you do setLayout in constructor for additional Bus it would pretty much be equivalent, as you’re still “under-construction” so the instance on the host side would be pretty much the same (at least from the current AudioProcessor constructor).


#8

Yes you are right, but don’t rely on it. We might change the internal behaviour of AudioProcessor at any time. It’s also clearer if we can simply say that audio plug-in’s should never use any of the set layout methods. Those methods are reserved for apps which host VSTs/AUs.


#9

Also with the ugly way I had to override the canAddBus / canRemoveBus. so it is really nice to have good clean code snippets across the forum.


#11

In that case, wouldn’t it make sense to have these methods be ifdef’d out in case of a non-host application?

So, for example, by default plug-ins projects created with the ProJucer would not have these methods, and to get access to you would need to add a specific macro by hand/toggle a checkmark in the ProJucer (for cases where your cool plug-in is also a host).


#12

No because many plug-ins use other AudioProcessors internally - in a graph for example. It’s not only about hosting another VST or AU. It could also be that you are hosting an internal AudioProcessor.


#13

Since AFAIK most AudioProcessor-based plug-ins don’t host anything (including other AudioProcessors), I think it still worth considering to exclude any extra hosting functionality by default using some technique. Just my two cents.

Thanks!