Right time to call AudioProcessor::addBus()


#1

Hi,

when is the right time to call AudioProcessor::addBus() on a newly constructed AudioProcessor? It can’t be called during construction since addBus() itself calls directly the virtual AudioProcessor::numChannelsChanged().

To me this looks like a conceptional bug in the AudioProcessor where JUCE should defer calling virtual AudioProcessor::numChannelsChanged() to after the AudioProcessor is constructed.

Cheers,
raketa.


#2

If you are creating an audio plug-in, you never call addBus/removeBus on your own plug-in. You are at the mercy of the host which will add/remove buses to your plug-in when it wants to.

In JUCE, you specify the default number of buses and their layouts in the constructor of your AudioProcessor. See, for example, the constructor of the GainPlugin example which adds one input and one output bus - both having a default stereo layout:

GainProcessor()
    : AudioProcessor (BusesProperties().withInput  ("Input",  AudioChannelSet::stereo())
                                       .withOutput ("Output", AudioChannelSet::stereo()))
{

Another, example is the MultiOutSynth example which adds 16 output buses - all with a default stereo layout:

MultiOutSynth()
    : AudioProcessor (BusesProperties()
                      .withOutput ("Output #1",  AudioChannelSet::stereo(), true)
                      .withOutput ("Output #2",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #3",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #4",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #5",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #6",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #7",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #8",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #9",  AudioChannelSet::stereo(), false)
                      .withOutput ("Output #10", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #11", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #12", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #13", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #14", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #15", AudioChannelSet::stereo(), false)
                      .withOutput ("Output #16", AudioChannelSet::stereo(), false))
{

Normally, plug-ins have a fixed number of buses (their individual layouts can change however). If you need a plug-in that has a dynamic number of buses, then you need to override the AudioProcessor::canAddBus/AudioProcessor::canRemoveBus callbacks. By default they will return false.

Again, adding/removing buses is initiated by the host. The host will first check if the plug-in supports adding or removing a bus by calling AudioProcessor::canAddBus/AudioProcessor::canRemoveBus. If yes, it will then suspend processing, add/remove the number of buses it desires and then call your prepareToPlay callback. In your prepareToPlay method you can now query the number of buses that you currently have and respond by allocating memory etc.


#3

Thanks, Fabian,

this way the number of I/O channels can only be set statically. My plugin needs to read its I/O configuration (number of I/O channels) out of an .xml. If I don’t mis something the only way to achieve this is by awkwardly overriding bool canAddBus(), bool canApplyBusCountChange(), bool isBusesLayoutSupported () and requiring to call addBus() to create an initial in and out bus.

Cheers,
raketa


#4

If you can read this XML at the time your derived AudioProcessor is constructed then your could construct an appropriate BusesProperties struct and pass this to the base AudioProcessor constructor.


#5

Exactly. Try creating a static method which returns the BusProperties structure that you need. Something like this:

class MyAudioProcessor: public AudioProcessor
{
public:
    MyAudioProcessor() : AudioProcessor (readBusesPropertiesFromXml())
    {
        ...
    }

    ...
private:
    static BusesProperties readBusesPropertiesFromXml()
    {
        BusesProperties buses;

        ...
        // repeat this for every bus in the xml file
        buses.addBus (busDirection, busName, AudioChannelSet::stereo());

        return buses;
    }
};