[PATCH] stepped/ramped parameters for AAX, VST3 & AU

We would also vote for the “discrete/continuous” terminology. It’s what we already use internally in our code.

Regarding testing and backwards compatibility: afaik, it will be impossible for any JUCE Audio Unit plugin that is updated to use discrete parameters to be backwards compatible. Any session saved with the original plugin would no longer map parameter values correctly. This is because discrete parameter support in AU will require changing maxValue to be the true maximum value (or the number of steps) instead of just hardcoded 1.0f as it was previously. Perhaps it would be cleaner to use the true parameter values instead of zero-to-one values everywhere in AU (and other wrappers that support it?) since there may be other AU features that require non-zero-to-one values, and it would be difficult to make this transition twice.

Well, I’m so sorry we have to come back to this terminology issue. “discrete/continuous”. The issue with this is that it is confusing people about the fact that a limited number of possible parameter values is NOT tied with the fact that the parameters are ramped by the DAW and that a continuously variable parameter value is NOT tied with the values being ramped in the DAW. Which confusion was initially implemented in the JUCE wrappers (e.g. RTAS…). This terminology in DAW SDKs is confusing and we are not tied to use it. But whatever.

About the backward compatibility: my patch implements it by providing a legacy parameter configuration.

Cool. That’s oldRampCompatibility in your patch?

yep it’s oldRampCompatibility

Is there a situation where you would want to have getNumSteps() return something other than the default (i.e. you are indicating that your parameter is stepped) but still retain continuous/ramped behaviour?

I’ve been testing in a range of hosts and they all seem to ignore the result of getNumSteps() unless you also flag the parameter as discrete… If possible it would be nice to have the discrete flag set automatically if getNumSteps() is changed from the default.

FWIW, all of our parameters return a non-default number of steps because we use it to indicate a reasonable granularity for the control.

Here’s an example:

  • A volume control with range -96 to +12 dB
  • The control’s granularity is 0.01 dB, meaning that for both display & processing, we always round it to steps of 0.01 dB
  • numSteps is (12 + 96) / 0.01 + 1 = 10801, effectively continuous but not the same as 0x7fffffff
  • Automation should be continuous

Please please do not tie the continuous/discrete flag to the number of steps. In my opinion, it is the most problematic assumption that the AAX wrapper makes at the moment. I understand that most hosts may not use getNumSteps until a parameter is marked as discrete, but that doesn’t mean that none do or that none will in the future.

2 Likes

But where is the granularity indicated?

Logic, Reaper, Ableton, Bitwig, FL Studio and Pro Tools (on all supported platform and plug-in types) all appear to ignore the number of steps completely. I’m only omitting other hosts as I’ve not yet tested in them.

(Isn’t it (12 / 96) / 0.01 + 1 = 10801 in you case?)

Pro Tools does not ignore the number of steps, plus it uses it on control surfaces. I can’t test it again but I’ve found multiple hosts that support it anyway. IMHO it’s not because few hosts support it that plug-ins should not provide the info.

I’ve created an AAX parameter with 4 steps and marked it as continuous. Pro Tools then lets me set arbitrary values in the automation lane, and these arbitrary values get transmitted to the plug-in. Where does the number of steps come into play?

I don’t have a control surface to hand at the moment.

Could you please provide an example?

IIRC there is a VENUE emulator… You can run a software surface…
See http://www.avid.com/products/venue-software/features -> “work offline”

Example: Pro Tools with Control Surfaces that have rotary encoders, but my bad for other host examples.

Doesn’t mean it has no sense. Otherwise forbidding the num steps + continuous would prevent ramping between the discrete values, or would force using “continuous” with no meaning to the C++ parameter config side, and prevent adequate handling on the control surfaces.

Yes! My bad, should be +1. I’ll update my post.

Very much this:

As one of the original implementors of the automation and control surface support in Pro Tools 20+ years ago (and author of 40+ plugins since) , I can tell you there are numerous very valid reasons that discrete/continuous is decoupled from the number of steps in the Avid SDK (and at least the VST3 SDK, I didn’t hunt it down in the others) – and should likewise be decoupled in JUCE. One specific example is to determine the “increment” size for, say, the up/down arrows during text entry, or if there is “nudge” functionality in the UI or a control surface.

Don’t discount it just because you can’t think of a reason for it, or because a limited survey of limited functions in limited hosts didn’t seem to make a difference for your limited test case.

ROLI, please stop trying to be “clever” with the plug-in wrappers. There have been many times a “clever” shortcut in the JUCE wrappers lead to headaches for developers, e.g.: using param index instead of IDs, tying chunk version to plug-in version, using num steps to determine discrete/continuous. The AAX, AU, and VST3 plug-in SDKs are the product of decades of (often painful) experience. Don’t assume that just because you don’t see why something is done a certain way that there isn’t a good reason.

1 Like

I wasn’t discounting it, I was simply asking where I could see the effect.

Where is it decoupled in the VST3 SDK?

I called out the wrong SDK. I was incorrectly thinking of Vst::ParameterInfo::kIsList, which differentiates between parameters with string lists or dynamically generated strings. Similar to kAudioUnitParameterFlag_ValuesHaveStrings on the AU side.

The one it does matter for is AU, where there’s kParameterUnit_Indexed which discriminates between parameters that need to be passed normalized or non-normalized in order to appear correctly in the AU “Generic” UIs.

And - shoot me now - in AU there’s kParameterFlag_CanRamp which doesn’t appear to be documented anywhere.

I can’t speak to what aspects the JUCE parameter classes do or don’t support, but in the parameter classes I rolled before they existed there is quite a bit of differentiated behavior necessary for correct operation across GUI, Generic UI, automation, and control surfaces based on whether a parameter is discrete or not.

It’s hard to understand the pushback on this. The use of number of steps to set continuous/discrete in the AAX wrapper is an unquestionably wrong hack. It is a useful thing to keep the number of steps and discrete/continuous separated, because at least Pro Tools uses the number of steps distinctly from whether the control is continuous or discrete when it comes to control surfaces and automation. Once you make that distinction you can also use the number of steps to drive useful UI behaviors on all hosts and formats, even for continuous controls. The downside is…?

At the end of the day, I already have my own solution that works. It’s just frustrating that there is such resistance to fixing it once, in the main repo, leaving it instead for every developer to reinvent the wheel. Issues like this are why I and others continue to write and maintain our own custom wrappers and parameter classes.

Again, I’m not discounting those points I’m simply asking questions to ensure I haven’t missed anything, like what would have been a relevant part of the VST3 SDK.

1 Like

We’ve added a new method: AudioProcessorParameter::isDiscrete.

Backwards compatibility can be maintained with the macro JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE.

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

2 Likes