Initial Commit
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# `hooks/use-midi-input`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`useMidiInput(selector)` returns a typed `MidiPortLike` adapter over
|
||||
a single Web MIDI input. The adapter parses raw bytes into the
|
||||
discriminated `MidiMessage` union before delivering them through
|
||||
`onMessage`, so consumers never touch byte-level details. The
|
||||
`selector` is either an explicit `MIDIInput.id` or the literal
|
||||
`"first"` shorthand that picks whichever input the access enumerates
|
||||
first — useful when the host has exactly one device plugged in.
|
||||
|
||||
The hook returns `null` when access is still pending, when the
|
||||
selector misses (e.g. a stale id), or when there are zero inputs.
|
||||
This null-return shape composes cleanly with conditional rendering;
|
||||
consumers don't need to thread an explicit loading state.
|
||||
|
||||
## Features
|
||||
|
||||
- Two selector forms: `id` string or `"first"` literal.
|
||||
- Returns `null` during loading / denial / unknown id.
|
||||
- Adapter identity memoised against access + stateVersion + selector.
|
||||
- Multi-subscriber fan-out from a single Web MIDI input.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```tsx
|
||||
import { useMidiInput } from "@suaveplan/react-midi";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function NoteListener() {
|
||||
const port = useMidiInput("first");
|
||||
useEffect(() => {
|
||||
if (port === null) return;
|
||||
return port.onMessage((msg) => {
|
||||
if (msg.type === "noteOn") console.log(msg.note, msg.velocity);
|
||||
});
|
||||
}, [port]);
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```tsx
|
||||
function PerDeviceListeners() {
|
||||
const { inputs } = useMidi();
|
||||
return (
|
||||
<>
|
||||
{inputs.map((i) => (
|
||||
<PortFan key={i.id} portId={i.id} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PortFan({ portId }: { portId: string }) {
|
||||
const port = useMidiInput(portId);
|
||||
// ... attach handlers via port.onMessage
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `useMidiInput(selector: string | "first"): MidiPortLike | null`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The hook calls `adaptInput` inside `useMemo` so the adapter identity
|
||||
matches the underlying `MIDIInput` for the duration of the hook's
|
||||
lifetime. Because `adaptInput` keeps its own `Set<subscriber>` and
|
||||
the `useMemo` recreates the adapter when the underlying port changes
|
||||
(plug/unplug), any active subscription should re-bind from a
|
||||
`useEffect` keyed on `[port]`.
|
||||
Reference in New Issue
Block a user