Files
skills/docs/ui/react/react-control-surface/src/runtime/binding-registry/handlers/midi-in.md
2026-05-29 08:20:56 +01:00

1.9 KiB

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

import { BindingRegistry } from "@suaveplan/react-control-surface/runtime/binding-registry";

const registry = new BindingRegistry({
    midiIn: (binding, value) => surfaceValueStore.set(binding, value),
});

Usage: Advanced

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.