Hey guys -
An edge case issue here, where setting the param (via setParamNotifyingHost) can cause an infinite loop in AAX plugins.
Since it’s in code marked as “will be deprecated” in Juce, I just commented it out and don’t see any negative side effects so far.
Anyway, just letting you know.
It’s only in AAX, and it seems only to happen when I set the param value from a thread other than UI (basically, I have a worker thread that changes a couple values in certain cases).
More generally, I’d love to know why we have these two listener systems, are they both needed / used for some DAWs? Why send parameterValueChanged, and then audioProcessorParameterChanged?
Correction, audioProcessorParameterChanged is apparently still needed for nuendo / cubase / sound forge … which otherwise snap the parameter values back to their defaults when gestures end if you have only called paramterValueChanged. Guessing this is part of why we still have both of these systems around.
Pro Tools has some issues either way.
I know it’s hard/impossible to support all DAWs since they all deal with the gestures and change messages differently, but if I can get any clarity on when the audioProcessorParameterChanged calls might be deprecated, it would be quite helpful.
Thanks as always!
AudioProcessorParameterChanged is actually quit handy, I use it and few time in my repo, especially to observe the state of a processor without need to change it and add a listener to any single parameter. Right? It shouldn’t be removed. (Or am I wrong, whats the alternative?)
I agree! AudioProcessor listeners are very useful (Though, as you probably know, they are also something to be used carefully since the calls are synchronous).
There are no plans to lose this functionality, but it seems like they are deprecating those listeners in favor or listeners places on the individual parameters, see the note here:
I suspect that the issues I’m seeing are a result of that change, which seems to be in progress.
Hopefully someone from Juce can confirm here, and give us an idea of the path forward.
Aha! Looks like the infinite loop only happens when calling setParamNotifyingHost on a parameter that has NOT actually changed (which causes Pro Tools to freak out, apparently).
It’s not Juce’s job to check if the value has actually changed of course, so I’m not sure this could be done better … but there it is, for whomever might have the same issue.
Just a bump here, this is another AAX specific issue that keeps coming up.
It is also (I suspect) a fairly easy fix for someone over there at Juce HQ.
It’s easy to reproduce, simply set a parameter to its current value (the value it’s already at) using setParameterNotifyingHost().
As long as there is no actual change to the value, you get stuck in this infinite loop. In at least one spot in that loop, there is code that has been marked for deprecation for a very long time.
I don’t see that problem. In setAudioProcessorParameter(), it checks if the values are equal or not, before calling sendValueChangedMessageToListeners(). So it should stop propagating at that point. The only thing that comes to mind is perhaps the value returned from param->getValue() is returning a value that is not what it was set to (possibly due to an error in your parameter or its associated range)?
…or param->setValue() could be setting it incorrectly? One thing to look for would be converting between value types (and getting something like 0.4000001 versus 0.4 somehow).
Ahhh, yeah I see it. I have a listener that changes the value.
Apparently the listener (my local one) gets a message indicating that the value has changed (though it has not), and then tries to set it again. If I check there and make sure that a change has actually occurred before trying to set the value, the cycle breaks.
This only fails on AAX though, so the other wrappers must check if the value has actually changed before sending a message.
[EDIT - ok, you changed your latest comment, so you can ignore this one now, I guess, since you already answered it, in part at least.]
But isn’t that already handled by this code (in setAudioProcessorParameter()?
auto newValue = static_cast<float> (value);
if (newValue != param->getValue())
This converts the double value back to a float value before comparing and setting the new value. So it’s not comparing a double to a float; it’s comparing float values.
What are the values of newValue and param->getValue() in this function? And where exactly does the change happen? What is being passed to SetParameterNormailizedValue(), and what does it change to when static_cast back to float in setAudioProcessorParameter()?
As I said, I don’t have this problem with our AAX software, and by the lack of replies here, I’m guessing others do not, either.
Ok, then the place to look seems to be the parameter itself, or its range. Do you convert to an integer at some point, by multiplying by the number of steps, or something similar? Or use a skew, as you suggested? I’d step into setValue() and see what actually gets stored in the parameter, and then step into getValue() and see what how if gets that changed value back.
Ha! You are more active than I thought … sorry for the confusion on editing.
I found it just now, though I’m still not entirely sure what the difference is with AAX.
Basically, try setting up a parameter listener that constrains the bounds of the parameter and you will see the issue.
Any time a listener alters the value of the parameter, you get an infinite loop.
That makes sense. A listener should just listen, not alter the value. You can use a range for any parameter that needs to be limited to specific legal values. One of the lambdas allows snapping to specific values. Then just let the listeners listen, and not change the value.
In this case the parameter values are constrained only by the current values of other parameters … so slightly different use case.
The listener is the audio processor, which is keeping them all in line.
Easy enough to just check the values and be sure to not setValueNotifyingHost when the value is already what we want it to be though.
Still, quite annoying that only AAX has a problem with that.
Presumably the other wrappers check the value, see that it hasn’t actually changed, and don’t bother with triggering another paramChangeMessage.
I don’t think that’s the difference. The AAX code does check if the value has changed. You’re changing it in a listener after setValue() is called. I don’t know where else in the wrapper you’re thinking that such a check might be made, but you can always look at those other wrappers yourself and see.
The difference with AAX may be that parameter changes are asynchronous. If I recall, when you send a new parameter change to Pro Tools, it queues up a message that is processed some amount of time later. How that affects your particular use case, I don’t know (since I can’t debug your code for you), but that may be why AAX differs from VST3/AU.
Ahhh, good to know, thanks