first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
# `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`.