Audio synchronisation - I/O latency


#1

Hello all,

This is hypothetical, but it has realworld implication for what we are doing.

Imagine a device that clicks twice, exactly one second apart. We have a microphone (@44100) that picks this up and a -hypothetically perfect- algorithm to find this first click in the audio buffer. Now we want to generate a click ourselves (exactly 1 second in the future) which will sound through the speakers EXACTLY at the same time as the second click from the device. Say that the first click falls on sample number 10 in a buffer, on what sample should we send out a click in order for it to coincide with the second click?

We think it might be either

[list]
[] at sample 10 + ( 44100 samples - (inputLatencyInSamples + outputlatencyInSamples) )[/]
[] at samples 10 + (44100 samples - (inputLatencyInSamples + outputlatencyInSamples) ) - audioCardBufferSize[/][/list]

However, we measured the I/O latency manually: we have a mic + code in juce that does audio through, we hit the microphone and record the signal from the speakers and the microphone with standalone different recorder. Juce says that the I/O latencies are both 715 samples, that would mean 1430 samples (buffersize=512, ASIO). The measured latency is approx 1170 samples. Looking at the Juce code I see that the calculated i/o latency is calculated as the i/o latency of the ASIO driver, PLUS one quarter of the buffersize:

    int getOutputLatencyInSamples()     { return outputLatency + currentBlockSizeSamples / 4; }
    int getInputLatencyInSamples()      { return inputLatency + currentBlockSizeSamples / 4; }

If I remove this quarter I would get: inputLatency + outputLatency = 715+715-512/2 = 1174. That’s almost too close to the measured latency than what could be coincidental!

So, Jules, why the “+ currentBlockSizeSamples / 4” bit?

  • Bram

#2

Well, it’s quite a few years since I wrote that, but I guess that at the time I was testing a lot of devices, and that must have provided the nearest result to what I was actually measuring - maybe not on all devices, but in general.

Haven’t you played with the juce demo’s latency detector page? That does all these measurement for you already…


#3

Thx for that answer jules…!
I tried the demo app, but I’ll need to recompile it with ASIO to make sure I’m no seeing ghosts…

So, I guess we should still be using input+output latency and give the user a slider to control the exact aspects of it…

  • bram

#4

Bram,

I’ve built a utility for measuring round trip latency for audio cards with a loopback cable between input and output. In my testing with ASIO devices I’ve concluded that the currentBlockSizeSamples/4 correction is spurious for my application - so I subtract that back off the reported latency figures.

BTW, my utility uses a different technique to Jule’s demo so it can get subsample accuracy. Send me a pm if you’re interested in having a play with it.

-Andrew


#5

Hey Andrew,

Thanks a lot for the offer - that would be great! Did you test with various soundcards or just the one?
Jules also has a latency calculator in the Juce Demo which does seem to do the same, but the demo isn’t compiled with ASIO support on per default.

I am interested in trying your app, you can reach me at bram dot dejong at samplesumo dot com :wink:

  • bram

#6

If you look in the ASIO specification, the latencies that are reported by the device are supposed to include also the actual buffer size, plus any device-specific latencies. Therefore, I think that (at least for ASIO), JUCE does not return the correct latency here, when it adds quarter of the block size on top of the device latency in each direction.

Perhaps it was needed for legacy ASIO drivers a long time ago?

In any case, I think this is a serious issue for audio applications that depend on a correctly reported latency.

There should be a way of retrieving the reported latency directly from the device, without any extra components. Perhaps this could be changed, or at least introduce a module flag to change the behavior?