2.4 KiB
port/web-midi-port
(no submodules)
Purpose
Bridges the native Web MIDI WebMIDIInput / WebMIDIOutput shapes
into the structural MidiPortLike consumed by the rest of the
package. The adapter handles two responsibilities the underlying
DOM types do not: it parses MIDIMessageEvent.data into a typed
MidiMessage (so consumers never touch raw bytes), and it owns the
fan-out from the single onmidimessage slot to multiple subscribers.
Two factories ship: adaptInput for inputs (yielding parsed messages
via onMessage) and adaptOutput for outputs (encoding MidiMessage
to bytes via encodeMessage before forwarding to port.send). Both
record traffic via the telemetry module so dashboards see one
counter per direction.
Features
- Multiple subscribers on a single input — the adapter fans the
single
onmidimessageslot out to aSetof handlers. - Lazy bind/unbind — the
onmidimessageslot is occupied only while at least one subscriber is active; the last unsubscribe restoresnull. - Input-side decode swallows malformed frames silently (the runtime
already filters; defensive
nullcheck keeps subscribers safe). - Output-side
sendMessageencodes a typedMidiMessage; rawsend(bytes)remains available for SysEx pass-through.
Usage: Basic
import { adaptInput, adaptOutput } from "@suaveplan/react-midi/port/web-midi-port";
const port = adaptInput(midiAccess.inputs.get("midi-in-0")!);
const unsubscribe = port.onMessage((msg) => {
if (msg.type === "noteOn") console.log("note", msg.note);
});
Usage: Advanced
const out = adaptOutput(midiAccess.outputs.get("midi-out-0")!);
// Typed send (encoded):
out.sendMessage({
type: "noteOn",
channel: 0,
note: 60,
velocity: 100,
});
// Raw send (for SysEx pass-through):
out.send(new Uint8Array([0xf0, 0x7e, 0x00, 0xf7]));
API Reference
adaptInput(input: WebMIDIInput): MidiPortLikeadaptOutput(output: WebMIDIOutput): MidiPortLike & { sendMessage(msg: MidiMessage): void }
Implementation Notes
The input adapter uses Set (not array) for subscribers so
unsubscribing during fan-out doesn't reorder iteration over the
remaining subscribers. The output adapter's onMessage returns a
no-op unsubscriber rather than throwing, which lets generic code that
walks both directions on a port handle either shape without a runtime
type check.