Breaking change: Added an option to declare plug-in parameters as either continuous or discrete, irrespective of their number of steps


#1

https://github.com/WeAreROLI/JUCE/commit/4dcce5083c9128989577617facf6bd7ed3bc67a3

Change

The method used to classify AudioUnit, VST3 and AAX plug-in parameters as either continuous or discrete has changed.

Possible Issues

Plug-ins: DAW projects with automation data written by an AudioUnit, VST3 or AAX plug-in built with JUCE version 5.1.1 or earlier may load incorrectly when opened by an AudioUnit, VST3 or AAX plug-in built with JUCE version 5.2.0 and later.

Hosts: The AudioPluginInstance::getParameterNumSteps method now returns correct values for AU and VST3 plug-ins.

Workaround

Plug-ins: Enable JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE in the juce_audio_plugin_client module config page in the Projucer.

Hosts: Use AudioPluginInstance::getDefaultNumParameterSteps as the number of steps for all parameters.

Rationale

The old system for presenting plug-in parameters to a host as either continuous or discrete is inconsistent between plug-in types and lacks sufficient flexibility. This change harmonises the behaviour and allows individual parameters to be marked as continuous or discrete.


[PATCH] stepped/ramped parameters for AAX, VST3 & AU
Fix for quantization of automation data by Logic
#2

I haven’t updated yet, but it seems to me that your commit breaks much more things than just this continuous/discrete thing.

you have replaced many calls like those:

audioProcessor.getParameterDefaultValue (parameterIndex)
processorParam->getDefaultValue()
 juceFilter->isParameterAutomatable (index))

by the (not so) new AudioProcessorParameter class ‘equivalents’:

processorParam->getDefaultValue()
param->isAutomatable()

Isn’t it going to break all the plugins for people that are still using those AudioProcessors methods?
I know those that are commented with :

 NOTE! This method will eventually be deprecated! It's recommended that you use
        AudioProcessorParameter::isAutomatable() instead.

but they haven’t been deprecated yet, and many people are not using AudioProcessorParameter yet:


#3

Ah, yes. That managed to sneak past us.

A fix has been pushed to the develop branch.


#4

Thanks so much Tom! This is looking great in most hosts so far.

One issue: REAPER doesn’t seem to correctly show discrete parameters with JUCE-made Audio Unit plugins — they still appear continuous and the string names aren’t shown. We’ve confirmed with our old non-JUCE, AU plugins that REAPER does correctly show discrete parameters. As far as I can tell, all the flags you’ve set are more or less the same as what we were doing in our AU wrapper, so I’m not sure why it doesn’t work or what’s different.


#5

I have a fix for this - it’s just working it’s way though testing and review.


#6

https://github.com/WeAreROLI/JUCE/commit/743c9d55e7eb5c1a204383ae0b0c3983e8016761


#7

Thank you! This fix is looking great, behavior is now matching our non-JUCE AU plugins. Glad to have this resolved, your work is very appreciated.


#8

Tom, there are still 2 calls to AudioProcessor::getParameters() lines 921 and 939 that won’t work when we don’t use the AudioProcessorParameter classes.

patch.txt (1,3 Ko)


#9

Another fix will appear on the develop branch shortly. Thanks again for reporting.


#10

Hello @t0m ! New issue report :wink:

Let’s say I create a new plug-in from scratch with the Projucer on macOS. In the PluginProcessor constructor, I add a new parameter that I have declared as an AudioParameterChoice in the header, and I provide three string values for the choices. I compile it in VST + AU formats.

Now in Reaper, if I open the AU version, I’ll see… the Hello World on the UI :smile: That’s fine. If I click on the “UI” button on the top right of the window associated with the plug-in, I’ll see a list of all the parameters available. That’s where the problem is…

Since we have now the isDiscrete option enabled for AudioParameterChoice, instead of a slider, we’ll see now in Reaper a ComboBox (with Reaper UI) displaying the available options. And I’ll see the three options I provided in the constructor of my PluginProcessor. If I click on the first, everything is fine. If I click on the second, it’s fine as well. But if I click on the third, for a reason I don’t get the plug-in itself works as the third was properly selected, but in Reaper it’s still the second that is displayed as the one I have clicked on.

This bug has a lot of implications, as I see the same behaviour in other DAWs, and strange things happening in Logic Pro X.

By the way, in the AudioProcessor classes, should we set the return value of “getNumSteps” for AudioParameterChoice and AudioParameterInt to other values than AudioProcessorParameterWithID::getNumSteps() a.k.a. AudioProcessor::getDefaultNumParameterSteps() since they are discrete now ?

Thanks in advance !


#11

Fixed:

https://github.com/WeAreROLI/JUCE/commit/598b7919642bd00cb1687797a70269fa6ba32baa

getNumSteps has already been changed from the default for AudioPrameterChoice (which is discrete), and I’ve now done the same for AudioPrameterInt (which is not discrete). For AudioPrameterInt this will let the user continuously select values in the automation lane, but Pro Tools, and perhaps other DAWs, can still indicate the steps in other places.


#12

Thanks t0m, and you’re right about AudioParameterInt, it shouldn’t be discrete :wink:


#13

I’m a little confused. So, to properly set the isDiscrete flag in createAndAddParameter(), I also have to override isDiscrete() and getNumSteps() and therefore, subclass AudioProcessorParameter ? But then I can’t use AudioProcessorValueTreeState.createAndAddParameter() ?

I’m definitely confused. What’s the proper way to create/use discrete parameters with AudioProcessorValueTreeState?

It always seemed odd to me that the AudioParameterFloat/Int/Bool/Choice classes did not have counterparts when using AudioProcessorValueTreeState.


#14

No, you don’t. The AudioProcessorValueTreeState::Parameter is a generic parameter, that has the same bas class like the AudioParameterFloat etc, which is AudioProcessorParameterWithID, hence you can use the same interface.

getNumSteps() is already implemented, it deduces the information from the NormalisableRange.

I think it is an alternative to the AudioParameterFloat/Int/Bool classes. But the AudioProcessorValueTreeState version has already a better interface providing the AudioProcessorValueTreeState::Listener and the different attachment classes, so IMHO there is no need for the subclasses any longer.

HTH


#15

Thanks for the reply.

This is very cool. I’ve always wondered why some other plugins’ parameters show up in MainStage’s parameter list with sliders, on/off buttons and comboBoxes when mine were all only sliders. I just added the isDiscrete flag to my parameters that are really ints & bools and viola…MainStage shows them correctly.

And now…let me see if this breaks already created automation…


#16

Sorry to revive this topic, but I could use some clarification about this JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE flag: is this only relevant for plugins that use the new AudioProcessorParameter(WithID) + related classes, or also if your plugin is still using the AudioProcessor.setParameter calls?

Context: I have a plugin built with an old Juce version (a few commits before Juce 2.1.2), for which I recently released a new updated using Juce 5.3.2. The plugin is still using the AudioProcessor.set/getParameter calls, no AudioProcessorParameter classes.

(I had seen the other flag JUCE_FORCE_USE_LEGACY_PARAM_IDS, which is apparently only relevant when using the newer parameter classes, but was wondering about this automation flag as well)


#17

In your case I suspect it would be safest to enable this option. However, this one is easy to test: record some automation for a parameter using an old version of JUCE, then recompile and attempt to read the automation back. It will be really obvious if things are not working correctly. AUs in Logic X would the be easiest way to find out.


#18

OK, I’ll do some testing if it’s not clear what the effect should be.

Edit: I never declared any parameters explicitly as discrete/continuous, and am not doing that now either, so it’s not clear to me how things could change (unless there is something clever in the code that tries to find out if my parameters are continuous or discrete, but can’t see how that would work as I don’t have AudioProcessorParameter stuff in my code). Oh well, I guess I’ll have to go test each and every parameter then, right?


#19

Have a search for JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE in the source code to see what’s changed.

If you’ve never indicated that your parameters are discrete then the relevant changes are confined to the AU and AAX backends. Without the macro set AU parameters will be marked as HighResolution which allows the parameter to take more fine grained values in the automation lane, and AAX parameters will not have their “discreteness” set by whether they have more that 1000 steps or not.


#20

OK, I did some testing today, and I’m logging my experience with this flag here for the sake of clarity (I hope) in case anyone else finds it useful. Note that the following is all for the case where you are NOT using the AudioProcessorParameter(WithID) etc… classes, and still using the set/getParameterValue calls (possibly with your own parameter handling system).

  1. In Logic Pro X, I created automation ramps for several of my parameters with the old version of the AU plugin installed (from way before this flag even existed), with values ramping from 0.0 to 1.0. This moved the parameters in the plugin from their minimum values to their maximum values. I saved this project.

  2. I then installed the recently released version of my plugin (using Juce 5.3.2, and since I missed this change, with the JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE flag NOT enabled). When I open the project, the automation in Logic Pro X shows ramps from 0.0 to only around 0.79 (NOT 1.0), and my plugin’s parameters don’t move up to their maximum values any longer. This means that automation data is now incorrectly being read by this version of the plugin!

  3. I then rebuilt the plugin after setting JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE=1 in the project settings and installed that version. When I now open the project, automation ramps in Logic Pro X are again from 0.0 to 1.0, and my plugin’s parameters again move from their minimum to their maximum values.

So, this means that:

  • apparently this macro needs to be enabled to avoid automation data corruption if you are NOT using the AudioProcesorParameter(WithID) classes
  • users of the recent update of my plugin are screwed: if they created automation data while that version was installed, as soon as they install the new version with this flag enabled (or the old version from way before this macro existed), their automation data will lead to higher values than they intended

I also noticed that just opening and saving a project with that recent version of my plugin installed does not modify the automation data (although the automation data values look lower in Logic Pro X), and these projects again show correct automation data values when the new fixed version with that flag enabled is installed, and the plugin parameter values are being automated correctly again.

Not sure how to break this news to the people who created automation data with that recent version of my plugin now…