I switched to using the AudioProcessorValueTreeState classes and am loving it.
However, I noticed that AttachedControlBase::parameterChanged() calls triggerAsyncUpdate() in order to update the UI widget with an audio processor parameter change. And if I understand correctly the audio callback thread could be doing the parameterChanged() call.
Sooo, wasn't AsyncUpdater supposed to be sort of "evil" for this? I hope the answer is no, because I like this pattern and would like to use it myself to sync stuff between audio and gui threads.
btw I saw some very informative old threads on this subject about specialized libs that deal with this, but could anyone from the Juce team perhaps give an update on the current best practices of lock-free audio-gui parameter syncing using all the new V4 built-in goodies? I assume if we just stick to those, we should be reasonably safe, right? Perhaps a good topic for a tutorial/whitepaper?
I'm using the AsyncUpdater approach right now in my own code and it seems to work well so far. What would be the best "pure" lock-free alternative here then? A lock-free fifo + a 10Hz timer thread that polls the fifo and updates the widget - sort of like in the AudioParameterValueTree?
on a related note: I noticed that the Synthesiser class uses a ScopedLock during each note on/off and other midi event handlers - and rightly so I guess. But shouldn't that be lock-free as well, in the spirit of being consistent?
The more general question being: should a good plugin design be completely lock-free, or is it more of a gradual thing: the more locks you can get rid of the better, but a few remaining ones won't hurt ? IOW, is a lock-free design viral or not?
In the case of the synthesiser, it uses a lock that should never be contended during normal operation, it's only when you do things like add/remove voices while it's playing that it could block.
In that case, changing voices isn't something that people generally do very often, and if they do it then it's unlikely to glitch, and even if it does, it's almost certainly just while they're tinkering around with the plugin settings to optimise performance, so they probably won't care or notice. And since it'd be a nightmare to implement in a lock-free way, we just used a lock there for simplicity.
So yes, a pure lock-free solution is always ideal, but it's always a balance of hassle vs necessity!
Still any plan regarding that?
If you say it’s totally fine in practice I trust you, but it just sounds a bit weird that the recommended parameter handling way (AudioProcessorValueTreeState) uses some unrecommended asyncupdates.
btw regarding AttachedControlBase, I’m not sure why there is a removeListener() method that must be called from the childs destructors, instead of a virtual AttachedControlBase destructor calling state.removeParameterListener(). would’nt it work just the same?