# `midi-in` handler ## Purpose The `midiIn` handler is the binding-registry slot that hosts an inbound MIDI subscription — a control bound this way reflects external CC traffic rather than driving it. The default export is the "unwired" implementation that throws `REACT_CONTROL_SURFACE.BINDING_HANDLER_MISSING`; consumers replace it with a closure that captures a subscription created by `useMidiInput(binding.portId)` and pumps the inbound value back into the control via the runtime's `setValue` channel. Throwing at the default site is the right call even for a "passive" inbound binding: silently dropping inbound updates would leave the control's visual state out of sync with the device. ## Features - Strongly-typed signature `(binding: MidiInBinding, value: number) => never`. - Error context preserves `portId`, `channel`, `cc`, and the most recent inbound value. ## Usage: Basic ```ts import { BindingRegistry } from "@suaveplan/react-control-surface/runtime/binding-registry"; const registry = new BindingRegistry({ midiIn: (binding, value) => surfaceValueStore.set(binding, value), }); ``` ## Usage: Advanced ```ts import { midiInHandler } from "@suaveplan/react-control-surface/runtime/binding-registry"; try { midiInHandler({ kind: "midiIn", portId: "p1", channel: 1, cc: 7 }, 0); } catch (err) { // err.context.kind === "midiIn" } ``` ## API Reference - `midiInHandler(binding: MidiInBinding, value: number): never` — always throws with code `REACT_CONTROL_SURFACE.BINDING_HANDLER_MISSING`. ## Implementation Notes Because inbound bindings are an "inverse" of outbound ones, the same handler signature is reused with the understanding that the production handler treats the `value` argument as the most recent inbound observation rather than a value to send. Keeping the signatures unified simplifies the generic dispatcher and lets test spies swap inbound + outbound paths with identical types.