audioJS

@audio/lpc

Status calibrated

npm1.2.0licenseMIT

Linear predictive coding — Levinson-Durbin AR analysis, prediction, forward extrapolation, and least-squares gap interpolation

Overview

Install
Updated
Family
denoise, 20 packages under it

Linear predictive coding — model a signal as an autoregressive process, then predict, extrapolate, or fill gaps from it.

The Levinson-Durbin solution to the Yule-Walker equations, plus the AR-prediction tools that classical audio restoration is built on. Pure math, no dependencies.

import { lpc, arExtrapolate, arInterpolate } from '@audio/lpc'

let { a, e } = lpc(window, 16)          // AR(16) coefficients a[], residual variance e
let filled = arExtrapolate(context, a, 32)   // project 32 samples forward (de-clip)

lpc(x, p) / arFit(x, p)

LPC analysis of order p over window x (lpc is the conventional alias). Returns { a: Float64Array(p+1), e } — a[0] === 1, e is the residual variance. Internally levinson(autocorr(x, p), p).

autocorr(x, p) · levinson(R, p)

The two stages, exposed separately: biased autocorrelation R[0..p], and the Levinson-Durbin Toeplitz solve. Call directly when you already have an autocorrelation, or want the reflection-coefficient path.

arPredict(a, hist)

One-step prediction x̂[n] = -∑ a[k]·x[n−k] from a history buffer.

arExtrapolate(context, a, m)

Project m samples forward from context under model a. Used to reconstruct clipped regions from their un-clipped neighbourhood.

arInterpolate(x, gap, a)

Least-squares fill of missing indices gap (sorted) inside x, in place, under model a — the interpolator behind de-crackle. Gauss-Seidel, 30 sweeps: close for a few scattered samples; arFill solves the same exactly.

arFill(x, gap, a)

arInterpolate's problem solved exactly, for unknowns scattered anywhere in x: the normal equations couple two unknowns only when they lie within p samples of each other, so they are banded in the gap's order, and Cholesky within that band solves them in O(m·b²) for m unknowns with at most b of them within p of one another. Returns false (and leaves x as it was) when the model makes the system singular. The interpolator behind denoise-declip, where every clipped sample of a window is unknown at once (Janssen, Veldhuis & Vries 1986).

let gap = []                              // every clipped sample of the window
for (let i = 0; i < w.length; i++) if (Math.abs(w[i]) >= rail) gap.push(i)
let { a } = lpc(w, 64)
arFill(w, gap, a)                         // the least-squares fill of all of them at once, in place

arBridge(x, from, to, a)

The same least-squares fill for one contiguous gap x[from..to), in place, solved exactly: the normal equations are Toeplitz in the autocorrelation of a, so Levinson recursion takes O(m²) for m missing samples at any order (Janssen, Veldhuis & Vries 1986; the solve of the Audio Inpainting Toolbox's Janssen step, Adler et al. 2012). Where arInterpolate suits scattered clicks at order ~60, this suits a dropout of hundreds or thousands of samples at order ~1000: the interpolator behind denoise-repair's AR tier.

segment.fill(0, 4096, 4096 + 882)         // a 20 ms dropout at 44.1 kHz, zeroed
let { a } = lpc(segment, 1024)            // AR fit on its surroundings
arBridge(segment, 4096, 4096 + 882, a)    // least-squares fill, in place; refit and refill once more for Janssen's method

Notes

Foundation for LPC vocoders and formant tracking (Markel & Gray 1976); restoration methods follow Godsill & Rayner (1998). Used by @audio/denoise's declick/decrackle/declip/repair. MIT.