No description
  • Rust 99.7%
  • Python 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jorrit 11cf5b4cb7 Docs: strict header and table forms for base's docs importer
One-time pass so base can import docs/ as a space:

- Intents: `> Stage: **intent**` as the first header line of all 88
  (`(blocked)` on open-decisions); Status kept. `> Area:` is exactly the
  folder; the commentary on 47 of them moved to a `> Touches:` line.
- Features: the Verified line is exactly
  ``> Verified against master @ `<sha>` on <date>.``; the extra text on 26
  of them (the `+ …` before `on`, the tails after the date, wrapped lines)
  moved to an `> Also verified:` line. No sha or date changed.
- intents/bugs.md ends with one `| Area | Bug | Where | Source |` table
  (3 rows, Bug = `BUG-<n>: <symptom>`); the empty per-section headings go.
- docs/README.md Areas: `Hardware IO` and `Plugins — instruments` slug to
  their folders; a Prototypes row for intents/prototypes/.
- 7 history files renamed to lowercase-hyphen (refactor/a-12-…, a-13-…,
  a-6-…, d-6-…; the three voicebank research notes), every reference in
  docs, code comments and plok-voicebank-index.json updated.
- Templates and CLAUDE.md describe the forms.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 20:08:54 +02:00
.cargo Optimized plugins for latency 2026-04-11 21:29:53 +02:00
cocoa-plugin-gui Merge dependency majors: midir 0.11 + cpal 0.17.3, pipewire 0.10, dirs 7, strum 0.28, phf 0.14, sha2 0.11, criterion 0.8, zip 9, opus 0.4, libloading 0.9, ort rc.14 2026-10-15 19:46:37 +02:00
docs Docs: strict header and table forms for base's docs importer 2026-10-17 20:08:54 +02:00
plugin-gui-core egui/egui_glow 0.34 -> 0.37: runtimes, plugin-gui-core, editor_widgets 2026-10-15 18:30:21 +02:00
plugins Merge dependency majors: midir 0.11 + cpal 0.17.3, pipewire 0.10, dirs 7, strum 0.28, phf 0.14, sha2 0.11, criterion 0.8, zip 9, opus 0.4, libloading 0.9, ort rc.14 2026-10-15 19:46:37 +02:00
resonance-agent-plugin Placing a section again installs its parts, vocal line and current take at the new placement (BUG-73) 2026-10-15 16:48:50 +02:00
resonance-app Docs: strict header and table forms for base's docs importer 2026-10-17 20:08:54 +02:00
resonance-audio Docs: strict header and table forms for base's docs importer 2026-10-17 20:08:54 +02:00
resonance-common Upgrade zip 2 → 9 (kit, voicebank and vocoder installs) 2026-10-15 18:33:30 +02:00
resonance-control Merge Wave B4: tagged save replies (BUG-61) and plugin-state echoes (BUG-39), Save As carries history WAVs (BUG-60) and clears a replaced project (BUG-62) 2026-10-15 16:56:27 +02:00
resonance-dsp Point code comments at the archived design docs 2026-10-07 17:08:06 +02:00
resonance-dsp-test-support License the workspace MIT OR Apache-2.0 (DEP-04); LAME linking decision still open 2026-10-04 20:35:34 +02:00
resonance-mastering-assist License the workspace MIT OR Apache-2.0 (DEP-04); LAME linking decision still open 2026-10-04 20:35:34 +02:00
resonance-mcp Merge Wave B4: tagged save replies (BUG-61) and plugin-state echoes (BUG-39), Save As carries history WAVs (BUG-60) and clears a replaced project (BUG-62) 2026-10-15 16:56:27 +02:00
resonance-metering Reverb R7: per-algorithm tank view; editor strip fits; clippy 2026-10-06 01:39:19 +02:00
resonance-music-theory Upgrade strum 0.26 → 0.28, phf 0.11 → 0.14 (resonance-music-theory) 2026-10-15 18:00:19 +02:00
resonance-plugin Merge branch 'master' into worktree-agent-afd863c737e6c20ce 2026-10-15 19:34:07 +02:00
resonance-svs Upgrade ort 2.0.0-rc.12 → rc.14 (ONNX Runtime 1.24.2 → 1.31.0) 2026-10-15 19:38:41 +02:00
scripts Singing skill: bundled intelligibility check on a vocal stem (plugin 0.5.0) 2026-10-13 14:14:01 +02:00
tools Move LoopRecordSession into its own module, under the mod.rs ratchet (BUG-22) 2026-10-15 16:26:05 +02:00
wayland-plugin-gui editor_size: drive Hyprland 0.56's Lua dispatchers (BUG-77) 2026-10-15 18:39:39 +02:00
.gitignore Remove ba tooling: ba.conf, CLAUDE.md ba-agent workflow, .ba-worktrees ignore 2026-09-27 21:57:51 +02:00
ARCHITECTURE.md Reorganise documentation into features, intents, guides and history 2026-10-07 17:08:13 +02:00
Cargo.lock Cargo.lock: re-resolve after merging the egui and dependency-major branches 2026-10-15 19:51:46 +02:00
Cargo.toml Merge dependency majors: midir 0.11 + cpal 0.17.3, pipewire 0.10, dirs 7, strum 0.28, phf 0.14, sha2 0.11, criterion 0.8, zip 9, opus 0.4, libloading 0.9, ort rc.14 2026-10-15 19:46:37 +02:00
CLAUDE.md Docs: strict header and table forms for base's docs importer 2026-10-17 20:08:54 +02:00
LICENSE-APACHE License the workspace MIT OR Apache-2.0 (DEP-04); LAME linking decision still open 2026-10-04 20:35:34 +02:00
LICENSE-MIT License the workspace MIT OR Apache-2.0 (DEP-04); LAME linking decision still open 2026-10-04 20:35:34 +02:00
README.md Upgrade opus 0.3 → 0.4 (audiopus_sys → opusic-sys) 2026-10-15 18:37:54 +02:00
THIRD_PARTY_LICENSES.md License the workspace MIT OR Apache-2.0 (DEP-04); LAME linking decision still open 2026-10-04 20:35:34 +02:00

Resonance

A DAW written in Rust: an iced app, a realtime audio engine that hosts CLAP plugins, a set of first-party CLAP plugins (synth, drums, EQ, compressor, reverb, mastering, …), and a control surface an AI client can drive over MCP.

It runs on Linux (PipeWire, Wayland) and macOS (CoreAudio, Cocoa).

For how the code is organised, see ARCHITECTURE.md. For tests and contributor conventions, see CLAUDE.md. Every feature — what it does, where its code is, how it is tested — and everything still planned is indexed in docs/README.md.


Linux

Requirements

  • A PipeWire session. It's the default audio server on current Fedora, Ubuntu, Debian, and Arch installs. The engine talks to PipeWire directly and falls back to ALSA through cpal.
  • A Wayland session (GNOME, KDE, Sway, Hyprland, …). The plugin editor windows are native Wayland windows.
  • A GPU driver with Vulkan or OpenGL. The UI renders through wgpu.
  • Rust, stable, installed with rustup.

System packages

The PipeWire bindings are generated with bindgen, so they need clang. MP3 export compiles LAME from source, so it needs a C compiler. Opus export builds libopus from source with CMake. The file dialogs use GTK 3.

Debian / Ubuntu

sudo apt install build-essential clang pkg-config cmake \
  libpipewire-0.3-dev libspa-0.2-dev libasound2-dev \
  libgtk-3-dev libwayland-dev libxkbcommon-dev libegl-dev \
  mesa-vulkan-drivers

Fedora

sudo dnf install gcc gcc-c++ clang pkgconf-pkg-config cmake \
  pipewire-devel alsa-lib-devel \
  gtk3-devel wayland-devel libxkbcommon-devel mesa-libEGL-devel \
  mesa-vulkan-drivers vulkan-loader

Arch

sudo pacman -S --needed base-devel clang pkgconf cmake \
  pipewire alsa-lib gtk3 wayland libxkbcommon mesa vulkan-icd-loader

The engine renders on several threads. A worker thread is used only when it can run at the same realtime priority as the audio thread. Otherwise the engine renders serially, which works but is slower. To grant realtime priority, add yourself to the audio group and allow it realtime scheduling:

sudo usermod -aG audio "$USER"
printf '@audio - rtprio 95\n@audio - memlock unlimited\n' \
  | sudo tee /etc/security/limits.d/95-audio.conf

Log out and back in, then check that ulimit -r prints 95.

Where plugins are found

The app scans ~/.clap, /usr/lib/clap, every directory in $CLAP_PATH, and the checkout's target/bundled/. You don't need to install the first-party plugins to use them from a checkout.


macOS

Requirements

  • macOS on Apple Silicon or Intel.
  • Xcode Command Line Tools: xcode-select --install
  • Rust, stable, installed with rustup.
  • Homebrew, for two build dependencies:
brew install pkgconf cmake

CMake builds libopus from source for Opus export (opusic-sys, which works with CMake 4).

Microphone permission

The first time Resonance touches an audio input, macOS asks for microphone access. The app keeps working while the dialog is open. The input list, and anything that records or monitors, waits until you answer. Resonance is attributed to the app that launched it: your terminal, your IDE, or Claude Code if an agent started it. To change the answer later, go to System Settings → Privacy & Security → Microphone.

Where plugins are found

The app scans ~/Library/Audio/Plug-Ins/CLAP, /Library/Audio/Plug-Ins/CLAP (including vendor subfolders), every directory in $CLAP_PATH, and the checkout's target/bundled/. On macOS, scripts/bundle.sh produces real .clap bundle directories with an Info.plist. To make them visible to other hosts too, copy them into ~/Library/Audio/Plug-Ins/CLAP.


Build and run

The steps are the same on both platforms.

git clone <this repo> resonance && cd resonance

# 1. Build the first-party CLAP plugins into target/bundled/
./scripts/bundle.sh

# 2. Build and start the app
cargo run --release -p resonance-app

Skip step 1 and the app still starts, but it has no instruments. It logs a warning that names scripts/bundle.sh. Re-run the script after changing any plugin.

.cargo/config.toml builds with -C target-cpu=native. The binaries are tuned for the machine that built them and aren't portable to older CPUs.

Running the tests

./scripts/run-tests.py            # whole suite, in parallel
./scripts/run-tests.py -p <crate> # one crate

The golden images and bit-exact audio baselines were recorded on the Linux x86-64 reference machine. On macOS, and on Apple Silicon in general, expect those snapshot and hash tests to fail. The failures are platform baselines, not regressions. CLAUDE.md covers the rest: the grouped test binaries, re-blessing goldens, and the live editor-window tests you run by hand.

Useful environment variables

Variable Effect
RUST_LOG Log level, e.g. RUST_LOG=info or RUST_LOG=resonance_audio=debug.
RESONANCE_NO_CONTROL=1 Don't open the control socket (disables MCP control).
RESONANCE_CONTROL_SOCKET Put the control socket at this path instead of the default.
RESONANCE_RENDER_THREADS=<n> Number of render threads (1 = serial).
RESONANCE_FORCE_CPAL_OUTPUT=1 Linux: use cpal/ALSA output instead of native PipeWire.
RESONANCE_NO_GRAPH_FORCE=1 Linux: don't force the PipeWire graph to the project rate; follow the graph rate.
RESONANCE_AUDIO_STATS=1 Verbose audio-stats report every period (by default only over-budget cycles, shortfalls and lock misses are logged).
CLAP_PATH Extra plugin directories, :-separated.

MCP server

resonance-mcp lets Claude Code, Claude Desktop, or any MCP client drive a running Resonance. It can create a project, write chords and parts, add instruments and effects, mix, measure, and export. Every edit appears live in the GUI and goes on the normal undo history.

The server is a thin stdio bridge. The app serves a JSON-RPC control socket, and resonance-mcp connects to it and exposes each control method as an MCP tool (mcp__resonance__<tool>).

Claude ──stdio──▶ resonance-mcp ──unix socket──▶ resonance-app

1. Build the server

cargo build --release -p resonance-mcp
# → target/release/resonance-mcp

2. Register it with Claude Code

claude mcp add --scope user --transport stdio resonance -- \
  "$PWD/target/release/resonance-mcp"
  • Keep the name resonance. The tools are then named mcp__resonance__<tool>, which is what the skills in resonance-agent-plugin/ and any permission allowlists expect.
  • --scope user makes it available in every project. Leave it out to register it for the current directory only.
  • Use an absolute path. Re-run cargo build after pulling so the server and the app come from the same checkout.

3. Start the app, then check the connection

cargo run --release -p resonance-app   # in another terminal
claude mcp list                        # expect: resonance ... ✔ Connected

In a Claude Code session, /mcp lists the tools. To check the connection, ask Claude to call control_hello, which returns the app version and every control method the running app implements.

The server starts fine when the app isn't running. Its tools then return "resonance is not running: could not connect to the control socket at …", and it reconnects on the next call once the app is up.

Claude Desktop (macOS)

Add this to ~/Library/Application Support/Claude/claude_desktop_config.json and restart Claude Desktop:

{
  "mcpServers": {
    "resonance": {
      "command": "/absolute/path/to/resonance/target/release/resonance-mcp"
    }
  }
}

Where the socket lives

Both sides compute the same path, so normally there's nothing to configure:

Platform Control socket
Linux $XDG_RUNTIME_DIR/resonance/control.sock (usually /run/user/<uid>/…)
macOS <per-user temp dir>/resonance/control.sock (under /var/folders/…)
Fallback /tmp/resonance-<uid>/control.sock

On macOS the per-user temp dir is asked of the OS (confstr(_CS_DARWIN_USER_TEMP_DIR), what $TMPDIR normally points at), not read from the environment, so it holds even when Claude Desktop starts the MCP server without $TMPDIR set. If the two sides still can't agree (e.g. a sandboxed client with its own temp dir), give both the same path:

export RESONANCE_CONTROL_SOCKET="$HOME/.resonance-run/control.sock"   # for the app
claude mcp add --scope user --env RESONANCE_CONTROL_SOCKET="$HOME/.resonance-run/control.sock" \
  --transport stdio resonance -- "$PWD/target/release/resonance-mcp"

The socket's directory must be a real directory (not a symlink), owned by you, with mode 0700. The app creates it that way. Both sides refuse a directory that isn't private, because anything that can write there could feed Claude fake tool results. Keep the path short: on macOS a Unix socket path has to be under 104 bytes.

Optional: the agent skills

resonance-agent-plugin/ is a Claude Code plugin of skills (song structure, arranging, drumming, mixing, spatial, mastering). The skills teach Claude the procedure for using the tools well. Load it with:

claude --plugin-dir "$PWD/resonance-agent-plugin"

It ships no MCP config of its own, so register the server as above first. See resonance-agent-plugin/README.md and docs/features/control-api/method-catalogue.md for the full tool surface.


Troubleshooting

The plugin list is empty / no instruments. Run ./scripts/bundle.sh. The app logs a warning that lists the directories it scanned.

macOS: the input list is empty, or arming a track hangs. A microphone-permission dialog is waiting for an answer. It may be behind other windows.

Linux: libspa / pipewire bindgen errors. Install clang and the PipeWire development headers. See System packages.

claude mcp list shows the server as failed. Check the path passed to claude mcp add exists and is executable, and run it directly to see its error (target/release/resonance-mcp waits on stdin; press Ctrl-C to quit).

Tools say "not running" while the app is open. The app and the server are resolving different socket paths. Set RESONANCE_CONTROL_SOCKET for both. Also check the app wasn't started with RESONANCE_NO_CONTROL=1.

Tools report unsupported. The app binary is older than the MCP server. Rebuild both from the same checkout and restart the app.