Files
skills/docs/media/audio-fx/audio-fx-plugin-widener/src/widener/widener.md
2026-05-29 08:20:56 +01:00

3.9 KiB
Raw Blame History

widener

(no submodules)

Purpose

StereoWidenerPlugin is the universal mid/side stereo-width control. It decomposes a stereo input into mid ((L + R) / 2) and side ((L - R) / 2) components, scales the side by width, and recomposes the output. width === 1 is exactly bit-transparent — mid + side = L and mid - side = R collapse to the original samples in IEEE arithmetic. width === 0 collapses the stereo image to mono (both channels equal mid). width > 1 exaggerates the stereo image, useful for over-narrow recordings.

The plugin is stateless on the processing path, so it adds no latency, has no reset() work, and runs identically across browser, server, offline, and worklet renderers.

Features

  • One parameter: width (ratio, 0..2).
  • Pure M/S transform: outL = mid + side·width, outR = mid − side·width. No filtering, no allocation, no per-channel state.
  • width === 1 early-out: copies L/R bit-exact via Float32Array.set, avoiding even the M/S decomposition arithmetic when fully transparent.
  • Mono input passes through unchanged because there is no side component to manipulate.
  • Surround channels (third channel and beyond) pass through unchanged so the plugin can sit in a multichannel chain without disturbing the rear-channel routing.

Usage: Basic Example

import { StereoWidenerPlugin } from "@suaveplan/audio-fx-plugin-widener";

const widener = new StereoWidenerPlugin({ initialWidth: 1.4 });
chain.add(widener);

Usage: Advanced Example

import { StereoWidenerPlugin } from "@suaveplan/audio-fx-plugin-widener";

// Automate width from mono to wide over a build-up — a classic
// "stereo reveal" effect for the first chorus of a track.
const reveal = new StereoWidenerPlugin({ initialWidth: 0 });
await reveal.setup(
    { sampleRate: 48_000, channels: 2, blockSize: 512 },
    ctx
);

reveal.setParameterAt("width", 0, 0);
reveal.setParameterAt("width", 1.6, 4);

API Reference

  • StereoWidenerPlugin (class extends AbstractAudioFxPlugin)
    • new StereoWidenerPlugin(options?: StereoWidenerPluginOptions) — throws AUDIO_FX.INVALID_OPTIONS on malformed options.
    • Inherited parameter accessor for width.

Implementation Notes

The M/S transform is mathematically lossless: starting from (L, R), computing mid = (L+R)/2, side = (L-R)/2, then recomposing as (mid+side, mid−side) returns (L, R) exactly in IEEE-754. We exploit this by early-returning at width === 1 with a Float32Array.set copy. The early-out is logical, not just for performance — without it, the recomposition path would still introduce one bit of rounding error on subnormal inputs, which an audit would catch as a violation of the "width=1 is bit-transparent" contract.

Mono input (channels === 1) and surround channels (channels > 2) pass through unchanged because the M/S transform only defines L/R semantics for the first two channels. Surround applications typically run a separate widener on the front pair and leave the rear pair untouched, which is exactly what this implementation does without requiring an explicit channel-routing parameter.

The maximum width of 2 is conservative — some "extra-wide" plugins go up to 4 or 8. The cap is a phase-coherence guard: at width = 2, a mono signal stays mono (no side to amplify), but a typical pop track with side / mid ≈ 0.3 produces outL − outR ≈ 1.2 · (L − R), already past the point where the mono fold-down starts to lose punch. Going higher would not break the plugin, but it would surprise users; if a future surface needs width > 2, raise the cap in both the Zod schema and the parameter declaration in one commit.

There is no plugin-specific preset payload — width is a universal parameter and travels through the parameter snapshot built by AbstractAudioFxPlugin. reset() is a no-op by design and the test exercises it to lock in that contract.