# ai-piano **Repository Path**: brt2/ai-piano ## Basic Information - **Project Name**: ai-piano - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-16 - **Last Updated**: 2026-10-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ai-piano A browser-first virtual piano with configurable keyboard layouts, MIDI score playback, recording, chords, and pluggable audio engines. The primary runtime is Flask + Waitress using POST commands and Server-Sent Events. The FastAPI/WebSocket adapter exposes the same HTTP application behavior and uses the same service and playback implementation; only the live event transport differs. ## Architecture ```text Browser / desktop client │ JSON commands and events ▼ Flask adapter (`server/server.py`) │ ▼ PianoService + AppContext ├── layout / notes / chord settings ├── score catalog and MIDI compiler └── PlaybackController state machine │ ▼ structured events ``` MIDI files are compiled once into canonical score notes containing `startMs`/`durationMs`. The server scheduler and staff UI consume the same timing model. ## Project Layout ```text run.py launcher server/ server.py Flask/SSE transport adapter and app factory asgi_app.py FastAPI/WebSocket adapter and app factory context.py complete dependency assembly + shared event bus service.py transport-independent commands and queries events.py structured in-process event hub playback.py playback clock, runner, and state machine score_model.py canonical score schema and timing compiler midi_loader.py Standard MIDI File parser notes.py / layout.py keyboard layout registry web/ templates/index.html static/js/app.js browser composition and event coordination static/js/recording.js local recording and draft lifecycle static/js/score-browser.js score selection and loading static/js/staff-view.js staff state and animation static/js/transport.js SSE/WebSocket adapter static/js/audio/ Synth, Sample, and SoundFont engines static/samples/piano/ optional MP3 samples clients/desktop/ optional pygame/pynput client tools/score_fetcher.py practice MIDI search and import CLI docs/ architecture, MIDI, and decision records ``` ## Practice Score Tool Search the verified MeowField catalog or import a local MIDI without coupling network access to the piano server: ```bash python tools/score_fetcher.py search '周杰伦 晴天' python tools/score_fetcher.py inspect meowfield: python tools/score_fetcher.py install meowfield: --transpose auto python tools/score_fetcher.py import ~/Downloads/song.mid python tools/score_fetcher.py list ``` The tool caches provider data under `runtime/score-fetcher/`, verifies size and SHA-256, parses the complete MIDI, reports active-layout coverage, and installs through a same-directory atomic rename. Existing score names are never overwritten; use `--rename` to keep another version. `--json` provides machine-readable output for future UI integration. ## Install and Run ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt python run.py --stack flask --flask-port 18123 ``` Open `http://localhost:18123/`. The primary requirements include Flask, Waitress, PyYAML, and mido. The FastAPI adapter is optional: ```bash pip install fastapi 'uvicorn[standard]' websockets python run.py --stack fastapi --fastapi-port 18124 ``` To use WebSocket transport explicitly, open `http://localhost:18124/?transport=ws&ws_host=localhost:18124`. ## Audio Engines The browser selects an engine through the `audio_engine` setting or the 音色 selector: - `synth` — default, resource-free Web Audio synthesis; works offline. - `sample` — loads the bundled MP3 piano samples. - `soundfont` — dynamically loads the configured WebAudioFont player and preset; automatically falls back to Synth if loading fails. All engines share a master gain, compressor, and light convolution reverb. Settings are stored in `~/.config/piano-settings.yaml` (or `$XDG_CONFIG_HOME/piano-settings.yaml`): ```yaml audio_engine: synth audio_master_gain: 0.62 audio_reverb_mix: 0.08 ``` SoundFont URLs and the preset variable name can also be overridden with `soundfont_player_url`, `soundfont_preset_url`, and `soundfont_preset_name`. ## HTTP API Key endpoints on the Flask stack: ```text GET /api/notes GET /api/layouts POST /api/layouts GET /api/scores GET /api/score/ GET /api/score-txt/ GET /api/settings POST /api/settings GET /api/health GET /api/stream POST /api/play ``` The FastAPI stack exposes the same HTTP API. Live events use `/api/stream` on Flask/SSE and `/ws` on FastAPI/WebSocket. Commands sent to `/api/play` include `play_note`, `play_key`, `play_score`, `pause_score`, `stop`. Playback events include a `playbackId` so clients can distinguish separate sessions. Each manual or automatic key activation is broadcast once as `performance_active`, containing the complete note/file list, effective chord or arpeggio mode, source, delay, and optional `echoId`. ## Verification ```bash python -m compileall run.py server clients/desktop python -m unittest discover -s tests -v node --check web/static/js/app.js curl http://localhost:18123/api/health ``` See [Architecture](docs/architecture.md), [MIDI specification](docs/midi-spec.md), and [Known limitations](docs/known-limitations.md) for implementation details.