Start · Sprachen · JavaScript · Referenz · MIDIOutput

MIDIOutput

Schnittstelle

Steht für einen MIDI-Ausgang und schickt mit <code>send()</code> MIDI-Nachrichten an ein angeschlossenes Gerät. <code>clear()</code> leert die Warteschlange noch nicht gesendeter Nachrichten.

seit JavaScript Web MIDI API — Chromium-Browser (Chrome/Edge/Opera Kategorie: webapi

Signatur

interface MIDIOutput extends MIDIPort

Beschreibung

MIDIOutput gehört zur Web MIDI API und steht für einen einzelnen MIDI-Ausgang, etwa einen Hardware-Synthesizer, ein USB-MIDI-Interface oder einen virtuellen MIDI-Port des Betriebssystems. Selbst erzeugen kann man solche Objekte nicht. Man bekommt sie über die Map MIDIAccess.outputs, nachdem navigator.requestMIDIAccess() erfolgreich war.

Das Interface erbt von MIDIPort und damit auch von EventTarget. Deshalb gibt es alle Port-Eigenschaften wie id, name, manufacturer, state und connection, außerdem die Methoden open() und close() und das Event statechange. Dazu kommen zwei eigene Methoden:

  • send(data, timestamp) stellt eine MIDI-Nachricht (ein Byte-Array) in die Warteschlange. Sie wird sofort gesendet oder zu einem bestimmten Zeitpunkt auf der Zeitachse von performance.now().
  • clear() verwirft alle Nachrichten, die in der Warteschlange stehen und noch nicht gesendet wurden. Diese Methode ist nicht in allen Browsern umgesetzt.

Typische Einsatzfälle sind Web-Sequencer, Editoren für Synthesizer-Patches, Lichtsteuerung per MIDI, Lernanwendungen und das Senden von SysEx-Nachrichten (System Exclusive) an Hardware. Weil man Nachrichten mit einem Zeitstempel einplanen kann, lassen sich Noten sehr genau timen, ohne dass setTimeout ungenau wird.

Parameter

Name Typ Default Beschreibung
$data Pflicht Array<number> | Uint8Array Parameter von send(): eine vollständige MIDI-Nachricht als Folge von Bytes (0–255), z. B. [0x90, 60, 127] für Note-On. Ist die Nachricht ungültig, wird ein TypeError geworfen.
$timestamp DOMHighResTimeStamp (number) 0 (sofort senden) Parameter von send(): Zeitpunkt in Millisekunden auf der Zeitachse von performance.now(), zu dem die Nachricht gesendet werden soll. Liegt der Wert in der Vergangenheit oder ist er 0, wird sofort gesendet.

Rückgabewert

Typ
void
Beschreibung
send() und clear() geben undefined zurück. Ein Fehler wird als Ausnahme geworfen: InvalidStateError, wenn der Port getrennt ist, InvalidAccessError bei SysEx ohne Berechtigung und TypeError bei ungültigen Daten.

Beispiele

Ausgänge auflisten und einen Ton spielen

const spieleTon = async () => {
  const midi = await navigator.requestMIDIAccess();

  for (const output of midi.outputs.values()) {
    console.log(`${output.name} (${output.manufacturer}) – ${output.state}`);
  }

  const [output] = midi.outputs.values();
  if (!output) {
    console.warn('Kein MIDI-Ausgang gefunden');
    return;
  }

  // Note-On: Kanal 1, mittleres C (60), Anschlagstärke 100
  output.send([0x90, 60, 100]);
  // Note-Off 500 ms später, zeitgenau geplant
  output.send([0x80, 60, 0], performance.now() + 500);
};

document.querySelector('#play').addEventListener('click', spieleTon);
Mein Synth (Roland) – connected

Akkordfolge zeitgenau planen und abbrechen

const planeAkkorde = (output, bpm = 120) => {
  const schlag = 60000 / bpm;
  const akkorde = [[60, 64, 67], [57, 60, 64], [65, 69, 72], [67, 71, 74]];
  const start = performance.now() + 100;

  akkorde.forEach((akkord, i) => {
    const an = start + i * schlag;
    for (const note of akkord) {
      output.send([0x90, note, 90], an);
      output.send([0x80, note, 0], an + schlag * 0.9);
    }
  });
};

const stopp = (output) => {
  // Geplante Nachrichten verwerfen (sofern unterstützt)
  if (typeof output.clear === 'function') output.clear();
  // All Notes Off (CC 123) auf allen 16 Kanälen
  for (let ch = 0; ch < 16; ch++) {
    output.send([0xB0 | ch, 123, 0]);
  }
};

SysEx-Nachricht senden (mit Berechtigung)

const sendeSysEx = async () => {
  try {
    const midi = await navigator.requestMIDIAccess({ sysex: true });
    const output = [...midi.outputs.values()].find((o) => o.name.includes('Synth'));
    if (!output) throw new Error('Gerät nicht gefunden');

    await output.open();
    // Universal Identity Request
    output.send(new Uint8Array([0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7]));
    console.log('Identity Request gesendet an', output.name);
  } catch (err) {
    console.error('MIDI-Fehler:', err.name, err.message);
  }
};

sendeSysEx();
Identity Request gesendet an Mein Synth

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chrome, Edge und Opera unterstützen die API, Firefox erst ab Version 108 und dort mit einer Abfrage bzw. per Website-Berechtigungs-Add-on. Safari unterstützt die Web MIDI API nicht. Vor der Nutzung sollte man prüfen, ob sie vorhanden ist: 'requestMIDIAccess' in navigator.
  • Sicherer Kontext und Berechtigung: Die API funktioniert nur über HTTPS bzw. localhost. Der Browser fragt den Nutzer um Erlaubnis. SysEx braucht { sysex: true }, weil man damit die Firmware eines Geräts verändern kann. Ohne diese Freigabe wirft send() bei SysEx einen InvalidAccessError. Außerdem kann eine Permissions-Policy (midi) den Zugriff in iframes sperren.
  • clear(): Die Methode ist in Chromium lange Zeit nicht umgesetzt worden. Vor dem Aufruf sollte man daher prüfen, ob es sie gibt. Hängende Noten lassen sich zuverlässig mit „All Notes Off“ (CC 123) oder mit einzelnen Note-Off-Nachrichten beenden.
  • Zeitstempel: Der Zeitstempel bezieht sich auf performance.now() und nicht auf Date.now() und auch nicht auf AudioContext.currentTime (Sekunden). Wer MIDI und Web Audio synchronisieren will, muss die Zeitwerte umrechnen.
  • Laufender Status (Running Status) ist nicht erlaubt: Jede Nachricht muss ein vollständiges Statusbyte haben. Die Bytes einer SysEx-Nachricht müssen mit 0xF0 beginnen und mit 0xF7 enden.
  • Ist der Port noch geschlossen, öffnet send() ihn automatisch. Ist das Gerät getrennt (state === 'disconnected'), wird ein InvalidStateError geworfen.