4.1. AudioProcessor


#1

Why there are plugin-depended macros like JucePlugin_PreferredChannelConfigurations used inside the AudioProcessor implementation? I'm really scared! I use this class internally for a lot of different things :-/ 

 


#2

It's just there as a fallback so that old plugins still work with our new multi-bus stuff. That macro isn't needed any more if you use the new bus methods, and we'll eventually deprecate it completely.


#3

For you its maybe a minor issue, but this is something which can stop my developing the next 6 month.

I develop Multichannel-Plugins which are working with Logic, Cubase, ProTools, Sonar, Reaper, Live, Bitwig ....

Even the slightest change can have a big influence on end user experience.

If you a implement a fallback, it should work 100% exactly like it work before. If not, don't implement it.

Instead, give us a explanation how the old behavior can be simulated.

Maybe add a abstract function which loads the old JucePlugin_PreferredChannelConfigurations, which can be used only on the Main AudioProcessor.

AudioProcessor is a generic class, which is used a lot in my internal classes.

You cannot use the macro which was previously used only by the wrappers now for every time i use this generic class, even as fallback, this looks half-baked.

 


#4

What on earth are you getting so worked up about?

Of course it's supposed to be 100% backwards compatible! The new stuff aren't taking anything away, it's just providing a much more flexible way to define your plugin's channel config.

We internally use that old macro to set up the config like it would have been in the old version - if it fails to do what it used to, let us know and we'll fix it. Calling it "half-baked" is ridiculous, it's a perfectly legitimate way to provide legacy support until people no longer use the macro.


#5

I'm just irritated that the macro is used inside the AudioProcessor-class and not only by the wrappers anymore. (The AudioProcessor is a base class, for example for AudioProcessorGraph, its also a base class for a lot of other internal classes I've done.)

And i have the fear that i have a lot of hassle to be compabilte with the many configurations my costumers are running.

 

 

A few questions

- Is setPreferredBusArrangement always called while the processor is unprepared (before prepareToPlay, after releaseResources?)

- How to setup setPreferredBusArrangemen() when the plugin should work with one bus, but any different bus configuration?

mono, stereo, surround 5.1, surround  7.1

I always used {1,1},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},{8,8}

- How do  hosts behave which previously always the maximum configuration {8,8} in the past, will older projects compatible?

 

 

 

 


#6

So anything i have to do, to create a similar behavior like {1,1},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},{8,8} is to use this in my main AudioProcessor class?

bool setPreferredBusArrangement (bool isInputBus, int busIndex,
                                     const AudioChannelSet& preferred) override

    {

        const int numChannels = preferred.size();

        if (numChannels == 0) return false;
        if (numChannels > 8) return false;

        if (! AudioProcessor::setPreferredBusArrangement (! isInputBus, busIndex, preferred))
            return false;

        return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);

    }

#7

Yes, that looks like it'd work.


#8

Hi Jules,

Is there a way you guys can update the IntroJucer template so it do not use deprecated stuff ?

warning C4996: 'juce::AudioProcessor::getNumOutputChannels': was declared deprecated

warning C4996: 'juce::AudioProcessor::getNumInputChannels': was declared deprecated

 

Thanks !


#9

Thanks for reminding us! Yes, had forgotten about the templates, I'll have a look at that now.


#10

Thanks !


#11

I was checking your new AudioParameter stuff.

And it looks like it misses some kind of callback to be notified on the UI.

Right now the only way, as you have done in your simple ParameterSlider, is to poll the value which is not very nice.

Some kind of lock free intrusive single linked list for listeners would be great.

The UI would need to trigger an AsyncUpdater and then check the current value in the UI thread.

 

By the way the impl of updateSliderPos of ParameterSlider should probably be more along


  void updateSliderPos()
  {
    if (isMouseButtonDown())
      return;
    const float newValue = param.getValue();
    if (newValue != (float)Slider::getValue())
      Slider::setValue(newValue, juce::dontSendNotification);
  }

#12

We deliberately avoided adding anything to the base class for callbacks, as it's better to leave that for specialised classes to handle.

And actually, although the polling system might seem naive, it's actually pretty good when you think about the alternatives. 

Even if you had some kind of lock-free list (..and where would it live, in the paramter? one list per plugin? one global list?), then something still has to poll it. If your listener callbacks happen on the audio thread then there's not really anything useful you can do there other than set some kind of 'dirty' flag and wait for something else  to poll it and do the real work. So by keeping it simple, we just cut out the middle-man and let the message thread do the hard work of polling, and let the Timer's internal list implicitly manage the list of listeners. It's basically the same algorithmic complexity, and I can't see how there'd be anything to gain by adding the extra overhead of listener lists as well.

Yes, good point about the demo slider thing, that would be better, thanks for the heads-up.


#13

Well, I would have some kind of ParameterManager that handle the list of UI listeners

The parameter itself notify the manager, that push the id that has changed in a lock free FIFO, then call an asyncUpdater (or use a timer that poll the queue) then empty the queue in the UI thread and call listeners accordingly to notify that the value is dirty.

Having one timer per UI widget which bind with a parameter is really a bad practice imho.

 


#14

Timers are actually very cheap. The only advantage of that system would be in not unnecessarily polling unchanged parameters, but that's something that would only become significant when there are a lot of parameters. The downside is that the FIFO would need to have a fixed size so could overflow, and there'd be threading complexity around adding/removing/calling listeners, as well as the fact that a singleton parameter manager is probably a bit clunky to manage.

It's totally possible to build something that works like that based on the base classes as they are. But whether it'd be worth the effort would depend on many factors. Certainly when we've profiled things like Equator, the polling was completely insignficant in terms of its effect on performance.


#15

Well, there won't be any threading complexity around adding/removing/calling listeners are all of those are done in the UI thread.

The manager could be given to the parameter ctor, so no singleton.

 

Well, if you only use this for exported parameters then it could maybe do the trick as it's probably below 128, still I don't find this very elegant.

I have a more complex architecture than Equator, so this maybe explains this.

http://www.uvi.net/en/software/falcon.html

which by the way now supports the ROLI seaboard using a dedicated lua MPE script.


#16

Hi chkn,

Thank you for your questions. Allow me to answer them inline:

I'm just irritated that the macro is used inside the AudioProcessor-class and not only by the wrappers anymore. (The AudioProcessor is a base class, for example for AudioProcessorGraph, its also a base class for a lot of other internal classes I've done.)

It really shouldn't be a problem. It basically sets a default layout but this default layout shouldn't really ever be used (the old code for example sets the number of in&out channels to zero). As was the case before the recent multi-bus changes: you need to call setPlayConfigDetails before actually using the processor to override the default anyway. Now - with multibus - you may instead call setRateAndBufferSizeDetails and setPreferredBusArrangement if your "host" needs more control over the layout other than just the number of channels.

 Is setPreferredBusArrangement always called while the processor is unprepared (before prepareToPlay, after releaseResources?)

Yes exactly!

 

How to setup setPreferredBusArrangemen() when the plugin should work with one bus, but any different bus configuration?

Having only one bus is the default anyway. If you need more buses you add them in the constructor of your plugin. As your plug-in requires the same number of ins & outs you can use the following setPreferredBusArrangement:

    bool setPreferredBusArrangement (bool isInputBus, int busIndex,
                                     const AudioChannelSet& preferred) override
    {
        const int numChannels = preferred.size();

        // do not allow disabling a bus
        if (numChannels == 0) return false;

        // always have the same channel layout on both input and output on the main bus
        if (! AudioProcessor::setPreferredBusArrangement (! isInputBus, busIndex, preferred))
            return false;

        // you must ALWAYS call through to the base class if you accept the layout change
        return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
    }

The above is taken from the GainPlugin sample in the new examples/PlugInSamples folder. Have a look at that folder for more examples!

- How do  hosts behave which previously always the maximum configuration {8,8} in the past, will older projects compatible?

I can't think of a reason why they shouldn't be compatible but please get back to me if you do discover incompatibilities.

 

 


#17

I just setup a new computer, and now getting these warnings when opening a plugin for the first time in xcode:

 

testJucePlugin Group

/Users/user/Development/JuceCode/testJucePlugin/Source/PluginProcessor.cpp

/Users/user/Development/JuceCode/testJucePlugin/Source/PluginProcessor.cpp:103:18: 'getNumInputChannels' is deprecated

/Users/user/Development/JuceCode/testJucePlugin/Source/PluginProcessor.cpp:103:45: 'getNumOutputChannels' is deprecated

/Users/user/Development/JuceCode/testJucePlugin/Source/PluginProcessor.cpp:108:37: 'getNumInputChannels' is deprecated

/Users/user/Development/JuceCode/testJucePlugin/Source/PluginProcessor.cpp:110:16: Unused variable 'channelData'

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:46:13: 'AudioHardwareServiceHasProperty' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:49:31: 'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:58:23: 'AudioHardwareServiceHasProperty' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:71:13: 'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:85:20: 'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:99:13: 'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:113:20: 'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp:127:16: 'AudioHardwareServiceIsPropertySettable' is deprecated: first deprecated in OS X 10.11

/Users/user/Development/juce-grapefruit-osx/modules/juce_core/native/juce_mac_Network.mm

/Users/user/Development/juce-grapefruit-osx/modules/juce_core/native/juce_mac_Network.mm:264:47: 'initWithRequest:delegate:' is deprecated: first deprecated in OS X 10.11 - Use NSURLSession (see NSURLSession.h)


#18

The CoreAudio warnings are really odd. I just tried with the audio plugin demo, and I am not getting them. (use the newest JUCE tip & the newest Xcode)

Could you please tell me how I reproduce those warnings?

About the NSURL thing: yes this one is not fixed yet, will do asap.