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 (
0x00prefix signals the extended form). - Looks up the manufacturer name from the registry; returns it on
SysExFrame.manufacturerNamewhen 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 betweenF0andF7. ThrowsMidiError("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.