2.0 KiB
hooks/use-nrpn
(no submodules)
Purpose
useNRPN(selector) wraps the universal NRPN reducer from the
midi-contract module and exposes the consolidated NRPNChange as
React state. NRPN ("Non-Registered Parameter Number") edits arrive
over the wire as a four-CC dance — CC 99 (param MSB), CC 98 (param
LSB), CC 6 (data MSB), CC 38 (data LSB) — and consumers usually want
a single React-level event per completed dance rather than four
intermediate controlChange events. The hook performs that fold
internally and re-renders once per consolidated change.
The reducer is owned per port: when the underlying input identity changes (plug/unplug, selector switch) the reducer is reset, so a half-completed dance from a previous device does not leak into the new one.
Features
- Folds CC 99/98/6/38 into one
NRPNChangeper dance. - Per-port reducer — no cross-device interference.
- Resets internal state on port identity change.
- Returns
nulluntil the first completed dance.
Usage: Basic
import { useNRPN } from "@suaveplan/react-midi";
function ParamPanel() {
const change = useNRPN("first");
if (!change) return <p>Move a knob…</p>;
return (
<p>
NRPN ({change.paramHigh}.{change.paramLow}) → {change.value}
</p>
);
}
Usage: Advanced
function NRPNLog() {
const change = useNRPN("first");
const log = useRef<NRPNChange[]>([]);
useEffect(() => {
if (change !== null) log.current.push(change);
}, [change]);
return <pre>{JSON.stringify(log.current, null, 2)}</pre>;
}
API Reference
useNRPN(selector: string | "first"): NRPNChange | null
Implementation Notes
The hook keeps the reducer in a useRef (rather than a useMemo or
useState) because the reducer is conceptually an external store
attached to the lifetime of the port subscription, not a render
output. When the port becomes null the ref is cleared so a fresh
port gets a fresh reducer.