Sample accurate parameter automation?

Are there any plans to introduce sample accurate parameter automation in JUCE?

4 Likes

i would like this to be a thing as well. when more and more daws will make it easier to modulate plugin parameters from outside of the plugin itself it will become increasingly important to decrease the need for parameter smoothing, cause that should and probably will be handled by those modulators as well

but if it isn‘t, it’s your plugin that sounds bad.
I am undecided if that’s a good idea

it should at least be an option

Just wonder if it’s on the roadmap, that’s all.

I don’t think it is. The main issue is that Juce provides a unified framework for all plugin formats, and not all formats support it. Also the discussion came up many times and the main argument against the need for it is that hosts are already working around the issue by slicing the processing buffers small enough so it sounds smooth. So I doubt that it ever made it to the roadmap.

All hosts don’t do that. The only one I am even aware of is FL Studio.

2 Likes

I believe major hosts do. Providing that Logic (AU) and PT (AAX) don’t need to. I believe Ableton is (or they use parameter smoothing instead?). Cakewalk is now doing it too. Haven’t tried Reaper but I’d be surprised if it’s not at least an option somewhere. FL is as you said. I think I remember reading a Jules’s post saying that Traktion does that too.

So not saying it’s for certain solved that way, but as VST does not support sample accurate automation and is still widely used, not sure it’d make it to the roadmap just yet (although we would all love that!).

A few things to note:

  1. There’s no problem to support sample accurate parameters in JUCE even with hosts/plugin formats that don’t support it. All it needs to do is pass those parameters at sample position #0 in case the exact position is unknown.

  2. sample accurate parameters will not magically make parameter smoothing unneeded, as parameters are also modified from the UI, or from stepped automation that isn’t smoothed, and the plugin needs to make sure those transitions sound good.

It would maybe allow a plugin to let a user disable the smoothing if the user knows it’s used in a modular synth and smoothed externally, or something like that.

  1. In terms of implementation, slicing the buffer for smaller sections is a very valid way to do sample accurate automation, but it also spikes the CPU due to the smaller buffer sizes, so I think it should be up to the plugin to decide if it wants to do it that way, VS read the parameter changes as stamped events (similar to MIDI messages).
3 Likes

This is a very relevant point. Slicing the buffers is a ‘hack’ that reduces the effectiveness of optimisations in the plugin like SIMD (which is more efficient on groups of 4 samples, or even just plain old loop-unrolling.

The second issue is: Many parameters are not required to be sample-accurate, or are not meant to be automated anyhow. This can lead to the DAW pointlessly slicing up the buffers and hurting performance for no real benefit. It’s better to let the plugin decide on a case-by-case basis which parameter changes are worth splitting the buffer over. i.e. the DAW should just timestamp the parameter change, and let the plugin handle the rest.

Thirdly, in plugins like mine things like oscillators and filters are themselves plugins. If the DAW changes say the Osc pitch, I will slice the buffer only for the Oscillator, while the filter will be left to process the entire clean block in one hit. This is far more efficient than having the DAW force slicing of the Filter buffer for no reason whatsoever.

Lastly, most major plugin formats now support sample-accurate parameters. How long do we intend to have JUCE forcing our plugins to have lowest-common-denominator host support, now that the only format that does not support sample-accurate automation (VST2) is deprecated?

4 Likes

All fair points. Just to be clear, what I mentioned above is just what transpired from previous discussions on the forum. And also from the reality of what hosts have to deal with. Not saying that’s how it should be.

If a user writes an automation on a VST with a large buffer size and hear “steps” or “lags”, 100% of the time the user will complain to the host manufacturer. It’s always the DAW’s bad. So it’s fair for DAWs to do what’s necessary to make automations sound smooth. Hopefully ditching VST will make this go away but although deprecated it looks like it won’t go away tomorrow.

:100: Please JUCE team put this on the roadmap (if not already).

Yes, but hosts can’t really handle smoothing like the plugin can, unless they split the buffer to extremely small sizes, like 1-4 samples.

And fortunately, most hosts don’t do crazy things like that. :slight_smile: FL studio is the only major one I know of that constantly splits the buffer to smaller sizes to gain more accuracy, but as far as I know it also doesn’t smooth parameters.

If the host would try to smooth a parameter, that is also smoothed by the plugin, I’m not sure the result would be as pleasant, so it’s one of those things hosts would only do if they control which plugin it is and when to do something that extreme.

These are usually high level decisions like @JeffMcClintock mentioned, that require deeper knowledge of your context to do correctly.

Anyway I definitely vote for sample accurate parameters in JUCE.

The challenges are probably to express that concept in the API in a clean way that wouldn’t break existing plugins. I believe that’s totally possible, but I haven’t entered the rabbit hole of checking how difficult that would be.

2 Likes

Constantly splitting buffers is silly. It should only happen when a parameter is automated and when the buffer size is too big. And then it is not that crazy! Having worked on a DAW I can guarantee you that automations not sounding accurate or smooth for VST is a major source of complaints. And from our testing DAWs seem to do some things to work around it. You cannot always push customers to use the VST3 version as it is still not available for some major plugin vendors. And even when it is, sometimes sample accurate changes are ignored by the plugin (all processed at sample 0).

It does not smooth parameters, but it definitely makes automations “steps” inaudible at large buffer sizes. Usually slicing at something like 256 samples should be enough. It’s also worth mentioning that slicing buffers not only allows the host to make automations “sound smooth”, but also to make them accurate. This is particularly relevant if a user automates a toggle parameter and wants to sync it with a specific musical time. You certainly do not want to toggle the parameter too early or too late. Think about toggling an EQ band at the end of a verse for example, or extreme things like that.

3 Likes

I believe it would be totally feasible to have the AudioProcessorParameter (or RangedAudioParameter that is) and have the getValue() unchanged, but add a

  • getNumValues() // how many keypoints
  • getValueAtIndex (int keypoint)
  • getValueAtSample (int) // within the block

That wouldn’t break anything and the plugin developer can make use of the added granularity of the parameter changes midway through the buffer.

I think it would be a great addition for those plugins which need sample accurate automation.
Which or how many that are is surely debateable.

5 Likes

True, but I think that would be hard to implement from the plugin’s side, because then you’d need to run a for loop over each sample over all the parameters, which could get pretty costly.

A better interface to me would be like the one of MidiBuffer, where you can at the start of the block iterate all the messages in a sorted order according to sample position, and decide if you apply block splitting for each parameter, apply smoothing from that sample position, or just read them at the start of the block.

1 Like

Not really, you have all options. But I realise we need one more function, or have the getValueAtIndex() return a tuple of sample position and value

  • keep using getValue() or getValueAtIndex (0) which is the same. That will yield the same result as it is now
  • use something like applyGainRamp (getValueAtIndex(0), getValueAtIndex (1)); (pseudo code ofc.)

You can even add a free function to apply the whole chain of keypoints as multiplication for instance. It can be made very convenient.

The biggest argument is for me, that when switching the buffer size the rendered result potentially changes, which is problematic.

1 Like

VST2 plugins have been smoothing their parameters since forever. Sure - some of them don’t, but the vast majority of successful commercial plugins have implemented that regardless of format.

More accurate, yes. Smoothed - no. Those are totally different concepts. Slicing only achieves the first one.

Yes, that would work. But I would say smoothing is just a use case of sample accurate automation.

What you want many times is to process the entire buffer at the smaller size for the parameters where it matters, just like juce::Synthesiser does when splitting the buffer for incoming MIDI messages.

For that, I think you need an interface telling you all the events that happened in order. I think the plugin APIs have the events already organized in a similar way, don’t they?

VST3 has it pretty much like I described it, and IIRC they have always at least two values, which is at the begin of the buffer and at the end.

1 Like

As I’ve said before, one reason I’d like to see this implemented is to have actual separation between editor / message thread and processor / audio thread. Even if you don’t need sample accuracy, the current mechanism is kind of a disgrace at least for VST3, because it merges two separate channels of communication and forces to resynchronize in the plugin something that was already synchronized. I don’t know if this is also the case for AU and AAX. I’m also not sure what would be a good solution though, because currently AudioProcessorParameter is supposed to hold an up-to-date value from both UI edits and processing callbacks, so the merge is quite ingrained in the design.

3 Likes