first commit
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# `hooks/use-parameter`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`useParameter(plugin, paramId)` is the canonical read/write hook for
|
||||
a single declared parameter on any `AudioFxPlugin`. It returns the
|
||||
parameter's current value (sampled at frame rate) and three
|
||||
write-paths: an immediate `set`, a `curve` for ramps/automation, and
|
||||
a `scheduleAt` for transport-anchored value changes.
|
||||
|
||||
The hook throws `ReactAudioError(REACT_AUDIO.UNKNOWN_PARAMETER)`
|
||||
synchronously on first render if the `paramId` is not declared in
|
||||
the plugin's `parameterIndex` — so a typo fails fast in the render
|
||||
tree rather than silently dropping writes.
|
||||
|
||||
## Features
|
||||
|
||||
- Frame-rate sampled `value` (60 Hz default, configurable via
|
||||
provider `sampleRateHz`).
|
||||
- `set(v)` → `plugin.setParameter(paramId, v)`.
|
||||
- `curve(c)` → `plugin.setParameterCurve(paramId, c)`.
|
||||
- `scheduleAt(v, t)` → `plugin.setParameterAt(paramId, v, t)`.
|
||||
- Throws `REACT_AUDIO.UNKNOWN_PARAMETER` on first render for an
|
||||
unknown `paramId`, carrying the available ids in `context`.
|
||||
- SSR-consistent snapshots (both `getSnapshot` and
|
||||
`getServerSnapshot` read `plugin.getParameter(paramId)`).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```tsx
|
||||
import { useParameter } from "@suaveplan/react-audio";
|
||||
|
||||
function GainKnob({ plugin }: { plugin: AudioFxPlugin }) {
|
||||
const { value, set } = useParameter(plugin, "gain");
|
||||
return (
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={value}
|
||||
onChange={(e) => set(Number(e.currentTarget.value))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```tsx
|
||||
import { useParameter } from "@suaveplan/react-audio";
|
||||
|
||||
function Sweep({ plugin }: { plugin: AudioFxPlugin }) {
|
||||
const { curve, scheduleAt } = useParameter(plugin, "cutoff");
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
curve({
|
||||
kind: "linear",
|
||||
startValue: 200,
|
||||
endValue: 8000,
|
||||
duration: 4,
|
||||
})
|
||||
}
|
||||
>
|
||||
Linear sweep
|
||||
</button>
|
||||
<button type="button" onClick={() => scheduleAt(440, 2)}>
|
||||
Set to 440 at t=2s
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `useParameter(plugin, paramId): { value, set, curve, scheduleAt }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Parameter automation can change values per audio block (~689 Hz at
|
||||
128/88.2k); the React commit cycle cannot run at that rate. The hook
|
||||
samples the live value at `sampleRateHz` (60 Hz default) via a
|
||||
`useSyncExternalStore` subscription whose subscribe path schedules a
|
||||
`setInterval` and getSnapshot path reads `plugin.getParameter(paramId)`.
|
||||
`setInterval` is used rather than `requestAnimationFrame` so the
|
||||
sampling behaves deterministically in tests (happy-dom RAF is
|
||||
synchronous-per-microtask which makes the per-frame-cap test
|
||||
impossible). The unknown-param check runs on every render —
|
||||
parameter indices are immutable on a typical plugin so the lookup is
|
||||
O(1) and the throw site is the same.
|
||||
Reference in New Issue
Block a user