Files
2026-05-27 23:47:53 +01:00

3.0 KiB

sysex/sysex

(no submodules)

Purpose

parseSysEx and buildSysEx are the canonical helpers for working with MIDI System Exclusive payloads — the manufacturer-defined byte streams that sit between an F0 prefix and an F7 terminator. Every vendor uses SysEx for patch dumps, parameter sysex, MMC (MIDI Machine Control), and identity-request handshakes; standardising the parse / build code in one place prevents off-by-one errors with the one-byte vs three-byte manufacturer-id forms.

parseSysEx expects the body of the frame (i.e. everything between F0 and F7, exclusive of both endpoints). buildSysEx produces a complete F0...F7 frame; callers feed the result straight to MidiPortLike.send.

Features

  • Auto-detects one-byte vs three-byte manufacturer ids (0x00 prefix signals the extended form).
  • Looks up the manufacturer name from the registry; returns it on SysExFrame.manufacturerName when known.
  • Validates that every byte in the manufacturer id, device id, and body has bit 7 clear — surfaces wire corruption instead of silently masking.
  • Rejects short payloads and missing device-id bytes loudly.

Usage: Basic

import { buildSysEx, parseSysEx } from "@suaveplan/midi";

const frame = buildSysEx([0x43], 0x10, [0x4c, 0x00]);
// Uint8Array(6) [0xF0, 0x43, 0x10, 0x4C, 0x00, 0xF7]

const parsed = parseSysEx(frame.slice(1, -1));
// parsed.manufacturer = [0x43], parsed.manufacturerName = "Yamaha"

Usage: Advanced

import { buildSysEx, MANUFACTURERS, parseSysEx } from "@suaveplan/midi";

// Build a Native Instruments device-identity request.
const ni = MANUFACTURERS.NATIVE_INSTRUMENTS.id;
const req = buildSysEx(ni, 0x00, [0x01, 0x00]);
await outputPort.send(req);

// Wait for the device's response and parse it.
const responseBytes = await readNextSysEx(outputPort);
const response = parseSysEx(responseBytes);
console.log(response.manufacturerName, response.body);

API Reference

  • parseSysEx(payload: Uint8Array): SysExFrame — parses the body between F0 and F7. Throws MidiError("MIDI.INVALID_SYSEX") for short, malformed, or extended-id-truncated payloads.
  • buildSysEx(manufacturer: ManufacturerId, deviceId: number, body: Uint8Array | readonly number[]): Uint8Array — produces a full F0/F7-framed byte sequence; throws on high-bit-set inputs.
  • SysExFrame { manufacturer; manufacturerName?; deviceId; body } — the parsed shape.

Implementation Notes

The build path walks the input three times: once for manufacturer validation, once for body validation, once for the final write. The cost is three pure-numeric loops over typically very short arrays (manufacturer ids are 1 or 3 bytes; bodies are usually <64 bytes for parameter messages), so the constant is negligible compared to the IO that follows. Parse uses Uint8Array.slice to detach the body from the input buffer — callers that mutate the source buffer afterwards do not affect already-parsed frames.