Lab

meter

A level meter's scale, ballistics and painting from @audio-ui/core: where a level sits on an IEC, VU or linear scale, how a VU or a PPM reading follows the level, and the per-frame DOM writes of a channel.

pnpm add @audio-ui/core
import { createPpmBallistics, createVuBallistics, FLOOR_DB, iecDeflection, levelPosition, /* … */ } from "@audio-ui/core/meter";
Adapters@audio-ui/react/meter, @audio-ui/elements/meter
ExportKindWhat it is
createPpmBallisticsfunctionA PPM meter: it rises in attackSeconds, a time constant, and falls at a steady releaseDbPerSecond, so a peak reads long enough to be seen.
createVuBallisticsfunctionA VU meter: its pointer follows the voltage of the level as a mass on a spring does, symmetrically, taking riseSeconds to first reach 99% of a step and overshooting it by 1.3%, as the standard says.
FLOOR_DBconstThe lowest reading a meter shows, in dB: below it the level is silence.
MeterBallisticsinterfaceHow a meter's reading follows the level it measures, over time.
iecDeflectionfunctionThe deflection of an IEC 60268-18 style digital peak meter, from 0 at -70 dB to 100 at 0 dB: each stretch of the scale gets more room than the one below, so the top 20 dB take half the length.
LevelScaletypeHow a level in dB is spread along the meter's length: evenly, or the way digital peak meters spread it, with room at the top where it matters.
LevelScaleFunctiontypeA custom curve: any increasing function of the level, rescaled to the meter's range.
levelPositionfunctionA function from a level to its position along the length, 0 at min and 1 at max.
vuDeflectionfunctionThe deflection of a VU meter's pointer.
channelViewfunctionWhat a channel shows for its reading in frame: the length of its bar, its peak mark, whether it warns or clips, and its text.
createMeterConfigfunctionBuilds the config a meter reads its levels with: the position along its length, and how levels are written.
DEFAULT_METER_FORMATconstLevels read to one decimal: finer than a meter can be read, and a plain number rather than a share of the range.
MeterChannelNodesinterfaceThe DOM nodes of one channel that a live source writes to.
MeterChannelParttypeA part of a channel that a live source writes to.
MeterChannelViewinterfaceWhat one channel shows for a level: everything both the React render and the per-frame DOM writes derive from.
MeterConfiginterfaceWhat createMeterConfig returns: the range, the warning and clipping levels, the position of a level along the meter, and how a level is written.
MeterFrameinterfaceOne reading of the meter: a level per channel, and optionally a peak-hold level per channel.
MeterOrientationtypeWhich way a meter's bars run.
paintChannelfunctionWrite one channel's view straight to its nodes, touching only what changed.
setPresencefunctionSets attribute on node as an empty attribute, or removes it.

Usage

A meter has no gesture, so it has no controller. What it has is a scale, ballistics and a channel to paint.

The scale

createMeterConfig holds how levels are placed and written: min, max, warnThreshold, clipThreshold, and scale, which is "iec" (the deflection of a digital peak meter, with room at the top), "linear", or a function. position(level) gives a level's place on the meter, from 0 to 1:

import { createMeterConfig } from "@audio-ui/core/meter";

const config = createMeterConfig({ min: -60, max: 6, scale: "iec", clipThreshold: 0 });
config.position(-18); // 0.467

iecDeflection and vuDeflection are the two standard curves on their own, and levelPosition(scale, min, max) makes the function position is.

Ballistics

The levels come from a live source, and the meter has no clock of its own, so how a reading moves is yours to choose. A ballistic follows a level frame by frame:

import { createPpmBallistics, createVuBallistics } from "@audio-ui/core/meter";

const vu = createVuBallistics(); // 300 ms to reach 99% of a step, overshooting it by 1.3%
const ppm = createPpmBallistics(); // a 5 ms attack, then a fall of 20 dB in 1.5 s

const reading = vu.step(levelDb, elapsedSeconds);

step(level, seconds) moves the reading toward a level over a frame and returns it; reset(value) puts it somewhere at once. Below FLOOR_DB a reading is silence.

Painting a channel

channelView(frame, index, config) is what a channel shows for a reading: the length of its bar, its peak mark, whether it is at the warning level or clipping, and its text. paintChannel(nodes, view, index, orientation) writes that straight to the channel's DOM nodes, touching only what changed, so a meter repaints every frame with no render of its framework.

The Meter draws these in React.

Built by Ouest Labs, the source code is available on GitHub.
RSS