pnpm dlx shadcn@latest add @audio-ui/device-signal
import { deriveSource, curveDot, peakDots, createDeviceSignal } from "@/lib/device-signal";| Files | lib/device-signal.ts |
|---|---|
| Depends on | Nothing |
| npm | @audio-ui/core, @audio-ui/engine |
| Used by | arrangement-engine, device-panel, device-panels, use-device-signal |
| Export | Kind | What it is |
|---|---|---|
SignalTarget | interface | What a signal listens to: a device's engine, or anything with an output. |
StereoSamples | interface | The two channels of a point, their latest samples, -1 to 1, and how alike they are: what a stereo field is drawn from. |
SpectrumOptions | interface | |
ScopeOptions | interface | |
HistoryOptions | interface | |
SignalPoint | interface | One point of a device's sound, such as what goes in or what comes out, read as live sources. |
DeviceSignal | interface | Everything a device's face can show of its sound, as live sources: what goes in (an effect's), what comes out, the points its engine names in its taps and the readings it reports, each one present when the device declares it in signals. |
deriveSource | function | A source computed from another, once per change however many watch it: a face's own reading of a signal, such as a level turned into a height. |
curveDot | function | A dot on a transfer curve at the level of levels, the louder of its channels: where the sound sits on the curve now, for a Plot.Dot (x the level in, y what curve makes of it). |
peakDots | function | Two dots on a shaper's curve, from -1 to 1, at the held peak of levels, one each side of zero: how far along the curve the sound swings, from the clean middle towards where it bends. |
createDeviceSignal | function | The live signal of a device, from its engine, as a face shows it: what goes in and comes out, its readings, and the taps its device declares in signals (its modulator and its wet sound). |
Usage
createDeviceSignal(target, device) reads an engine as a panel draws it. target is read each frame, so the signal follows the engine a host makes again and is silent while it returns null; device says which points it has: input for an effect, key for a device with a sidechain, and the taps it declares in signals.
import { createDeviceSignal } from "@/lib/device-signal";
const signal = createDeviceSignal(() => engine, compressorDevice);
signal.input?.levels; // the RMS and held peak of each channel, in dB
signal.output.spectrum({ minHz: 20, maxHz: 20_000 }); // dB along a log axis
signal.output.scope({ fit: true }); // the newest wave, held still on each cycle
signal.wet?.history({ of: "level", seconds: 3 }); // a reverb's or a delay's tail over time
signal.readings; // what the engine reports, such as the gain it takes offA component holding an engine uses useDeviceSignal instead, and a project's engine gives one per device with ArrangementEngine.signal(id, device).
Each point (input, output, key, wet, modulator) reads:
levels: the RMS of each channel in dB, rising at once and falling at 30 dB a second, and the loudest sample, held a moment, in the shape aMeterpaints.active: whether sound passes,falseonce it has been silent for 400 ms. A panel's frame is idle while its input is not active.spectrum({ minHz, maxHz, points }): dB along a log frequency axis.scope({ length, fit }): the newestlengthsamples from where the wave last rose through zero; withfit, scaled so the loudest of the last moments reaches 1.history({ seconds, points, of, newestFirst }): the signal itself ("value") or its level in dB ("level") over the lastseconds, its slots counted on the audio clock;newestFirstputs now at the start.stereo: the two channels' newest samples, how alike they are from -1 to 1, and whether both are silent.
A point puts its analysers on the engine when the first of its sources is watched and takes them off with the last, and every source of the page is read in one animation frame that sleeps once nothing is watched. A source publishes silence once rather than every frame.
Three helpers turn a source into what a face draws, without a React render:
deriveSource(source, compute): a source computed from another, once per change however many watch it.curveDot(levels, curve): a point on a transfer curve at the louder channel's level, for aPlot.Dot.peakDots(levels, curve): two points on a shaper's curve at the held peak,positiveandnegative.
const dot = useMemo(() => {
const levels = signal?.input?.levels;
return levels && curveDot(levels, curve);
}, [curve, signal]);
{dot ? <PlotDot className="group-data-idle/device:hidden" source={dot} /> : null}The Device signal guide says what each kind of device draws and how a device declares its taps.