Start · Sprachen · JavaScript · Referenz · MIDIAccess: statechange

MIDIAccess: statechange

Ereignis

Wird auf <code>MIDIAccess</code> ausgelöst, wenn ein MIDI-Port hinzukommt, entfernt wird oder seinen Status (<code>state</code>/<code>connection</code>) ändert.

seit JavaScript Chrome 43+, Edge 79+, Firefox 108+, Opera 30+; Saf Kategorie: webapi

Signatur

midiAccess.addEventListener("statechange", handler)

Beschreibung

Das Ereignis statechange des MIDIAccess-Objekts feuert immer dann, wenn sich an einem MIDI-Port etwas ändert: Ein Gerät wird angeschlossen oder abgezogen, oder ein Port wechselt zwischen den connection-Zuständen "open", "closed" und "pending". Der Handler bekommt ein MIDIConnectionEvent, dessen Eigenschaft port auf den betroffenen MIDIInput bzw. MIDIOutput verweist.

Einsatzgebiet sind vor allem Hot-Plug-Szenarien: Web-Synthesizer, DAWs im Browser oder Controller-Editoren sollen ihre Geräteliste aktuell halten und neu angeschlossene Keyboards automatisch verbinden, ohne dass jemand die Seite neu laden muss. Registrieren lässt sich der Handler per addEventListener("statechange", handler) oder über die Eigenschaft midiAccess.onstatechange.

Wichtig: Das Ereignis feuert zusätzlich auch auf dem einzelnen MIDIPort, und zwar dort vor dem MIDIAccess. Auf MIDIAccess hört man, wenn man alle Ports zentral überwachen will. Ein bestimmtes Gerät beobachtet man besser direkt am Port.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Ereignistyp, hier immer "statechange".
$handler Pflicht (event: MIDIConnectionEvent) => void Callback, der ein MIDIConnectionEvent bekommt. event.port ist der betroffene MIDIPort mit den Eigenschaften id, name, manufacturer, type ("input"/"output"), state ("connected"/"disconnected") und connection.
$options boolean | AddEventListenerOptions false Übliche Listener-Optionen wie once oder signal (z. B. ein AbortSignal, um den Listener später zu entfernen).

Beispiele

An- und Abstecken von Geräten protokollieren

const access = await navigator.requestMIDIAccess();

access.addEventListener("statechange", (event) => {
  const { port } = event;
  console.log(`${port.type} "${port.name}" (${port.manufacturer}): ${port.state}, ${port.connection}`);
});
input "Launchkey Mini" (Novation): connected, closed input "Launchkey Mini" (Novation): disconnected, closed

Neue Eingänge automatisch verbinden (Hot-Plug)

const handleMessage = (msg) => {
  const [status, note, velocity] = msg.data;
  if ((status & 0xf0) === 0x90 && velocity > 0) {
    console.log(`Note an: ${note}, Anschlagstärke ${velocity}`);
  }
};

const access = await navigator.requestMIDIAccess();

// bereits vorhandene Eingänge verbinden
access.inputs.forEach((input) => { input.onmidimessage = handleMessage; });

// später angeschlossene Eingänge ebenfalls verbinden
access.onstatechange = ({ port }) => {
  if (port.type === "input" && port.state === "connected" && !port.onmidimessage) {
    port.onmidimessage = handleMessage; // öffnet den Port implizit
  }
};
Note an: 60, Anschlagstärke 100

Geräteliste in der UI aktuell halten und Listener entfernen

const controller = new AbortController();
const access = await navigator.requestMIDIAccess();

const renderDevices = () => {
  const names = [...access.inputs.values()]
    .filter((p) => p.state === "connected")
    .map((p) => p.name);
  document.querySelector("#devices").textContent = names.join(", ") || "Keine Geräte";
};

renderDevices();
access.addEventListener("statechange", renderDevices, { signal: controller.signal });

// Überwachung beenden, z. B. beim Verlassen der Ansicht
document.querySelector("#stop").addEventListener("click", () => controller.abort());

// Wichtig · Fallstricke

  • Mehrfache Ereignisse: Ein einziges An- oder Abstecken kann mehrere statechange-Ereignisse auslösen, etwa einmal für die state-Änderung und einmal für die connection-Änderung beim Öffnen des Ports. Außerdem hat ein Gerät oft einen Eingang und einen Ausgang. Handler sollten deshalb idempotent sein, also z. B. prüfen, ob schon ein onmidimessage gesetzt ist.
  • Nicht nur neue Geräte: Das Ereignis feuert auch, wenn eine Seite selbst einen Port per open()/close() öffnet oder schließt. Setzt man onmidimessage, öffnet das den Port implizit und löst dadurch ebenfalls ein Ereignis aus.
  • Abgezogene Geräte bleiben mit state === "disconnected" in den Maps inputs/outputs sichtbar, solange sie offen waren. Beim Rendern also nach state filtern.
  • Sichere Umgebung und Berechtigung: Web MIDI gibt es nur in sicheren Kontexten (HTTPS). requestMIDIAccess() fragt die Nutzerin oder den Nutzer um Erlaubnis. Mit { sysex: true } ist die Freigabe strenger, und die Permissions-Policy midi kann den Zugriff in iframes sperren.
  • Browser-Kompatibilität: Unterstützt von Chromium-Browsern und Firefox ab Version 108 (dort nur mit Site-Permission-Add-on). Safari unterstützt Web MIDI nicht. Vorher mit "requestMIDIAccess" in navigator prüfen.