Midi Mapping - How to update parameter value from processBlock?

BTW, that check on all parameters is what’s happening now during setValueNotifyingHost()

What I’m suggesting is to remove that check from the audio thread, unless you need it (which you probably don’t for most parameters, and you’re fine with just reading the value as-is with no checks).

I mean the checks for changes. In many cases, parameter values are not used directly, and derived values need to be computed which are stored in the processor. These computations may be reasonable to do on changes, but unreasonable to repeat on every callback, so you have to check if parameters have changed to know if you have to recompute your internal state.

I don’t really have a position on this, I just observe that it doesn’t seem so simple. I understand your stance, and it sounds reasonable, but every time this comes around JUCE seems to have a different view on the matter, and in spite of the constant warning about locks, allocations and system calls, for some uses they seem to be considered a lesser evil. I’m not sure if the expense of checking all parameters on every callback can be dismissed. If you have, say, 500 parameters, and you’re processing 64-sample blocks with 4x vectorization, the proportion of checking 500 atomics per block may not be that low. But mainly, it’s unnecessary, at least for VST3. There are no sync mechanisms needed because all parameter changes are passed to each thread separately, regardless of source. If the UI reports a change to the host through performEdit, the host will later pass that change to the process callback through ProcessData. The JUCE wrapper is actively dismissing this information to accommodate its single source approach. I suppose the problem could come from other formats (like AAX, which seems to run automation on a separate thread), but on the whole it looks more like technical debt.

1 Like

I agree. But again, that check already happens with setValueAndNotifyIfChanged(). On All parameters.

I suggest to make those checks opt in for the users: Both in audio thread listeners and for UI listeners that can for the most part be discarded completely when the editor is closed.

Well yes, in VST3, but in other plugin wrappers, and in my/everyone’s current code that writes directly to parameters, that’s not the case. All of my UI code writes param->setValueNotifyingHost() freely from both the message thread, knowing it’s perfectly safe to do so and doesn’t require, say, an additional FIFO to let the processor know about that value.

So I think refactoring the entire JUCE and JUCE-based code base to save a few atomics and comparison cycles (that I suggest will be opt-in), are not worth it and also not practical.

I’m not convinced they are. For me the trade off here is between:

  1. Locks and allocations in the audio thread.
  2. A timer running a few minimal checks on the message thread.

And in my experience there’s a very clear-cut decision on which is the “winner” for audio use cases. I think it’s only a ‘lesser’ evil if you consider that some significant refactoring effort, which I don’t think it is - in fact I’m happy to submit a PR that would probably be very short and non-intrusive.

1 Like

That’s indeed true, my fault.

setValueNotifyingHost() is not problematic in any case -in VST3, it’s a call to performEdit(). I’m pretty sure I’m failing to explain myself, sorry. It’s now that we need additional synchronization which the format doesn’t call for. If we use separate audio thread listeners, as you say, we can’t compare to the previous value as it’s currently stored, we need to compare to the value since the last process callback, which again implies separate sources of truth. For VST3, we don’t need to check or store anything, we can just pass the changes as they come in ProcessData. If another format doesn’t have separate channels, the wrapper can store the last value and compare to it, and the same interface can be exposed.

Well, yes, but that sync is already in place due to the atomic that is set in the underlying setValue(). If that wasn’t atomic, I would need a FIFO or something to let the processor know that change happened. You have to remember - plugins are also used as subplugins of other plugins, so even if the VST3 host is making that extra call, other formats/my own code will not, and will need to create thread-safe sync after setValue()

Right, but since that check is needed anyway to trigger listeners, I suggest to move that check away from the audio thread, unless absolutely needed in case your code needs it for a particular parameter, regardless of plugin format. Then - it would be an opt-in check where as now you’re forced to pay for that check in your most critical thread - and also wrap that with system calls and allocations while we’re at it.

Optimizing the model for VST3 by removing the sync would just mean adding that sync everywhere else, including whenever you’re reusing your own code as AudioProcessors without an actual host that might be thread aware and dispatch those messages in the proper time.

1 Like

I think at this point we’re saying the same, I’m just expressing it poorly :sweat_smile: Your idea of having separate, optional audio thread notifications is something I hadn’t thought about, and it’s a good compromise -it solves the issue with minimal change to the API. I pointed that it would require to store the state before each processBlock, but only for the wrappers that need it. Doesn’t seem more costly than what is done now.

1 Like

I hope they don’t remove that function, because it wasn’t deprecated when I put it in my functions.

Hey Kamedin

Did you accomplish having midi program change change parameters in your code?

Kr,

Wim