Skip to content
wgpatrickPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

dotbeat

A git-native, agent-native DAW. Your song is a diff-friendly text file you — and an AI agent — can edit in a real GUI, render from the command line, git diff, and get sound-design critique on.

Solo project, built in paired sessions with Claude. The .beat text format is the product: a real GUI (dotbeat's own, not a wrapped teaching tool), a CLI (beat), and an MCP server for AI agents all edit the same file, and every edit is a one- or two-line git diff — not a binary blob you hope merges.

npm install
npm test                          # 1,426 tests: format, conversion, daemon sync, CLI surface, vary/humanize, DSP metrics, MCP parity
node cli/beat.mjs init song.beat --bpm 124 && node cli/beat.mjs add-track song.beat drums drums
node cli/beat.mjs inspect examples/real-groove.beat
node cli/beat.mjs set examples/real-groove.beat bass.cutoff 900   # prints "bass: cutoff 700 -> 900"
node cli/beat.mjs quantize examples/real-groove.beat bass --grid 1 --amount 0.6   # partial-strength snap to 16ths
node cli/beat.mjs vary examples/real-groove.beat drums kick --render             # small-diff variants to audition...
node cli/beat.mjs score vary-kick-42 3 7 1                        # ...ranked picks -> git-tracked taste log
node cli/beat.mjs diff --git HEAD~1 HEAD song.beat                # a musical edit list, not line noise
node cli/beat.mjs render examples/real-groove.beat -o out.wav     # dotbeat's own engine, headless
node cli/beat.mjs metrics out.wav                                 # LUFS (BS.1770), true peak, crest, spectrum, stereo
node cli/beat.mjs checkpoint song.beat --label "rough mix"        # a restorable version, git-backed
node cli/beat.mjs macro apply song.beat bass space 50              # a knob that resolves to real literal edits, no indirection
node cli/beat.mjs mcp                                             # the whole toolchain as MCP tools for an AI agent
node cli/beat.mjs daemon examples/real-groove.beat                # two-way sync backend for the GUI

cd ui && npm install && npm run dev   # dotbeat's own frontend (Vite + React), talks to the daemon above

Everything above runs with zero Python. The ML-backed commands shell out to a fleet of eight Python sidecars (beat/downbeat detection, text-to-audio generation, Surge XT patch rendering, roughness curves, audio embeddings, MIDI figure extraction, Demucs stem extraction, Composer's Assistant 2 — the full table is in python/README.md); all of them share one spawn/doctor contract and degrade to actionable errors, and CI runs green with zero Python via stub backends. The two you need first — beat analyze (real beat/downbeat detection) and beat source gen (text-to-audio one-shots: Stable Audio Open locally, or hosted on fal.ai with --backend fal, where a provider adapter table also covers Stable Audio 2.5/3, Lyria 2, MiniMax Music, and ElevenLabs Music, plus BPM-aware downbeat trimming and per-role stem extraction) — need a Python 3.10 venv at python/.venv and, for local generation, a Hugging Face login + accepting the gated model license at stabilityai/stable-audio-open-1.0:

brew install [email protected] && /opt/homebrew/bin/python3.10 -m venv python/.venv
python/.venv/bin/pip install -r python/requirements-beatthis.txt -r python/requirements-stableaudio.txt
python/.venv/bin/hf auth login                     # token from huggingface.co/settings/tokens
node cli/beat.mjs analyze --doctor && node cli/beat.mjs source gen --doctor   # both should report ok

Step-by-step details (why 3.10, what each pinned dep fixes): python/README.md. For what this unlocks, see examples/recipe-song/ — a complete track in which every audio asset was generated by beat source gen: one bell one-shot pitch-mapped into a melody across six declared drum lanes, a found-sound kit whose snare was picked from three seed candidates by measured spectral centroid, and a pad repitched into key with a one-token audio-clip edit. Each media/*.wav carries a provenance sidecar recording prompt/seed/model, and regenerating from those fields reproduces the registered file byte-for-byte (sha256-verified) — the .beat file is literally a recipe.

Run node cli/beat.mjs with no arguments for the full command list — it's grown a lot (track groups, drum kits, audio-clip splitting, effect chains, checkpoint/restore/pin history, selection sync with the GUI, production tricks, per-section mix feedback, blind source showdowns, the beat board review surface) since the walkthrough above.

The idea in one picture

   song.beat  (plain text, in git)
      │
      ├─►  GUI            edit notes/knobs/arrangement → one-line diffs
      ├─►  CLI            beat render / inspect / set / diff / vary / checkpoint
      ├─►  AI agent        edits the file, renders, critiques, proposes diffs (MCP)
      └─►  git             branch, diff, merge, review — like code

Nobody currently holds all of GUI + diff-friendly-text-file + CLI/agent at once — openDAW has the GUI and a headless engine but zips its projects into an opaque binary bundle; REAPER has genuinely text project files but even its own practitioners say git "cannot meaningfully diff or merge" them; Ableton's .als is gzipped XML with no native diff story at all; Strudel/Tidal are text-native but have no GUI. This project aims at that gap. See ROADMAP.md for the full thesis and prior-art comparison.

What's here

Path What
docs/product-roadmap.md Start here for what's built. Every tracked feature (375 and counting), each rated done/in-progress/not-started across the core format, CLI/MCP, and GUI layers — the live source of truth, not a snapshot.
ROADMAP.md Start here for the big picture. Thesis, format design, architecture, prior-art comparison, research provenance.
src/core/ The .beat format: types, parser, serializer, converter, semantic diff, edit primitives (quantize/humanize/transpose/fit-to-scale/groove/…), inspect. Pure TS, no GUI deps.
src/daemon/ The beat daemon — owns a .beat file, two-way sync with the GUI over HTTP/SSE, echo suppression by canonical-text comparison.
src/history/ Checkpoint/restore/pin — a git-backed, append-only version history (beat checkpoint/history/restore/pin).
src/metrics/ The guardrail layer: integrated LUFS (ITU-R BS.1770), true peak, crest, spectral balance, stereo field, deterministic mix-lint rules, per-section energy-arc profiles, a pathology-screen suite (clicks, silence, arrangement flatness, ring), and a Daniel–Weber roughness ear (Python sidecar).
src/vary/ The variation-and-taste loop: beat vary generates small-diff variants, beat score records ranked picks, beat suggest proposes the next round from that history — all batches flow through one runVaryBatch orchestrator shared by CLI and MCP.
src/analysis/ The ML-sidecar and production layer: beat/downbeat detection, text-to-audio generation (local + hosted provider adapters), Demucs stems, Surge XT rendering, pitch detection, produced-defaults profiles, the beat trick catalog. TS owns caching/hashing/contracts; Python stays tiny (see python/README.md).
src/taste/ The taste-model program: blind source showdowns (beat showdown), figure sources (archetype bank / theory composer / commercial MIDI / Composer's Assistant 2), production-task evals (beat prodtask), the DSP+Aesthetics ranker behind beat suggest --taste, and the overnight critic-guided pilot (beat pilot).
src/mcp/ beat mcp — zero-dep stdio MCP server exposing the toolchain to AI agents (71 tools, golden-snapshot + CLI↔MCP parity tested).
src/telemetry/ Opt-in edit telemetry: one append-only JSONL of every document edit across GUI/CLI/MCP (off by default, lives outside the project repo).
ui/ dotbeat's own GUI (Vite + React + Tone.js) — arrangement view, piano-roll/drum-lane clip editing, mixer, effects chain, content browser. Its own product design, not a wrapped teaching app (see docs/decisions.md D12).
desktop/ Tauri desktop shell — early-stage, working toward a native Mac app (docs/product-spec-desktop.md).
cli/beat.mjs The unified beat CLI — run with no args for the full, current command list.
test/ 1,426 tests — format round-trips, conversion fidelity, daemon sync + undo, a CLI surface test (help↔dispatch integrity, unknown-flag rejection), DSP metrics vs known-answer signals, MCP protocol + CLI↔MCP parity, vary/humanize/groove determinism, frozen-eval-constant guards.
presets/ Factory sound + drum-kit libraries — curated voicings applied as ordinary edits, never referenced by the format itself.
ui/verify-*.mjs Measured, Playwright-driven proofs against the real running app — not mocked assertions. Now registered in ui/verify-manifest.mjs and runnable as a suite: npm run verify (and a verify:engine tier for audio-engine gates).
examples/ Real projects as .beat text, incl. a multi-track song with full arrangement/automation (night-shift-song.beat).
docs/research/ 130 research passes — landscape/prior-art, engine architecture, three full passes against Ableton Live's own reference manual (feature-by-feature 50-69, implementation-level UI/UX 70-74, round-2 live re-verification 75-79), the taste/production program's eval arcs (107-129), a six-stream codebase review synthesis (130), and thirty-three exploratory usability pilots (80-113 and 129, see docs/usability-testing.md) — an agent driving the real app (or, for the CLI/MCP variant, its own command output) with no pre-scripted checklist, reacting like a human tester. Covers realistic musical workflows, focused GUI audits, following real published Ableton tutorials step by step in dotbeat instead of Ableton, and — the newest variant — testing the beat CLI and MCP tool surface directly, no GUI at all, since that's dramatically cheaper (~4 minutes per pilot vs. 15-50+ for a GUI one) and tests dotbeat's actual agent-native thesis.
docs/decisions.md 29 numbered design decisions (D1-D29) with rationale and "revisit when" — check before proposing something that might contradict one.
docs/usability-testing.md The exploratory usability-pilot methodology — no checklist, an agent reads its own screenshots (or, for the CLI/MCP variant, every command's real output) and reacts like a human tester. A standing practice, run alongside ui/verify-*.mjs's scripted assertions whenever GUI-facing behavior changes — and, since CLI/MCP pilots run in minutes rather than tens of minutes, whenever a beat subcommand or MCP tool changes too.
docs/format-spec.md The .beat format grammar.
docs/architecture.md Component architecture (daemon, engine, CLI, MCP, GUI/desktop tiers).

Status

The core loop this project was built to prove works and is exercised daily: a hand-inspectable .beat file is the source of truth for a live GUI session, a CLI, and an AI agent, all at once — turn a knob in the GUI and git diff shows exactly one changed line; edit the file by hand and the GUI hot-reloads without stopping playback.

Built and stable (177 of 375 tracked features done, 9 more in progress — the live list is docs/product-roadmap.md):

  • The format and edit surface — round-trip parser/serializer, semantic diff, edit primitives (quantize/humanize/transpose/groove/fit-to-scale), track groups, drum kits, audio clips with splitting, curved automation, and macros that resolve to real literal edits.
  • dotbeat's own GUI — arrangement view, piano-roll/drum-lane clip editing, mixer, device panel, content browser, in-session undo/redo alongside the git-backed checkpoint/restore history. Its design was shaped by three research passes against Ableton Live 12's own reference manual and hardened by ~30 exploratory usability pilots.
  • CLI/MCP parity — 71 MCP tools mirror the project-editing toolchain for AI agents, with per-command --help. Parity is increasingly structural rather than reviewed-in: a tools/list golden snapshot, a table-driven CLI↔MCP byte-parity test, a CLI surface test (help↔dispatch integrity, unknown-flag rejection), and shared orchestrators like runVaryBatch. The daemon, the human review surfaces (beat rate, beat board), and the owner-side taste/eval loop (showdown, prodtask, pilot, taste-*) stay deliberately CLI-only.
  • Render and guardrails — headless renders through dotbeat's one canonical engine (live-capture by default; --offline computes the same mix through an offline context, and batch renders default to offline where it's both exact and fast), BS.1770 LUFS / true-peak / spectral / stereo metrics, and beat lint mix critique against reference profiles derived from music the owner loves — now joined by per-section energy-arc feedback (beat feedback --sections, arc reference profiles), a calibrated pathology-screen suite (clicks, silence, arrangement flatness), and a psychoacoustic roughness ear. Clip automation renders truthfully — automation lanes win over static patch values (the research/121 stomp bug, fixed and golden-WAV-gated).
  • The agent↔owner loop — beat board (a non-blind picking UI over undecided batches, with a separate decisions log that never mixes with the blind scores log), beat open (deep-link the running GUI to a track/param), beat diff --since --rollup (the agent's morning read of what the owner changed), and opt-in edit telemetry across all three write surfaces (research/128, D29).
  • ML sidecars, contained — eight Python sidecars behind one shared spawn/doctor scaffold (src/analysis/spawn-sidecar.ts): beat analyze (Beat This beat/downbeat detection), beat source gen (Stable Audio Open locally; hosted providers via a fal.ai adapter table — Stable Audio 2.5/3, Lyria 2, MiniMax, ElevenLabs — with downbeat trimming and Demucs stem extraction), Surge XT patch rendering, roughness curves, Audiobox-Aesthetics embeddings (CLAP measured below chance and retired from the default), MIDI figure extraction, and Composer's Assistant 2. Python stays tiny and dumb; TypeScript owns caching/hashing/contracts; stub backends keep CI green with zero Python; owner-side tests cover the real-model paths CI structurally can't. The proof: examples/recipe-song/ regenerates every audio asset byte-for-byte from provenance sidecars.
  • The generative sampler — beat sample-info pitch detection, beat keymap minting a playable, diffable sampler instrument from any one-shot, and generation candidates flowing through the same score/adopt loop as everything else.

The active frontier: the taste-model program (docs/taste-loop-design.md) — teach a model the owner's musical taste from blind-rated batches, then let it steer search. The model is advisory by construction; the owner's picks stay the only ground truth. As of 2026-07-21, on 66 blind-rated batches (re-evaluated after fixing the CLAP fusion bug below): the DSP Bradley-Terry ranker predicts held-out picks at 33% top-1 / 62% pairwise (chance 21%/50%) — replicates the earlier 37-batch result; the four Audiobox-Aesthetics axes alone reach a similar 33% top-1 but a much stronger 81% pairwise on source-showdown batches specifically; DSP+Aesthetics combined is now the best scorer (36% top-1, 65% pairwise). CLAP embeddings, once correctly pooled, turned out to hurt rather than help — embed-bt scores below chance held-out, and adding CLAP to DSP makes the combined scorer worse than DSP alone (see docs/taste-loop-design.md "CLAP retired from the active ensemble" for the diagnosis). This doesn't touch the live beat suggest --taste tool, which was DSP-only already — it's an ablation-study-only finding. Batch renders are loudness-normalized by default so "louder" can't masquerade as "better." The data pipeline (taste-seeds → taste-collect → a blind web rating UI) was hardened by ear — six classes of silent no-op batches found and closed.

The generator question, decomposed by blind data (2026-07-21/22 eval arc — decisions D24-D27). beat showdown (blind per-role source comparisons, now 60+ rated batches) split the engine's deficit into two measured axes: production (width/air/motion — a production-only ablation moved the engine from 3% to 29% pairwise; the format had the DSP all along, nothing set it) and timbre (the T6 ceiling study: envelope solved, spectrum unreachable). The response, all built and blind-verified: produced defaults (src/analysis/produce.ts — gen-kit and taste-seeds ship with role-appropriate production), the beat trick catalog (15 named production moves with preconditions and measurable receipts — verified by ear via beat prodtask transform: tricked beat a random-edit control 90% vs 33% pairwise), Surge XT as an out-of-process sound factory (--with-surge; 639 factory patches; a surgepy channel-corruption bug was root-caused and fixed — upstream issue drafted), and commercial-MIDI figures (--midi-dir, private) that hold composition at commercial quality. Composition since grew two more figure sources that don't need private data: a theory composition layer (voice-leading chord generation + a motif-first lead generator with pre-render gross-error gates, --theory) and Composer's Assistant 2 (--ca2, composing over the chord track — the winner of the research/125 MIDI-model trials). Current standings with commercial figures: refs ~93% pairwise, gen 52% ≈ surge 50% ≈ keymap 45%, raw engine 0% — the chosen path (D26) is making engine/surge sound commercial, and the program's north star (D27) is the first blind batch where the owner genuinely ranks a dotbeat-rendered clip above the reference. T4 (beat suggest --taste) is live; the critic carries bootstrap-ensemble uncertainty (pessimistic scoring that auto-discounts its measured blind spots), and the first constrained T5 overnight pilot is built as beat pilot — critic-guided quality-diversity search over per-seed lineages, with beat board as the owner's morning review surface.

How it's kept honest. 1,426 tests plus a manifest-run Playwright verify fleet (npm run verify, with a verify:engine tier) assert known-correct behavior; exploratory usability pilots — an agent driving the real app or CLI with no checklist (docs/usability-testing.md) — keep finding what scripted suites structurally cannot, and their findings land as roadmap rows, never a second backlog. A six-stream codebase review (docs/research/130, 2026-07-25) turned "parity by review discipline" into structure: safety gates first (CLI surface test, MCP parity snapshot, committed engine golden WAVs, === guards on frozen eval constants), then the top-ranked extractions (one sidecar spawn scaffold, one seeded RNG, one figure vocabulary, one vary-batch orchestrator) and thousands of lines of dead code deleted. The phase-by-phase history that used to live in this section is in docs/ (phase plans, 130 research passes) and the git log.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages