diff --git a/src/components/SendSysex.tsx b/src/components/SendSysex.tsx index 314ec3a..4a17457 100644 --- a/src/components/SendSysex.tsx +++ b/src/components/SendSysex.tsx @@ -1,5 +1,5 @@ import { Dropdown } from "primereact/dropdown"; -import { useMidiAccess, useMidiPermission } from "../hooks/use_midi"; +import { useMidiPermission, useMidiPortNames } from "../hooks/use_midi"; import { Flex } from "./Flex"; import { FormEventHandler, useState } from "react"; import { Button } from "primereact/button"; @@ -15,31 +15,35 @@ export const SendSysex: React.FC<{ readonly waveform: Waveform }> = ({ waveform, }) => { const perm = useMidiPermission(); - const midi = useMidiAccess(); + const { midi, portNames } = useMidiPortNames(); - const [portId, setPortId] = useState(undefined); + const [portName, setPortName] = useState(undefined); const sendSysex: FormEventHandler = (e) => { e.preventDefault(); e.stopPropagation(); - if (!portId) throw new Error("You must select a port"); + if (!midi) throw new Error("MIDI is not ready"); - const port = midi?.outputs.get(portId); + if (!portName) throw new Error("You must select a port"); - if (!port) throw new Error(`Invalid port ${portId}`); + const port = [...midi.outputs.values()].find((o) => o.name === portName); + + if (!port) throw new Error(`Port not found ${portName}`); sendWaveformSysex(port, waveform); }; if (!perm) return Error: Permission unavailable; - if (!midi?.sysexEnabled) return Error: SysEx not enabled; - if (!midi) return Error: No MIDIAccess; - if (!portId && midi.outputs.size) { - setPortId([...midi.outputs.values()][0].id); + if (!midi.sysexEnabled) return Error: SysEx not enabled; + + if (!portName && midi.outputs.size) { + const first = [...midi.outputs.values()][0]; + + if (first.name) setPortName(first.name); } return ( @@ -58,15 +62,9 @@ export const SendSysex: React.FC<{ readonly waveform: Waveform }> = ({ {option?.name ?? placeholder}} - onChange={(e) => setPortId(e.value)} + options={portNames} + value={portName} + onChange={(e) => setPortName(e.value)} placeholder="MIDI Port" /> )} diff --git a/src/hooks/use_midi.ts b/src/hooks/use_midi.ts index e270ad4..7fea032 100644 --- a/src/hooks/use_midi.ts +++ b/src/hooks/use_midi.ts @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useMemo, useState } from "react"; export function useMidiPermission() { const [granted, setGranted] = useState( @@ -20,17 +20,31 @@ export function useMidiPermission() { return granted; } -export function useMidiAccess() { +function useMidiAccess() { const [midi, setMidi] = useState(undefined); - (async () => { - try { - const midiAccess = await navigator.requestMIDIAccess({ sysex: true }); - setMidi(midiAccess); - } catch (e) { - console.error(`Failed to get MIDI access`, e); - } - })(); + useEffect(() => { + (async () => { + try { + const midiAccess = await navigator.requestMIDIAccess({ sysex: true }); + setMidi(midiAccess); + } catch (e) { + console.error(`Failed to get MIDI access`, e); + } + })(); + }, []); return midi; } + +export function useMidiPortNames() { + const midi = useMidiAccess(); + + const portNames = useMemo(() => { + if (!midi) return []; + + return [...midi.outputs.values()].map((o) => o.name); + }, [midi]); + + return { midi, portNames }; +}