Files
suaveplan/packages/ui/react/react-midi/src/hooks/use-midi-output/use-midi-output.ts
2026-05-27 23:47:53 +01:00

40 lines
1.6 KiB
TypeScript

import { useMemo } from "react";
import type { MidiMessage } from "../../midi-contract/midi-message.types.js";
import { adaptOutput } from "../../port/web-midi-port.js";
import { useMidiContextOrThrow } from "../use-midi-context.js";
import type { PortSelector } from "../use-midi-input/use-midi-input.js";
export interface MidiOutputHandle {
readonly id: string;
readonly name: string;
readonly manufacturer: string | undefined;
readonly state: "connected" | "disconnected";
send(bytes: Uint8Array): void;
sendMessage(msg: MidiMessage): void;
}
/**
* Returns a typed output handle for the selected Web MIDI output, or
* `null` while access is loading / the selector misses. The handle's
* `sendMessage` encodes a `MidiMessage` via `encodeMessage` and
* forwards the resulting bytes to the underlying `MIDIOutput.send`;
* `send(bytes)` is the raw escape-hatch (typically used for SysEx
* pass-through).
*/
export function useMidiOutput(selector: PortSelector): MidiOutputHandle | null {
const ctx = useMidiContextOrThrow();
const stateVersion = ctx.stateVersion;
return useMemo<MidiOutputHandle | null>(() => {
void stateVersion;
if (ctx.access === null) {
return null;
}
if (selector === "first") {
const next = ctx.access.outputs.values().next();
return next.done === true ? null : adaptOutput(next.value);
}
const target = ctx.access.outputs.get(selector);
return target === undefined ? null : adaptOutput(target);
}, [ctx.access, stateVersion, selector]);
}