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.