docs(phase-s): spec three-view editor redesign (S-VIEW) — Sample/Browse/Zone
This commit is contained in:
+290
-27
@@ -2139,6 +2139,274 @@ not a raw literal). What S18 adds is only the missing *plugin identity* layer.
|
||||
headers before use — several §1a claims are experienced estimates until the spike
|
||||
confirms them.
|
||||
|
||||
## Editor view-model redesign — three views: Sample / Browse / Zone (S-VIEW; Daniel, 2026-07-27, r9)
|
||||
|
||||
> **Additive sub-phase of Phase S — an *editor* redesign, not an engine change.** Re-partitions
|
||||
> the ReaSampler 9000 editor from today's two-view toggle (Browser + Zones) into a **three-view
|
||||
> model where the loaded sample is the home**, adds two new performance parameters (key-tracking,
|
||||
> preview velocity) and two visual components (envelope overlay, real piano-key pattern), and
|
||||
> frames two engineering prerequisites (drop-to-FX bug, default window size). The S3 voice
|
||||
> engine, keymap resolution, and read-only-over-bank contract are **unchanged**; the
|
||||
> component-state format extends additively for key-tracking. Product framing: `docs/product/
|
||||
> midi-playback.md` §Addendum r9. Same standing discipline: **LICE/SWELL drawing only,
|
||||
> all layout/hit-test in pure geometry modules, RT-safe, VST3 class UID unchanged, verify every
|
||||
> API name/signature against the vendored headers before use.**
|
||||
|
||||
### The view model — Sample is home; Browse is modal; Zone is a dedicated surface
|
||||
|
||||
The three views are **not a flat three-way toggle** (today's Browser|Zones segmented switch is
|
||||
retired). The model is **document-with-modal-picker** (mirror: Ableton Simpler — the device face
|
||||
*is* the loaded sample; loading a new one is a distinct act):
|
||||
|
||||
- **Sample (the home / default face).** What the editor shows on open with a capture loaded. The
|
||||
hero waveform, the envelope overlay, all per-sample tuning controls, the preview-trigger. This
|
||||
is where the user lives.
|
||||
- **Browse (a modal page layered over Sample).** Summoned by a **Browse button** (and, when
|
||||
nothing is loaded, the empty-state's primary affordance — Browse must be *very* easy to open
|
||||
when there is no capture selected). It renders as a **full-window overlay** over the Sample
|
||||
face — filters + captures grid + **select-then-confirm** to change the loaded sample, then
|
||||
dismisses back to Sample. It is a picker sheet, not a peer tab.
|
||||
- **Zone (a dedicated editing surface).** Opened by its own **Zone button** when the user wants
|
||||
to map the capture(s) across the keyboard. Not shown by default ("most of the time zones won't
|
||||
be used" — the S10 reframe). Returns to Sample on close.
|
||||
|
||||
**Navigation contract.** From Sample: a Browse button opens the Browse overlay; a Zone button
|
||||
opens the Zone surface. From Browse: select a card + confirm (or cancel) returns to Sample with
|
||||
(or without) a new loaded capture. From Zone: a close/back affordance returns to Sample. The
|
||||
empty state (no capture loaded) surfaces Browse as its dominant call-to-action. **The fresh
|
||||
instance stays silent with a "pick a capture" empty state (S10 reversal, unchanged).**
|
||||
|
||||
### View 1 — Sample (the new main view)
|
||||
|
||||
The home face. Composition follows the reference devices (Simpler / Phase Plant): a **hero
|
||||
waveform up top with the envelope drawn over it at accurate time**, a **dense labelled
|
||||
value-strip beneath**, **root fenced as its own affordance**, and a **preview cluster**. Bands,
|
||||
top to bottom:
|
||||
|
||||
- **Title band.** Plugin name (channel-derived `vstPluginName()`) + live readout (loaded capture
|
||||
name / `[pick a capture]` / `[bank empty]` / `[host: no bridge]`) + the **Browse** and **Zone**
|
||||
view buttons. (Inherits today's title-band text logic.)
|
||||
- **Hero waveform band (enlarged) with the ENVELOPE OVERLAY (new).** The picked capture's
|
||||
full-resolution envelope (from `peaks` over the cached mono PCM — no new decode), given real
|
||||
vertical space (the Simpler/Phase-Plant hero, materially taller than today's 72px strip). Drawn
|
||||
over it, at **accurate wall-clock time**: (a) the **S11 markers** — start (teal/secondary),
|
||||
loop start/end (purple/tertiary), the faint loop-region fill — moved here from Browse
|
||||
unchanged; and (b) the **NEW amplitude-envelope overlay** — the AHDSR shape (Gate) or the
|
||||
fade-in/%-length/fade-out shape (Trigger) traced as a curve across the sample at the same time
|
||||
base the voice engine uses, in an accent hue. This is the "reads like a real sampler, not a
|
||||
spreadsheet" move: the envelope becomes a *shape over the sound*, not four abstract sliders.
|
||||
- **Root + preview cluster (fenced, new preview-trigger).** Root note shown as a first-class,
|
||||
always-visible control (fenced like Phase Plant's "Root" box), draggable/typeable — this is the
|
||||
keyboard-strip root-drag from today's Browse setup, promoted to a fenced control. Adjacent: the
|
||||
**NEW preview-trigger button** (fires the sampler at the loaded capture's root note through the
|
||||
live voice engine, off the audio-thread commit path — no MIDI controller needed) with an
|
||||
**adjacent velocity knob** setting the preview velocity level. The **Mono/Stereo toggle** moves
|
||||
here from Browse (it is a per-capture output-mode tuning concern, not a choosing concern).
|
||||
- **The "Modes-and-down" control strip (moved from Zone).** Every per-sample control that lives
|
||||
on today's Zones param panel for the single-capture case — **Mode** (Gate/Trigger), **Pitch
|
||||
engine** (Varispeed/Preserve), the **AHDSR** sliders (Gate) or **Length%/Fade-in/Fade-out**
|
||||
(Trigger), and the **AD pitch envelope** (Off/On + P.Attack/P.Decay/P.Depth) — renders here as
|
||||
the Sample view's control strip, laid out as a dense labelled value-row (bold micro-caps over a
|
||||
value/slider, the reference grammar). For a single loaded capture this is the same one-zone
|
||||
storage site the S15-F2 lean already established (the empty-map single-capture face reads/writes
|
||||
the same `PerformanceZone` defaults) — no new storage.
|
||||
|
||||
**Browse elements that MOVE to Sample (inventory — nothing silently dropped):** the large
|
||||
waveform preview, the S11 start/loop markers + loop fill, the keyboard-strip root affordance (now
|
||||
the fenced root control), and the Mono/Stereo toggle.
|
||||
|
||||
### View 2 — Browse (reduced to *choosing*, laid over Sample as a modal)
|
||||
|
||||
Browse's only job is **pick a capture**. Today's Browser view is close but overloaded; it is cut
|
||||
to the choosing essentials and rendered as a modal overlay:
|
||||
|
||||
- **Kept (the excellent core, unchanged):** the **type-to-filter search box**, the **bank filter
|
||||
tabs** (All + one per named bank), the **captures grid** (cards: peak thumbnail + name +
|
||||
root/key badge), **scroll** (wheel + thumb), and card **selection**.
|
||||
- **Added:** a **confirm/cancel** affordance (select a card, confirm to load it into Sample and
|
||||
dismiss; cancel to dismiss unchanged) — the modal-picker close semantics. Double-click-to-load
|
||||
is the natural accelerator.
|
||||
- **Removed from Browse (moved to Sample or cut):** the **large waveform preview** (redundant —
|
||||
the grid thumbnails already show every capture's waveform; moved to Sample as the hero); the
|
||||
**Mono/Stereo toggle** (moved to Sample); the **root-note keyboard-strip** in the setup band
|
||||
(moved to Sample as the fenced root control); the **loop-point labels** and the **track-root
|
||||
message** (cut — they waste space and add nothing to *choosing*).
|
||||
|
||||
**Rationale (why cut, not keep-and-hide):** Browse is a picker. Every tuning affordance on it is
|
||||
a mode error — you tune what you *have*, you browse for what you *want*. Concentrating tuning on
|
||||
Sample and choosing on Browse makes each view do one job, and makes the modal overlay light
|
||||
enough to summon and dismiss without ceremony.
|
||||
|
||||
### View 3 — Zone (dedicated keyboard-mapping surface + key-tracking + real piano pattern)
|
||||
|
||||
Zone is the multi-zone keymap editor — RS5K structurally lacks a multi-zone-in-one-instance view,
|
||||
so this is a genuine capability, kept as the deliberate secondary surface. Retains today's Zones
|
||||
view wholesale, with two changes:
|
||||
|
||||
- **Kept (inventory — nothing silently dropped):** **+ Add Zone** / **Delete** buttons, the
|
||||
**keyboard strip with one bar per zone** (selected zone lit accent-primary + static glow, others
|
||||
categorical), the **selected-zone legend** with the three **Low/High/Root numeric-entry fields**
|
||||
(click-to-type, `parseNoteEntry`), and the **per-zone param control panel** (Mode, Pitch engine,
|
||||
AHDSR/Trigger, AD pitch envelope) — the same panel Sample now also hosts for the single-capture
|
||||
case (one storage site, two surfaces).
|
||||
- **NEW — key-tracking parameter (0%–200%, default 100%).** A per-`PerformanceZone` scalar on how
|
||||
sample pitch tracks the keyboard around the root note. **100% = standard 12-tone-ET tracking**
|
||||
(today's behavior, bit-identical); **0% = no tracking** (the sample plays at root pitch on every
|
||||
key — a fixed one-shot); **200% = double-rate tracking**. Additive on `PerformanceZone`,
|
||||
version-bumped, defaulting to 100% so pre-existing zones are unchanged. Applies inside the
|
||||
repitch math in **both** engines: under **Varispeed** it scales the semitone offset feeding
|
||||
`pitchRatio(note, root)` (`effectiveSemis = (note − root) · keyTrack`); under **Preserve** it
|
||||
scales the semitone offset feeding `set_shift(2^(effectiveSemis/12))`. Surfaces as a control in
|
||||
the Zone param panel (and, for the single capture, on the Sample control strip). **The pure
|
||||
sampler core owns the key-track math** (unit-tested: a known note/root/keyTrack triple asserts
|
||||
the expected ratio); the shell only maps the 0–200% control to the scalar.
|
||||
- **NEW — real piano-key pattern on the keyboard strip.** Today's spectral strip is pretty but
|
||||
does not read as a keyboard (Daniel's note). Keep the pastel spectral hue as the backdrop, but
|
||||
**overlay the actual alternating white/black key pattern** — bright cells for naturals, dark
|
||||
cells for accidentals (C#/D#/F#/G#/A#), per the palette (bright ≈ a light neutral, dark ≈
|
||||
`bg/base`/hairline) — so the strip is instantly identifiable as a keyboard. It need not be
|
||||
*shaped* like a keyboard (no protruding black keys); it carries the **pattern** as an overlay,
|
||||
so a glance reads pitch position without counting. The pure `keyboard_strip` geometry gains a
|
||||
`isBlackKey(note)`/per-key-natural query (12-tone pattern, pure + unit-tested); the shell draws
|
||||
the two-tone overlay over the spectral fill. This same strip serves the Sample view's fenced
|
||||
root affordance (one keyboard grammar everywhere).
|
||||
|
||||
### New parameters — ownership and persistence (D-B; instrument-owned, never bank facts)
|
||||
|
||||
- **Key-tracking** — per-`PerformanceZone`, additive/version-bumped component state, default 100%.
|
||||
A **performance choice**, never written to `Sample` or the bank. Back-compat: an absent field on
|
||||
an older blob → 100% (bit-identical playback).
|
||||
- **Preview velocity** — a **utility** setting for the Sample view's preview-trigger button, not a
|
||||
musical parameter of the capture. **Lean: transient editor state** (like a metronome level) —
|
||||
it does not need to persist in component state, so it adds no version bump and no bank-fact risk.
|
||||
*(Fork S-VIEW-F1, Daniel's call: transient vs. a small persisted editor convenience. Lean
|
||||
transient — simplest, no compat surface, and a preview level is not something users expect to
|
||||
survive a reload.)*
|
||||
|
||||
### The envelope overlay — visual component (new)
|
||||
|
||||
The amp envelope drawn as a curve over the Sample view's hero waveform at accurate wall-clock
|
||||
time (the Simpler/Phase-Plant grammar). Gate → the AHDSR shape (attack ramp, hold, decay to
|
||||
sustain, release tail); Trigger → the fade-in/unity/%-length/fade-out shape anchored to `playEnd`.
|
||||
The time base is the same the voice engine resolves (seconds → frames at the live rate), so the
|
||||
drawn shape lines up with the waveform under it. **Pure geometry:** an `envelope_overlay` module
|
||||
(mirror of `waveform_view` / `param_slider`) maps the AHDSR/Trigger params + the sample's
|
||||
frame-length to a polyline in the waveform rect (`param↔pixel` at the shared time base),
|
||||
unit-tested against known param sets; the shell traces it via kit line draws in an accent hue.
|
||||
Decorative + informative — it never captures input (the sliders remain the edit surface); dragging
|
||||
the envelope *nodes* directly is a deferred stretch (fork S-VIEW-F2, lean defer — sliders first,
|
||||
node-drag is polish once the overlay reads).
|
||||
|
||||
### The real piano-key pattern — visual component (new)
|
||||
|
||||
Covered under View 3 above. Pure: `keyboard_strip` gains the natural/accidental predicate; shell
|
||||
draws the bright/dark overlay over the existing pastel spectral fill. Shared by the Zone strip and
|
||||
the Sample root affordance.
|
||||
|
||||
### Engineering prerequisite 1 — drop-to-FX bug (routed to implementation, NOT a design call)
|
||||
|
||||
**Symptom (Daniel):** dropping a capture onto a track's FX chain does not instantiate + init
|
||||
ReaSampler 9000 — the audio-to-arrange drop works, but the "instrument init never fires."
|
||||
|
||||
**SDK sweep (done this pass — no false ceiling asserted):** the S17 drop-to-FX machinery is
|
||||
**present and SDK-correct**. `src/instrument_drop_win.cpp` calls `TrackFX_AddByName(track,
|
||||
"VST3:" + vstPluginName(), /*recFX*/false, /*instantiate*/-1)` then injects component state via
|
||||
`TrackFX_SetNamedConfigParm(track, fx, "vst_chunk", <base64>)`; both signatures + semantics are
|
||||
**verified present** in `reaper_plugin_functions.h` (the `VST3:` prefix, negative-instantiate =
|
||||
always-new, and the `vst_chunk` base64 write-parm are all documented). The gesture is wired
|
||||
(`src/bank_panel.cpp`: `decideGesture` → `InstrumentDrop` → on release `buildInstrumentDropChunk`
|
||||
→ `performInstrumentDrop`), FX-hotspot detection uses `GetThingFromPoint` (`fx_*` prefix), and the
|
||||
factory registers `kInstrumentSynthSampler` correctly. **So the platform CAN do this — the
|
||||
capability is not in question; the wiring is present.** This is therefore a **runtime diagnosis
|
||||
task, not a design decision or a platform-ceiling problem.** The likely fault domains for
|
||||
staff-engineer to investigate (in order):
|
||||
1. **FX-name resolution:** whether REAPER's scanned name for the plugin exactly matches `"VST3:" +
|
||||
vstPluginName()` (a display-name/scan-name mismatch would make `TrackFX_AddByName` return −1).
|
||||
2. **The gesture reaching `performInstrumentDrop`:** whether `decideGesture` actually resolves
|
||||
`InstrumentDrop` over an FX button (vs. falling through to `OsDrag`, which produces exactly the
|
||||
observed "drops as audio into arrange" symptom) — check the `overFxHotspot`/`GetThingFromPoint`
|
||||
path and the single-capture arming guard.
|
||||
3. **The `vst_chunk` write / blob format:** whether `TrackFX_SetNamedConfigParm` returns true and
|
||||
the injected blob matches what `setState` accepts (a format drift would create-then-play-nothing
|
||||
rather than fail to instantiate).
|
||||
|
||||
**Routing:** flagged for **staff-engineer** as a bug diagnosis. No product fork; no redesign
|
||||
gates on it, but it is a **functional prerequisite** for the drop-to-FX gesture to feel finished.
|
||||
**Verify in DAW:** drag a capture onto a track's FX button → a ReaSampler 9000 instance appears on
|
||||
that track already playing that capture (one Ctrl-Z removes it).
|
||||
|
||||
### Engineering prerequisite 2 — default window size for 1080p (routed to implementation)
|
||||
|
||||
**Symptom (Daniel):** the editor window is too small by default; assume a 1080p minimum screen.
|
||||
|
||||
**SDK sweep (done this pass — mechanism verified):** the VST3 editor size is set by the
|
||||
`IPlugView`/`CPluginView` contract. `getSize()` returns the view's `rect` (set via `setRect` — the
|
||||
default the host opens at); `checkSizeConstraint()` is where a minimum is enforced; `onSize()`
|
||||
handles host resizes; `canResize()` already returns `kResultTrue`. **Verified in
|
||||
`vendor/vst3sdk/public.sdk/source/common/pluginview.h`.** Today `ReaSamplerEditor`'s constructor
|
||||
sets `ViewRect(0, 0, 560, 400)` — the undersized default. **The fix is a one-line default change**
|
||||
(a larger initial `ViewRect` sized for the new three-band Sample face on a 1080p display) **plus
|
||||
an optional `checkSizeConstraint` minimum** so the host cannot shrink the window below a usable
|
||||
floor. **This is not a platform limitation — the mechanism exists and is trivial.** The exact
|
||||
default dimensions are a build-time value to set against the Sample face's band heights (hero
|
||||
waveform + control strip want materially more than 400px tall; a ~840×560 or larger default is the
|
||||
starting point, tuned at build). **Routing:** flagged for **staff-engineer**; no product fork.
|
||||
**Verify in DAW:** the editor opens at the new default on a 1080p screen showing the full Sample
|
||||
face without scrolling, and cannot be resized below the constraint floor.
|
||||
|
||||
### Module architecture (preserve the pure/shell split)
|
||||
|
||||
- **Pure (new/extended):** `envelope_overlay` (AHDSR/Trigger params + frame-length → polyline in a
|
||||
rect; unit-tested); `keyboard_strip` extended with the natural/accidental predicate; the sampler
|
||||
core extended with the **key-track scalar** in the repitch math (unit-tested against known
|
||||
note/root/keyTrack → ratio); `sample_map` (`PerformanceZone`) extended with the additive
|
||||
`keyTrack` field + component-state version bump + back-compat default.
|
||||
- **Shell (`reasampler_editor.cpp`):** re-partition the paint/hit-test into the three views
|
||||
(Sample face, Browse modal overlay, Zone surface) replacing the two-view toggle; add the
|
||||
preview-trigger button + velocity knob wired to an off-audio-thread preview note through the
|
||||
voice engine; draw the envelope overlay + piano-key overlay via the kit; set the larger default
|
||||
`ViewRect` + `checkSizeConstraint`. All layout/hit-test math stays in the pure geometry modules.
|
||||
|
||||
### Precision / invariant implications
|
||||
|
||||
- **Read-only bank consumer (unchanged).** Key-tracking, preview velocity, and every marker/mode
|
||||
control are the instrument's **performance map** (D-B) — never written to `Sample` or the bank.
|
||||
- **Additive, back-compat component state.** `keyTrack` is a new optional field defaulting to 100%;
|
||||
an older blob (absent field) restores to 100% → **playback bit-identical** under the same engine.
|
||||
No existing field changes.
|
||||
- **RT discipline (unchanged).** The preview-trigger fires a note through the existing voice engine
|
||||
via the off-audio-thread commit path (`commitMapAndReload` idiom); no new `process`-thread work,
|
||||
no allocation on the audio thread.
|
||||
- **VST3 class UID unchanged.** A view reorganization + additive param is **not** a compat event;
|
||||
saved instances rebind and restore. The UID stays the S-NAME-1/S18 forever-locked identity.
|
||||
- **Capture ≠ placement ≠ playback (unchanged).** The preview-trigger plays; it never captures,
|
||||
never inserts a timeline item. The three acts stay distinct.
|
||||
|
||||
### Open questions / forks (Daniel / Phase S team)
|
||||
|
||||
- **S-VIEW-F1 — preview velocity persistence.** Transient editor state (lean) vs. a small persisted
|
||||
editor convenience. Lean transient — no compat surface, no version bump.
|
||||
- **S-VIEW-F2 — envelope-overlay interactivity.** Read-only informative overlay + sliders as the
|
||||
edit surface (lean, ship first) vs. draggable envelope nodes on the overlay (deferred stretch —
|
||||
polish once the overlay reads).
|
||||
- **S-VIEW-F3 — Browse modal presentation.** Full-window overlay (lean — the modal-picker feel) vs.
|
||||
a large centered sheet with a dimmed Sample behind. Presentation detail; either satisfies "easy
|
||||
to summon and dismiss."
|
||||
|
||||
### Must-verify before build (S-VIEW)
|
||||
|
||||
- **Editor size mechanism** — `getSize`/`setRect`/`checkSizeConstraint`/`onSize`/`canResize`
|
||||
**verified present** in `vendor/vst3sdk/public.sdk/source/common/pluginview.h`; confirm the exact
|
||||
min-size enforcement point (`checkSizeConstraint`) behaves under REAPER's host at build.
|
||||
- **Drop-to-FX** — `TrackFX_AddByName` / `TrackFX_SetNamedConfigParm` / `GetThingFromPoint` all
|
||||
**verified present** in `reaper_plugin_functions.h`; the remaining work is **runtime diagnosis**
|
||||
(name match, gesture routing, blob format), not an SDK question.
|
||||
- **Preview note through the voice engine off-thread** — confirm the existing `commitMapAndReload`
|
||||
/ off-thread reload idiom is the right seam to fire a one-shot preview note without touching
|
||||
`process` on the UI thread; no torn state on the atomic voice-engine pointer.
|
||||
- **Envelope-overlay time base** — confirm the seconds→frames resolution the overlay draws against
|
||||
matches the voice engine's live-rate resolution so the drawn shape lines up with the waveform.
|
||||
|
||||
---
|
||||
|
||||
# Look-and-feel — visual design language (Phase L)
|
||||
@@ -2520,12 +2788,10 @@ slots that persist independent of their occupant, no slot actions, no MIDI-binda
|
||||
no capture-to-slot-N. A slot is just a display position a sample occupies; dragging cards
|
||||
rearranges which sample sits where.
|
||||
|
||||
**M9 overlap (awareness note — unchanged intent).** M9 "slots" (capture-to-slot-N /
|
||||
insert-slot-N, MIDI-bindable, MPC-style) remains **explicitly deferred (Daniel, 2026-07-26).**
|
||||
The interchangeable substrate L7 builds still *eases* a future M9 revival — it lays the
|
||||
addressable-position groundwork M9 would sit on — but L7 adds **no** slot-numbered capture/insert
|
||||
actions and **no** MIDI bindings. The "plain vs. M9-shaped" sub-fork is closed: plain
|
||||
gap-preserving substrate, per F2 above.
|
||||
**M9 note.** M9 "slots" (capture-to-slot-N / insert-slot-N, MIDI-bindable, MPC-style) is
|
||||
**abandoned (Daniel, 2026-07-27)** — will not be built. L7 adds **no** slot-numbered
|
||||
capture/insert actions and **no** MIDI bindings. The "plain vs. M9-shaped" sub-fork is closed:
|
||||
plain gap-preserving substrate, per F2 above.
|
||||
|
||||
### 2. Decorative metadata overlay (bars.beats · s.ms)
|
||||
|
||||
@@ -2656,20 +2922,18 @@ overlay/selection-border draw. The L1 kit draws; no palette/font decision re-ope
|
||||
|
||||
## The L3 gate + Phase S coordination contract
|
||||
|
||||
**L3 (VST editor + embed-strip restyle) is GATED on Phase S landing on dev.** The VST
|
||||
editor (`IPlugView` LICE surface), the S6 embed strip, and the keyboard strip live in
|
||||
Phase S, which is **not on dev yet** (it exists on the phase-s worktree). L3 cannot be
|
||||
built on dev until Phase S's editor/embed surfaces (≈ S1 / S6 / S10) merge to dev — **the
|
||||
Phase L team must not chase these files on dev; they are not there.** Until then L3 is a
|
||||
planned, blocked point; L1, L2, L4, L5, L6, and **L7 have all landed** — see `COMPLETED.md`.
|
||||
L4, L5, L6, and L7 are independent of the L3 gate.
|
||||
**L3 (VST editor + embed-strip restyle) has landed (merged `c53683e`, 2026-07-27).** The
|
||||
Phase S surfaces (`reasampler_editor.cpp` + `reasampler_embed.cpp`) arrived on dev drawing
|
||||
flat `LICE_FillRect` blocks + raw GDI `DrawTextA`, off a local pre-L1 forest-green palette
|
||||
— the coordination contract's "born in the kit" branch did not occur — so L3 performed a
|
||||
full restyle of both draw shells through the L1 kit. **L1, L2, L3, L4, L5, L6, and L7
|
||||
have all landed — see `COMPLETED.md`. Phase L is complete.** The Phase Q gate condition
|
||||
"Phase S + L3 merged to dev" is now satisfied.
|
||||
|
||||
**Coordination contract (load-bearing):** Phase S's S10–S13 build their interaction UX with
|
||||
the **current** drawing and **adopt the L1 kit when it is available — they are NOT gated on
|
||||
Phase L.** Whichever lands first (the L1 kit or the S10–S13 UX), the kit is the **one source
|
||||
of drawing**: if S10–S13 reach dev before L1, they draw in the current language and L3
|
||||
restyles them; if L1 lands first, they are born in the kit. Either way there is one kit and
|
||||
one look; L3 completes the VST/embed adoption and applies the settled-and-revised **B +
|
||||
**Coordination contract (load-bearing — resolved):** Phase S's S10–S13 built their
|
||||
interaction UX with the current drawing and adopted the L1 kit via L3 (the coordination
|
||||
contract's "L3 restyles them" branch). There is now one kit and one look across both
|
||||
artifacts; L3 completed the VST/embed adoption and applied the settled-and-revised **B +
|
||||
three-accent pastel** treatment (with C's **pastel** spectral keyboard strip as the
|
||||
signature surface), routing text through the kit's cached-font `text()` (§3.1 — the kit's
|
||||
current face; no font change). The VST3 class UID is unchanged — a visual refresh is not a
|
||||
@@ -2925,8 +3189,9 @@ and **(2) Phase L L3** merged to dev (the VST restyle, itself gated on Phase S).
|
||||
have already landed** (see `COMPLETED.md`) — the earlier "L2 + L3" wording was stale and is
|
||||
corrected to **L3 only**. **D2** is functionally complete (D2-W1..W3-B landed; its lone open item,
|
||||
a per-track lane-split panel indicator, is *explicitly deferred*, not a blocking residual). **M9**
|
||||
(slots) is *explicitly deferred* (Daniel, 2026-07-26), not scheduled work. D2 and M9 are named here
|
||||
only so that *reactivating* either re-arms the quiescence condition; neither blocks the gate today.
|
||||
(slots) is **abandoned** (Daniel, 2026-07-27) — will not be built. D2 is named here only so that
|
||||
*reactivating* its deferred panel indicator re-arms the quiescence condition; neither D2 nor M9
|
||||
blocks the gate today.
|
||||
*Why:* Phase Q touches **nearly every file in `src/`** (relocate, re-namespace, split the four
|
||||
largest TUs, plus the §2b renames); every large in-flight branch (Phase S on its worktree, L3 once
|
||||
it lands) is diffed against the *current flat layout*, so landing a rename-and-relocate-everything
|
||||
@@ -2935,10 +3200,8 @@ re-resolution, not a linear one. Phase Q is *last* precisely because it reshapes
|
||||
other pillar stands on: landing it early taxes every subsequent phase; landing it last taxes
|
||||
nothing. Re-confirm quiescence against dev before Q-W1.
|
||||
|
||||
> **M9 disposition (Daniel-decision note).** "Deferred indefinitely" ≠ "abandoned." Immaterial to
|
||||
> the gate (both clear it); matters only if M9 is reactivated — *before* Phase Q it lands cheaply on
|
||||
> the flat layout, *after* it is authored against the reorganized tree. Surfaced, not silently
|
||||
> resolved (full note: `docs/product/code-organization.md` §4).
|
||||
> **M9 disposition — resolved (Daniel, 2026-07-27): abandoned.** M9 is out; it will not be
|
||||
> reactivated. The gate remains satisfied; no re-arm condition applies.
|
||||
|
||||
## Wave sequencing (each independently landable, CTest-green at every step)
|
||||
|
||||
@@ -2991,7 +3254,7 @@ every commit), a property only an *incremental* reorg uses. Risk-ordered:
|
||||
the thumbnail path is noted but **not touched** — reworking it risks the hot path.
|
||||
- **No big-bang commit.** Every wave is independently landable and CTest-green; reject a change set
|
||||
that cannot be verified at each step.
|
||||
- **Do not begin before the GATE.** Re-confirm the tree is quiescent (Phase S + L + D2 + M9
|
||||
merged/closed) before any Q point.
|
||||
- **Do not begin before the GATE.** Re-confirm the tree is quiescent (Phase S + L + D2 merged/closed;
|
||||
M9 abandoned) before any Q point.
|
||||
- **Verify** the CMake `src/` path updates and the SWELL/LICE surfaces still resolve after
|
||||
relocation, as the existing build already requires.
|
||||
|
||||
@@ -16,8 +16,7 @@ it here and appends it to `COMPLETED.md`.
|
||||
|
||||
## Milestone 9 — slots (MPC-style)
|
||||
|
||||
> **Explicitly deferred (Daniel, 2026-07-26) — not silently dropped. Can be picked
|
||||
> up later if wanted.** An extra, not scheduled work.
|
||||
> **Abandoned (Daniel, 2026-07-27) — will not be built.**
|
||||
|
||||
**Goal:** "Capture to slot N" / "insert slot N", MIDI-bindable. CONTEXT.md
|
||||
Build order 9.
|
||||
@@ -177,6 +176,99 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
|
||||
*cut* (choke) on note-off or on a same-group re-trigger (hi-hat open/closed). Deliberately
|
||||
out of S15 scope (Trigger ignores note-off entirely there); a Tier-3 choke-group direction.
|
||||
|
||||
## Phase S — editor view-model redesign (three views: Sample / Browse / Zone)
|
||||
|
||||
> **Additive Phase S sub-phase (S-VIEW; Daniel, 2026-07-27, r9).** Re-partitions the ReaSampler
|
||||
> 9000 editor from a two-view toggle into a **three-view model where the loaded sample is the
|
||||
> home** — Sample (default face), Browse (modal picker over Sample), Zone (dedicated keymap
|
||||
> surface). Adds two performance parameters (key-tracking, preview velocity) and two visual
|
||||
> components (envelope overlay, real piano-key pattern), and frames two engineering prerequisites
|
||||
> (drop-to-FX bug, default window size). An **editor** redesign — the S3 voice engine, keymap
|
||||
> resolution, and read-only-over-bank contract are **unchanged**; component state extends
|
||||
> additively for key-tracking; VST3 class UID unchanged. Authoritative spec: **CONTEXT.md §Phase
|
||||
> S — editor view-model redesign (S-VIEW)**. Product framing: `docs/product/midi-playback.md`
|
||||
> §Addendum r9. When a point lands, doc-keeper moves it to `COMPLETED.md`.
|
||||
>
|
||||
> **Depends on Phase S being on dev** (this redesigns Phase S editor shells —
|
||||
> `reasampler_editor.cpp` + the pure `src/vst/` geometry modules). The Phase L L3 restyle and
|
||||
> this S-VIEW redesign both touch the editor; sequence so they do not collide (S-VIEW is a
|
||||
> layout/param change, L3 is a palette/kit change — best landed as one editor pass or S-VIEW then
|
||||
> L3-restyle-the-new-layout).
|
||||
|
||||
**Goal:** A three-view editor that makes "pick a capture, tune it, play it" fast, easy, and fun —
|
||||
Sample is home, Browse is an easy-to-summon modal picker, Zone is the deliberate keymap surface.
|
||||
**Verify (in DAW):** open on a 1080p screen → full Sample face (hero waveform + envelope overlay +
|
||||
fenced root + preview-trigger + control strip) with no scroll; Browse opens as a modal over
|
||||
Sample, select+confirm loads a new capture; Zone opens on its own button, key-tracking + the
|
||||
piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance.
|
||||
|
||||
- [ ] **S-VIEW-1 — three-view navigation model.** Retire the flat Browser|Zones toggle; introduce
|
||||
Sample (home/default), Browse (modal overlay over Sample, select+confirm), Zone (dedicated
|
||||
surface, own button). Empty state surfaces Browse as the dominant call-to-action. Fresh instance
|
||||
stays silent (S10 reversal). See CONTEXT.md §S-VIEW navigation contract.
|
||||
- [ ] **S-VIEW-2 — Sample view (the new main face).** Compose the home face: enlarged **hero
|
||||
waveform** with the S11 markers (moved from Browse), a **fenced root affordance**, the
|
||||
**Mono/Stereo toggle** (moved from Browse), and the **"Modes-and-down" control strip** (Mode /
|
||||
Pitch engine / AHDSR|Trigger / AD pitch env — moved from Zone's param panel, single-capture
|
||||
one-zone storage per S15-F2). Reference grammar: Simpler / Phase Plant (labelled value-strip
|
||||
under a hero waveform).
|
||||
- [ ] **S-VIEW-3 — envelope overlay on the hero waveform (new visual).** Draw the amp envelope
|
||||
(AHDSR for Gate, fade/%-length for Trigger) as a curve over the Sample waveform at accurate
|
||||
wall-clock time. New pure `envelope_overlay` module (params + frame-length → polyline; unit-
|
||||
tested); shell traces it in an accent hue. Informative + decorative — sliders stay the edit
|
||||
surface (node-drag deferred, fork S-VIEW-F2).
|
||||
- [ ] **S-VIEW-4 — preview-trigger + velocity knob (new, Sample view).** A button firing the
|
||||
sampler at the loaded capture's root note through the live voice engine (off the audio-thread
|
||||
commit path — no MIDI controller needed) + an adjacent velocity knob. Preview velocity leans
|
||||
**transient editor state** (fork S-VIEW-F1). RT discipline: no `process`-thread work.
|
||||
- [ ] **S-VIEW-5 — Browse reduced to *choosing* (modal over Sample).** Keep search + bank tabs +
|
||||
captures grid + scroll + selection; add **confirm/cancel** (double-click loads). **Remove** the
|
||||
large waveform preview, Mono/Stereo toggle, root keyboard-strip (all moved to Sample), and the
|
||||
loop-point labels + track-root message (cut). Render as a full-window modal overlay (fork
|
||||
S-VIEW-F3).
|
||||
- [ ] **S-VIEW-6 — key-tracking parameter (Zone + Sample, 0%–200%, default 100%).** A per-
|
||||
`PerformanceZone` scalar on keyboard pitch tracking around the root (100% = 12-tone-ET, 0% = no
|
||||
tracking, 200% = double). Additive/version-bumped, defaults 100% (bit-identical). **Key-track
|
||||
math lives in the pure sampler core** (unit-tested note/root/keyTrack → ratio), applied in both
|
||||
Varispeed and Preserve repitch. Surfaces as a control on the Zone param panel + Sample control
|
||||
strip.
|
||||
- [ ] **S-VIEW-7 — real piano-key pattern on the keyboard strip (new visual).** Overlay the actual
|
||||
alternating white/black (bright/dark per palette) key pattern over the pastel spectral fill so
|
||||
the strip reads as a keyboard. Pure `keyboard_strip` gains a natural/accidental predicate (12-
|
||||
tone, unit-tested); shell draws the two-tone overlay. Shared by the Zone strip + Sample root
|
||||
affordance.
|
||||
- [ ] **S-VIEW-8 — Zone view retained + wired.** Keep +Add Zone / Delete, the per-zone keyboard
|
||||
strip (now with the piano pattern), the Low/High/Root numeric-entry legend, and the per-zone
|
||||
param panel; add the key-tracking control. Nothing from today's Zones view dropped.
|
||||
|
||||
### Phase S editor prerequisites — routed to staff-engineer (bug + default; NOT design forks)
|
||||
|
||||
> Framed in CONTEXT.md §S-VIEW; both are functional prerequisites with the SDK swept and no
|
||||
> platform ceiling — a diagnosis and a one-line default, not product decisions.
|
||||
|
||||
- [ ] **S-VIEW-BUG-1 — drop-to-FX diagnosis (staff-engineer).** Dropping a capture onto a track's
|
||||
FX chain does not instantiate + init ReaSampler 9000 (drops as audio to arrange instead). The
|
||||
S17 machinery is **SDK-correct and present** (`TrackFX_AddByName` + `vst_chunk` injection, all
|
||||
verified); this is a **runtime bug**. Investigate in order: (1) FX-name match (`"VST3:" +
|
||||
vstPluginName()` vs REAPER's scanned name); (2) gesture routing (`decideGesture` →
|
||||
`InstrumentDrop` vs falling to `OsDrag` — the observed symptom); (3) `vst_chunk` write result +
|
||||
blob-format match with `setState`. **Verify in DAW:** drop → a playing instance on the track,
|
||||
one Ctrl-Z removes it.
|
||||
- [ ] **S-VIEW-SIZE-1 — 1080p default window size (staff-engineer).** The editor opens too small
|
||||
(`ViewRect(0,0,560,400)`). Mechanism **verified** (`getSize`/`setRect`/`checkSizeConstraint`/
|
||||
`onSize`/`canResize` in `vendor/vst3sdk/public.sdk/source/common/pluginview.h`): set a larger
|
||||
default `ViewRect` sized for the new three-band Sample face on 1080p (~840×560+ starting point,
|
||||
tuned to the band heights) + a `checkSizeConstraint` minimum floor. **Verify in DAW:** opens at
|
||||
the new default showing the full Sample face without scroll; cannot shrink below the floor.
|
||||
|
||||
### Phase S editor redesign — forks (Daniel's to call)
|
||||
- **S-VIEW-F1 — preview velocity persistence:** transient editor state (**lean**) vs. a small
|
||||
persisted convenience. Lean transient — no compat surface, no version bump.
|
||||
- **S-VIEW-F2 — envelope-overlay interactivity:** read-only overlay + sliders edit (**lean**, ship
|
||||
first) vs. draggable envelope nodes (deferred stretch).
|
||||
- **S-VIEW-F3 — Browse modal presentation:** full-window overlay (**lean**) vs. a centered sheet
|
||||
over a dimmed Sample. Presentation detail.
|
||||
|
||||
---
|
||||
|
||||
# Phase L — Look-and-feel (system-wide visual design language)
|
||||
@@ -194,13 +286,17 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
|
||||
> directions: `docs/product/visual-design-language.md`. When a point lands, doc-keeper
|
||||
> moves it to `COMPLETED.md`.
|
||||
>
|
||||
> **L1 (shared LICE drawing kit — the foundation), L2 (dock-panel layout redesign), L4
|
||||
> (dock-panel button layout enhancement), L5 (dock-panel button refinements), L6 (toolbar
|
||||
> polish), and L7 (capture ordering, card metadata, and selection styling) have landed** —
|
||||
> **L1 (shared LICE drawing kit — the foundation), L2 (dock-panel layout redesign), L3
|
||||
> (VST editor + embed-strip restyle), L4 (dock-panel button layout enhancement), L5
|
||||
> (dock-panel button refinements), L6 (toolbar polish), and L7 (capture ordering, card
|
||||
> metadata, and selection styling) have all landed** —
|
||||
> `theme`/palette module, `component_geometry` geometry/hit-test helpers, `draw_kit` shell, GDI
|
||||
> `DrawText` retirement in `bank_panel` (L1); `action_bar` pure task-grouped layout module, full
|
||||
> M11-aware button inventory placed by task cluster, `bank_panel` redesigned through the L1 kit
|
||||
> (L2); three-zone layout (top capture/placement/maintenance toolbar, bottom Design-View toolbar,
|
||||
> (L2); VST editor (`reasampler_editor.cpp`) + embed strip (`reasampler_embed.cpp`) restyled
|
||||
> through the L1 kit — REAPER-grey neutrals + three pastel accents, pastel spectral keyboard
|
||||
> strip + zone bars, hover/pressed/drag states, local `kCol*` forest-green palette retired (L3);
|
||||
> three-zone layout (top capture/placement/maintenance toolbar, bottom Design-View toolbar,
|
||||
> footer toggle + Tail button + Prune), `footer_bar` pure module, `ActionCluster::Tagging`/
|
||||
> `Switching` in `action_bar` (L4); top-bar overflow menu (`overflow_menu` pure module),
|
||||
> custom LICE-kit hover-delay tooltips (`tooltip` pure module), opposite-mode Item/Track tag
|
||||
@@ -209,7 +305,7 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
|
||||
> Cancel RT moved to overflow, top-bar cluster order tidied (L6); per-bank `SlotMap`
|
||||
> (id→slot) in `bank_book`, sparse-grid rendering, `card_drag` + `card_meta` pure modules,
|
||||
> `captureTimeSigNum`/`captureTimeSigDenom` on `Sample`, tertiary-border selection (L7). See
|
||||
> `COMPLETED.md`. **L3 remains** — L3 gated on Phase S landing on dev.
|
||||
> `COMPLETED.md`. **Phase L is complete.**
|
||||
>
|
||||
> **This section is self-contained for a team without Phase S context.** Where a point
|
||||
> touches a Phase S surface (the VST editor, the embed strip, the keyboard strip), the
|
||||
@@ -245,84 +341,16 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
|
||||
> out the full button inventory (including M11's action-button additions) intuitively,
|
||||
> uncluttered, and useful — then applies the kit. Sequenced after M11 merges.
|
||||
|
||||
## L3 — VST editor + embed-strip restyle (GATED on Phase S landing on dev)
|
||||
**Goal:** Bring the ReaSampler 9000 VST editor (`IPlugView` LICE surface) and the S6 embed
|
||||
strip up to the settled-and-revised **B + three-accent pastel** look via the L1 kit: kit
|
||||
cached-font text (§3.1 — the kit's current face, no font change), kit component draws, the
|
||||
Neon-Console palette with **REAPER-grey neutrals** (`#2b2b2b`/`#333333`/`#3a3a3a`) and the
|
||||
**three pastel accents** (primary lime / secondary teal / tertiary purple), the **pastel
|
||||
spectral keyboard strip** as the signature surface (DS-2
|
||||
revised), and hover/pressed/drag states throughout. CONTEXT.md §Phase L (VST restyle + the
|
||||
Phase S coordination contract). Product framing: `docs/product/visual-design-language.md` §5.3.
|
||||
**Verify (in DAW):** the VST editor + embed strip render in the settled B + three-accent
|
||||
pastel language through the L1 kit — kit AA cached-font text, gradient/rounded kit
|
||||
components, the pastel spectral keyboard strip, working hover/pressed/drag; the VST3 class
|
||||
UID is unchanged (a visual refresh is not a compat event).
|
||||
**Depends on:** L1 (the kit) **AND — GATE — Phase S landing on dev.** The VST editor, embed
|
||||
strip, and keyboard strip live in Phase S, which is **not on dev yet** (it exists on the
|
||||
phase-s worktree). **L3 cannot be built on dev until Phase S's drawing shells
|
||||
(`src/vst/reasampler_editor.cpp` + `reasampler_embed.cpp`) merge to dev. The Phase L team
|
||||
must NOT chase these files on dev — they are not there.** Until then L3 is a planned,
|
||||
blocked point; L1 and L2 are the live Phase L work.
|
||||
|
||||
> **Coordination contract with Phase S (load-bearing).** Phase S's editor/embed UX
|
||||
> (S10–S13, S15–S18) build their interaction UX with the **current** drawing and **adopt the
|
||||
> L1 kit when it is available — they are NOT gated on Phase L.** Whichever lands first (the
|
||||
> L1 kit or the Phase S UX), the kit is the **one source of drawing**: if the Phase S
|
||||
> surfaces reach dev before L1, they draw in the current language and L3 restyles them; if
|
||||
> L1 lands first, they are born in the kit. **Reality check (product-designer, 2026-07-27,
|
||||
> read-only against the phase-s worktree): the Phase S surfaces did NOT adopt the kit —
|
||||
> `reasampler_editor.cpp` and `reasampler_embed.cpp` still draw flat `LICE_FillRect` blocks
|
||||
> + raw GDI `DrawTextA`, off a local pre-L1 forest-green palette (`kColBackground` etc.),
|
||||
> not `theme`/`draw_kit`.** So L3 lands as a **full restyle**, not a born-in-kit no-op — all
|
||||
> three plan points below are live and confirmed still-needed. Either way there is one kit
|
||||
> and one look, and L3 is the point that completes the VST/embed adoption and applies the
|
||||
> settled B+spectral treatment.
|
||||
>
|
||||
> **Landed-scope note (product-designer, 2026-07-27).** All Phase S drawing is centralized
|
||||
> in **exactly two shells** — `reasampler_editor.cpp` (the `IPlugView` editor) and
|
||||
> `reasampler_embed.cpp` (the S6 embed strip). Every other `src/vst/` UI file
|
||||
> (`editor_geometry`, `keyboard_strip`, `waveform_view`, `capture_browser`, `param_slider`,
|
||||
> `browser_scroll`, `embed_strip`) is a **pure geometry/hit-test module — zero LICE, zero
|
||||
> draw** (the house discipline held on the branch). So L3 touches two draw shells, but their
|
||||
> rendered component set is broader than the original plan named: the editor draws a
|
||||
> **capture-first browser** (search + tabs + thumbnails, S10), **channel toggles** (S7),
|
||||
> **waveform + start/loop markers** (S11), the **keyboard strip + zone bars** (S10/S10-Z),
|
||||
> and **ADSR / pitch sliders + mode toggles** (S12/S15/S16). Every one of these is on the
|
||||
> restyle surface — enumerated in the points below.
|
||||
|
||||
- [ ] Route the VST editor's + embed strip's text through the kit's cached-font `text()`
|
||||
(the kit's current face — §3.1, no font change); retire their raw GDI `DrawTextA` path
|
||||
(present in both shells today). (Gated — Phase S surfaces must be on dev.)
|
||||
- [ ] Retire the shells' **local pre-L1 palette** — the `kColBackground`/`kColCardBg`/
|
||||
`kColThumb`/… forest-green-on-charcoal constants block in `reasampler_editor.cpp` (and the
|
||||
mirrored constants in `reasampler_embed.cpp`) — and draw every surface through the L1
|
||||
`theme` roles instead. **This is the coordination-contract reconcile: today there are two
|
||||
palettes (the landed `theme` kit + this local constants block); L3 collapses them to the
|
||||
one kit.** (Gated.)
|
||||
- [ ] Restyle the editor + embed components through the kit (browser search/tabs/thumbnails,
|
||||
channel toggles, ADSR + pitch sliders, mode toggles, zone bars, list rows, waveform,
|
||||
segmented controls) in the B (Neon Console) palette — **REAPER-grey neutrals** (`bg/base`
|
||||
`#2b2b2b` / `bg/panel` `#333333` / `bg/cell` `#3a3a3a`) with the **three pastel accents**
|
||||
(primary lime = live layer; secondary teal / tertiary purple = categorical); add
|
||||
hover/pressed/drag states. (Gated.)
|
||||
- [ ] Apply **Direction C's pastel spectral treatment to the keyboard strip + zone bars**
|
||||
(hue-mapped zones as a pastel sweep anchored on the three accents, active zone lifting to
|
||||
`accent/primary` + a static glow — never a pulse, per the speed constraint) as the
|
||||
signature surface; also carry the waveform + loop/start markers onto the kit's
|
||||
`drawWaveform` + `warn`/accent marker roles; VST3 class UID unchanged. (Gated.)
|
||||
|
||||
## Phase L — sequencing
|
||||
```
|
||||
L1 (shared kit) ──► L2 (dock-panel layout redesign) [LANDED]
|
||||
├─────────► L3 (VST editor + embed-strip restyle; GATED on Phase S landing on dev)
|
||||
├─────────► L3 (VST editor + embed-strip restyle) [LANDED]
|
||||
└─────────► L4 (dock-panel button layout enhancement) [LANDED]
|
||||
└────► L5 (dock-panel button refinements; ungated, after L4) [LANDED]
|
||||
└────► L6 (toolbar polish; ungated, after L5) [LANDED]
|
||||
└────► L7 (capture ordering + card metadata + selection styling; ungated, after L6) [LANDED]
|
||||
```
|
||||
L1, L2, L4, L5, L6, and L7 have all landed. L3 waits for Phase S to reach dev. Phase S
|
||||
feature work runs in parallel, ungated by Phase L.
|
||||
L1, L2, L3, L4, L5, L6, and L7 have all landed. **Phase L is complete.**
|
||||
|
||||
## Phase L — must-verify-before-build
|
||||
- **LICE design-kit surfaces (L1)** — `LICE_GradRect`, `LICE_RoundRect`, AA
|
||||
@@ -352,23 +380,6 @@ feature work runs in parallel, ungated by Phase L.
|
||||
cursors chosen for drop-result cues (Reorder→IDC_SIZEALL, Move→IDC_HAND, Copy→IDC_UPARROW,
|
||||
Replace→IDC_SIZEWE); existing pool-privilege guard reused as-is for Alt-replace. Gap navigation
|
||||
in the grid = skip gaps (arrow keys skip empty slots). See `COMPLETED.md` §L7.
|
||||
- **L3 restyle surface (L3)** — **PRE-CONFIRMED read-only against the phase-s worktree
|
||||
(product-designer, 2026-07-27); re-confirm against dev once Phase S merges.** (1) Both draw
|
||||
shells (`reasampler_editor.cpp`, `reasampler_embed.cpp`) still draw flat — `LICE_FillRect` +
|
||||
raw GDI `DrawTextA`, no `theme`/`draw_kit`/`LICE_CachedFont` include — so all three L3 points
|
||||
are live (no born-in-kit no-op). (2) There is a **second palette** to reconcile: a local
|
||||
`kCol*` forest-green-on-charcoal constants block in the editor shell, divergent from the
|
||||
landed `theme` roles. (3) Draw is centralized in those two shells only; every other
|
||||
`src/vst/` UI file is pure geometry (kit adoption is a shell-side change, no geometry
|
||||
rework). (4) The phase-s branch carries an **older L1 kit** (its `action_bar` predates dev's
|
||||
L4–L7 `theme` palette revisions) — after Phase S merges, L3 draws against dev's current
|
||||
`theme`/`draw_kit`, so re-confirm the palette roles L3 consumes are dev's, not the branch's
|
||||
stale copy. **The single open question is now RESOLVED (Daniel, 2026-07-27):** the S18 beta
|
||||
channel title band gets **no distinct visual accent** — L3 restyles the title band in the
|
||||
standard B pastel palette, and the beta-vs-stable distinction stays **purely textual** (the
|
||||
channel-derived plugin name, as today), no channel-specific accent color. With that closed,
|
||||
the settled DS-1/2/3 spec forces the rest.
|
||||
|
||||
---
|
||||
|
||||
# Phase Q — Quality (structural reorganization; zero-runtime-cost)
|
||||
@@ -388,29 +399,26 @@ feature work runs in parallel, ungated by Phase L.
|
||||
>
|
||||
> **THE GATE (load-bearing — state first; reconciled to reality 2026-07-27).** Phase Q is
|
||||
> **gated on the tree being otherwise quiescent.** Daniel's plain readiness target: **"when
|
||||
> Phase S and L3 are finished."** As of 2026-07-27 the outstanding work is precisely: **(1)
|
||||
> Phase S** merged to dev (the large second-artifact branch, currently on the phase-s worktree —
|
||||
> the dominant gate item); **(2) Phase L L3** merged to dev (the VST restyle, itself gated on
|
||||
> Phase S landing on dev). **L1/L2/L4/L5/L6/L7 have already landed** (see `COMPLETED.md`) — the
|
||||
> earlier "L2 + L3" wording was stale and is corrected here to **L3 only**. **D2** is functionally
|
||||
> complete (D2-W1..W3-B landed; the lone open item, a per-track lane-split panel indicator, is
|
||||
> *explicitly deferred*, not a blocking residual). **M9** (slots) is *explicitly deferred*
|
||||
> (Daniel, 2026-07-26), not scheduled work. D2 and M9 are named in the gate only so that
|
||||
> *reactivating* either re-arms the quiescence condition; neither blocks the gate today. *Why the
|
||||
> gate:* Phase Q touches **nearly every file in `src/`** (relocate into subdirectories,
|
||||
> re-namespace every header, split the four largest TUs, plus the §2b renames). Every large
|
||||
> in-flight branch (Phase S on its worktree, and L3 once it lands) is diffed against the *current
|
||||
> flat layout*; landing a rename-and-relocate-everything reorg mid-flight forces every open branch
|
||||
> through the worst conflict class (every hunk moved, every qualified reference changed) — a
|
||||
> combinatorial re-resolution, not a linear one. Phase Q is *last* precisely because it reshapes
|
||||
> the ground every other pillar stands on. Landing it early taxes every subsequent phase; landing
|
||||
> it last taxes nothing. **Do not begin any Q point until the gate is satisfied.**
|
||||
> Phase S and L3 are finished."** **As of 2026-07-27 both gate conditions are satisfied:**
|
||||
> Phase S merged to dev (2026-07-27); Phase L L3 (the VST restyle) merged to dev
|
||||
> (2026-07-27, commit `c53683e`) — **Phase L is complete** (L1/L2/L3/L4/L5/L6/L7 all
|
||||
> landed, see `COMPLETED.md`). **D2** is functionally complete (D2-W1..W3-B landed; the
|
||||
> lone open item, a per-track lane-split panel indicator, is *explicitly deferred*, not a
|
||||
> blocking residual). **M9** (slots) is **abandoned** (Daniel, 2026-07-27) — will not be
|
||||
> built. D2 is named in the gate only so that *reactivating* its deferred panel indicator
|
||||
> re-arms the quiescence condition; neither D2 nor M9 blocks the gate today. *Why the gate:* Phase Q
|
||||
> touches **nearly every file in `src/`** (relocate into subdirectories, re-namespace every
|
||||
> header, split the four largest TUs, plus the §2b renames). Every large in-flight branch
|
||||
> (Phase S on its worktree, and L3 once it lands) is diffed against the *current flat
|
||||
> layout*; landing a rename-and-relocate-everything reorg mid-flight forces every open
|
||||
> branch through the worst conflict class (every hunk moved, every qualified reference
|
||||
> changed) — a combinatorial re-resolution, not a linear one. Phase Q is *last* precisely
|
||||
> because it reshapes the ground every other pillar stands on. Landing it early taxes every
|
||||
> subsequent phase; landing it last taxes nothing. **The gate is now satisfied — Phase Q
|
||||
> may begin.**
|
||||
>
|
||||
> **M9 disposition (Daniel-decision note).** M9 is recorded "deferred indefinitely," which is not
|
||||
> the same as "abandoned." Immaterial to the gate (both clear it). It matters only if M9 is ever
|
||||
> reactivated: *before* Phase Q it lands cheaply on the flat layout; *after*, it is authored
|
||||
> against the reorganized tree. Surfaced, not silently resolved — no action unless Daniel schedules
|
||||
> M9. (Full note: `docs/product/code-organization.md` §4.)
|
||||
> **M9 disposition — resolved (Daniel, 2026-07-27): abandoned.** M9 is out; it will not be
|
||||
> reactivated. The gate remains satisfied; no re-arm condition applies.
|
||||
>
|
||||
> **Settled (Q-1, this-doc):** the phase is **`Q` (Quality)**; point-id family `Q1..Qn`, wave
|
||||
> prefixes `Q-W1..Q-W6`. **Recommended, Daniel's to call (Q-2..Q-9, see
|
||||
@@ -612,8 +620,8 @@ droppable point if the phase needs narrowing (Q-6).
|
||||
|
||||
## Phase Q — sequencing
|
||||
```
|
||||
GATE: Phase S + Phase L L3 merged to dev (D2 complete, M9 deferred) — tree quiescent
|
||||
("when Phase S and L3 are finished" — L1/L2/L4–L7 already landed)
|
||||
GATE: Phase S + Phase L L3 merged to dev (D2 complete, M9 abandoned) — tree quiescent
|
||||
("when Phase S and L3 are finished" — L1/L2/L3/L4–L7 all landed — GATE SATISFIED)
|
||||
│
|
||||
▼
|
||||
Q-W1 (safe opener: core/json extract + directory/namespace layout on clean modules)
|
||||
@@ -646,5 +654,4 @@ is independently landable and CTest-green.
|
||||
or VST3 class UID is renamed (naming audit §2b.5). A rename that would alter a shipped contract
|
||||
literal is out of scope, full stop.
|
||||
- **The GATE** — do not begin any Q point until **Phase S + Phase L L3** are merged to dev and the
|
||||
tree is quiescent (D2 complete, M9 deferred; a reactivation of either re-arms the gate).
|
||||
Re-confirm quiescence against dev before W1.
|
||||
tree is quiescent (D2 complete, M9 abandoned). Re-confirm quiescence against dev before W1.
|
||||
|
||||
@@ -965,6 +965,119 @@ adds only the identity fork on top.
|
||||
|
||||
---
|
||||
|
||||
### Addendum — three-view editor model + drop-to-FX + default window size (Daniel, 2026-07-27, r9)
|
||||
|
||||
**Framing.** Daniel opened a fresh design pass on the ReaSampler 9000 **editor** after living
|
||||
with the S10–S18 UX in the DAW. The instrument *works* and the capture browser is genuinely
|
||||
good — but the two-view editor (today's "Browser" + "Zones" toggle) misallocates its space,
|
||||
the default window is undersized for a 1080p world, and the drop-a-capture-onto-FX gesture is
|
||||
broken in practice. The directive: **make the one job — pick a capture, tune it, play it —
|
||||
fast, easy, and fun. Style is a critical ingredient. No spreadsheet aesthetics.** These are the
|
||||
`r9` calls. Authoritative spec: **CONTEXT.md §Phase S — editor view-model redesign (S-VIEW)**;
|
||||
build roadmap: **PLAN.md §Phase S — editor view-model redesign**.
|
||||
|
||||
**The reference devices (the north star for control density).** Daniel named Ableton **Simpler**
|
||||
and a Kilohearts/Phase-Plant **sampler group** as the composition targets. Both share one
|
||||
grammar, and it is the grammar the redesign adopts:
|
||||
|
||||
- **A large waveform up top is the hero**, with markers and the envelope drawn *over it at
|
||||
accurate time* — not a separate abstract envelope box. Simpler shades the sustain-loop region
|
||||
teal directly on the waveform; Phase Plant traces the amp envelope as a bright curve across the
|
||||
sample. The waveform is where the eye lives.
|
||||
- **A thin, dense value-strip of labelled controls** sits under the waveform (Simpler's
|
||||
Gain/Start/Loop/Length/Fade ribbon; Phase Plant's LEVEL/SEMI/HARMONIC/SHIFT/PHASE row) — bold
|
||||
ALL-CAPS micro-labels over a value, compact, scannable in one pass.
|
||||
- **Root note is fenced off as its own affordance** (Phase Plant boxes "Root C 4 +00" and an
|
||||
"Offset" knob to the right; Simpler puts Key% and Transp in the pitch cluster). Root is not
|
||||
buried in a list of sliders — it is a first-class, always-visible control.
|
||||
- **Modular horizontal bands.** Each concern (sample/pitch, then envelope) is its own band with
|
||||
its own drawn visual. This is how both devices avoid the spreadsheet look: every band leads
|
||||
with a *picture* (waveform, filter curve, envelope shape), and the numbers hang off it.
|
||||
|
||||
**The three calls (r9).**
|
||||
|
||||
1. **Three views, not two — and they are NOT a flat toggle.** Today "Browser" and "Zone" sit as
|
||||
two equal segments. That framing is wrong: it implies the browser and the zone editor are
|
||||
peers, when in truth **the loaded sample is the home** and browsing/zoning are things you
|
||||
*reach for*. So: **Sample is the home view** (the default face — the hero waveform, the
|
||||
envelope overlay, all the per-sample controls). **Browse** is a **modal page layered over
|
||||
Sample** — a full-window overlay you summon to change the loaded capture (select + confirm),
|
||||
the way a file-open sheet layers over a document. **Zone** is a **dedicated editing surface**
|
||||
opened by its own button when you want to map across the keyboard. This is a
|
||||
*document-with-modal-picker* model (Simpler's own shape: the device face is the sample, and
|
||||
loading a new one is a distinct act), not a three-way radio. *Why the reframe matters:* it
|
||||
makes "I just want to play this capture" the zero-click default, and "I want a different one"
|
||||
a single deliberate gesture, instead of making the user re-choose their whole stance every
|
||||
time. See CONTEXT.md §S-VIEW for the precise navigation model.
|
||||
|
||||
2. **The Sample view earns the hero treatment; Browse gets ruthlessly cut.** Browse today
|
||||
carries a waveform preview, root-note piano-roll, loop-point labels, a track-root message, and
|
||||
a Mono/Stereo toggle — all of which are *tuning* concerns, not *choosing* concerns. Browse's
|
||||
only job is **pick a capture**; the grid thumbnails already show the waveform, so every one of
|
||||
those tuning affordances moves to Sample (where the hero waveform lives) and Browse shrinks to
|
||||
filters + grid + select/confirm. Conversely, Sample **gains a new envelope overlay** drawn on
|
||||
the hero waveform at accurate time (the Simpler/Phase-Plant move), a **preview-trigger button +
|
||||
velocity knob** (audition the sample at its root without a MIDI controller — the single most
|
||||
"fun/fast" affordance the current editor lacks), and inherits the Mono/Stereo toggle and every
|
||||
"Modes-and-down" control that lives on Zone today.
|
||||
|
||||
3. **Two engineering prerequisites, framed but routed to implementation.** The **drop-to-FX bug**
|
||||
(dropping a capture onto a track's FX chain does not instantiate + init ReaSampler 9000) and
|
||||
the **undersized default window** are not design decisions — they are a bug and a one-line
|
||||
default. Both are framed in CONTEXT.md §S-VIEW with the SDK reality swept (drop-to-FX: the S17
|
||||
machinery is SDK-correct, so this is a *diagnosis* task, not a redesign; window size: the
|
||||
`getSize`/`checkSizeConstraint` mechanism is verified), and both are flagged for
|
||||
staff-engineer, not for a product fork.
|
||||
|
||||
**New parameters this introduces (both instrument performance state, D-B — never bank facts):**
|
||||
|
||||
- **Key-tracking (Zone view).** A 0%–200% scalar on how sample pitch tracks the keyboard around
|
||||
the root note. **100% (default) = standard 12-tone equal-temperament tracking** (a semitone up
|
||||
the keyboard = a semitone of repitch — exactly today's behavior). 0% = the sample plays at root
|
||||
pitch on every key (a fixed, un-tracked one-shot — the classic drum-machine "no tracking"
|
||||
mode). 200% = double-rate tracking (an octave of keyboard spans two octaves of pitch — an
|
||||
intentional special effect). This is a *per-zone performance choice*, additive on
|
||||
`PerformanceZone`, defaulting to 100% so existing playback is bit-identical. It is the sampler
|
||||
idiom every serious sampler has (RS5K's "Pitch for start/end note", Kontakt's "Tracking",
|
||||
Simpler's "Key %" — visible in the reference screenshot at "Key 100%"). *Why 200% and not
|
||||
higher:* the useful musical range is 0–200%; past 200% it is noise, and a bounded slider reads
|
||||
cleaner than an open one.
|
||||
- **Preview velocity (Sample view).** The velocity level the preview-trigger button fires at,
|
||||
set by an adjacent knob. Not persisted as a musical parameter of the sample — it is a
|
||||
*utility* setting for the audition button (like a metronome level), so it can live as
|
||||
transient editor state or a small persisted convenience; the spec leans transient (see
|
||||
§S-VIEW). This is what makes the preview button *fun*: tap it hard or soft without reaching for
|
||||
a controller.
|
||||
|
||||
**Two visual components the redesign commits to:**
|
||||
|
||||
- **The envelope overlay** on the Sample view's hero waveform: the amp envelope (AHDSR for Gate,
|
||||
the fade/%-length shape for Trigger) drawn as a curve *at accurate wall-clock time* across the
|
||||
waveform, the way Simpler draws its amp envelope over the sample and Phase Plant traces it in
|
||||
bright blue. This is the single biggest "reads like a real sampler, not a spreadsheet" move —
|
||||
the envelope stops being four abstract sliders and becomes a *shape you see over the sound*.
|
||||
The sliders stay (precise entry), but the picture leads.
|
||||
- **The real piano-keyboard pattern** on the Zone view's keyboard strip. Today's spectral strip
|
||||
is pretty but does not *read as a keyboard* — Daniel's note. The redesign keeps the pastel
|
||||
spectral hue but overlays the **actual alternating white/black key pattern** (bright/dark per
|
||||
the palette) so the strip is instantly identifiable as a keyboard. It need not be *shaped* like
|
||||
a keyboard (no protruding black keys) — just carry the pattern as an overlay, so a glance reads
|
||||
"this is C, this is F#" without counting.
|
||||
|
||||
**What does NOT change (guardrails restated).** The instrument stays a **read-only bank
|
||||
consumer** — every new control (key-tracking, preview velocity, the loop/start markers Sample
|
||||
inherits) is *performance map*, never written to `Sample` or the bank (D-B). LICE/SWELL drawing
|
||||
only, all layout/hit-test in pure geometry modules (D-A). RT discipline untouched — the
|
||||
preview-trigger fires a note through the same voice engine off the audio-thread commit path, no
|
||||
new audio-thread work. The VST3 class UID is unchanged — a view reorganization is not a compat
|
||||
event. And this is an *editor* redesign: the S3 voice engine, the keymap resolution, the
|
||||
component-state format (extended additively for key-tracking) are the same load-bearing core.
|
||||
|
||||
**Where the spec lives:** CONTEXT.md §Phase S — editor view-model redesign (S-VIEW); PLAN.md
|
||||
§Phase S — editor view-model redesign. This Addendum is the *why*; those are the *what/how*.
|
||||
|
||||
---
|
||||
|
||||
## Where this landed
|
||||
|
||||
With D1/D5/D6 locked and **D-A..D-D all settled (2026-07-26)**, the instrument is scoped
|
||||
|
||||
Reference in New Issue
Block a user