diff --git a/filters.lib b/filters.lib index 9ca4dcd..90d8aff 100644 --- a/filters.lib +++ b/filters.lib @@ -2908,6 +2908,49 @@ dynamicSmoothing(sensitivity, baseCF, x) = f ~ _ : ! , _ }; }; + +//-----------------`(fi.)oneEuro`---------------------------------- +// The One Euro Filter (1€ Filter) is an adaptive lowpass filter. +// The input signal is smoothed according to an exponential +// moving average (EMA) whose alpha value is determined +// according to an EMA of the input's first-order derivative. +// This kind of filter is commonly used in object-tracking, +// not necessarily audio processing. +// +// #### Usage +// +// ``` +// _ : oneEuro(derivativeCutoff, beta, minCutoff) : _ +// ``` +// +// Where: +// +// * `derivativeCutoff`: Used to filter the first derivative of the input. 1 Hz is a good default. +// * `beta`: "Speed" parameter where higher values reduce latency. Range is [0-1]. +// * `minCutoff`: Minimum cutoff frequency in Hz. Lower values remove more jitter. +// +// #### References +// * +//------------------------------------------------------------------------ +declare oneEuro author "David Braun"; +declare oneEuro copyright "Copyright (C) 2024 by David Braun "; +declare oneEuro license "MIT"; +oneEuro(derivativeCutoff, beta, minCutoff, x) = x : ema(adaptiveCutoff) +with { + // exponential moving average that calculates its own alpha from a cutoff in Hz + // _ : ema(cutoff) : _ + ema(cutoff) = tick ~ _ + with { + alpha = 1.0 / (1.0 + ma.SR / (2 * ma.PI * cutoff)); + tick(prev, y) = prev*(1-alpha) + y*alpha; + }; + + derivative = x - x'; + derivativeFiltered = derivative : ema(derivativeCutoff); + adaptiveCutoff = minCutoff + beta * abs(derivativeFiltered); +}; + + //===========Linkwitz-Riley 4th-order 2-way, 3-way, and 4-way crossovers===== // // The Linkwitz-Riley (LR) crossovers are designed to produce a fully-flat