Files
2026-05-27 23:47:53 +01:00

3.5 KiB

<MeterVU> — VU meter with IEC 60268-10 ballistics

(no submodules)

Purpose

<MeterVU> renders a single-channel level meter with the classic analogue VU response defined by IEC 60268-10: a 300 ms attack and 300 ms release single-pole low-pass smoothing the displayed needle relative to the instantaneous input level. The component is a pure value-in / DOM-out leaf — consumers feed a normalised level in [0, 1] and the meter handles ballistic smoothing on a requestAnimationFrame loop.

Use it for output-bus meters, mixer-strip meters, and any human-readable loudness indication where peak-precise behaviour is less important than the perception of "musical loudness".

Features

  • IEC 60268-10 default ballistics (300 ms attack, 300 ms release)
  • Caller-tunable attackMs and releaseMs for non-standard ballistics
  • Pure BoundControlProps-compatible value contract (value only)
  • role="meter" with aria-valuemin / aria-valuemax / aria-valuenow
  • CSS-variable themed fill (--cs-meter-vu-fill-color)
  • RAF-driven smoothing, automatic cleanup on unmount

Usage: Basic

import { MeterVU } from "@suaveplan/react-control-surface";

<MeterVU value={0.6} label="Master Out" />;

Usage: Advanced

import { MeterVU } from "@suaveplan/react-control-surface";

// Live-driven, fast attack / slow release for a punchy display
function LiveMeter({ source }: { source: () => number }) {
    const [v, setV] = useState(0);
    useEffect(() => {
        const id = setInterval(() => setV(source()), 16);
        return () => clearInterval(id);
    }, [source]);
    return <MeterVU value={v} attackMs={40} releaseMs={600} width={260} />;
}

API Reference

Prop Type Default Description
value number required Source level in [0, 1], clamped on input.
attackMs number 300 Single-pole attack time-constant.
releaseMs number 300 Single-pole release time-constant.
width number 160 Root width in CSS pixels.
height number 48 Root height in CSS pixels.
label string — Visible + accessible label.
ariaLabel string derived Overrides the accessible label.
className string — Appended to rcs-meter-vu.

The exported stepBallistic(previous, target, dtMs, attackMs, releaseMs) helper is the single-pole smoothing primitive used internally; it is exported for re-use in custom meters and is exhaustively unit-tested.

Implementation Notes

The meter holds a useRef containing { level, last } so that the ballistic state persists across React renders without forcing a re-render on every smoothing tick. The animation loop is created once on mount and torn down via cancelAnimationFrame on unmount. Time deltas are measured with Date.now() rather than the RAF callback's high-resolution timestamp to keep the math identical to the stepBallistic unit tests, which run without requestAnimationFrame.

The fill bar uses a single absolutely-positioned div whose width is recomputed from the smoothed level on every frame. The data-level attribute is provided as a deterministic hook for E2E assertions.