Add README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 04:31:11 +00:00
parent 1b476d4336
commit 0f0d1ed361

93
README.md Normal file
View File

@@ -0,0 +1,93 @@
# midi-sequencer
A browser-based MIDI step sequencer with a C ALSA backend for accurate timing and a Node.js/Express web UI.
## Architecture
```
Browser (app.mjs)
↕ HTTP + SSE
Node server (server.mjs, port 3000)
↕ Unix socket (/tmp/midi-sequencer.sock)
C backend (midi-sequencer binary)
↕ ALSA sequencer API
MIDI output
```
- **`protocol.yaml`** — single source of truth for the binary protocol; drives codegen for both C and Node
- **`codegen/gen.mjs`** — generates `c-backend/generated/protocol.{h,c}` and `node-server/src/generated/protocol.mjs`
- **`c-backend/`** — C11, drift-free tick thread using `clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME)`, links libasound + libpthread
- **`node-server/`** — Express 5 web app, serves the UI and bridges the browser to the C backend
## Features
- **Multi-track playback** — up to 16 patterns playing simultaneously, each looping at its own independent length
- **Live track control** — add/remove patterns from the playing set without stopping; mute and solo per track
- **GM percussion editor** — channel 10 patterns show GM drum names in drum-machine layout with family colour coding
- **Auto-save** — step grid edits are sent to the backend immediately on each toggle
- **Preview notes** — per-row ▶ button auditions a note without affecting sequencer state
- **Click-to-rename** — note and percussion labels are editable inline
- **Sub-patterns** — patterns can reference other patterns as sub-sequences at any step
- **BPM** — tempo settable to 0.1 BPM resolution (stored as `bpm_x10` uint16, no floats in protocol)
## Protocol
Binary frames: `[record_type: u8][payload_length: u16le][payload…]`
| ID | Name | Direction | Description |
|---|---|---|---|
| 0x01 | HELLO | node→C | Version handshake |
| 0x02 | DEFINE_PATTERN | node→C | Create/redefine a pattern |
| 0x03 | CLEAR_PATTERN | node→C | Remove all notes from a pattern |
| 0x04 | ADD_NOTE | node→C | Add a note event at a step |
| 0x05 | ADD_SUB_PATTERN | node→C | Schedule a sub-pattern within a pattern |
| 0x06 | PLAY | node→C | Single-pattern play (backward compat) |
| 0x07 | STOP | node→C | Stop all playback |
| 0x08 | SET_TEMPO | node→C | Set BPM (as bpm×10) |
| 0x09 | PREVIEW_NOTE | node→C | Play a single note immediately |
| 0x0A | ADD_TRACK | node→C | Add a pattern to the multi-track set |
| 0x0B | REMOVE_TRACK | node→C | Remove a pattern from the multi-track set |
| 0x0C | PLAY_TRACKS | node→C | Start the multi-track engine |
| 0x0D | SET_TRACK_MUTE | node→C | Mute/unmute a track |
| 0x81 | ACK | C→node | Acknowledge a command |
| 0x82 | ERROR | C→node | Report an error |
| 0x83 | BEAT_TICK | C→node | Step notification (one per track per tick) |
| 0x84 | PATTERN_END | C→node | Pattern completed one full cycle |
## Build
Requires: GCC, make, libasound2-dev, Node.js ≥ 18
```sh
# Full build (codegen + npm install + C binary)
make
# C backend only
cd c-backend && make
# Run the Node server
cd node-server && make start
# → http://localhost:3000
```
The C backend runs separately and is started independently:
```sh
./c-backend/midi-sequencer [socket_path] [alsa_client_name]
# defaults: /tmp/midi-sequencer.sock midi-sequencer
```
## Usage
1. Start the C backend
2. Start the Node server (`make start` in `node-server/`)
3. Open `http://localhost:3000`
4. Create melodic or drum patterns with **+ Melodic** / **🥁 Drums**
5. Click the **●** dot next to each pattern to add it to the playback set
6. Press **▶ Play** to start — all active patterns loop independently
## Timing
One step = one 16th note. Step duration: `150,000,000,000 ns / bpm_x10`
At 120.0 BPM: 125 ms/step. The tick thread uses an absolute deadline so tempo drift does not accumulate.