# `hooks/use-midi-input` _(no submodules)_ ## 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) => ( ))} ); } 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` 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]`.