diff --git a/COMPLETED.md b/COMPLETED.md index 3622dc1..6120419 100644 --- a/COMPLETED.md +++ b/COMPLETED.md @@ -114,7 +114,25 @@ folder still resolves the bank). - Storage: `SetProjExtState` / `GetProjExtState`, namespace `"reasampler"`, keys `bank_index` (serialized JSON) and `project_guid`; relative paths only in the persisted index. - Project identity: keyed off a **minted GUID** stored in ext state (REAPER exposes no native per-project GUID), not the raw `ReaProject*` — a recycled pointer cannot misread a project switch as a Save-As. - Save-As: **copy** semantics (Daniel's decision) — the `reasampler_bank/` folder is copied under the new `.rpp`; the old project's bank stays intact. Every ext-state write calls `MarkProjectDirty` so captures/GUID changes flush on the normal save. -- Save-As collision — fixed (DAW-verified): the project-identity classifier now keys off the **`ReaProject*` object identity** (`sameProjectObject` signal), not the stored GUID alone. A different project object (tab-switch or open) is always treated as a Load and never relocates a bank, so two Save-As-forked projects sharing a copied GUID on disk cannot cross-contaminate. A forked sibling that still shares the original GUID is re-GUID'd on detection so identities diverge. The hole is closed without force-saving — non-destructive preserved. +- Save-As collision — fixed (DAW-verified): project identity is **GUID-primary** — the stored per-project GUID is the identity of record; a different stored GUID always means a different project (Load its bank), immune to REAPER recycling `ReaProject*` addresses across close/open. The `ReaProject*` pointer is a secondary signal that disambiguates the same-GUID case only: a different object with the same GUID = a Save-As fork (Load + re-GUID to diverge); the same object with the same GUID + a new path = a genuine Save-As in progress (relocate bank). This replaced two earlier iterations: GUID-only (mis-detected forks sharing a copied GUID) and pointer-primary (mis-detected reopen/new-project because it ignored the GUID on address recycling). Non-destructive preserved. + +--- + +## 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. + +- [x] Docked window + LICE grid render loop. +- [x] Thumbnail draw from `peaks` bins. +- [x] Audition (play selected sample) + stop. +- [x] Multi-select + keyboard navigation. + +**Notes/decisions:** +- Thumbnail cache: in-memory recompute keyed by `(sampleId, drawWidth, bankGeneration)`; peak bins are NOT persisted alongside the index. Cache is discarded on bank change and rebuilt on next draw. (Closes the PLAN "thumbnail cache" open question.) +- Audition: stock `PlayPreview` / `StopPreview` API, read-only — display + select + audition only, never inserts into the arrange. Single stop-funnel ensures a leak-free preview lifecycle. Flagged undocumented assumption: `StopPreview` detaches the source before returning; mitigated by the single-funnel design. Escalation path if a runtime pop appears: switch to `StartPreviewFade` + deferred free. --- diff --git a/PLAN.md b/PLAN.md index cab1e2d..476278e 100644 --- a/PLAN.md +++ b/PLAN.md @@ -14,18 +14,6 @@ it here and appends it to `COMPLETED.md`. --- -## 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. @@ -108,8 +96,6 @@ 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