Files
reasampler/CLAUDE.md
T
daniel 93e2783098 Archive Milestone 2 in docs
Move completed M2 (peaks module) from PLAN.md to COMPLETED.md; add peaks_tests
to the CLAUDE.md targets table and update the pure-core status to M0-M2 done.
2026-07-22 10:00:32 -04:00

79 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repo identity and current state
The CMake project and binary are now named `reaper_reasampler`. This is **ReaSampler** — a per-project audio sample-bank capture tool. The MPE modules (`mpe_model`, `mpe_view`) have been removed. The pure core (M0M2) is complete: `bank_model` (Sample metadata + BankIndex with JSON round-trip) and `peaks` (waveform min/max bin computation) are both implemented and fully tested. The REAPER-facing shells (`capture`, `insert`, `bank_panel`, `persist`, `actions`) are being built out per CONTEXT.md / PLAN.md. The *discipline* — pure REAPER-free testable core split from REAPER-facing shells — is **preserved** throughout.
CONTEXT.md is the authoritative spec and build roadmap. Read it first for any non-trivial task. Every REAPER API name cited there is correct-by-intent; verify argument order, types, and flag values against `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use.
## One-time submodule setup
git submodule update --init
Vendors two submodules (see `.gitmodules`):
- `vendor/reaper-sdk``sdk/reaper_plugin.h`, `sdk/reaper_plugin_functions.h`, SWELL headers
- `vendor/WDL` — WDL utilities and the SWELL cross-platform Win32 layer
## Build and test
cmake -B build -S .
cmake --build build
ctest --test-dir build
Three targets:
| Target | Kind | Purpose |
|---|---|---|
| `bank_model_tests` | executable | Pure unit tests for `bank_model` — no REAPER, no DAW. |
| `peaks_tests` | executable | Pure unit tests for `peaks` — no REAPER, no DAW. |
| `reaper_reasampler` | loadable module | The actual extension binary (`.dll` / `.dylib` / `.so`). |
### macOS / Linux: SWELL dialog resources
`src/resource.rc` must be pre-processed by SWELL's resgen once per platform:
php vendor/WDL/WDL/swell/mac_resgen.php src/resource.rc # macOS; Linux reuses the output
Add the generated file to the appropriate `APPLE` / Linux `target_sources` block in CMakeLists.txt. The SWS extension build is the canonical reference for this step.
### Install / reload
There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folder (Options → Show REAPER resource path) and restart REAPER. Extensions load at startup only.
## Architecture: the load-bearing split
**Pure core (no REAPER types, unit-testable outside the DAW):**
- `bank_model``Sample` metadata struct + `BankIndex` (add/remove/query/tier/dedup-by-hash + JSON round-trip). Test it hard — it is the heart.
- `peaks` — waveform min/max bin computation from raw PCM. Fed a known signal, asserts envelope. Does not depend on REAPER's peak API.
**REAPER-facing shells:**
- `capture``ICaptureBackend` interface; `OfflineRenderBackend` (deterministic default) and `RealtimeRecordBackend`. Input: `CaptureRequest`. Output: finished file + populated `Sample` handed to `bank_model`.
- `insert` — placement via `InsertMedia`; conform-to-project-tempo is an explicit opt-in flag, never silent stretching.
- `bank_panel` — docked LICE-drawn grid: thumbnails, audition, multi-select, keyboard navigation.
- `persist` — project ext state (`SetProjExtState` / `GetProjExtState`, namespace `"reasampler"`) ↔ `bank_model` JSON; project-relative path resolution.
- `actions` — registers the capture/placement/slot action family and routes each to the modules above.
## REAPER extension contract (src/main.cpp)
- Exactly **one** translation unit defines `REAPERAPI_IMPLEMENT` — that is `main.cpp`. Every other `.cpp` includes `reaper_plugin_functions.h` without the define and gets `extern` declarations for the global API function pointers.
- REAPER dlopen()s any `reaper_*.dll|dylib|so` found in `UserPlugins/` and calls the `ReaperPluginEntry` export (produced by `REAPER_PLUGIN_ENTRYPOINT`). `rec->GetFunc` resolves API pointers; `rec->Register` plugs extension callbacks in.
- Action registration pattern (preserve this for all new actions):
1. `rec->Register("command_id", (void*)"STABLE_FOREVER_STRING")` — mints a persistent command id. **Never change this string after shipping**; user keybindings key off it.
2. `rec->Register("gaccel", &accel)` — puts the action in the Actions list.
3. `rec->Register("hookcommand", ...)` — receives every action fired; claim only your own id, return `false` otherwise.
4. On unload (`rec == nullptr`), mirror-unregister everything with the same strings prefixed by `'-'`.
## The load-bearing principle
**Capture and placement are separate acts.** Capturing audio writes a file to the bank and adds an index entry. It **never** puts an item in the arrange view. Placement is a distinct, on-demand action (`insert` module / `InsertMedia`). Any code path that auto-inserts a capture into the timeline violates the purpose of the tool and **must be rejected in review**.
## Precision invariants — required before any feature ships
- **Null test:** a dry offline capture of a range, re-inserted at its source position, nulls to silence against the source. Ship as a verification action.
- **Bit-identical repeats:** identical offline capture requests produce identical files.
- **Non-destructive:** capture never mutates source items or tracks; the realtime backend's temp track is created and removed cleanly, and source routing is restored.
- **Exact bounds:** no rounding of the requested range; no added silence unless a tail is explicitly requested; channel count preserved (no silent stereo fold).
- **Relative paths only** in the persisted `BankIndex`.