Files
reasampler/PLAN.md
T
daniel ec211a5620 Archive Milestone 4 in docs
Move completed M4 (persist) from PLAN.md to COMPLETED.md with a decisions
note (GUID identity, Save-As copy, MarkProjectDirty, known limitation);
update CLAUDE.md repo-identity to M0-M4 complete.
2026-07-22 20:21:36 -04:00

215 lines
11 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.
# PLAN.md — ReaSampler milestone roadmap
Living milestone roadmap for ReaSampler. Derived from CONTEXT.md's 11-step build
order; CONTEXT.md remains the authoritative spec — this file is the tickable
checklist, not a re-statement of the spec. When a point lands, doc-keeper removes
it here and appends it to `COMPLETED.md`.
**Conventions**
- One checkbox `- [ ]` = one discrete, independently-landable point.
- Each milestone opens with a **Goal** (one line) and a **Verify** criterion
(the acceptance gate; precision invariants pulled in where one applies).
- Verify-in-DAW points require a manual REAPER run; pure points are gated by CTest.
- "See CONTEXT.md §…" points at the authoritative detail — do not duplicate it here.
---
## Milestone 5 — bank_panel (docked grid)
**Goal:** Docked LICE-drawn grid: thumbnails (from `peaks`), audition,
multi-select, keyboard navigation. Reuses the docking setup from the retired
`mpe_view.cpp`. CONTEXT.md §bank_panel.
**Verify (in DAW):** Grid docks; thumbnails render from computed peaks; audition
plays selected sample; multi-select + keyboard nav work.
- [ ] Docked window + LICE grid render loop.
- [ ] Thumbnail draw from `peaks` bins.
- [ ] Audition (play selected sample) + stop.
- [ ] Multi-select + keyboard navigation.
## Milestone 6 — insert (placement)
**Goal:** "Insert selected sample at edit cursor" via `InsertMedia`. CONTEXT.md
§insert, Build order 6.
**Verify (in DAW):** Selected sample inserts at the edit cursor wrapped in
`Undo_BeginBlock2` / `Undo_EndBlock2`; conform-to-tempo is an explicit flag —
**no silent time-stretch** when off.
- [ ] `InsertMedia(path, mode)` at edit cursor (verify mode bits against SDK).
- [ ] Conform-to-project-tempo vs literal as an explicit flag (never silent).
- [ ] Undo-block wrapping.
## Milestone 7 — capture action family
**Goal:** Bindable capture actions for master / selected tracks / selected items /
razor area, each with wet-dry + tail options. CONTEXT.md §actions, Build order 7.
**Verify (in DAW):** Each action registered (bindable in Actions list), routes to
the offline backend, and honors wet/dry + tail. **Load-bearing principle:** none
auto-inserts into the arrange.
- [ ] Source resolvers: master mix, selected tracks, selected items, razor area
(`GetSet_LoopTimeRange`, `P_RAZOREDITS`, `CountSelectedMediaItems`, etc.).
- [ ] Register each as a bindable action (`command_id`/`gaccel`/`hookcommand`).
- [ ] Wet-dry + tail options per action.
- [ ] Review gate: confirm no capture path touches the timeline.
## Milestone 8 — RealtimeRecordBackend
**Goal:** Realtime record behind the same `ICaptureBackend`, producing identical
bank entries. CONTEXT.md §capture (realtime), §Precision invariants.
**Verify (in DAW):** Hidden temp track resamples wet output; recorded file moves
into the bank; **non-destructive** — temp track removed cleanly, source routing
and user monitoring restored unchanged.
**Note (from M3):** The realtime backend captures during playback and does NOT invoke the offline-render path, so it is inherently dialog-free (no render-progress window) — a secondary benefit beyond hardware/performed-FX capture.
- [ ] Hidden-track resample recipe (`I_RECMODE`/`I_RECINPUT`/`I_RECARM`,
`CSurf_OnRecord`/`CSurf_OnStop`); verify record-mode values against SDK.
- [ ] Resolve wet-master routing that does not alter user monitoring (open
question).
- [ ] Move recorded source into bank; populate identical `Sample`; clean teardown.
## Milestone 9 — slots (MPC-style)
**Goal:** "Capture to slot N" / "insert slot N", MIDI-bindable. CONTEXT.md
Build order 9.
**Verify (in DAW):** Slot capture and slot insert fire from MIDI bindings; slot
state persists via the index.
- [ ] Slot model + slot↔sample assignment.
- [ ] "Capture to slot N" / "insert slot N" actions, MIDI-bindable.
## Milestone 10 — provenance + null-test verify action
**Goal:** Provenance (parent sample id + FX-chain snapshot) and "re-capture from
source"; ship the null-test verification action. CONTEXT.md §Precision invariants,
Build order 10.
**Verify (in DAW):** **Null test** — a dry offline capture of a range, re-inserted
at its source position, nulls to silence against the source. This action is the
tool's trust anchor and must pass.
- [ ] Provenance fields populated on resample-from-sample (parent id + FX-chain
snapshot string).
- [ ] "Re-capture from source" action.
- [ ] Null-test verification action (capture → re-insert at source pos → assert
silence sum).
## Milestone 11 — polish
**Goal:** Batch capture (per selected item / per razor area),
resample-and-mute-source, conform-on-insert, native OS drag-out. CONTEXT.md
Build order 11, §Non-goals (drag-out deferred to last).
**Verify (in DAW):** Each polish action works without regressing the precision
invariants; drag-out places a valid file in the OS target.
- [ ] Batch capture: per selected item / per razor area.
- [ ] Resample-and-mute-source.
- [ ] Conform-on-insert (explicit).
- [ ] Native OS drag-out (deferred final; `InsertMedia` path must already work).
---
## Open questions to resolve during build
Carried from CONTEXT.md §Open questions — keep visible until each is closed by a
landed milestone.
- **Realtime wet-master routing** that captures master output without altering the
user's monitoring. (blocks M8)
- **Thumbnail cache:** recompute peaks vs store peak bins alongside the index.
(touches M2/M4/M5)
- **`parseInt` narrowing hardening:** `src/bank_model.cpp` `parseInt` casts
`int64_t → int` via `static_cast` without a range check; integers that fit
in int64 but exceed `INT_MAX` are implementation-defined. Hardening candidate
— add bounds check before the cast when integer-field validation is in scope.
---
# Phase D — Design View (parallel to the M0M11 capture roadmap)
> **Separate phase namespace.** The M-numbers belong to the capture pillar
> (M0M11, M4 in flight). Design View is an orthogonal feature on its own track,
> so it uses a **lettered** namespace (D1, D2, …) rather than extending the M-line.
> This keeps the two roadmaps from colliding on numbering and reads correctly:
> Phase D is not "the twelfth capture step," it's a different pillar. Authoritative
> spec: **CONTEXT.md §Design View**. Product framing: `docs/product/design-view.md`.
> When a point lands, doc-keeper moves it to `COMPLETED.md`.
## D1 — view_model (pure)
**Goal:** REAPER-free mode registry + membership index + folder-tree-aware
visibility derivation + parking/restore planner + JSON round-trip. The heart of the
phase; mirror of `bank_model`. CONTEXT.md §Design View (Module architecture — pure).
**Verify:** CTest green. N-mode model (not a boolean); Arrange + Design seeded.
Restore-planner round-trip (snapshot → park → restore) returns every driven flag to
its captured value. Parent-derivation correct against a supplied folder tree.
JSON round-trip lossless across modes + membership + show-both + snapshots + active
mode.
- [ ] Mode registry: ordered (id, display name, ordinal); Arrange + Design seeded;
add/query more modes (prove N-mode, not binary).
- [ ] Membership index: `GUID → { mode ids }` + per-track show-both flag;
add / remove / retag / query; untagged = Arrange.
- [ ] Folder-tree-aware visibility derivation: given a supplied parent↔child tree +
active mode, compute the visible set (active leaves, derived-visible parents,
show-both leaves, master always in).
- [ ] Parking/restore planner: emit exact (track, flag, value) op-lists for park and
restore from active mode + snapshot record.
- [ ] JSON round-trip: modes + membership + show-both + snapshots + active mode.
- [ ] Tests: N-mode add/query; parent follows tagged leaf (multi-mode parent);
restore-round-trip returns snapshot values (never hardcoded "on"); show-both leaf
never parked; unknown/stale GUID tolerated; JSON lossless.
## D2 — view shell (apply flags in the DAW)
**Goal:** Read the folder tree and drive REAPER flags per the planner.
CONTEXT.md §Design View (view shell, REAPER API surface).
**Verify (in DAW):** Toggling active mode hides + parks inactive leaves
(`B_SHOWINTCP`/`B_SHOWINMIXER`/`B_MAINSEND`/`I_FXEN` + per-FX offline) and restores
active ones from snapshot. **Master untouched. `B_MUTE`/`I_SOLO` untouched.**
Untagged tracks untouched. Parents follow their tagged descendants.
- [ ] Build parent↔child tree from `I_FOLDERDEPTH`; feed to `view_model`.
- [ ] Snapshot prior flag values (`GetMediaTrackInfo_Value`) before parking.
- [ ] Apply park/restore ops (`SetMediaTrackInfo_Value` for the four flags;
`TrackFX_GetCount` + per-FX `TrackFX_SetOffline`). Verify flag names/signatures.
- [ ] GUID resolution: `GetTrackGUID` / `guidToString` / `stringToGuid` (never index).
- [ ] Review gate: no path touches master visibility or `B_MUTE`/`I_SOLO`, or any
untagged track's owned flags.
## D3 — persist slice (view state ↔ project ext state)
**Goal:** Serialize the view section into the `"reasampler"` namespace alongside the
bank; reapply the active mode on project open. CONTEXT.md §Design View (persist).
**Verify (in DAW):** Membership + active mode + snapshots survive Save / Save As /
close+reopen; on open, the active mode's visibility + processing is reapplied.
Saved-while-parked project restores parked tracks from persisted snapshots (not to a
guessed "on").
- [ ] Serialize/deserialize the view section under `"reasampler"` (shared blob,
distinct section from the bank index).
- [ ] Reapply active mode on project open (rebuild tree, run the planner).
- [ ] Confirm survival across Save / Save As; snapshot durability across
save-while-parked.
## D4 — actions
**Goal:** Bindable action set for the mode workflow. CONTEXT.md §Design View
(actions). **Verify (in DAW):** Each action registered (bindable in Actions list);
toggle + mode-jumps MIDI-bindable; tag/untag acts on the current track selection.
- [ ] Toggle active mode (cycle; extensible to cycle-all for >2 modes).
- [ ] Activate mode: Arrange / Activate mode: Design (direct jumps).
- [ ] Tag selected tracks → Design / → Arrange; Untag selected (= → Arrange).
- [ ] Show-both for selected tracks (toggle).
- [ ] Register each (`command_id`/`gaccel`/`hookcommand`); toggle + jumps MIDI-bindable.
## D5 — in-window toggle affordance (UI)
**Goal:** The segmented mode switch in the ReaSampler / bank_panel window header.
CONTEXT.md §Design View (UI). **Verify (in DAW):** Segmented control shows current
mode (lit segment), one click flips modes via the D4 toggle action, per-mode
membership count visible, offlined-FX caveat surfaced as a tooltip.
- [ ] Segmented mode switch `[ Arrange | Design ]` in the window header; active lit.
- [ ] Wire the switch to the toggle/activate actions from D4.
- [ ] Per-mode membership count display.
- [ ] Offlined-FX re-init caveat as a tooltip on the switch.
## Phase D open questions
- **Snapshot durability across save-while-parked** — persisted here by decision;
lean alternative is force-restore-to-Arrange on save (product notes item 4).
(touches D3)
- **Reconcile on delete/restructure** — tagged leaf deleted or folder restructured
while parked leaves a stale GUID; ignore-and-prune on next toggle/open.
(touches D1/D2)
- **Screenset coexistence** — Design View drives the same flags a screenset recall
would; confirm last-writer-wins is not surprising. (touches D2)