Search guides and the APICtrl K
  1. API reference
  2. DSP

interpolation.h

Reading a stream at a rate that is not one sample per sample.

#include <sonore/interpolation.h>
On this page

Design notes

Every varispeed thing in audio is this: a tape effect, a pitch shifter, a sampler transposing, a chorus whose delay is moving, a session running at a rate the material was not recorded at. The SDK could already do the whole- buffer case (resample.h) and the sampler had a Catmull-Rom reader welded into it, and there was nothing in between: nothing that takes a STREAM, block after block, remembering what it had from last time.

That memory is the entire difficulty. An interpolator needs samples on both sides of the point it is reading, and at a block boundary the ones on the left belong to the previous call. Get that wrong and the result is a click every block, at exactly the block rate, which people diagnose as anything except an interpolator.

Four points about the kernels, since choosing between them is the reason there is more than one:

Zero-order hold  no cost, no delay, and audible aliasing. Real use: a
                 control signal, or a deliberate lo-fi effect.
Linear           a lowpass whose corner moves with the fraction, which is
                 why a linearly-interpolated delay sounds duller as it
                 sweeps.
Catmull-Rom      four points, C1 continuous, passes through its points.
Lagrange (3rd)   four points, the polynomial that fits them exactly.
Windowed sinc    what the maths actually says, at the cost of a table and
                 a wide window; the only one whose error keeps falling as
                 you spend more on it.

Every kernel declares its LATENCY, in samples, and the test measures that rather than believing it. A latency that is documented and wrong is worse than one that is undocumented, because the host compensates by it.

Types 6

No interpolation at all: the newest sample, held.

Straight line between the two samples the point falls between.

Catmull-Rom: a cubic through the middle two points, with the outer two setting the slopes. Continuous in value and first derivative, which is why a swept delay using it does not buzz.

Third-order Lagrange: the unique cubic through all four points.

Not the same thing as Catmull-Rom, which only passes through the middle two. Fitting all four exactly costs some smoothness at the joins, and which of the two sounds better depends on the material -- hence both.

template <int HalfWidth = 8> struct WindowedSincKernel

Windowed sinc, from a table.

The weights depend only on the fraction, so they are computed ONCE for a grid of fractions and looked up. Computing them per sample would be correct and would put sixteen sin() calls in an audio callback, which is the kind of correct that gets a plugin uninstalled.

Between grid points the two neighbouring filters are blended. That is an approximation of an approximation, and it is why the grid is 512 wide: at that spacing the blend error is far below the window's own stopband.

template <typename Kernel> class Interpolator

Reads a stream at speedRatio input samples per output sample, carrying the samples it needs across block boundaries.

Ratio above 1 reads faster than real time (pitch up, shorter); below 1 is slower. Nothing here band-limits on the way DOWN in rate: reading at 2x without a lowpass first will alias, and it will alias whatever kernel is chosen, because the aliasing happened before the interpolation did. For a whole buffer at a fixed ratio, resample.h does it properly.

Functions 1

Aliases 5

↑↓ to move↵ to openEvery public name in the headers, and every guide