|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Rustortion is a real-time guitar/bass amp simulator built in Rust. It runs as a standalone JACK app and as a VST3/CLAP plugin. The GUI is shared between both targets via the `rustortion-ui` crate. |
| 8 | + |
| 9 | +## Workspace Crates |
| 10 | + |
| 11 | +- **`rustortion-core`** — DSP engine, amp stages, IR cabinet, preset management. No GUI dependencies. |
| 12 | +- **`rustortion-ui`** — Shared GUI: stages, components, messages, handlers, i18n, `SharedApp<ParamBackend>`. Uses `iced = "0.14"`. |
| 13 | +- **`rustortion-standalone`** — Standalone JACK app. Thin shell wrapping `SharedApp<StandaloneBackend>` with MIDI, tuner, settings, recording. |
| 14 | +- **`rustortion-plugin`** — VST3/CLAP plugin via nih-plug. Editor uses `iced_baseview` + `SharedApp<PluginBackend>`. |
| 15 | +- **`xtask`** — Build automation. |
| 16 | + |
| 17 | +## Build & Development Commands |
| 18 | + |
| 19 | +```bash |
| 20 | +# Build and run standalone (requires JACK/PipeWire) |
| 21 | +cargo run --release |
| 22 | + |
| 23 | +# Build plugin |
| 24 | +cargo build -p rustortion-plugin --release |
| 25 | + |
| 26 | +# Lint (formatting + clippy) — this is what CI runs |
| 27 | +make lint |
| 28 | + |
| 29 | +# Run tests |
| 30 | +make test # all tests |
| 31 | +cargo test test_name # single test |
| 32 | + |
| 33 | +# Benchmarks |
| 34 | +make bench |
| 35 | + |
| 36 | +# Coverage (requires cargo-tarpaulin) |
| 37 | +make cover |
| 38 | +``` |
| 39 | + |
| 40 | +**System dependencies** (must be installed before building): |
| 41 | +```bash |
| 42 | +sudo apt-get install libjack-jackd2-dev libasound2-dev pkg-config |
| 43 | +``` |
| 44 | + |
| 45 | +**Clippy flags** used in CI: `-D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery` |
| 46 | +(`lib.rs` has `#![allow(...)]` overrides for specific pedantic/nursery lints) |
| 47 | + |
| 48 | +**Dev profile** uses `opt-level = 1` because IR cabinet processing is too slow in pure debug mode. |
| 49 | + |
| 50 | +## Architecture |
| 51 | + |
| 52 | +### Shared GUI Pattern |
| 53 | + |
| 54 | +Both standalone and plugin use `SharedApp<B: ParamBackend>` from `rustortion-ui`: |
| 55 | + |
| 56 | +``` |
| 57 | +rustortion-standalone rustortion-plugin |
| 58 | + AmplifierApp PluginApp (iced_baseview::Application) |
| 59 | + └─ SharedApp<StandaloneBackend> └─ SharedApp<PluginBackend> |
| 60 | + └─ StandaloneBackend └─ PluginBackend |
| 61 | + └─ Manager/Engine (JACK) └─ EngineHandle + GuiContext |
| 62 | +``` |
| 63 | + |
| 64 | +`ParamBackend` trait (`rustortion-ui/src/backend.rs`) abstracts engine communication. `Capabilities` struct controls which UI sections render (e.g. plugin hides tuner, MIDI config, recording, settings). |
| 65 | + |
| 66 | +### Audio Signal Flow |
| 67 | + |
| 68 | +``` |
| 69 | +Input → [Tuner bypass] → Input Filters (HP/LP) → [Upsample] → Amp Chain (stages) → [Downsample] → Pitch Shifter → IR Cabinet → Peak Meter → Recorder → Output |
| 70 | +``` |
| 71 | + |
| 72 | +### Key Modules |
| 73 | + |
| 74 | +#### rustortion-core |
| 75 | +- **`src/amp/chain.rs`** — Ordered list of processing stages. |
| 76 | +- **`src/amp/stages/`** — 10 registered DSP stages: preamp, compressor, noise_gate, tonestack, poweramp, multiband_saturator, level, delay, reverb, eq. Plus utilities: `clipper`, `filter`, `common`. |
| 77 | +- **`src/audio/engine.rs`** — Core audio processing loop. Controlled via crossbeam channels. |
| 78 | +- **`src/ir/`** — IR cabinet, convolver (FIR/FFT), loader. |
| 79 | +- **`src/preset/`** — Preset save/load/delete, `StageConfig` enum, `InputFilterConfig`. |
| 80 | + |
| 81 | +#### rustortion-ui |
| 82 | +- **`src/app.rs`** — `SharedApp<B>` — shared state, update(), view(), subscription(). |
| 83 | +- **`src/backend.rs`** — `ParamBackend` trait, `Capabilities`, `ExternalEvent`. |
| 84 | +- **`src/stages/mod.rs`** — `gui_stage_registry!` macro, `ParamUpdate`, all 10 stage view modules. |
| 85 | +- **`src/components/`** — Reusable UI components: widgets, dialogs, preset_bar, peak_meter, ir_cabinet_control, minimap, etc. |
| 86 | +- **`src/handlers/`** — Portable handlers: preset, hotkey. |
| 87 | +- **`src/messages/`** — Message enums for Iced event-driven updates. |
| 88 | +- **`src/i18n/`** — `tr!()` macro, EN + ZH_CN locales. |
| 89 | +- **`src/tabs.rs`** — Tab navigation: Amp, Effects, Cabinet, IO. |
| 90 | + |
| 91 | +#### rustortion-standalone |
| 92 | +- **`src/gui/app.rs`** — `AmplifierApp` wrapping `SharedApp<StandaloneBackend>` + standalone handlers (MIDI, tuner, settings, recording). |
| 93 | +- **`src/backend.rs`** — `StandaloneBackend` implementing `ParamBackend` via `Manager`/`Engine`. |
| 94 | +- **`src/audio/`** — JACK client, Manager, ports. |
| 95 | +- **`src/gui/handlers/`** — Standalone-only: midi, tuner, settings. |
| 96 | +- **`src/gui/components/dialogs/`** — Standalone-only dialogs: midi, settings, tuner. |
| 97 | + |
| 98 | +#### rustortion-plugin |
| 99 | +- **`src/lib.rs`** — nih-plug `Plugin` impl, audio processing, initialization. |
| 100 | +- **`src/editor.rs`** — `PluginEditor` (nih-plug `Editor` trait) + `PluginApp` (iced_baseview `Application`). |
| 101 | +- **`src/backend.rs`** — `PluginBackend` implementing `ParamBackend` via `EngineHandle` + `GuiContext`. |
| 102 | +- **`src/params.rs`** — Full nih-plug parameter set: global params + 8 slots × 10 stage types. |
| 103 | + |
| 104 | +### Stage Registration (`rustortion-ui/src/stages/mod.rs`) |
| 105 | + |
| 106 | +The `gui_stage_registry!` macro generates `StageType`, `StageConfig`, and `StageMessage` enums plus all boilerplate. Adding a new stage requires: |
| 107 | +1. Add one line to the macro invocation |
| 108 | +2. Create `rustortion-ui/src/stages/new_stage.rs` with config, message, and view implementations |
| 109 | +3. Create `rustortion-core/src/amp/stages/new_stage.rs` implementing the `Stage` trait |
| 110 | +4. Add i18n keys to EN and ZH_CN in `rustortion-ui/src/i18n/mod.rs` |
| 111 | +5. Add slot params to `rustortion-plugin/src/params.rs` |
| 112 | + |
| 113 | +### Thread Model |
| 114 | + |
| 115 | +The JACK process callback (standalone) or nih-plug `process()` (plugin) runs on a real-time thread. The GUI communicates with the engine via crossbeam channels. Shared state (tuner data, peak meter) uses `ArcSwap` for lock-free reads. |
| 116 | + |
| 117 | +## Common Pitfalls |
| 118 | + |
| 119 | +- **JACK/PipeWire must be running** before `cargo run --release`. If JACK is not available the app will panic on startup. |
| 120 | +- **Dev profile uses `opt-level = 1`** — benchmarks and performance comparisons must use `--release`. |
| 121 | +- **The `gui_stage_registry!` macro** in `rustortion-ui/src/stages/mod.rs` generates boilerplate. Do not hand-write — add one line to the macro invocation instead. |
| 122 | +- **Preset JSON format** — each preset is a JSON file in `~/.config/rustortion/presets/`. Structure: `{ "name": "...", "stages": [...], "ir_name": "...", "ir_gain": N, "pitch_shift_semitones": N, "input_filters": {...} }`. |
| 123 | +- **IR files** are in `impulse_responses/` and `~/.config/rustortion/impulse_responses/`. Loading is async (off RT thread). |
| 124 | +- **Clippy is strict** — CI runs `-D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery`. |
| 125 | +- **iced_baseview** is a fork at `github.com/OpenSauce/iced_baseview`, upgraded to iced 0.14 crates.io. |
| 126 | + |
| 127 | +## Conventions |
| 128 | + |
| 129 | +- Rust edition 2024 |
| 130 | +- Conventional commits: `feat:`, `fix:`, `refactor:`, `chore:`, etc. |
| 131 | +- Changelog generated via `git-cliff` |
| 132 | +- Standalone entry point: `rustortion-standalone/src/bin/gui.rs` |
| 133 | +- Releases via `cargo-dist` (`.github/workflows/release.yml`, `dist-workspace.toml`) |
0 commit comments