measuring latency with pd
a pd-patch for measuring latency
goal
we want to measure the latency of a certain pd-patch (our test piece).
files
test-signal
we want to measure, how long it takes for one single sample that is sent to the [ outlet~ ] of the test-patch to reapppear on the [ inlet~ ]
the simplest test-signal for such things is the dirac-pulse, which is a single 1 surrounded by 0s, probably shifted in time.
measurement
when the dirac-pulse is fired, we reset a counter. this counter counts the (zero-)samples.
when the pulse appears on the output of the test-patch the state of the counter is displayed.
two step measurement:
in a first, coarse measurement we count the number of blocks, where the output-pulse is not yet present.
in a second refinement step, the sample-offset of the pulse in the first block holding the output-pulse is detected.
the result is the sum of the (number of blocks)*(blocksize) plus the offset.
problems
the setting described aboce works well, as long as the test-patch doesn't do anything to the incoming signal but delay it. this is true, when testing simple delay-lines (not very thrilling) or when your sound-card has digital I/O and you are connecting the digital O to the digital I to measure the system-latency (quite thrilling)
however, if some signal-processing or analog/digital-conversion (or vice versa) is involved, the output of the test-patch will not be a dirac-pulse any more.
in case of ad/da-conversion and/or simple filtering the dirac-pulse will be widened in time. additionally some noise might be added.
in case of heavy signal processing we cannot predict the result, and thus the measurement patch might fail.
in the former case, we can still detect the latency of the patch. - noise-reduction: in most cases simple thresholding (noise-gate) will do
- we can detect either the start of the pulse or the peak of the pulse. for the sake of simplicity we detect the start of the pulse.
details:
- when a [ bang( appears on the first inlet, the block-counter is resetted. simultaneously, the dirac-pulse is triggered, by sending a [bang( to the '[ dirac~ ] object.
- the test-signal is sent to the test-patch (light-green)
- the output of the test-patch is processed by a noise-gate. the threshold of the noise-gate can be adjusted, and defaults to -20dB.
- the absolute value of the gated signal is sent to the 1st step of the measurement.
- the [ sigzero~ ] object detects whether the whole signal-block of the incoming signal is zero or not. it outputs 0 (for blocks holding only zero-samples) or 1 (otherwise).
- when a non-zero signal-block is detected, the state of the counter is output to the second outlet.
- the signal is passed through to the first outlet~.
note: it is important that the first stage is in a separate sub-patch of pd, to ensure, that the whole signal-block is entirely being processed by this coarse measurement, before it is passed to the fine measurement. (see pd-documentation 3.audio.examples/J07.execution.order.pd)
- the 2nd stage transforms the signal into message-domain using [ pack~ ].
- the output of [ pack~ ] is a list of floats. the length of this list is equal to the blocksize.
- the signal-block (in message-domain) is reblocked to a larger blocksize. this is for future uses (just in case, we want to detect the peak of the pulse instead of the beginning)
- on start of the fine measurement, [ repack ] is banged to reset the reblocking. the sample counter is reset (see below)
- the signal-block (in message-domain) is passed throught [ once ]
- the list is unwrapped (with [ reblock 1 ]).
- each zero-sample increments the sample-counter.
- the first non-zero sample outputs the state of the sample counter.
- we only output the position of the very first non-zero sample (with [ once ]) to ensure, that a broadened peak does not produce multiple values.
- finally the result of coarse and fine measurement are added