Files
skills/docs/ui/react/react-audio/README.md
2026-05-29 08:20:56 +01:00

207 lines
21 KiB
Markdown

# @suaveplan/react-audio - React surface for the Suaveplan audio family — Phase 2 + Phase 2b (extras) + Phase 3 shipped. Provides provider + hooks + stores + error codes + a11y helpers + Phase-2 primitives (PluginSlot, PluginChainView, PresetManager, knob/slider) + composed-plugin UIs (TransportControls, TrackList/TrackRow, MasterMeter, Mixer, AudioVisualizer, AudioPlayer/BasicPlayer/PremiumPlayer, MicrophoneControls, GLaDOSControls, PluginLoader) + Phase 3 MIDI learn-mode (`<MidiControllerSetup>` + `useMidiController`).
React surface for the Suaveplan audio family. **Phase 1 of 3 —
foundation** (provider + hooks + stores + error codes + a11y helpers).
Components ship in Phase 2 (`enterprise-react-audio-components`);
the MIDI learn-mode panel ships in Phase 3
(`enterprise-react-audio-midi`).
<!-- begin:auto-docs -->
## Documentation tree
- [aria-value-text](./src/a11y/aria-value-text/aria-value-text.md) — Pure `aria-valuetext` formatter consumed by Phase-2 parameter controls (knobs, sliders, scrubbers). Returns a screen-re…
- [aria-value-text](./src/a11y/aria-value-text/aria-value-text.md) — Pure `aria-valuetext` formatter consumed by Phase-2 parameter controls (knobs, sliders, scrubbers). Returns a screen-re…
- [keyboard-bindings](./src/a11y/keyboard-bindings/keyboard-bindings.md) — Pure-value table mapping keyboard keys to parameter-control actions (`fine-decrement`, `coarse-increment`, `page-decrem…
- [keyboard-bindings](./src/a11y/keyboard-bindings/keyboard-bindings.md) — Pure-value table mapping keyboard keys to parameter-control actions (`fine-decrement`, `coarse-increment`, `page-decrem…
- [audio-player](./src/components/audio-player/audio-player.md) — `<AudioPlayer>` is the generic media-player surface for a live `AudioPlayerPlugin` instance from `@suaveplan/audio-fx-p…
- [audio-player](./src/components/audio-player/audio-player.md) — `<AudioPlayer>` is the generic media-player surface for a live `AudioPlayerPlugin` instance from `@suaveplan/audio-fx-p…
- [audio-visualizer](./src/components/audio-visualizer/audio-visualizer.md) — `<AudioVisualizer>` is a canvas-based visualiser for a published bus. It subscribes through the foundation `useBus` hoo…
- [audio-visualizer](./src/components/audio-visualizer/audio-visualizer.md) — `<AudioVisualizer>` is a canvas-based visualiser for a published bus. It subscribes through the foundation `useBus` hoo…
- [basic-player](./src/components/basic-player/basic-player.md) — `<BasicPlayer>` is the minimal media-player surface for an `AudioPlayerPlugin`. It is implemented as a thin composition…
- [basic-player](./src/components/basic-player/basic-player.md) — `<BasicPlayer>` is the minimal media-player surface for an `AudioPlayerPlugin`. It is implemented as a thin composition…
- [glados-controls](./src/components/glados-controls/glados-controls.md) — `<GLaDOSControls>` is the composed UI for the `GLaDOSPlugin` voice transform from `@suaveplan/audio-fx-plugin-glados`.…
- [glados-controls](./src/components/glados-controls/glados-controls.md) — `<GLaDOSControls>` is the composed UI for the `GLaDOSPlugin` voice transform from `@suaveplan/audio-fx-plugin-glados`.…
- [parameter-keyboard](./src/components/internal/parameter-keyboard.md) — Internal helper consumed by `<PluginParameterKnob>` and `<PluginParameterSlider>` to translate a `KeyboardEvent` into a…
- [parameter-unit](./src/components/internal/parameter-unit.md) — Internal helper that converts the controlled `ParameterUnit` enum exposed by `@suaveplan/audio-fx-plugin-base` (`"db"`,…
- [master-meter](./src/components/master-meter/master-meter.md) — `<MasterMeter>` is a RAF-sampled master-output level meter. It subscribes to a named sidechain bus through the foundati…
- [master-meter](./src/components/master-meter/master-meter.md) — `<MasterMeter>` is a RAF-sampled master-output level meter. It subscribes to a named sidechain bus through the foundati…
- [microphone-controls](./src/components/microphone-controls/microphone-controls.md) — `<MicrophoneControls>` is the composed UI for `MicrophoneSimulationPlugin` from `@suaveplan/audio-fx-plugin-microphone`…
- [microphone-controls](./src/components/microphone-controls/microphone-controls.md) — `<MicrophoneControls>` is the composed UI for `MicrophoneSimulationPlugin` from `@suaveplan/audio-fx-plugin-microphone`…
- [midi-controller-setup](./src/components/midi-controller-setup/midi-controller-setup.md) — `<MidiControllerSetup>` is the Phase-3 learn-mode panel for the Suaveplan React audio stack. It renders the connected c…
- [midi-controller-setup](./src/components/midi-controller-setup/midi-controller-setup.md) — `<MidiControllerSetup>` is the Phase-3 learn-mode panel for the Suaveplan React audio stack. It renders the connected c…
- [mixer](./src/components/mixer/mixer.md) — `<Mixer>` is the per-channel strip view for a live `MixerPlugin` instance from `@suaveplan/audio-fx-plugin-mixer`. It r…
- [mixer](./src/components/mixer/mixer.md) — `<Mixer>` is the per-channel strip view for a live `MixerPlugin` instance from `@suaveplan/audio-fx-plugin-mixer`. It r…
- [plugin-chain-view](./src/components/plugin-chain-view/plugin-chain-view.md) — Reorderable, accessible view of a `PluginChain`. Renders one `<PluginSlot>` per chain entry, supports HTML5 drag-and-dr…
- [plugin-chain-view](./src/components/plugin-chain-view/plugin-chain-view.md) — Reorderable, accessible view of a `PluginChain`. Renders one `<PluginSlot>` per chain entry, supports HTML5 drag-and-dr…
- [plugin-loader](./src/components/plugin-loader/plugin-loader.md) — `<PluginLoader>` is the dynamic plugin-registration UI over the provider's `PluginRegistry`. It lists every currently-r…
- [plugin-loader](./src/components/plugin-loader/plugin-loader.md) — `<PluginLoader>` is the dynamic plugin-registration UI over the provider's `PluginRegistry`. It lists every currently-r…
- [plugin-parameter-knob](./src/components/plugin-parameter-knob/plugin-parameter-knob.md) — Rotary-knob primitive for a single `AudioFxPlugin` parameter. The knob implements the full keyboard contract mandated b…
- [plugin-parameter-knob](./src/components/plugin-parameter-knob/plugin-parameter-knob.md) — Rotary-knob primitive for a single `AudioFxPlugin` parameter. The knob implements the full keyboard contract mandated b…
- [plugin-parameter-slider](./src/components/plugin-parameter-slider/plugin-parameter-slider.md) — Linear-slider primitive for a single `AudioFxPlugin` parameter. Mirrors `<PluginParameterKnob>`'s a11y contract and exp…
- [plugin-parameter-slider](./src/components/plugin-parameter-slider/plugin-parameter-slider.md) — Linear-slider primitive for a single `AudioFxPlugin` parameter. Mirrors `<PluginParameterKnob>`'s a11y contract and exp…
- [plugin-slot](./src/components/plugin-slot/plugin-slot.md) — Generic renderer for any `AudioFxPlugin`. Reads the plugin's declarative `parameters` array and renders each one throug…
- [plugin-slot](./src/components/plugin-slot/plugin-slot.md) — Generic renderer for any `AudioFxPlugin`. Reads the plugin's declarative `parameters` array and renders each one throug…
- [premium-player](./src/components/premium-player/premium-player.md) — `<PremiumPlayer>` is the full-featured media-player surface — a composition of `<AudioPlayer>`, `<AudioVisualizer>`, an…
- [premium-player](./src/components/premium-player/premium-player.md) — `<PremiumPlayer>` is the full-featured media-player surface — a composition of `<AudioPlayer>`, `<AudioVisualizer>`, an…
- [preset-manager](./src/components/preset-manager/preset-manager.md) — `ChainSnapshot` save / load / delete UI layered over the provider's preset store. The save path persists the snapshot t…
- [preset-manager](./src/components/preset-manager/preset-manager.md) — `ChainSnapshot` save / load / delete UI layered over the provider's preset store. The save path persists the snapshot t…
- [track-list](./src/components/track-list/track-list.md) — `<TrackList>` is a composed-plugin UI that renders every track in the provider's `TimelineEngine`. It is the canonical…
- [track-list](./src/components/track-list/track-list.md) — `<TrackList>` is a composed-plugin UI that renders every track in the provider's `TimelineEngine`. It is the canonical…
- [track-row](./src/components/track-row/track-row.md) — `<TrackRow>` is the per-track row primitive consumed by `<TrackList>`. It subscribes to a single `Track` through the fo…
- [track-row](./src/components/track-row/track-row.md) — `<TrackRow>` is the per-track row primitive consumed by `<TrackList>`. It subscribes to a single `Track` through the fo…
- [transport-controls](./src/components/transport-controls/transport-controls.md) — `<TransportControls>` is the composed-plugin UI for the provider-owned `Transport` instance. It exposes the spec-mandat…
- [transport-controls](./src/components/transport-controls/transport-controls.md) — `<TransportControls>` is the composed-plugin UI for the provider-owned `Transport` instance. It exposes the spec-mandat…
- [error-codes](./src/error-codes/error-codes.md) — This module is the single source of truth for every error code thrown inside `@suaveplan/react-audio`. The codes are na…
- [error-codes](./src/error-codes/error-codes.md) — This module is the single source of truth for every error code thrown inside `@suaveplan/react-audio`. The codes are na…
- [hooks](./src/hooks/use-provider-state.md) — Internal helpers shared across every public hook. They centralise the two structured-error throws every engine-dependen…
- [use-analyser](./src/hooks/use-analyser/use-analyser.md) — `useAnalyser(opts?)` polls an `AnalyserNode`-shaped source and returns the latest byte-magnitude FFT frame plus the mat…
- [use-analyser](./src/hooks/use-analyser/use-analyser.md) — `useAnalyser(opts?)` polls an `AnalyserNode`-shaped source and returns the latest byte-magnitude FFT frame plus the mat…
- [use-audio-engine](./src/hooks/use-audio-engine/use-audio-engine.md) — `useAudioEngine()` returns the full resolved `ProviderState` bundle — the adapter, the `TimelineEngine`, the `Transport…
- [use-audio-engine](./src/hooks/use-audio-engine/use-audio-engine.md) — `useAudioEngine()` returns the full resolved `ProviderState` bundle — the adapter, the `TimelineEngine`, the `Transport…
- [use-audio-fx-plugin](./src/hooks/use-audio-fx-plugin/use-audio-fx-plugin.md) — `useAudioFxPlugin(pluginType)` instantiates a plugin via the provider's `PluginRegistry.create(pluginType)` and memoise…
- [use-audio-fx-plugin](./src/hooks/use-audio-fx-plugin/use-audio-fx-plugin.md) — `useAudioFxPlugin(pluginType)` instantiates a plugin via the provider's `PluginRegistry.create(pluginType)` and memoise…
- [use-bus](./src/hooks/use-bus/use-bus.md) — `useBus(name)` reads the named sidechain bus from the provider's `ProviderBusRegistry` and subscribes to its publish/cl…
- [use-bus](./src/hooks/use-bus/use-bus.md) — `useBus(name)` reads the named sidechain bus from the provider's `ProviderBusRegistry` and subscribes to its publish/cl…
- [use-chain-plugin](./src/hooks/use-chain-plugin/use-chain-plugin.md) — `useChainPlugin(trackId, slotIndex)` returns the `AudioFxPlugin` currently occupying a specific slot in a track's `Plug…
- [use-chain-plugin](./src/hooks/use-chain-plugin/use-chain-plugin.md) — `useChainPlugin(trackId, slotIndex)` returns the `AudioFxPlugin` currently occupying a specific slot in a track's `Plug…
- [use-chain-snapshot](./src/hooks/use-chain-snapshot/use-chain-snapshot.md) — `useChainSnapshot(chain)` exposes chain-level snapshot operations. `get` reads the in-memory `ChainSnapshot`, `restore`…
- [use-chain-snapshot](./src/hooks/use-chain-snapshot/use-chain-snapshot.md) — `useChainSnapshot(chain)` exposes chain-level snapshot operations. `get` reads the in-memory `ChainSnapshot`, `restore`…
- [use-engine-state](./src/hooks/use-engine-state/use-engine-state.md) — `useEngineState()` reports the `<AudioProvider>`'s async-init lifecycle phase as one of `'pending' | 'ready' | 'error'`…
- [use-engine-state](./src/hooks/use-engine-state/use-engine-state.md) — `useEngineState()` reports the `<AudioProvider>`'s async-init lifecycle phase as one of `'pending' | 'ready' | 'error'`…
- [use-midi-controller](./src/hooks/use-midi-controller/use-midi-controller.md) — `useMidiController(controllerId)` is the React 19 binding for a single `MidiControllerPlugin` from `@suaveplan/audio-co…
- [use-midi-controller](./src/hooks/use-midi-controller/use-midi-controller.md) — `useMidiController(controllerId)` is the React 19 binding for a single `MidiControllerPlugin` from `@suaveplan/audio-co…
- [use-parameter](./src/hooks/use-parameter/use-parameter.md) — `useParameter(plugin, paramId)` is the canonical read/write hook for a single declared parameter on any `AudioFxPlugin`…
- [use-parameter](./src/hooks/use-parameter/use-parameter.md) — `useParameter(plugin, paramId)` is the canonical read/write hook for a single declared parameter on any `AudioFxPlugin`…
- [use-playlist](./src/hooks/use-playlist/use-playlist.md) — `usePlaylist(items, opts?)` manages a queue of `PlaylistItem` entries and exposes the standard playlist verbs (`next`,…
- [use-playlist](./src/hooks/use-playlist/use-playlist.md) — `usePlaylist(items, opts?)` manages a queue of `PlaylistItem` entries and exposes the standard playlist verbs (`next`,…
- [use-plugin-chain](./src/hooks/use-plugin-chain/use-plugin-chain.md) — `usePluginChain(trackId)` returns a handle for the `PluginChain` associated with a track. The provider lazily creates t…
- [use-plugin-chain](./src/hooks/use-plugin-chain/use-plugin-chain.md) — `usePluginChain(trackId)` returns a handle for the `PluginChain` associated with a track. The provider lazily creates t…
- [use-preset](./src/hooks/use-preset/use-preset.md) — `usePreset(plugin)` exposes plugin-level preset operations as React-friendly callbacks: `get` reads the current preset,…
- [use-preset](./src/hooks/use-preset/use-preset.md) — `usePreset(plugin)` exposes plugin-level preset operations as React-friendly callbacks: `get` reads the current preset,…
- [use-timeline](./src/hooks/use-timeline/use-timeline.md) — `useTimeline()` returns the provider's single `TimelineEngine` instance, the canonical owner of timeline state — tracks…
- [use-timeline](./src/hooks/use-timeline/use-timeline.md) — `useTimeline()` returns the provider's single `TimelineEngine` instance, the canonical owner of timeline state — tracks…
- [use-track](./src/hooks/use-track/use-track.md) — `useTrack(trackId)` subscribes to a single track on the `TimelineEngine` by id and re-renders only when that specific t…
- [use-track](./src/hooks/use-track/use-track.md) — `useTrack(trackId)` subscribes to a single track on the `TimelineEngine` by id and re-renders only when that specific t…
- [use-transport](./src/hooks/use-transport/use-transport.md) — `useTransport()` wraps the provider's `Transport` with a small, React-friendly façade: `{ transport, play, pause, stop,…
- [use-transport](./src/hooks/use-transport/use-transport.md) — `useTransport()` wraps the provider's `Transport` with a small, React-friendly façade: `{ transport, play, pause, stop,…
- [use-transport-time](./src/hooks/use-transport-time/use-transport-time.md) — `useTransportTime()` returns the transport's current time in seconds, sampled at the provider's configured `sampleRateH…
- [use-transport-time](./src/hooks/use-transport-time/use-transport-time.md) — `useTransportTime()` returns the transport's current time in seconds, sampled at the provider's configured `sampleRateH…
- [use-provider-state](./src/hooks/use-provider-state.md) — Internal helpers shared across every public hook. They centralise the two structured-error throws every engine-dependen…
- [audio-context](./src/provider/audio-context.md) — Declares the React context object (`AudioReactContext`) that `<AudioProvider>` populates and that every hook reads from…
- [audio-provider](./src/provider/audio-provider.md) — `<AudioProvider>` is the single React component that owns the audio engine bundle for a React subtree. It constructs ex…
- [chain-map](./src/provider/chain-map.md) — `ChainMap` is the provider-scoped lazy registry of `PluginChain` instances, keyed by track id. The hook `usePluginChain…
- [provider-bus-registry](./src/provider/provider-bus-registry.md) — `ProviderBusRegistry` is a thin wrapper around `DefaultBusRegistry` from `@suaveplan/audio-fx-plugin-base` that adds a…
- [provider-options](./src/provider/provider-options.md) — Defines the `AudioProviderOptions` shape consumed by `<AudioProvider>`, the Zod schema that validates it, and the `pars…
- [audio-store](./src/stores/audio-store/audio-store.md) — `useAudioStore` is a slim provider-scoped Zustand store reserved for application-level audio UI overrides (display name…
- [audio-store](./src/stores/audio-store/audio-store.md) — `useAudioStore` is a slim provider-scoped Zustand store reserved for application-level audio UI overrides (display name…
- [ui-store](./src/stores/ui-store/ui-store.md) — `useUiStore` is the cross-component UI state store for the React audio workspace. It owns presentation-only state — whi…
- [ui-store](./src/stores/ui-store/ui-store.md) — `useUiStore` is the cross-component UI state store for the React audio workspace. It owns presentation-only state — whi…
- [test-utils](./src/test-utils.md) — Test-only helpers for the `@suaveplan/react-audio` test suite. The module exports three utilities: `makeFakeAudioContex…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/react-audio
```
Peer deps: `react@^19`, `react-dom@^19`.
## Quick start
```tsx
import { AudioProvider, useTransport } from "@suaveplan/react-audio";
function PlayButton() {
const { play, stop, transport } = useTransport();
return (
<button type="button" onClick={() => (transport.state === "playing" ? stop() : play())}>
{transport.state === "playing" ? "Stop" : "Play"}
</button>
);
}
export default function App() {
return (
<AudioProvider options={{ adapter: { sampleRate: 48000 } }}>
<PlayButton />
</AudioProvider>
);
}
```
## What ships in Phase 1
### Provider
- `<AudioProvider>` — owns one `BrowserTimelineAdapter`, one
`TimelineEngine`, one `Transport`, one `ProviderBusRegistry`, one
`ChainMap`, and one `PluginRegistry`. Strict-mode safe; disposes
cleanly on unmount.
### 13 hooks
| Hook | Returns |
|------|---------|
| `useEngineState()` | `'pending' \| 'ready' \| 'error'` |
| `useAudioEngine()` | full `ProviderState` bundle |
| `useTimeline()` | `TimelineEngine` |
| `useTransport()` | `{ transport, play, pause, stop, seek, setTempo }` |
| `useTransportTime()` | current seconds, sampled at frame rate |
| `useTrack(trackId)` | `{ track, update, remove }` |
| `usePluginChain(trackId)` | chain composition + events |
| `useChainPlugin(trackId, slot)` | plugin at slot |
| `useAudioFxPlugin(pluginType)` | new plugin from the registry |
| `useParameter(plugin, paramId)` | value + set + curve + scheduleAt |
| `usePreset(plugin)` | plugin-level preset get/apply/save/load |
| `useChainSnapshot(chain)` | chain-level snapshot get/restore/save/load |
| `useBus(name)` | sidechain bus by name |
### Stores
- `useAudioStore` — UI override store (no engine state mirrored).
- `useUiStore` — panel/theme/visualization/selectedTrack/dragState.
### Accessibility helpers
- `PARAMETER_KEY_BINDINGS` + `matchKeyBinding(event)` — central
keymap consumed by Phase-2 components.
- `formatAriaValueText(value, unit, min, max, options?)` — unit-aware
`aria-valuetext` formatter.
### Error codes
All errors are `ReactAudioError extends SuaveplanError`. Codes:
- `REACT_AUDIO.NO_PROVIDER`
- `REACT_AUDIO.PROVIDER_PENDING`
- `REACT_AUDIO.UNKNOWN_PARAMETER`
- `REACT_AUDIO.PRESET_STORE_FAILED`
- `REACT_AUDIO.INVALID_OPTIONS`
## Subpath exports
```ts
import { AudioProvider } from "@suaveplan/react-audio/provider";
import { useTransport } from "@suaveplan/react-audio/hooks/use-transport";
import { useAudioStore } from "@suaveplan/react-audio/stores";
import { formatAriaValueText } from "@suaveplan/react-audio/a11y";
import { ReactAudioError } from "@suaveplan/react-audio/error-codes";
```
`./components` is reserved for Phase 2 and is **not** declared in
Phase 1.
## Coming next
- **Phase 2 (`enterprise-react-audio-components`)** — Storybook-covered
components: `<TransportControls>`, `<TrackList>`, `<PluginChainView>`,
`<PluginSlot>`, `<MasterMeter>`, `<Mixer>`, `<PresetManager>`, …
- **Phase 3 (`enterprise-react-audio-midi`)** — `useMidiController`
hook + `<MidiControllerSetup>` learn-mode panel.
## License
MIT