If I understood it correctly, at the moment setting up a multi-bus plug-in involves two steps:
-
In the constructor for our plug-in class derived from
AudioProcessor
, set up the correct number of busses in thebusArrangement
member of theAudioProcessor
instance, also giving each bus its preferred set of channels (mono, stereo, etc.) -
By mean of
setPreferredBusArrangement()
, “negotiate” with the wrapper which other set of channels are valid for the busses inbusArrangement
(while, of course, the number of input and output busses must not change)
While this is a perfectly valid way for the wrapper to “probe” and get to know which channel configurations are valid, the discussion in the main multi-bus thread has made it quite clear that this, especially step #2 above, is rather convoluted and hard to get right at first attempt.
The reason is that it forces us developer to translate an explicit requirement (for example: my plug-in should deal with mono->mono, mono->stereo, stereo->stereo main bus, and should have a mono sidechain input) into a set of rules to be put inside setPreferredBusArrangement()
so that the same requirement results implicitly from them.
Now I wonder: can this be improved further, allowing us to expose/declare/register in the constructor of our AudioProcessor all the valid bus arrangements (complete with the channel configuration for each bus) for the plug-in?
Speaking in code, I imagined something like this (to express the same valid configs I mentioned before):
// Allow mono -> mono
{
AudioBusArrangement a;
a.inputBuses.add (AudioProcessorBus ("Main In", AudioChannelSet::mono()));
a.inputBuses.add (AudioProcessorBus ("Sidechain In", AudioChannelSet::mono()));
a.outputBuses.add (AudioProcessorBus ("Main Out", AudioChannelSet::mono()));
registerValidBusArrangement (a);
}
// Allow mono -> stereo
{
AudioBusArrangement a;
a.inputBuses.add (AudioProcessorBus ("Main In", AudioChannelSet::mono()));
a.inputBuses.add (AudioProcessorBus ("Sidechain In", AudioChannelSet::mono()));
a.outputBuses.add (AudioProcessorBus ("Main Out", AudioChannelSet::stereo()));
registerValidBusArrangement (a);
}
// Allow stereo -> stereo
{
AudioBusArrangement a;
a.inputBuses.add (AudioProcessorBus ("Main In", AudioChannelSet::stereo ()));
a.inputBuses.add (AudioProcessorBus ("Sidechain In", AudioChannelSet::mono()));
a.outputBuses.add (AudioProcessorBus ("Main Out", AudioChannelSet::stereo ()));
registerValidBusArrangement (a);
}
Considerations:
-
This can be added to the current scheme rather than replace it. Simply, the current implementation of
setPreferredBusArrangement()
could check if the list/array populated byregisterValidBusArrangement()
is not empty and, in that case, use that list to determine if the proposed arrangement is acceptable or not. -
To enforce the requirement that the number of busses must stay the same,
registerValidBusArrangement()
could check and reject them with a jassert if inconsistent with the first one provided. -
It may look too verbose, but one will have the option to make it more concise by mean of for loops (I know this will resemble the whole
setPreferredBusArrangement()
mechanism, but as I said in this case this is an option, not mandatory) -
It provides a more straightforward conversion from the old
JucePlugin_PreferredChannelConfigurations
macro.
In particular, this will make it is possible to move out of the currentsetPreferredBusArrangement()
the code to deal with that macro, which will solve the problem described here: Subprocessor bus arragements.
The conversion can then be performed by the wrapper: if it sees the macro to be defined, it will register the appropriate bus arrangements for theAudioProcessor
right after it has been obtained bycreatePluginFilter()
Does this make sense or am I missing something obvious?