# `midi-contract/midi-message` ## Purpose Defines the local mirror of the `@suaveplan/midi` `MidiMessage` discriminated union plus its peer types (`Channel`, `MidiPortLike`, `NRPNChange`, `RPNChange`, `CC14Change`, `Unsubscribe`). This file exists so `@suaveplan/react-midi` can be developed and tested on its own branch while `@suaveplan/midi` is being authored in parallel on `feat/midi`. Once both branches land, the type aliases here SHALL be replaced by a re-export from `@suaveplan/midi`; no shape change is intended at swap time. ## Features - Channel-voice variants: `noteOn`, `noteOff`, `polyAftertouch`, `controlChange`, `programChange`, `channelPressure`, `pitchBend`. - System variants: `sysEx`, `clock`, `start`, `continue`, `stop`, `activeSensing`, `systemReset`. - High-resolution reducer events: `NRPNChange`, `RPNChange`, `CC14Change`. - Structural `MidiPortLike` interface compatible with any transport. ## Usage: Basic ```ts import type { MidiMessage } from "@suaveplan/react-midi/midi-contract"; function isNote(msg: MidiMessage): boolean { return msg.type === "noteOn" || msg.type === "noteOff"; } ``` ## Usage: Advanced ```ts import type { MidiPortLike } from "@suaveplan/react-midi/midi-contract"; class FakePort implements MidiPortLike { readonly id = "fake-1"; readonly name = "Fake In"; readonly state = "connected" as const; private subs = new Set<(m: MidiMessage) => void>(); send(_: Uint8Array): void {} onMessage(handler: (m: MidiMessage) => void) { this.subs.add(handler); return () => this.subs.delete(handler); } } ``` ## API Reference - `Channel = 0..15` literal union. - `MidiMessage` discriminated union — see Features. - `MidiMessageType = MidiMessage["type"]`. - `MidiPortLike { id, name, manufacturer?, state, send, onMessage }`. - `NRPNChange`, `RPNChange`, `CC14Change` — reducer outputs. - `Unsubscribe = () => void`. ## Implementation Notes The file deliberately uses interface declarations (not type aliases) for variant shapes so each one can be discriminated in user code by hovering over the inferred type. The structural `MidiPortLike` mirrors the Web MIDI shape but adds a `manufacturer` field and a typed `onMessage` that yields parsed `MidiMessage` rather than raw bytes — that lift is performed inside `port/web-midi-port.ts`.