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,72 @@
# `hooks/use-midi-messages`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`useMidiMessages(selector, options?)` exposes a bounded ring buffer of
the most recent parsed MIDI messages from the selected input. It is a
convenience built on top of `useMidiInput` for UI consumers that want
to render a live activity feed (e.g. an "incoming messages" panel) or
debug a controller wiring problem. The ring buffer trims the oldest
entry once `capacity` is exceeded, so the array length is stable and
the component can render it directly without further bookkeeping.
An optional `filter` whitelist accepts only specific message types
into the buffer — handy when a device floods the bus with active-
sensing or clock ticks the operator does not want in the visible log.
## Features
- Bounded ring buffer, default capacity 64.
- Optional `filter: readonly MidiMessageType[]` whitelist.
- Rebinds the underlying `port.onMessage` automatically when the
port identity changes (plug/unplug, selector switch).
- Buffer resets when the underlying port becomes `null`.
## Usage: Basic
```tsx
import { useMidiMessages } from "@suaveplan/react-midi";
function ActivityLog() {
const msgs = useMidiMessages("first", { capacity: 32 });
return (
<ul>
{msgs.map((m, i) => (
<li key={`${m.type}-${i}`}>{m.type}</li>
))}
</ul>
);
}
```
## Usage: Advanced
```tsx
function NotesOnly({ portId }: { portId: string }) {
// Drop active-sensing/clock noise.
const notes = useMidiMessages(portId, {
filter: ["noteOn", "noteOff"],
capacity: 128,
});
return <NoteRoll messages={notes} />;
}
```
## API Reference
- `useMidiMessages(selector, options?): readonly MidiMessage[]`
- `interface UseMidiMessagesOptions { capacity?, filter? }`.
## Implementation Notes
The internal state holds the ring buffer as a `readonly MidiMessage[]`
rather than a `Map` or a separate write-cursor so consumers can drop
straight into a `.map(...)` render. The buffer-replace path always
allocates a fresh array (rather than mutating in place) so React
detects the state change. The set-of-accepted-types is rebuilt only
when the `filter` reference or the joined key changes, not per
incoming message.