Multibus API

OK I’ve pushed a fix for this on develop. It was related to the fix I did for chkn above.

@pflugshaupt I can confirm that this fixed your bug
@chkn As I can’t seem to reproduce your issue, this commit may break the fix for your white noise bug. Please test!

1 Like

Thanks for the immediate action. The last change fixes the issue I saw. I’ll be sure to test more the next days.

Need advise. Planing to release a plug-in in two weeks and I’m a bit confused about the multibus subject. Temporarily my plug-in is on juce 4.2.3 and the multibus is implemented according the “deprecated multibus guide”. Is it ok to release “as is” or should I better update to 4.2.4 with the new multibus classes?

I’m in the same situation, the problem is, if you need quick fixes now, need the latest juce, the new api will break. Then you fix the changes, and have maybe new issues.
This is not a good situation at all.
I decided to wait and use the new new api, but its your choice.

Hopefully newer juce releases will not break the api anymore.

1 Like

I guess you should either use the older api or wait a few more weeks until more bugs have been fixed. Personally I wouldn’t release a plugin with the new stuff right now… not even a non-multibus plugin. I am seeing some weirdness with the new api, but I’m not sure what’s going on. I’m hoping many developers are adapting to the newest multibus api so we can get something that’s really stable.

Right now I am seeing some new problems with AudioProcessGraph and AudioProcessors using many discrete channels. I’ll post here again once I figure out where the issue might be.

Turns out it was my own bug (unsurprisingly). I am also having some unrelated problems using an AudioProcessorGraph inside a plugin I really could use some help with: AudioProcessorGraph crashes after removing node

@chkn @chip: I can understand your frustration having to adapt your plug-in to a new API two times. Obviously, I’d love people to use the new API as it is - IMHO - much more stable than the old one.

Having mostly written the new API, I obviously think that the transition from the old API to the new one is really not that hard. But I’m biased of course.

In any case, to make it easier for anyone using the old API to migrate to the new one, I’d like to offer free 1 on 1 help via Skype/Hangouts. Just drop me a PM and we schedule some time.


Fabian, I think rewriting the API was a good choice and I very much like what you came up with. It’s much easier to understand that the one before and so far it’s working nicely for me.


Any estimate date for the promotion of this new API from develop to master?

Projucer tip needing an update:

1 Like

I’m currently trying to manage the update to the latest release of Juce (namely, 4.3.0). Many things are not clear, the documentation is not clear about what is required to make it work, or what to do if we want to achieve some (a bit more than simplest) goals. Here is an issue I’m encountering:
I’ve got a plug-in with 10 inputs and 4 outputs. i’ve declared it using the following constructor:

AudioProcessor(BusesProperties().withInput("In", AudioChannelSet::discreteChannels(10), true)
                                .withOutput("Out", AudioChannelSet::ambisonic(), true))

The first issue I encounter with REAPER is the additional channels visible in the plug-in I/O pane: I’ve got 8in/8out whereas I previously had 10in/4out:

The second issue I encounter is the following code from processBlock() erasing some of my first output channels:

    for (int i = 4 ; i < std::max(getTotalNumInputChannels(), getTotalNumOutputChannels()); ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

Indeed, some channel buffers >=4 repeat some channel buffers <4

Also, some of my 10 input channels pointers repeat the first channels’ pointers.

  1. Did I miss a virtual function’s override? If so, how am I supposed to implement these? (some code is appreciated as I’ve found no (clear) documentation or example anywhere)

  2. In case of issue for a buffer (not connected, etc.) it would be appreciated that the channel buffers be initialized with a nullptr (so that behaviour of the code could be adapted in a simple manner) or an external buffer which does not interfere with the valid channels (like for now, it duplicates inputs or overwrites output) -> “fail gracefully”

With the new API, where are we supposed to respond to the channel config changing? I used to allocate the new buffers etc in prepareToPlay however that seems to not always get called when setting a new config now. Is there a better place?

Edit: This is specifically in the VST3 Wrapper

Perhaps one of these AudioProcessor callbacks is what you are looking for?

/** This method is called when the total number of input or output channels is changed. */
virtual void numChannelsChanged();

/** This method is called when the number of buses is changed. */
virtual void numBusesChanged();

/** This method is called when the layout of the audio processor changes. */
virtual void processorLayoutsChanged();

I was using

getTotalNumInputChannels ();

to get the Number of InputChannels in my AudioProcessor Constructor in order to create the right number of Parameters for the plugin. Now, after the update, this always returns 0 in the constructor. Only in the prepareToPlay function it returns correctly. I’m not using any of the Multibus features, I just use 3 different possible channel configurations in the Projucer ( {8,2}, {2,2,}, {1,2} )


1 Like

Have you had a look at the examples in JUCE/examples/PluginSamples? There are a few use cases there?[quote=“fbecker, post:78, topic:18491”]
I’ve got a plug-in with 10 inputs and 4 outputs. i’ve declared it using the following constructor:

AudioProcessor(BusesProperties().withInput(“In”, AudioChannelSet::discreteChannels(10), true)
.withOutput(“Out”, AudioChannelSet::ambisonic(), true))

The first issue I encounter with REAPER is the additional channels visible in the plug-in I/O pane: I’ve got 8in/8out whereas I previously had 10in/4out:

The formats in the constructor are just the default formats of your plug-in. The host can change the format of the plug-in to anything else. You should be overriding the isBusesLayoutSupported callback and only return true if you are supporting the layout. This way you can restrict the layouts.

I don’t quite understand this. The buffers you receive will always have the correct channel size. It just that reaper has initialized you plug-in to have too many ins and outs. I think overriding isBusesLayoutSupported will help you here as well.

If you run into problems please send me a pm and when schedule a skype meeting to get you started.

@Logan_Thomas @yfede A quick note on callbacks when the layout changes: As @yfede mentions, the callbacks numChannelsChanged etc. can be used to get a callback when the number of channels changes. However, you should very rarely need to use them. This is because the API is passive: you only know the number of channels and layout when your prepareToPlay method is called - usually just before playback, i.e. several layout changes may be requested behind the scenes while your plug-in is suspended. This was always the way JUCE worked even before multibus (i.e. setPlayConfigDetails does not give you a callback either).

This should not be a problem though: as your plug-in is suspended you will not get any processBlock calls. If you need to do some work when the layout/channels change, then you should be doing this in the prepareToPlay method anyway. If you need to reject layout changes, then you should be doing this in the isBusesLayoutSupported callback.

But if you need to the callbacks are there for you to use.

1 Like

Sorry about this. The fact that you were getting the correct number of channels in the constructor is actually a “bug” with the first multi-bus implementation that was on master recently. The current implementation on master is now in line with how JUCE worked before multi-bus was introduced, i.e. the number of channels was always zero when the constructor is called. This behaviour is needed for backwards compatibility.

However, fixing this is easy: you can get the correct number of channels if you simply use the non-default AudioProcessor base constructors and specify a default layout for your plug-in.

I’m not sure this will work very well. Many DAWs will request a layout change after the plug-in was constructed (this has nothing to do with multi-bus). However, hosts don’t really like you changing the number of parameters after you plug-in is constructed.

I think the only feasible way to do this is to construct as many parameters as there can maximumly be channels (i.e. 8) and let your editor respond to the layout changes by hiding unused parameters.

1 Like

@fabian, it looks like the AudioProcessor documentation on the website is not up to date with this new multibus API.
Can you please update it?

@fabian No, the examples in the juce repository were of no help.

I’ve finally achieved to make it run (my 10in/4out plug-in) doing the following:

-> Implement isBusesLayoutSupported:

    bool isBusesLayoutSupported (const BusesLayout& layouts) const override
        return (layouts.getMainInputChannels() == 10
             && layouts.getMainOutputChannels() == 4);

-> Hack Juce (because otherwise I would end up with a crash in REAPER) for the channel count limit:

diff --git a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
index c4c9274..7eb56a7 100644
--- a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
+++ b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
@@ -305,7 +305,7 @@ public:
-        maxChannelsOfNamedLayout = 8
+        maxChannelsOfNamedLayout = 16
     /** Adds a channel to the set. */
diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
index 37f4f3f..4cf0f73 100644
--- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
+++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
@@ -1943,7 +1943,7 @@ private:
         AudioChannelSet inputLayout  = filter->getChannelLayoutOfBus (true,  0);
         AudioChannelSet outputLayout = filter->getChannelLayoutOfBus (false,  0);
-        const std::size_t speakerBaseSize = sizeof (VstSpeakerConfiguration) - (sizeof (VstIndividualSpeakerInfo) * 8);
+        const std::size_t speakerBaseSize = sizeof (VstSpeakerConfiguration) - (sizeof (VstIndividualSpeakerInfo) * 16);
         cachedInArrangement .malloc (speakerBaseSize + (static_cast<std::size_t> (inputLayout. size()) * sizeof (VstSpeakerConfiguration)), 1);
         cachedOutArrangement.malloc (speakerBaseSize + (static_cast<std::size_t> (outputLayout.size()) * sizeof (VstSpeakerConfiguration)), 1);
diff --git a/modules/juce_audio_processors/format_types/juce_VSTInterface.h b/modules/juce_audio_processors/format_types/juce_VSTInterface.h
index 502f367..e077a48 100644
--- a/modules/juce_audio_processors/format_types/juce_VSTInterface.h
+++ b/modules/juce_audio_processors/format_types/juce_VSTInterface.h
@@ -409,7 +409,7 @@ struct VstSpeakerConfiguration
     int32 type;
     int32 numberOfChannels;
-    VstIndividualSpeakerInfo speakers[8];
+    VstIndividualSpeakerInfo speakers[16];
 enum VstSpeakerConfigurationType

Not sure about everything in this patch but “it works”, “allows 10 channels”, “prevents an unavoidable crash”.

I hope it helps (ROLI & juce users),

seems reasonable, thanks for the detailed answer.