Syncing Plugin Audio and UI

I’ve recently had an interesting discussion with a user who noticed that in project with several latency-bearing plugins (like my Dynamic Grading) in a Logic project, there is a noticeable lag between real-time plugin visuals and the audio that is heard, but only with third-party plugins. Logic’s own analyzers don’t have that problem, they seem to have syncing mechanism in place.

It’s clear why it happens: plugins typically process audio as they get it and then display it in realtime. But when latency compensation is in place, the processed audio will be delayed and thus displayed well before it is actually heard.

To fix that, the actual display of realtime visuals would need to be delayed as well so it is in time with the final audio output. The processBlock() gets a time stamp, but the UI to my knowledge doesn’t, so it’s impossible to know how much delay there is between the already processed audio data and “now”. Or is there?

I’m hoping that I’m missing something, so is there any way I can find out what audio time stamp the host playback is currently at, so what the user is hearing right now?

If your plugin reports latency, then surely you must know, as developer, in which part of the processing the latency is added?

Then you have the required information that you need for you UI.
I would not build special support for users who decide to disable latency compensation, just make sure that from the perspective of your plugin the UI timing is in sync with your processing.

For instance with a look-ahead compressor, show the levels after the look-ahead (or from the delay running in sync). Not before.

That‘s what I‘m doing now, but it only helps if it‘s the only latency-inducing instance in the graph. So as soon as the graph gets more complex or multiple instances are in a chain, that falls apart.

If this approach “falls apart”, how are you able to report latency?
Isn’t the latency a sum of latencies in the graph?

And what you show in the UI is “tapped” from somewhere in the graph?

Maybe I am incorrectly thinking this is a non-issue, sorry if I am.

As the plugin I‘m only part of the graph and don‘t know what the whole looks like. Only the host knows.

To elaborate a little bit about the problem, now on a proper keyboard:

Let’s say I’m a plugin with 1 second latency and have a built-in level meter. For now I’m the only plugin running in a project. When I run the meter on the input data, it will display peaks a second before the user actually hears it. But when I run it on the (latency-laden) output, it will be more or less in sync (give or take the actual scheduling of the host, but it will be close to realtime). So far so good.

Now let’s add another instance in series. The second instance will be fine and in sync. But the first one’s level meter will be again 1 second ahead of what goes to the output.

I could record the data for the levelmeter in a ringbuffer, but in the GUI thread I have no way of knowing huch much I need to delay that data for display. Because to do that I would need to know either the sum of latencies that come after my own instance in the graph, or I would need to get a sequencer timestamp of the audio that’s currently at the output.

I there a way?