# How to report Plugin latency?

**URL:** <https://forum.juce.com/t/how-to-report-plugin-latency/55869>\
**Category:** Audio Plugins\
**Created:** [April 19, 2023, 3:17pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869 "2023-04-19T15:17:24Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 19, 2023, 3:17pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/1 "2023-04-19T15:17:24Z")

</div>

Hello

Having a problem, where using several FIIR filters, and processing all of them introduces an expected delay. Now I am trying to call setLatencySamples() to report this delay, but it does not seem to work.

On playback there is enough wait time between each audioBlock that it works fine, but if the audio is bounced offline then the filters’ processing is lost.

In Logic there is no apparent change when calling setLatencySamples(). In Reaper there is an ever weirder behavior, when playing an audio, there is a visual/auditive change, where everything else starts playing but the channel with the Plugin kicks after the delay, and when rendering, the output is not filtered.

Please help.  
Andres

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [April 19, 2023, 3:19pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/2 "2023-04-19T15:19:31Z")

</div>

Set it Asynchronously

Rail

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 19, 2023, 3:21pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/3 "2023-04-19T15:21:02Z")

</div>

Wow, your response was fast. Thank you Rail.

How do you set it Asynchronously?

Do you mean the setLatencySamples()?

Andres

---

<div class="post-metadata">

**Author:** ![jackwcampbell](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jackwcampbell](https://forum.juce.com/u/jackwcampbell)\
**Post date:** [April 19, 2023, 3:41pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/4 "2023-04-19T15:41:23Z")

</div>

Which version of JUCE are you using? Depending on the version, the propagation of setLatencySamples might behave differently. For instance, whether or not you have this change could affect the behavior:

> <https://github.com/juce-framework/JUCE/commit/47dcc31e775edbaef47abacdebc86467bc4c47d1>

Also, you might try stepping in to the setLatencySamples call, in particular the updateHostDisplay to see whether the change is taking effect in the JUCE plugin wrapper layer

---

<div class="post-metadata">

**Author:** ![HowardAntares](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/howardantares/32/4629_2.png) [@HowardAntares](https://forum.juce.com/u/HowardAntares)\
**Post date:** [April 19, 2023, 3:42pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/5 "2023-04-19T15:42:22Z")

</div>

When are you setting the latency? We report it from prepareToPlay(), and also when/if the user selects a Low Latency mode option. Not during playback, though. Has to be set before playback starts.

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [April 19, 2023, 4:06pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/6 "2023-04-19T16:06:43Z")

</div>

There are some plugins which change their latency dynamically based on the parameters/algorithm… I assumed the OP was trying to set the latency from inside the processBlock() which can be done asynchronously - the easiest way to do that is derive the AudioProcessor class from AsyncUpdater and have a member variable for the delay length… and in processBlock call triggerAsyncUpdate() and in handleAsyncUpdate() call setLatencySamples().

If your latency is fixed you can call setLatency() from prepareToPlay().

Rail

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 19, 2023, 4:08pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/7 "2023-04-19T16:08:00Z")

</div>

Juce version 7.0.5 on a Mac Studio. I guess it includes the change already.

I tried setting the latency from the processor constructor, from prepareToPlay and from the actual processBlock. Same results.

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 19, 2023, 6:06pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/8 "2023-04-19T18:06:38Z")

</div>

Actually, after checking the behavior in detail, I see a similar result on both DAWs on playback.

setLatencySamples() is called at the start of prepareToPlay(). When playing the track on Reaper what happens is that the audio starts ahead the number of samples defined, not playing the initial samples. And when playing on Logic the initial silence is the only portion not played, Logic jumps to the beginning of the sound disregarding the number of samples defined.

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [April 19, 2023, 7:13pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/9 "2023-04-19T19:13:45Z")

</div>

The latency setting has no affect on what’s sent to the processBlock… it’s used in the host’s Delay Compensation to delay other tracks (if necessary) to compensate for the delay in the plugin chains.

Rail

---

<div class="post-metadata">

**Author:** ![jackwcampbell](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jackwcampbell](https://forum.juce.com/u/jackwcampbell)\
**Post date:** [April 20, 2023, 3:32pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/10 "2023-04-20T15:32:35Z")

</div>

One sanity check you could do is to check the DAW’s view of the latency for the plugin. In Logic you can do this by hovering over the insert and viewing the latency in samples. This is the latency that the DAW expects to be reported by the plugin via setLatencySamples. If this latency doesn’t match what you expect, then there might be something wrong with the way you are calling setLatencySamples and you’ll have to look into why that value isn’t making it through all the way (because then the DAW’s delay comp won’t work as you expect).

 ![Screen Shot 2023-04-20 at 9.27.41 AM](https://us1.discourse-cdn.com/flex026/uploads/juce/original/2X/e/e0af108c295d098128f62a34491de674434f7bba.png)

However, if this value is what you expect, then the issue might actually be with the plugin implementation and its assumptions about how the latency should be working, which would be a different path of debugging

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 20, 2023, 5:11pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/11 "2023-04-20T17:11:22Z")

</div>

Thank you Rail and Jack

I am able to see the latency correctly on Logic. But my problem is not fixed with it at any value. Then the origin of the problem is beyond my comprehension. Let me describe it in a concise way…

The final product is a plugin. Actually you can check it here… [Chimerator](https://www.baknoaudio.com/chimerator/chimerator.html)

Basically it has several IIR filters, and at the same time it has some frequency visualization (not relevant) and a dry/wet mixer

Filters are setup on prepareToPlay, and on processBlock each one calls .process()

Then for the dry/wet mix it is necessary to store a copy of the buffer before filter processing to use it later at the end of the processBlock

The plugin works fine at playback. However the problem appears when bouncing the processed track offline (without hearing it). In which case, the filters do not affect the bounced track, just the mixing phase. It other words, at the mixing phase, the signal that is supposed to be filtered is just the original one.

---

<div class="post-metadata">

**Author:** ![HowardAntares](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/howardantares/32/4629_2.png) [@HowardAntares](https://forum.juce.com/u/HowardAntares)\
**Post date:** [April 20, 2023, 5:46pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/12 "2023-04-20T17:46:41Z")

</div>

It sounds as if your filters are checking if the transport is running in real time or not someplace. That part, at least, doesn’t sound related to latency, but to whether it’s running in real time or not. I’d look in my code if there is such a check being done anyplace, and see if that could possibly affect the output of the filters.

Or maybe you’re checking for isPlaying and the host isn’t setting that flag when bouncing offline?

Another idea comes to mind, and that is what if the buffer(s) your filters are being passed are not writeable when not in real time, because you’re assuming the input and output buffers are the same, but they’re not in that case, and your filters don’t write to where you think they are writing?

Just a few random thoughts; no idea if any hosts do that or if your code would handle it properly or not.

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [April 20, 2023, 5:53pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/13 "2023-04-20T17:53:03Z")

</div>

… look for AudioProcessor:: isRealtime()

[https://docs.juce.com/master/classAudioProcessor.html#ae3760540c7191ec83fe608df613ee33d](https://docs.juce.com/master/classAudioProcessor.html#ae3760540c7191ec83fe608df613ee33d)

Rail

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 20, 2023, 6:07pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/14 "2023-04-20T18:07:40Z")

</div>

Thank you again for the fast response.

Well, in the code there is no call for isPlaying() or for isRealtime()

I disabled the wet/dry mix code to check if somehow it created the problem and it continues. Then the problem is at the filters level. Somehow, when in offline mode, either they do not process, or they take too much time to process and the result never arrives on time.

Possible clues: There are approximately 50 filters (maybe there is a limit).  
And the call to process each one on the processBlock goes like this…  
.process(juce::dsp::ProcessContextReplacing\< **float** \>(audioBlock));

EDIT: After reducing the number of filters, the problem persists.

---

<div class="post-metadata">

**Author:** ![hugoderwolf](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/hugoderwolf/32/14039_2.png) [@hugoderwolf](https://forum.juce.com/u/hugoderwolf)\
**Post date:** [April 21, 2023, 6:21am UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/15 "2023-04-21T06:21:02Z")

</div>

I doubt it has to do anything with latency. Maybe you are making the implicit assumption about mapping of input/output blocks (e.g. input block = output block, in place), which is true in realtime, but may be handled differently by the host in offline mode? Just a shot in the dark though.

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 21, 2023, 11:46am UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/16 "2023-04-21T11:46:45Z")

</div>

Well, this is the basic original structure within processBlock:

scratchBuffer.copyFrom (buffer)  
filters.process(ContextReplacing(on buffer))  
buffer.WritePointer = buffer.WritePointer_Wet + scratchBuffer.WritePointer_Dry

It was changed to the following to check:

scratchBuffer.copyFrom (buffer)  
filters.process(ContextReplacing(on scratchBuffer))  
buffer.WritePointer = scratchBuffer.WritePointer_Wet + buffer.WritePointer_Dry

But the same problem continues to happen.

---

<div class="post-metadata">

**Author:** ![baKno](https://avatars.discourse-cdn.com/v4/letter/b/ac91a4/32.png) [@baKno](https://forum.juce.com/u/baKno)\
**Post date:** [April 21, 2023, 12:58pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/17 "2023-04-21T12:58:22Z")

</div>

Found the problem. Nothing to do with processBlock or latency.

In case this happens to other people…

prepareToPlay() had a basic filter initialization, but the real one happened after control variables changed, calling updateParameters().

The solution was simple, call updateParameters() at the end of prepareToPlay().

Thank you all for the help.

---

<div class="post-metadata">

**Author:** ![jonagon](https://avatars.discourse-cdn.com/v4/letter/j/919ad9/32.png) [@jonagon](https://forum.juce.com/u/jonagon)\
**Post date:** [November 7, 2023, 6:29pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/18 "2023-11-07T18:29:57Z")

</div>

Hi I just wanted to ask you about your solution for setting the latency asynchronously. I’ve read on other related forum topics that some DAWs will ignore any call to setLatencySamples that is not in prepareToPlay, or that calls to setLatencySamples outside of prepareToPlay can cause unintended consequences and crashes. Did you test your asynchronous solution in many different DAWs, and were there any unintended consequences of your solution? I’m trying to implement some lookahead processing and I know that I could notify the DAW that there is a constant latency and compensate in the DSP according to the user-selected lookahead time, But I want the plugin to be usable in a live setting where there can be no delay compensation which means users must be able to select a zero latency option. So perhaps this asynchronous solution will prevent having to build two versions of the plugin (one with zero latency and one with constant latency).

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [November 7, 2023, 6:48pm UTC](https://forum.juce.com/t/how-to-report-plugin-latency/55869/19 "2023-11-07T18:48:01Z")

</div>

My implementation works in all DAWs… obviously only trigger the change if the latency changes.

Rail
