AsyncUpdater for AudioProcessorParameter sync?


#1

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?

 

 


#2

Hmm. Yes.. Does seem like that snuck in there without us noticing. Thanks, I'll investigate..

(FWIW it clearly isn't causing any problems in practice though, or we'd have noticed!)


#3

Oops, missed your answer Jules

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?

 

 


#4

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!


#5

@jules @fabian

I realise this is an old thread but just out of interested did anything come of this ?

Just looking in the AttachedControlBase and also noticed the asynch updater which I have read allocates internally or something and can block ?

Should we not be updating the parameters from the process block when using the GUI attachment classes ?

Should a timer not be used to poll an updated flag or something instead ?

EDIT: Bump


#6

Does anyone have anything to add on this.

I’m interested to know whether this is something the JUCE team feel should be changed or not ?

Sooo, wasn’t AsyncUpdater supposed to be sort of “evil” for this?

I had also thought the above was true when mulling over synchronisation approaches.

I’m a little hesitant to use the value tree parameter classes…

Edit: One last Bump

Cheers


#7

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?