Implementation of parameterValueChanged


#1

Hello,

I’m currently working on a large project in which I need a slightly different setup than AudioProcessorValueTreeState offers, I am therefore attempting to write my own interface for automation to internal state. I am however unclear on the following:

  /** Receives a callback when a parameter has been changed.

        IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
        many audio processors will change their parameter during their audio callback.
        This means that not only has your handler code got to be completely thread-safe,
        but it's also got to be VERY fast, and avoid blocking. If you need to handle
        this event on your message thread, use this callback to trigger an AsyncUpdater
        or ChangeBroadcaster which you can respond to on the message thread.
    */
    virtual void parameterValueChanged (int parameterIndex, float newValue) 

this will be called synchronously when a parameter changes, and many audio processors will change their parameter during their audio callback

This raises some questions for me:

  • Is it garuanteed that this function will only be called during the audio callback in every DAW or is the danger in the word many?
  • If it is garuanteed, does this happen before / after processBlock?
  • Or should I not make any assumptions as usual?
  • My last question is about setValueNotifyingHost, Does this function guarantuee safe behaviour when being called from non-JUCE threads or should it be called from a certain place?

Thanks,

James


#2

You cannot make any assumptions on when parameterValueChanged is called. The comments just tell you that it may be called it synchronously, for example on the audio thread.

setValueNotifyingHost you can assume that the host (and JUCE internal code) will be able to handle a call setValueNotifyingHost on any thread, at any time. However, calling this method setValueNotifyingHost may indirectly lead to callback to your own code again - for example, if the host doesn’t want the parameter to be changed (maybe the parameter is in read mode) it may immediately and synchronously try to change the parameter value back again. Your code needs to be able to deal with such a situation (i.e. you get a parameterValueChanged callback while your setValueNotifyingHost is still processing).


#3

Thank you Fabian!


#4

@fabian: an occasional crash of my plugin in a host and tests with pluginval suggest that I run into troubles with this. Is there any locking mechanism one should use? I have not found any hints for this in the examples…
In my case I can see that a parameterChanged comes from my valueTreeState calling its listeners.

Cheers,
Peter


#5

Hmm really depends on the exact nature of your code. In the JUCE code we use a bunch of ScopedValueSetter<bool> to check if calls a re-entrant.


#6

Thanks :slight_smile:


#7

Just to follow up on this, I can’t get setValueNotifyingHost to work from any other thread than the message thread, I believe other posts confirm this is best practice as some DAWs, like Ableton require this.

However, I ran in to an issue with automation using the pattern I had seen in many other synths:

        beginChangeGesture(  );
        setValueNotifyingHost( normalizedValue );
        endChangeGesture(  ); 

Calling this recurrently caused ( only ) Ableton to glitch out. The plugin we’re building needs to output automation in some cases without user input, so I thought the glitch might be related to not binding to slider start and stop drag funcs? I tried a workaround calling beginChangeGesture only once before the first value and to call endChangeGesture after a period of no automation changes, as this seemed to cause the largest overhead. This however still produced the occasional glitch. This glitch also only occurs when the Ableton arrangement view is open, the glitch I’m referring to can be heard / seen here:

If I leave the beginChangeGesture and endChangeGesture calls out everything works fine in Ableton, I however wish not to do so.

Here is an example of the glitches when using the workaround I described above:

I just wanted to ask if there is anything I can do about this? Should I send less data to the host and stretch the begin and end calls out, or am I doing something else wrong? I think there are no feedback loops.


#8

In other posts I read, that Ableton seems to be sensitive to the number of automation data.
At what frequency did your other thread send the setValueNotifyingHost() calls?

Maybe try to throttle them, and see, if that improves the scenario?
Also if you can, avoid sending the same value more than once maybe? (i.e. check if the value changed before sending the data).


#9

10hz

Tried this as well.

Even when beginChangeGesture & endChangeGesture are bound to mouse state transitions I have noticed that these “glitches” can be percieved on endChangeGesture at low buffer sizes (very sporadically) in Ableton 9.5 with the Arrangement view open.

All of these tests were with vst2
This does not seem to happen with the Audio Unit build in Ableton 9.5 (64-bit). Although that is apples and oranges.

An indication that I might be doing something wrong is the fact that when allowing max 4 automation points/second with startTimer(250) it won’t record automation of the Audio Unit, while showing changes happening.

Hiding the automation view while the arrangement view is open makes everything run smoothly in Ableton.