Multi-out Synth

I’m trying to figure out how to have a synth with mono, stereo, and multi-out (6x mono/stereo) configuration. I’ve tried several methods but ended up with all kind of different problems between multiple DAWs.
AU, VST2, and VST3 seem to do different things also depending on which DAWs I’m using.

This is what I have in the constructor:

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)
               )

Method 1

bool isBusesLayoutSupported (const BusesLayout& layout) const override
{
    auto numInput = layout.getMainInputChannels();
    auto numOutput = layout.getMainOutputChannels();
    
    if (numInput == 0 && numOutput == 1) return true; // mono
    if (numInput == 0 && numOutput == 2) return true; // stereo
    if (numInput == 0 && numOutput == 6) return true; // multi out
    if (numInput == 0 && numOutput == 12) return true; // multi out
    
    return false;
}

Logic is reporting a bus count of 6 in processBlock, no matter which configuration I load (mono, stereo, multi). Also, getTotalNumOutputChannels() is reporting the following:
Mono: 11 channels
Stereo: 12 channels
Multi-Out (6xMono): 6 channels (for some other reason, bus 2 doesn’t work at all in this mode).
Multi-Out (6xStereo): 12 channels
So I don’t have a way to detect Mono and Stereo properly.


Method 2

    bool canAddBus    (bool isInput) const override   { return ! isInput; }
    bool canRemoveBus (bool isInput) const override   { return (! isInput && getBusCount (false) > 1); }
    
    bool canApplyBusCountChange (bool isInput, bool isAdding,
                                 AudioProcessor::BusProperties& outProperties) override
    {
        if (isInput)                              return false;
        if (getBusCount (false) == 0)             return false;
        if (  isAdding && ! canAddBus    (false)) return false;
        if (! isAdding && ! canRemoveBus (false)) return false;

        if (isAdding)
        {
            outProperties.busName = "Output " + String(getBusCount(false) + 1);
            outProperties.defaultLayout = AudioChannelSet::stereo();
            outProperties.isActivatedByDefault = true;
        }
        
        return true;
    }
    
    bool isBusesLayoutSupported (const BusesLayout& layouts) const override
    {
        if (layouts.inputBuses.size() > 0)
            return false;
        
        for (int i = 0; i < layouts.outputBuses.size(); ++i)
        {
            auto channelSet = layouts.outputBuses.getUnchecked (i);
            
            if (i == 0 &&
                channelSet != AudioChannelSet::stereo())
                return false;
            else if (channelSet != AudioChannelSet::stereo() &&
                     channelSet != AudioChannelSet::disabled())
                return false;
        }
        
        return true;
    }

Can’t figure out a way to limit the channels to 6 and to load also a mono configuration, so Logic is reporting only Stereo and Multi-Out (6xStereo).
This seems very stable though, bus count and channels are reported correctly, in Logic.

In Reaper instead, the AU and VST2 load as 12 out but the routing is wrong. Only the first bus is enabled (so only one bus is playing) and I have to manually use the Plug-in Pin Connector to enable the other Output. I couldn’t find a way to load is as normal mono/stereo as it always reports a bus count of 6, no matter what.

Reaper VST3 loads as it should, stereo first, then I can enable the other buses

I wonder, you are on one hand base your isBusesLayoutSupported in your first example on getMainOutputChannels(). I see, that you use in the second version the individual buses.

Does it work, if you do the following:

bool isBusesLayoutSupported (const BusesLayout& layout) const override
{
    if (layout.getMainInputChannels() > 0)
        return false;

    int selected = 0;

    for (auto& bus : layout.outputBuses)
    {
        if (bus.isDisabled())
            continue;

        if (selected == 0)
            selected = bus.size();

        if (bus.size() != selected)
            return false;  // only permit same kind of buses

        if (bus != AudioChannelSet::mono() 
            && bus != AudioChannelSet::stereo()))
            return false;
    }

    return true;
}

Thank you. I’ve tried your code, it seems to work really well in Logic, although I can’t figure out how to limit it to 6x instead of 16x. I’ve also left the canAddBus, canRemoveBus and canApplyBusCountChange as before though.

The problem is in Reaper, which is still doing the same. AU and VST2 report 6 busCount and 12 totalNumOutputChannels, so I have to manually enable the other buses using the Plug-in Pin Connector. VST3 instead reports 6 busCount but 2 totalNumOutputChannels, essentially loading as stereo, and I can easily add the other buses to create the multi-out.

Any idea of how can I have consistent behavior across DAWs?

Glad that it is at least an improvement. I guess, a real prediction can only someone give, who worked on all wrappers, if @fabian were around, or @t0m.

For Reaper I guess @Xenakios is your best bet.

Getting it right on most hosts is always a pain…
Good luck!

Thanks, I’ll wait for their replies.

bump!

One last bump. I’ve sent PMs to both @fabian and @t0m, no reply so far.

1 Like

I’m also having problems getting my Multi-Out version with on VST3. It works on VST2.
Using:

bool isBusesLayoutSupported(const BusesLayout& layout) const override;

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

I’ve honestly lost faith in the multi-out. It never really worked as other plugins that I’ve tested (like Kontakt or other synth/drum machines).
I remember that I could make VST3 work as it should, but with the same code AU and VST2 don’t.