Signatur
Beschreibung
Mit send() schickt man MIDI-Daten an einen Ausgangsport, zum Beispiel an einen Hardware-Synthesizer, eine DAW über einen virtuellen Port oder einen Controller mit LED-Rückmeldung. Die Daten werden als Folge von Bytes übergeben, etwa [0x90, 60, 127] für „Note On, Kanal 1, mittleres C, volle Anschlagstärke“.
Das Array muss aus vollständigen und gültigen MIDI-Nachrichten bestehen. Man kann mehrere Nachrichten hintereinander in ein Array packen. Running Status (also das Weglassen wiederholter Statusbytes) ist nicht erlaubt. System-Exclusive-Nachrichten (0xF0 … 0xF7) gehen nur, wenn der Zugriff mit navigator.requestMIDIAccess({ sysex: true }) angefordert wurde.
Mit dem optionalen Parameter timestamp legt man fest, wann die Nachricht gesendet wird. Der Wert ist ein DOMHighResTimeStamp auf derselben Zeitbasis wie performance.now(). So lassen sich Noten genau takten, ohne dass Timer im JavaScript-Hauptthread schwanken. Fehlt der Parameter oder liegt der Zeitpunkt in der Vergangenheit, wird die Nachricht sofort gesendet.
Ist der Port noch nicht offen, öffnet send() ihn automatisch. Wurde der Port geschlossen oder ist das Gerät getrennt, wird ein Fehler ausgelöst.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $data Pflicht | number[] | Uint8Array | Folge von Datenbytes (0–255), die eine oder mehrere vollständige MIDI-Nachrichten bilden. Statusbytes ≥ 0x80, Datenbytes 0–127. |
|
| $timestamp | DOMHighResTimeStamp (number) | 0 (sofort) | Zeitpunkt in Millisekunden relativ zu performance.timeOrigin, also auf derselben Zeitbasis wie performance.now(), zu dem gesendet werden soll. 0 oder ein Wert in der Vergangenheit bedeutet: sofort senden. |
Rückgabewert
TypeError ausgelöst, bei SysEx ohne Berechtigung ein InvalidAccessError, bei getrenntem Port ein InvalidStateError.Beispiele
Note sofort an- und nach 500 ms per Zeitstempel ausschalten
const playNote = async () => {
const access = await navigator.requestMIDIAccess();
const output = [...access.outputs.values()][0];
if (!output) {
console.log('Kein MIDI-Ausgang gefunden');
return;
}
// Note On: Kanal 1, mittleres C (60), Anschlagstärke 100
output.send([0x90, 60, 100]);
// Note Off genau 500 ms später, vom Browser getaktet
output.send([0x80, 60, 0], performance.now() + 500);
console.log(`Note gesendet an: ${output.name}`);
};
playNote();
Akkord und Programmwechsel mit einem einzigen Aufruf
const sendChord = (output, channel = 0) => {
const noteOn = 0x90 | channel;
// Mehrere vollständige Nachrichten in einem Array (kein Running Status!)
output.send([
0xC0 | channel, 5, // Programmwechsel auf Klang 6
noteOn, 60, 90, // C
noteOn, 64, 90, // E
noteOn, 67, 90 // G
]);
};
const access = await navigator.requestMIDIAccess();
const output = access.outputs.values().next().value;
if (output) sendChord(output);
Genau getaktete Tonfolge (Sequenzer)
const playSequence = (output, notes, bpm = 120) => {
const beatMs = 60000 / bpm;
const start = performance.now() + 100; // kleiner Vorlauf
notes.forEach((note, i) => {
const t = start + i * beatMs;
output.send([0x90, note, 100], t);
output.send([0x80, note, 0], t + beatMs * 0.9);
});
};
const access = await navigator.requestMIDIAccess();
const output = access.outputs.values().next().value;
if (output) playSequence(output, [60, 62, 64, 65, 67]);
SysEx-Nachricht senden (Berechtigung nötig)
try {
const access = await navigator.requestMIDIAccess({ sysex: true });
const output = access.outputs.values().next().value;
// Universal Identity Request
output?.send(new Uint8Array([0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7]));
console.log('Identity Request gesendet');
} catch (err) {
console.error('SysEx nicht erlaubt:', err.name);
}
// Wichtig · Fallstricke
- Browser-Unterstützung: Chrome, Edge und Opera unterstützen die Web MIDI API schon lange, Firefox ab Version 108 (mit Berechtigungsabfrage bzw. Site-Permission-Add-on). Safari unterstützt sie nicht. Vor der Nutzung prüfen:
'requestMIDIAccess' in navigator. - Nur in einem sicheren Kontext (HTTPS oder localhost) verfügbar. Der Browser fragt meist nach einer Berechtigung, bei
sysex: trueimmer. - Kein Running Status: Jede Nachricht braucht ihr eigenes Statusbyte, sonst gibt es einen
TypeError. Datenbytes über 127 sind ebenfalls ungültig. - Nachrichten mit Zeitstempel landen in einer internen Warteschlange. Mit
MIDIOutput.clear()lässt sich diese leeren (noch nicht überall umgesetzt). Wer beim Stoppen hängende Noten vermeiden will, sendet zusätzlich „All Notes Off“ ([0xB0, 123, 0]). - Sehr große SysEx-Datenmengen oder eine sehr hohe Nachrichtenrate können einen Engpass verursachen, weil die MIDI-Übertragung auf 31,25 kbit/s begrenzt ist.
- Der Zeitstempel muss auf der Zeitbasis von
performance.now()liegen, nicht auf der vonDate.now().