Multichannel configuration - get Reaper infos

Hi everyone,

I’m currently developing a multichannel plugin linked specifically to Reaper.
I’d like to create an adaptive plugin that changes channel configuration depending on what I modify in Reaper’s routing. But I’m really struggling with the relationship between the two.

  • First question: is it already possible to adjust a plugin depending on Reaper or vice versa (select a config in a drop down menu in the plugin and this changes the behaviour on Reaper in terms of routing).
  • Second question: if yes, in which zone on JUCE could I get back in real time the possible change of configuration of the user on Reaper, I saw that on certain forum the method prepareToPlay is made for that.

Thanks in advance for your help :slight_smile:

As I understand it, plugins don’t get to affect the host much. You can accept or reject channel configs/bus layouts in isBusesLayoutSupported, and you can find out which layout you have currently been put into with getBusesLayout. Aside from that, I suppose all you can do is output silence on all channels except one and say “I’m mono, damnit!”

I’ve created somehting like this:

#if !JucePlugin_IsMidiEffect
#if !JucePlugin_IsSynth
    props = props.withInput("Mono L", juce::AudioChannelSet::mono(), true)
                .withInput("Mono R", juce::AudioChannelSet::mono(), true);
#endif
    props = props.withOutput("L", juce::AudioChannelSet::mono(), true)
                .withOutput("R", juce::AudioChannelSet::mono(), true)
                .withOutput("C", juce::AudioChannelSet::mono(), true)
                .withOutput("LFE", juce::AudioChannelSet::mono(), true)
                .withOutput("WL", juce::AudioChannelSet::mono(), true)
                .withOutput("WR", juce::AudioChannelSet::mono(), true)
                .withOutput("SL", juce::AudioChannelSet::mono(), true)
                .withOutput("SR", juce::AudioChannelSet::mono(), true)
                .withOutput("LS", juce::AudioChannelSet::mono(), true)
                .withOutput("RS", juce::AudioChannelSet::mono(), true)
                .withOutput("TL", juce::AudioChannelSet::mono(), true)
                .withOutput("TR", juce::AudioChannelSet::mono(), true)
                .withOutput("LC", juce::AudioChannelSet::mono(), true)
                .withOutput("RC", juce::AudioChannelSet::mono(), true)
                .withOutput("TRL", juce::AudioChannelSet::mono(), true)
                .withOutput("TRR", juce::AudioChannelSet::mono(), true);

But when in Reaper I set the vst3 bus size to a value greater than 9, I get the JUCE assertion in juce_VST3Common.h:740 to fail.

void DPannerAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
    DBG("***** prepareToPlay *****");

    int totalInputChannels = getTotalNumInputChannels();
    int mainBusInputChannels = getMainBusNumInputChannels();
    int totalOutputChannels = getTotalNumOutputChannels();
    int mainBusOutputChannels = getMainBusNumOutputChannels();

    DBG("Total Number of Input Channels: " + juce::String(totalInputChannels));
    DBG("Main Bus Number of Input Channels: " + juce::String(mainBusInputChannels));
    DBG("Total Number of Output Channels: " + juce::String(totalOutputChannels));
    DBG("Main Bus Number of Output Channels: " + juce::String(mainBusOutputChannels));
Total Number of Input Channels: 9
Main Bus Number of Input Channels: 9
Total Number of Output Channels: 9
Main Bus Number of Output Channels: 9
JUCE Assertion failure in juce_VST3Common.h:740
JUCE Assertion failure in juce_VST3Common.h:740

How to shield code properly ?

It looks like your constructor does not match your isBusesLayoutSupported.

I use a similar little DBG to yours to see the negotiations between the DAW and the plugin.

bool processor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
    auto numIn = layouts.getMainInputChannels();
    auto numOut = layouts.getMainOutputChannels();
    bool supported = dspEngine::busLayoutSupported(numIn, numOut);

    DBG(
        String{ "Proposed: " } +
        layouts.getMainInputChannelSet().getDescription() + " -> " +
        layouts.getMainOutputChannelSet().getDescription() +
        "\t and we said " + (supported ? "yes" : "no")
    );

    return supported;
}

Ok thanks !
Where does the dspEngine comes from ?

I want to configure on init this


I can do it easily with ReaSurroundPan (Reaper’s panner) but when I try this kind of configuration:

props = props.withInput("Input", juce::AudioChannelSet::mono(), true);
props = props.withOutput("Output", juce::AudioChannelSet::mono(), true);

Just to get a stereo.


When I want to configure more channels (here selected 6), the inputs are also increasing.
For example, I want to be able to set my input to mono and select the number of outputs that I want.

Is this right?

UpMixProcessor::UpMixProcessor()
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::mono(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::create9point1point6(), true)
                     #endif
                       )

...

bool UpMixProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
    auto numIn = layouts.getMainInputChannels();
    auto numOut = layouts.getMainOutputChannels();

    bool supported = 
        numIn == 1 &&
        1 < numOut && numOut <= 16;

    DBG(
        String{ "Proposed: " } +
        layouts.getMainInputChannelSet().getDescription() + " -> " +
        layouts.getMainOutputChannelSet().getDescription() +
        "\t and we said " + (supported ? "yes" : "no")
    );

    return supported;
}

Oh actually I think what you want is this:
image

I only got this once I told Reaper I supported 16 channels no more no less. I couldn’t figure out how to get Reaper to give me 16 outs if I said I supported 2-16 channels.

Hi !
Yes this is great but the issue here is that the “Track channels” selector settles the output AND ALSO the inputs. I would like an asymmetrical and adaptive routing such as 1 IN - 16 OUT, 4 IN - 8 OUT and so on.

image
This is exactly the kind of think that I want effectively.
Did you configure the JUCE Processor as:

props = props.withInput("Input", juce::AudioChannelSet::stereo(), true)

props = props.withOutput("L", juce::AudioChannelSet::mono(), true)
                .withOutput("R", juce::AudioChannelSet::mono(), true)
                .withOutput("C", juce::AudioChannelSet::mono(), true)
                .withOutput("LFE", juce::AudioChannelSet::mono(), true)
                .withOutput("WL", juce::AudioChannelSet::mono(), true)
                .withOutput("WR", juce::AudioChannelSet::mono(), true)
                .withOutput("SL", juce::AudioChannelSet::mono(), true)
                .withOutput("SR", juce::AudioChannelSet::mono(), true)
                .withOutput("LS", juce::AudioChannelSet::mono(), true)
                .withOutput("RS", juce::AudioChannelSet::mono(), true)
                .withOutput("TL", juce::AudioChannelSet::mono(), true)
                .withOutput("TR", juce::AudioChannelSet::mono(), true)
                .withOutput("LC", juce::AudioChannelSet::mono(), true)
                .withOutput("RC", juce::AudioChannelSet::mono(), true)
                .withOutput("TRL", juce::AudioChannelSet::mono(), true)
                .withOutput("TRR", juce::AudioChannelSet::mono(), true);

Stereo or mono, doesn’t really matter yet in my situation.

Or did you change some configurations on Reaper ?

I used the same constuctor for both results:

UpMixProcessor::UpMixProcessor()
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::mono(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::create9point1point6(), true)
                     #endif
                       )

You can do 9.1.6 → 9.1.6 and then you’ll be able to support multichannel inputs as well.

I did with your config:

props = props.withInput("Input", juce::AudioChannelSet::mono(), true);
    props = props.withOutput("Output", juce::AudioChannelSet::create9point1point6(), true);

But I get something like this:

I imagine you would have got an assert there? Maybe post your layoutSupported too?

createBusesProperties() const
{
    BusesProperties props;

#if !JucePlugin_IsMidiEffect
#if !JucePlugin_IsSynth
    props = props.withInput("Input", juce::AudioChannelSet::mono(), true);
    props = props.withOutput("Output", juce::AudioChannelSet::create9point1point6(), true);
#endif
#endif

    return props;
}
#ifndef JucePlugin_PreferredChannelConfigurations
bool isBusesLayoutSupported(const BusesLayout &layouts) const
{
    auto numIn = layouts.getMainInputChannels();
    auto numOut = layouts.getMainOutputChannels();

    bool supported =
        numIn == 1 &&
        1 < numOut && numOut <= 16;

    DBG(
        String{"--------------------------------------------------- \n Proposed: "} +
        layouts.getMainInputChannelSet().getDescription() + " -> " +
        layouts.getMainOutputChannelSet().getDescription() +
        "\t and we said " + (supported ? "yes" : "no"));

    return supported;
}
#endif
void prepareToPlay(double sampleRate, int samplesPerBlock)
{
    DBG("***** prepareToPlay *****");

    int totalInputChannels = getTotalNumInputChannels();
    int mainBusInputChannels = getMainBusNumInputChannels();
    int totalOutputChannels = getTotalNumOutputChannels();
    int mainBusOutputChannels = getMainBusNumOutputChannels();

    DBG("Total Number of Input Channels: " + juce::String(totalInputChannels));
    DBG("Main Bus Number of Input Channels: " + juce::String(mainBusInputChannels));
    DBG("Total Number of Output Channels: " + juce::String(totalOutputChannels));
    DBG("Main Bus Number of Output Channels: " + juce::String(mainBusOutputChannels));
}

When I change the Track channels size from 2 to 16 in Reaper, the values in the prepareToPlay dosen’t change, it’s always:
***** prepareToPlay *****
Total Number of Input Channels: 1
Main Bus Number of Input Channels: 1
Total Number of Output Channels: 2
Main Bus Number of Output Channels: 2

Yes, this is what I saw. I couldn’t see how to convince Reaper to give 16 channels when 2 was an option in layoutSupported. Maybe with a 16 channel audio file on the track?

Edit: it seems that reaper just uses the smaller of the input channels and the output channels. I think for your purposes going with 16 → 16 will work. Make sure to keep your constructor in sync with your layoutSupported.

Hello,

Yep, thank your for your help.

props = props.withInput("In 1", juce::AudioChannelSet::mono(), true)
                .withInput("In 2", juce::AudioChannelSet::mono(), true);

    props = props.withOutput("Out 1", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 2", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 3", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 4", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 5", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 6", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 7", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 8", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 9", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 10", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 11", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 12", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 13", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 14", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 15", juce::AudioChannelSet::mono(), true)
                .withOutput("Out 16", juce::AudioChannelSet::mono(), true);

This config gives me:

So I think that I will go with this.
Now, the next step is to have a configuration that can also be adapted depending on the number of inputs, e.g. if I want to send 4 channels as inputs, the plugin can be adapted for.
I have the feeling that for the moment the inputs to my plugin remain fixed (if I create 4 of them, I can’t reduce them to two, for example).

Indeed, the plugin cannot change the inputs/outputs the DAW is giving it. It can output silence on certain channels/ignore the input of certain channels.

Please note that your constructor creates 16 mono buses, not 1 bus of 16 channels. To be honest, I don’t know how this translates to VST/Reaper but since @reuk felt it was worth pointing it out on the Discord, I wouldn’t ignore it.

I’m hitting this issue to. I’m setting what the plugin supports in my cmake

juce_add_plugin(INU
PLUGIN_CHANNEL_CONFIGURATIONS
“{2,2}”
“{2,8}”
“{2,10}”
“{2,12}”
“{2,14}”
“{2,16}”

)

Then in the process:

bool INUAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
// Requirements:
// - Exactly one input bus and one output bus
// - Stereo input only (INU is a stereo upmixer)
// - Output can be 2 / 8 / 10 / 12 / 14 / 16 channels
// (host may label these as surround, height sets, or discrete)

if (layouts.inputBuses.size() != 1 || layouts.outputBuses.size() != 1)
return false;

const auto inSet = layouts.getMainInputChannelSet();
const auto outSet = layouts.getMainOutputChannelSet();

// Only accept stereo input
if (inSet != juce::AudioChannelSet::stereo())
return false;

const int outs = outSet.size();

// Validate supported output channel counts
if (! isSupportedOutCount (outs))
return false;

// If the host provides a named layout (e.g. 7.1.4),
// we accept it as long as the channel count matches.
// Internally we map by channel count into our canonical 9.1.6 domain.
return true;
}

Reaper will just not seem to allow more than stereo unless a hardcode it to 16 and put “{16,16}” in my CMakeLists.

I just want a stereo input and if user has set up track to n-size channels then the output bus has a size of n-size channels: 2,8,10,12,14,16 (stereo, 5.1.2,5.1.4/7.1.2,7.1.4,9.1.6)

Been battling this all day and got nowhere other than forcing Reaper to 16 channels but it’s’ messy. I think for most surround formats Reaper reports it supports correctly. 9.1.6 seems to me missing and returns as 2:16 Discreet not 9.1.6 Surround??

This is what Reaper says it supports on a 16 channel track/bus even though it only supports 2in 2 out

INU isBusesLayoutSupported: in=1 out=1 outDesc=Mono
INU isBusesLayoutSupported: in=2 out=16 outDesc=Discrete #16
INU isBusesLayoutSupported: in=1 out=16 outDesc=Discrete #16
INU isBusesLayoutSupported: in=2 out=1 outDesc=Mono
INU isBusesLayoutSupported: in=2 out=2 outDesc=Stereo
INU isBusesLayoutSupported: in=1 out=2 outDesc=Stereo
INU isBusesLayoutSupported: in=3 out=3 outDesc=LRS
INU isBusesLayoutSupported: in=4 out=4 outDesc=Quadraphonic
INU isBusesLayoutSupported: in=4 out=4 outDesc=1st Order Ambisonics
INU isBusesLayoutSupported: in=5 out=5 outDesc=5.0 Surround
INU isBusesLayoutSupported: in=6 out=6 outDesc=5.1 Surround
INU isBusesLayoutSupported: in=7 out=7 outDesc=7.0 Surround
INU isBusesLayoutSupported: in=8 out=8 outDesc=7.1 Surround
INU isBusesLayoutSupported: in=9 out=9 outDesc=5.0.4 Surround
INU isBusesLayoutSupported: in=9 out=9 outDesc=2nd Order Ambisonics
INU isBusesLayoutSupported: in=10 out=10 outDesc=7.1.2 Surround
INU isBusesLayoutSupported: in=11 out=11 outDesc=Unknown
INU isBusesLayoutSupported: in=12 out=12 outDesc=7.1.4 Surround
INU isBusesLayoutSupported: in=12 out=12 outDesc=Unknown
INU isBusesLayoutSupported: in=2 out=0 outDesc=Discrete #0
INU isBusesLayoutSupported: in=0 out=0 outDesc=Discrete #0

so why does this come back false and switches to stereo when it’s’ exactly what my cmakelists says I support and want? So weird.

INU isBusesLayoutSupported: in=2 out=16 outDesc=Discrete #16

Seriously?? Nobody has solved this?? I don’t need IO to be different. In fact, an important solution to a bug I ran into in Nuendo early in development requires me to stipulate that Inputs and Outputs always match (with the exception of the aux inputs). I thought maybe I needed to make the aux channels scale up to 16 too to get around this issue, but that didn’t work and clearly that’s not the issue for everybody else.

All adding the channel config in Projucer settings did was make my aux channels disappear even though I thought I guarded against that). I’m too close to the end of development to suddenly remove the channel scaling and lock into 9.1.6, which wouldn’t work anyway for me because, in this particular plugin that would make it a ridiculous CPU hog when there’s benefit in in the extra load.

This issue is only a problem in Reaper, but I can’t just forget about Reaper users and expect the plugin to be as popular as it needs to be. I’ve given everything to this plugin. If it doesn’t sell my family is screwed. I’ve got kids depending on me to pull this thing off.

FML. I just had to get desperate enough to sacrifice the sidechain. As soon as I cut it out of the processor, the plugin built and channel-scaling worked in Reaper perfectly immediately. Now I have to change part of the UI again to add insult to injury.

Are you experiencing the same issue for both VST3 and AU? if not maybe you can just disable your side-chain on one of them and/or only for Reaper?