Add Design View phase spec (Phase D), parallel to capture roadmap
CONTEXT.md: additive Design View technical spec section. PLAN.md: additive Phase D (D1-D5) milestone breakdown. docs/product/design-view.md: product framing, N-mode reasoning, screenset differentiation, design-direction calls.
This commit is contained in:
+146
@@ -162,3 +162,149 @@ Persistence & paths:
|
||||
- Audio format for the bank (wav bit depth default; allow float for wavetable
|
||||
fidelity).
|
||||
- Thumbnail cache: recompute vs store peak bins alongside the index.
|
||||
|
||||
---
|
||||
|
||||
# Design View — additive phase spec
|
||||
|
||||
> **Additive section.** This is a standalone phase parallel to — not part of — the
|
||||
> M0–M11 capture roadmap above. Nothing above changes. Product framing (workflow
|
||||
> narrative, screenset differentiation, N-mode reasoning, design-direction calls)
|
||||
> lives in `docs/product/design-view.md`; this section is the authoritative
|
||||
> technical spec, matching the house style of the capture spec. Same standing
|
||||
> discipline applies: **verify every REAPER API name/signature against
|
||||
> `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use.**
|
||||
|
||||
## What it is
|
||||
|
||||
A **track-visibility-plus-processing "mode" system**, toggled from the ReaSampler
|
||||
window. Tracks used purely for sound design (scratch oscillators, FX mangling,
|
||||
resampling sources) are tagged into **Design** mode; the arrangement's real tracks
|
||||
are **Arrange** mode (the default). Toggling to a mode **hides and disables** the
|
||||
tracks that don't belong to it. Workflow value: mental separation + clutter
|
||||
elimination — be in Design view, resample into the bank, flip to Arrange, place it.
|
||||
|
||||
**This is not a separate canvas.** REAPER has exactly one arrange timeline. Design
|
||||
View is the *same timeline* with a curated, filtered track set and the inactive
|
||||
tracks parked — not a second surface, window, or duplicated project.
|
||||
|
||||
It is the visibility/processing analog of the capture pillar's load-bearing rule:
|
||||
**designing and arranging are separate stances on one timeline**, and the tool
|
||||
enforces the separation **without ever destroying the user's real state.**
|
||||
|
||||
## Settled decisions
|
||||
|
||||
- **Membership.** Default = Arrange; every untagged leaf belongs to it. Leaves
|
||||
**opt in** to Design (or any mode). No track appears in two modes at once except
|
||||
(a) via an explicit **show-both** toggle, or (b) parent/folder derivation.
|
||||
- **Parents are derived, never tagged.** A parent appears in — and is never parked
|
||||
in — every mode any of its descendant leaves belongs to. Rule of thumb: **tag
|
||||
leaves; parents follow.** Master track is always visible and never touched.
|
||||
- **N-mode model, two-mode UI.** The data model carries arbitrarily many modes; the
|
||||
UI ships **Arrange** + **Design**. A mode is (stable id, display name, ordinal).
|
||||
Arrange is special only as the default home for untagged leaves.
|
||||
- **Parking a track** (inactive-mode leaf): `B_SHOWINTCP=0`, `B_SHOWINMIXER=0`
|
||||
(hide both panels), `B_MAINSEND=0` (out of mix), `I_FXEN=0` (FX bypassed), and
|
||||
`TrackFX_SetOffline(track, fx, true)` for **each** FX (reclaim CPU). Full CPU-park
|
||||
is the deliberate choice over mix-removal-only.
|
||||
- **Never touches `B_MUTE` / `I_SOLO`.** The tool owns only visibility,
|
||||
`B_MAINSEND`, `I_FXEN`, and per-FX offline — and only on tracks it tagged. User
|
||||
mute/solo survives every toggle untouched.
|
||||
- **Persistence.** Membership index + last-active mode + per-track flag snapshots
|
||||
ride in the existing `"reasampler"` project ext-state namespace and travel with
|
||||
the `.rpp`. On project open, reapply the active mode's visibility + processing.
|
||||
|
||||
## Precision invariants (enforce, test)
|
||||
|
||||
- **Non-destructive restore.** For every flag the tool drives, snapshot the prior
|
||||
value **before** parking; on toggle-back restore **from the snapshot**, never to a
|
||||
hardcoded "on." Round-trip (snapshot → park → restore) returns every driven flag
|
||||
to its captured value. This is the phase's trust anchor — the analog of the
|
||||
capture null test — and is enforced in the pure layer.
|
||||
- **Mute/solo untouched.** No toggle ever reads or writes `B_MUTE` / `I_SOLO`.
|
||||
- **Master untouched.** The tool never drives the master track's visibility flags
|
||||
(the SDK forbids `B_SHOWINTCP`/`B_SHOWINMIXER` on master; the invariant agrees).
|
||||
- **GUID-keyed, reorder-safe.** Membership keys on track GUID (`GetTrackGUID`),
|
||||
never track index; tolerates unknown/stale GUIDs (prune on reconcile).
|
||||
- **Relative/portable state only** in the persisted view section (GUID strings, mode
|
||||
ids — no absolute paths, no index positions).
|
||||
|
||||
## Documented caveat
|
||||
|
||||
Offlined FX **re-instantiate** when a track returns to the active mode. Stateful
|
||||
plugins (convolution, loaded samplers, tail-holding effects) re-initialize on
|
||||
return — possible load hitch, un-persisted internal state lost. Accepted cost of
|
||||
the CPU reclaim; surface it at the toggle affordance (tooltip).
|
||||
|
||||
## Module architecture (preserve the pure/shell split)
|
||||
|
||||
Pure (no REAPER types, unit-tested — the mirror of `bank_model`):
|
||||
- `view_model` — mode registry (id/name/ordinal; Arrange + Design seeded);
|
||||
membership index (`track GUID → { mode ids }` + per-track show-both flag; add /
|
||||
remove / retag / query); **folder-tree-aware** visibility derivation (given the
|
||||
current parent↔child tree supplied by the shell + the active mode, compute the
|
||||
visible set); the **parking/restore planner** (given active mode + snapshot
|
||||
record, emit the exact (track, flag, value) operation lists for park and
|
||||
restore — where the restore invariant is enforced); JSON round-trip of modes +
|
||||
membership + show-both + snapshots + active mode.
|
||||
|
||||
REAPER-facing:
|
||||
- `view` shell — reads `I_FOLDERDEPTH` across the track list to build the
|
||||
parent↔child tree and feeds it to `view_model`; applies the planner's operations
|
||||
via `SetMediaTrackInfo_Value` (`B_SHOWINTCP` / `B_SHOWINMIXER` / `B_MAINSEND` /
|
||||
`I_FXEN`) and `TrackFX_GetCount` + per-FX `TrackFX_SetOffline`; snapshots prior
|
||||
flag values before parking; resolves GUIDs via
|
||||
`GetTrackGUID` / `guidToString` / `stringToGuid`. Never touches master
|
||||
visibility, never touches `B_MUTE` / `I_SOLO`.
|
||||
- `persist` (slice) — serialize/deserialize the view section into the
|
||||
`"reasampler"` namespace alongside the bank; on project open, rebuild the tree
|
||||
and reapply the active mode.
|
||||
- `actions` (entries) — toggle active mode; activate mode: Arrange / Design;
|
||||
tag/untag selected tracks → mode; show-both for selected tracks. Registered with
|
||||
the `command_id` / `gaccel` / `hookcommand` pattern; toggle + mode-jumps
|
||||
MIDI-bindable.
|
||||
- UI (in the ReaSampler / bank_panel window) — a **segmented mode switch**
|
||||
(`[ Arrange | Design ]`) in the window header, active segment lit; small per-mode
|
||||
membership count; the offlined-FX caveat as a tooltip. Tag/untag acts on the
|
||||
current REAPER track selection, not a per-track widget.
|
||||
|
||||
## Show-both semantics
|
||||
|
||||
A **per-track "pin visible across modes"** flag that **re-enables processing**
|
||||
whenever shown. A show-both leaf appears in every mode's visible set and is **never
|
||||
parked** — its driven flags stay at snapshot/restored values, FX online, in the
|
||||
mix. ("Show but keep parked" is not offered — a visible-but-silent-and-offline
|
||||
track is clutter with a thumbnail.) Stored on the membership record; persists;
|
||||
togglable per selection.
|
||||
|
||||
## REAPER API surface (verify all signatures)
|
||||
|
||||
- Visibility/routing/FX flags via `GetMediaTrackInfo_Value` (snapshot) /
|
||||
`SetMediaTrackInfo_Value` (apply): `B_SHOWINTCP`, `B_SHOWINMIXER`, `B_MAINSEND`,
|
||||
`I_FXEN`. (Note: brief cited `B_SHOWINMCP`; verified SDK name is `B_SHOWINMIXER`.)
|
||||
- Per-FX offline: `TrackFX_GetCount` + `TrackFX_SetOffline(track, fx, offline)`.
|
||||
- Folder tree: read `I_FOLDERDEPTH` per track to derive parent↔child structure.
|
||||
- GUID keying: `GetTrackGUID`, `guidToString`, `stringToGuid`.
|
||||
- Persistence: `SetProjExtState` / `GetProjExtState` under `"reasampler"` (shared
|
||||
with the bank index — one blob, two logical sections).
|
||||
- Wrap flag mutations in `Undo_BeginBlock2` / `Undo_EndBlock2` as appropriate.
|
||||
|
||||
## Non-goals / guardrails
|
||||
|
||||
- **No second canvas.** Do not build a parallel arrange surface — reject any such
|
||||
path in review.
|
||||
- **Never touch mute/solo.** Any code path reading/writing `B_MUTE` / `I_SOLO` is a
|
||||
bug.
|
||||
- **Never touch untagged tracks.** The tool acts only on tracks it tagged (plus
|
||||
derived parents' *visibility*); it never parks or restores a track it doesn't own.
|
||||
- **Restore from snapshot, never to a default.** No hardcoded "on" restores.
|
||||
- **Verify API names** against the SDK header before use.
|
||||
|
||||
## Open questions to resolve during build
|
||||
|
||||
- Snapshot durability across a save-while-parked (persisted here by decision; the
|
||||
lean alternative is force-restore-to-Arrange on save — see product notes item 4).
|
||||
- Reconcile behavior when a tagged leaf is deleted or a folder restructured while
|
||||
parked (ignore-and-prune stale GUIDs on next toggle/open).
|
||||
- Interaction with the user having a screenset active (Design View drives the same
|
||||
flags a screenset recall would; last writer wins — confirm no surprising fight).
|
||||
|
||||
Reference in New Issue
Block a user