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


#1

Hi,

On GitHub I’ve created a branch named “canramp” for the necessary patches for making the parameter automation stepped or ramped in the automation lanes of the hosts:

https://github.com/julianstorer/JUCE/compare/develop...francoisbecker:canramp

As most VST24 hosts don’t look at this flag this plug-in format is not included in the patch.

With this patch, you’ll be using the following enum when declaring a parameter thanks to AudioProcessorValueTreeState::createAndAddParameter :

/** Defines how the intermediate values between two automation points behave
    in automation lanes of DAWs.
*/
enum RampCapability
{
    paramCantRamp = 0,       /**< Stepped parameters in the automation lane,
                                  intermediate values are not taken. */
    paramCanRamp = 1,        /**< Successive automation points are linearly
                                  interpolated in the automation lanes. */
    oldRampCompatibility = 2 /**< Parameter are ramped, except with AAX when
                                  the number of steps is <= 1000. Should be
                                  avoided for new plug-ins and new
                                  parameters. */
};

Please note that changing the flag for a JUCE plug-in does break the DAW sessions with automation as automation behaviour changes, an especially with AU because stepped automations in AU require the parameter to be integer-valued, AFAIUnderstood/achieved.

You’re welcomed to test, comment, amend this patch, and eventually include it in JUCE

Best,
François


#2

How can the plugin determine what the right parameter value at a certain sample position is?
Its very important that the solution is downwardly compatible.
This must be tested extensively in separate branch, before it goes into the develop branch


#3

This is not the plug-in that determines the intermediate values, it’s the host. Actually currently in the vanilla JUCE all the parameters are already declared ramped, except with the AAX wrapper when numsteps <= 1000; this patch allows to declare parameters as stepped or ramped uniformly across AAX, VST3, AU plug-in formats, and independently from the number of steps.

You’re right, when changing the canRamp flag, even if recorded automation values are kept, intermediate values will change. However for new plug-ins or new parameters this is no issue.

I’ve made a fix for compatibility with the old (erroneous) AAX wrapper behaviour that stated that if the number of steps was > 1000 then it could ramp (erroneous because both concepts of number of steps and ramped or stepped automation are unrelated, even if VST3 chooses to make the link in some manner).


#5

Has anyone had a chance to have a try on this? That’s a feature many products want, it would be great to have it integrated into JUCE.


#6

Sorry, no time yet, my question was, how does a plugin looks like which uses these ramped parameters.
Maybe a simple gain-plugin. At least we need a parameter value for the beginning and the end of the block in processBlock(…)


#7

Hi chkn, the plug-ins don’t look different, the parameters don’t look different. It’s their automation in the host that is different between the automation points: here is ramping/continuous:

versus stepped/discrete, with the same automation points:

I hope this makes it clear, or maybe I didn’t understand your question?


#8

Ah okay it’s only about the host :wink:

I was thinking about, how to realize sample accurate handling of ramps over all hosts/formats as a plugin-developer.

This is something which is missing in JUCE.

PS:
The easiest way would be to give the plugin the beginning and end level of a ramp with the processBlock.

If the ramp begins/ends inside the processBlock call, the block could be split up into more pieces, and then they processed separately. This would be an easy interface for plugin-developers.


#9

That would be up to the DAWs, which don’t work like that. They provide the plug-ins with new (interpolated or not) parameter values between each block processing.

This kind of feature depends on the DAW and the plug-in API, IIUC VST3 attempts to implement that, but the juce VST3 wrapper doesn’t provide (yet) such a feature. But that’s another story.


#10

If this is folded in, I strongly urge the use of continuous/discrete nomenclature instead of can/can’t ramp. Ramp implies a rate (and linear change). Discrete/continuous is also more consistent with the existing nomenclature in RTAS and AAX.


#11

You want to discuss the nomenclature; indeed Discrete/Continuous is a Pro Tools nomenclature; however it should not be linked to the “number of steps”, but how the parameter should variate: does it take intermediate values or goes it directly to the target value. A parameter could want only a few different values, e.g. 3 but want that the intermediate values are used on automation. A parameter could otherwise with a huge number of steps, but not be capable of constant variation e.g. if it creates a zipper noise -> we want it to go directly to its target value without taking the intermediate values.

If you don’t like “ramp” it could be “interpolate”. Let’s try the forum’s polling :slight_smile:

  • continuous/discrete
  • canRamp/cantRamp
  • interpolate/jump

0 voters


#12

Do I understand correctly. Do you want different continous/discrete behaviour between your plugin GUI and plugin automation? I don’t understand your example.

I just tested in Reaper. For me the discrete functionality is working fine in VST3, but not with VST and AU. I implemented the AudioProcessorValueTreeState and added a Parameter with NormalisableRange with an interval value. That probably needs some bugfixing…

top AU, middle VST, bottom VST3


#13

Hi John, thanks for testing this!

This has nothing to do with the plug-in GUI nor different behaviour between the plugin GUI and plugin automation.

The automation lane is entirely implemented by the DAW according to how the DAW interprets (and implements) informations related to the parameters that are given by the plug-in. REAPER does not implement discrete/continuous for VST24 nor AU. REAPER does implement discrete/continuous for VST3. Logic implements discrete/continuous for AU.

So, for this, this is no JUCE bugfixing, this is REAPER bugfixing, or rather implementing (for AU solely, because I’ve found no host that implements that for VST24).


#14

ah ok. Thanks for clearing it up. I wasn’t aware.

The screenshots are not from your branch, but from a plugin made with the official JUCE repo and it seems to work there. Sorry, I don’t seem to understand what functionality can be achieved with your branch compared to the existing NormalisableRange’s interval value.


#15

Currently all VST3 parameters are declared discrete by the JUCE wrapper, the proposed patch allows to make them rampable (by declaring in the VST3 API a number of steps of 0, as required by their SDK)


#16

Dear fbecker,

It’s great job! I also faced same issue on my automation lane, so I did workaround as I make interval narrow for making over 1000 numOfSteps. I agree with your idea which user can choose the mode of parameterType(discrete/continuous). I will try it.


#17

Any progress on incorporating this patch? We’ve implemented a similar solution for VST3 for now, but it’d be nice to have a JUCE-sanctioned fix.

Also, it would be great to avoid this continuous / discrete determination in the AAX wrapper:

        parameter->SetType (parameterNumSteps > 1000 ? AAX_eParameterType_Continuous
                                                     : AAX_eParameterType_Discrete);

We have lots of parameters that should be automated as continuous but in actuality have less than 1000 steps.


#18

@jules, @fabian: A proposal to easily integrate this together with a few more features would be to extend the AudioProcessorParameter::Category (maybe renaming to Flags AudioProcessorParameter::Flags), adding:

  • DontAutomate
  • DontInterpolate
  • ParameterOrientationInverted
  • MetaParameter

And giving access to it in AudioProcessorValueTreeState::createAndAddParameter(). This solves three open issues, keeps the current behaviour as much as possible and adds minimal impact on the API.

EDIT: added MetaParameter, the only one exposed so far… the parameter to AudioProcessorValueTreeState::createAndAddParameter could be replaced with the flags and just keep a convenience version for backwards compatibility setting the flag accordingly would be an option.


#19

I fail to see any advantage in letting the host control the ramp behaviour of a plugin parameter over doing it in the plugin. So why would I want to use that feature? Thanks for any comments - and thanks for bearing with me!


#20

I thought the same first…

It is not about moving the plugins functionality towards the host rather than telling the host the preferred behaviour for that parameter, when recording automation data.

E.g. if you get automation data from a MIDI controller event, you get a new value. But the last automation point might have been a long time ago, in which case you don’t want to change all the values. But that would be the case, if you interpolate between the two automation points.

On the other hand, when drawing automation, most of the time you want smooth transitions, in which case the interpolating setting makes sense.

So in my opinion it is not something parameter specific but depends rather on the source of the automation data. But that’s not how the plugin interfaces are designed, I’m afraid.


#21

I still wonder: When the host does interpolate a parameter value - how are the ramped parameter values made accessible to the plugin? I am currently using callbacks which is fine as long as parameter values are not changed with a high frequency.

  • If an AudioProcessorValueTreeState is used: Will the parameterChanged callback function be called on every sample step during the ramp?
  • If the parameter value is retrieved via AudioProcessorValueTreeState::getRawParameterValue
    is there a mutex involved in the process? Is there a performance penalty involved?
  • What would be the least costly way to get the changing parameter value streamed into the process function?