# 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.

```bash
npm install @audio-ui/core
```

```ts
import { createPpmBallistics, createVuBallistics, FLOOR_DB, iecDeflection, levelPosition, /* … */ } from "@audio-ui/core/meter";
```

- Adapters: `@audio-ui/react/meter`, `@audio-ui/elements/meter`

| Export | Kind | What it is |
| --- | --- | --- |
| `createPpmBallistics` | function | A PPM meter: it rises in `attackSeconds`, a time constant, and falls at a steady `releaseDbPerSecond`, so a peak reads long enough to be seen. |
| `createVuBallistics` | function | A 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_DB` | const | The lowest reading a meter shows, in dB: below it the level is silence. |
| `MeterBallistics` | interface | How a meter's reading follows the level it measures, over time. |
| `iecDeflection` | function | The 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. |
| `LevelScale` | type | How 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. |
| `LevelScaleFunction` | type | A custom curve: any increasing function of the level, rescaled to the meter's range. |
| `levelPosition` | function | A function from a level to its position along the length, 0 at `min` and 1 at `max`. |
| `vuDeflection` | function | The deflection of a VU meter's pointer. |
| `channelView` | function | What a channel shows for its reading in `frame`: the length of its bar, its peak mark, whether it warns or clips, and its text. |
| `createMeterConfig` | function | Builds the config a meter reads its levels with: the position along its length, and how levels are written. |
| `DEFAULT_METER_FORMAT` | const | Levels read to one decimal: finer than a meter can be read, and a plain number rather than a share of the range. |
| `MeterChannelNodes` | interface | The DOM nodes of one channel that a live source writes to. |
| `MeterChannelPart` | type | A part of a channel that a live source writes to. |
| `MeterChannelView` | interface | What one channel shows for a level: everything both the React render and the per-frame DOM writes derive from. |
| `MeterConfig` | interface | What `createMeterConfig` returns: the range, the warning and clipping levels, the position of a level along the meter, and how a level is written. |
| `MeterFrame` | interface | One reading of the meter: a level per channel, and optionally a peak-hold level per channel. |
| `MeterOrientation` | type | Which way a meter's bars run. |
| `paintChannel` | function | Write one channel's view straight to its nodes, touching only what changed. |
| `setPresence` | function | Sets `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:

```ts
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:

```ts
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.

**In React**

The [Meter](/docs/components/base/meter) draws these in React.

**In Vue, Svelte and Web**

[`<audio-ui-meter>`](/docs/elements/meter) draws these in your framework.

