first commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# `<MeterSpectral>` — multi-band spectrum visualiser
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`<MeterSpectral>` renders a real-time bar graph of magnitude bins. Each
|
||||
bin is drawn as a vertical bar whose height is proportional to the
|
||||
bin's magnitude in `[0, 1]`. The component is deliberately tier-pure:
|
||||
it has no dependency on `@suaveplan/audio-analysis-spectrum` or any
|
||||
audio code at all. Bins are pre-computed by the caller — wire it up to
|
||||
whatever analyser is appropriate (web-audio `AnalyserNode`, the
|
||||
spectrum-analysis package, a network stream, or a synthetic generator).
|
||||
|
||||
This separation keeps the React rendering layer free of audio
|
||||
processing and makes it trivial to use the same component for any
|
||||
1-D magnitude signal — FFT magnitudes, wavelet bands, frequency-warped
|
||||
mel bins, or live envelope follower output.
|
||||
|
||||
## Features
|
||||
|
||||
- Static `Float32Array` or streaming `AsyncIterable<Float32Array>` source
|
||||
- Configurable `width`, `height`, and inter-bar `gap`
|
||||
- Per-bin `data-value` attributes for E2E and screen-reader inspection
|
||||
- `role="img"` with a single `aria-label` describing the visualisation
|
||||
- CSS-variable themed bars (`--cs-meter-spectral-bar-color`)
|
||||
- Out-of-range bin values are clamped to `[0, 1]` automatically
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```tsx
|
||||
import { MeterSpectral } from "@suaveplan/react-control-surface";
|
||||
|
||||
<MeterSpectral
|
||||
bins={new Float32Array([0.1, 0.5, 0.9, 0.3])}
|
||||
label="Output spectrum"
|
||||
/>;
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```tsx
|
||||
import { MeterSpectral } from "@suaveplan/react-control-surface";
|
||||
|
||||
async function* spectrumStream(
|
||||
analyser: AnalyserNode
|
||||
): AsyncIterable<Float32Array> {
|
||||
const buf = new Float32Array(analyser.frequencyBinCount);
|
||||
while (true) {
|
||||
analyser.getFloatFrequencyData(buf);
|
||||
const out = new Float32Array(buf.length);
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
out[i] = Math.max(0, Math.min(1, (buf[i] + 100) / 100));
|
||||
}
|
||||
yield out;
|
||||
await new Promise((r) => requestAnimationFrame(() => r(null)));
|
||||
}
|
||||
}
|
||||
|
||||
<MeterSpectral
|
||||
bins={spectrumStream(analyserNode)}
|
||||
width={480}
|
||||
height={160}
|
||||
label="Master spectrum"
|
||||
/>;
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------------------------------------------------- | ------- | ---------------------------------------- |
|
||||
| `bins` | `Float32Array \| AsyncIterable<Float32Array>` | req | Magnitude bins in `[0, 1]`. |
|
||||
| `width` | `number` | `240` | Total width in CSS pixels. |
|
||||
| `height` | `number` | `80` | Total height in CSS pixels. |
|
||||
| `gap` | `number` | `1` | Inter-bar gap in CSS pixels. |
|
||||
| `label` | `string` | — | Visible + accessible label. |
|
||||
| `ariaLabel` | `string` | derived | Override the accessible label. |
|
||||
| `className` | `string` | — | Appended to `rcs-meter-spectral`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
When `bins` is a `Float32Array`, the component sets its frame state
|
||||
directly on mount and whenever the prop identity changes. When `bins`
|
||||
is an `AsyncIterable`, an effect subscribes via `for await … of` and
|
||||
calls `setFrame` for every yielded frame. The subscription is torn down
|
||||
via a `cancelled` flag in the cleanup function; errors thrown from the
|
||||
iterator are swallowed because visualisation is best-effort.
|
||||
|
||||
Bars are absolutely-positioned `div`s aligned to the bottom of the
|
||||
container; bar width is `(width - totalGap) / count`. This keeps the
|
||||
layout pure CSS and avoids `<canvas>` — every bar is independently
|
||||
inspectable in DOM and accessible tooling.
|
||||
Reference in New Issue
Block a user