Proper use of Timer::CallAfterDelay()

My class inherits from juce::Timer to use CallAfterDelay(). When a Parameter is changed, it calls callAfterDelay(), to avoid big computations in the parameterChanged() callback:

void MyClass::parameterChanged(const juce::String& parameterID, float newValue) {
    if (parameterID == "xParam_" + (juce::String)m_ID)
    {
        m_xCurrPos = newValue;
        callAfterDelay(0, [this]() {this->reposition(); }); // to not do it in the callback
    }
}

Is this the proper way of using it?

From time to time it happens, that an read access violation appears, when I am closing the application. In reposition() a simple getWidth() call causes the error.

1 Like

You don’t need to inherit from Timer as the callAfterDelay method is static, thus you can just write Timer::callAfterDelay(...)

If the point is to ensure the reposition call is definitely made on the message thread you could instead call MessageManager::callAsync(...) https://docs.juce.com/master/classMessageManager.html#acfe6da5271c2ab76fdb0414b235ed095

What you’re seeing at the moment is this is no longer valid on the off chance the Timer call happens just as you’re closing down, I’m not 100% sure that callAsync will be immune from this either, someone with a bit more knowledge will have to chime in, but you could always capture it in a SafePointer https://docs.juce.com/master/classComponent_1_1SafePointer.html

Also I assume you have confirmed that the parameterChanged callback is happening on the audio thread? In which case I’d be concerned about the parameterID == "xParam_" + (juce::String)m_ID and if that is allocating or not.

Another thing to verify is if either callAfterDelay or callAsync are allocating.

A better option may well be to have a standard timer and a “dirty” flag that you set in the parameterChanged callback, then you can call reposition from the timer callback if the flag is true.

Sorry that these are a bit wooly answers, hopefully someone who knows more can chime in.

2 Likes

I guess you are looking for something similar to the “debounce” operation, as found in Reactive Programming?

I am also interested in this, in order to reduce “re-processing” calls when changing sliders and settings

(thus: subscribing :wink: )

Cheers

In audio code you should avoid calling anything asynchronous. The time you supplied might be in a different continuum, e.g. if you do an offline bounce. If you wait 100ms, the song might have been elapsed 1 minute worth of playback time.

If you want to coalesce calls, the juce::AsyncUpdater is a good choice.
Although it has to be said there are discussions, if AsyncUpdater is realtime safe, i.e. it doesn’t allocate.
It seems in rare occasions on windows it allocates a message to post to the message thread. But it is used in many programs with no observable effects.
Use the forum search for AsyncUpdater and audio thread or something similar.

Apart from that using the SafePointer or WeakReference by @asimilon is required in any asynchronous call.

1 Like

Thanks for pointing out it is static, i missed that!
Calling MessageManager::callAsync(…) seems to be what I was looking for, but the “dirty” flag solution seems to be the better solution to me!

I assume what @daniel mentioned about offline bouncing doesn’t apply in your use case as you want to do some heavy UI stuff in response to the parameter change?