docs: record GA DAW-fix pass (Preserve SOLA, voice declick, stereo bus-pin+v9, .vstpreset drop-fx, drag-out, panel toggle); correct stale vst_chunk mechanism

This commit is contained in:
2026-07-28 07:12:07 -04:00
parent 3e3b79d78a
commit e99bdcf264
3 changed files with 101 additions and 43 deletions
+82 -12
View File
@@ -2256,16 +2256,18 @@ is dragged from the `bank_panel`, a track's TCP **FX button** lights as a drop z
and dropping there instantiates a **ReaSampler 9000** on that track with the dragged
capture **already loaded and selected** for playback. A third `DragGesture` —
`InstrumentDrop` — added to the `drag_out` pure module. Mechanism: `TrackFX_AddByName` +
VST3 component-state injection via `TrackFX_SetNamedConfigParm(..., "vst_chunk", blob)`.
The shared `instrument_drop` pure module constructs the blob via the instrument's own
`sample_map::serializeComponentState`/`deserializeComponentState` — one serializer called
from both artifacts, so the blob format cannot drift. CONTEXT-ARCHIVE.md §Phase S (drop-and-load).
VST3 component-state injection via a Steinberg-format `.vstpreset` file built by
`instrument_drop` (applied via `TrackFX_SetPreset`). The `instrument_drop` pure module
constructs the `.vstpreset` image from the instrument's own
`sample_map::serializeComponentState` — one serializer called from both artifacts, so the
byte format cannot drift. CONTEXT-ARCHIVE.md §Phase S (drop-and-load). (`vst_chunk` write
was the original planned mechanism but is silently unappliable for VST3 — replaced by
`.vstpreset` + `TrackFX_SetPreset`, GA DAW-fix pass 2026-07-28.)
**Verify (in DAW):** dragging a single capture from the dock over a track's FX button
highlights it; dropping instantiates ReaSampler 9000 on that track with the dragged
capture loaded, selected, and MIDI-playable immediately; OS drag-out to Explorer still works
unchanged; internal bank-to-bank drag still works unchanged; no media item ever inserted
into the arrange. DAW-verify: whether REAPER's `vst_chunk` write-parm expects the plugin's
raw IComponent-state bytes or wraps them in a REAPER container header.
into the arrange. **VERIFIED (GA DAW-fix pass 2026-07-28).**
**Depends on:** M11 (`drag_out` gesture machinery), Phase S S4, the load-capture seam
(VST3 component-state injection — the shared blob contract).
@@ -2290,18 +2292,21 @@ raw IComponent-state bytes or wraps them in a REAPER container header.
- [x] **ReaSampler 9000 load-capture seam:** the instrument's existing `setState`/`getState`
already round-trip the full `ComponentState` via
`sample_map::serializeComponentState`/`deserializeComponentState` (S10). The extension
REUSES that exact serializer through the new pure `instrument_drop` module
(`buildInstrumentDropChunk` → `serializeComponentState` → base64). The shared-writer
REUSES that exact serializer through the new pure `instrument_drop` module (builds a
Steinberg-format `.vstpreset` image: 'VST3' header + 'Comp' chunk = serialized component
state, addressed to `vstClassIdHex()`; applied via `TrackFX_SetPreset`). The shared-writer
requirement is met STRUCTURALLY — the blob format cannot drift. Pure round-trip test decodes
back through the instrument's own reader and asserts the capture is selected.
**`instrument_drop` lives at `src/instrument_drop.{h,cpp}`** (extension-side pure module);
CTest target `instrument_drop_tests`.
CTest target `instrument_drop_tests`. (`TrackFX_SetNamedConfigParm` "vst_chunk" was the
original mechanism but is silently unappliable for VST3 — REAPER's wrapper cannot apply
unframed raw component-state bytes; replaced by the `.vstpreset` path, S-GA-DropFX.)
- [x] Tests: gesture disambiguation (inside-panel / over-REAPER-UI / left-REAPER) across
single- and multi-capture payloads; M11 OS drag-out and internal bank-to-bank drag both
unchanged. `test_drag_out.cpp` adds the InstrumentDrop cases with M11 cases retained as
the non-regression guard; `test_instrument_drop.cpp` is the blob round-trip + base64 codec
coverage. FX hit resolution is REAPER-API-bound (`GetThingFromPoint`) — DAW-verified in the
shell, not pure-tested (noted honestly).
the non-regression guard; `test_instrument_drop.cpp` covers the `.vstpreset` image
round-trip (structure, class-ID, chunk offset/size). FX hit resolution is REAPER-API-bound
(`GetThingFromPoint`) — DAW-verified in the shell, not pure-tested (noted honestly).
**Notes/decisions:**
- `resetDragState()` consolidation in `bank_panel` (prior drift cleaned up this wave).
@@ -2773,3 +2778,68 @@ Zone-authoring affordances intact; no regression on the Sample face.
- **Phase S editor Wave B complete.** S-VIEW-11 (knob deck + curve popup, FB1), S-VIEW-12
(full-width hero + master gain, FB1), and S-VIEW-13 (Zone-panel parity, FB2) are all landed.
No open r11 or S-VIEW Wave B items remain in PLAN.md.
---
## GA post-launch DAW-fix pass (2026-07-28)
> **Merged to dev 2026-07-28. Integrated suite 55/55 green.** Six fixes found during
> GA DAW testing — not tracked as PLAN points. PLAN.md has no corresponding entries to move.
**Preserve pitch engine (SOLA rewrite):** `pitch_shift` rewritten from a dual-tap OLA (taps hard-locked
half a window apart — fixed relative phase causes anti-phase cancellation on many source frequencies,
producing spectral garbage on repitched notes) to **correlation-aligned SOLA splices**: one active read
tap chases the write head at the shift ratio; each splice jump is refined by a cross-correlation search
so the new read point is waveform-aligned, then old and new taps are crossfaded with a raised-cosine,
amplitude-complementary fade. Clean pitch shift past +24 st; a repitched pure sine stays a single tone.
**Voice takeover declick:** `Voice::start` gained a `takeoverDeclick` parameter (gated on the envelope
complement, applied when the flag is true) to remove the click at mono retrig/fallback and poly at-cap
steal boundaries. The "steal-all" symptom observed in DAW was diagnosed as no-loop sample exhaustion
under Preserve (voices played to silence, not stolen); the engine steals exactly one voice per note-on
as designed.
**Stereo bus pin + channel-mode auto-default:** The output bus is now **permanently stereo** — the
dynamic mono↔stereo bus renegotiation that hard-panned dual-mono is deleted. `ChannelMode` is
decode-only (controls downmix vs. dual-mono on WAV decode). Channel mode **auto-defaults from the
loaded capture's channel count** via `channelModeFor()` (pure helper in `sample_map`) when the user
has not explicitly toggled it; explicit toggle latches the preference. `ComponentState` bumped **v8→v9**:
`channelModeExplicit` bool added; pre-v9 blobs treat the stored mode byte as an explicit preference
(no auto-override).
**Drop-to-FX injection fix:** Injection switched from `TrackFX_SetNamedConfigParm(..., "vst_chunk",
<base64>)` (silently unappliable for VST3 — REAPER's wrapper cannot accept unframed component-state
bytes) to a **Steinberg-format `.vstpreset` file** whose 'Comp' chunk is the serialized component
state, applied via `TrackFX_SetPreset`. The `instrument_drop` pure module builds the `.vstpreset`
image; `instrument_drop_win` writes a transient temp file and calls `TrackFX_SetPreset`. FX hotspot
now prefix-matches `tcp.fx*`/`mcp.fx*`/`fx_*` (embed strip tokens excluded). `reasampler_uid.h`
split out of `reasampler_vst.h` as an SDK-free header so `instrument_drop` can derive the class-ID
hex string without the VST3 SDK.
**Drag-out arm fix:** `SetCapture` moved to drag-arm (the `dragArmed` branch of `handleClick` in
`bank_panel`) so a first straight-out drag — pointer leaving the client rect before a second click
— correctly arms and fires the OS drag-out. Previously `SetCapture` was called only after the drag
threshold was crossed inside the panel, so a fast straight-out drag on the first attempt received no
`WM_MOUSEMOVE` messages outside the client rect and the gesture never transitioned to the OS drag.
**Panel mode-toggle repaint:** The Design/Arrange mode-toggle actions (`doToggleMode` /
`doActivateMode` in `actions.cpp`) now call `bankPanelInvalidate()` after applying the mode switch.
Previously the panel footer `[Arrange|Design]` toggle only repainted on a button click inside the
panel, not when the mode was changed via the registered action (e.g. from the Actions list or a
keybinding).
- [x] `pitch_shift`: dual-tap OLA replaced by correlation-aligned SOLA; CTest `pitch_shift_tests`
updated to assert single-tone output on repitched sine.
- [x] `sampler_core` `Voice::start`: `takeoverDeclick` parameter added; mono retrig/fallback + poly
at-cap steal pass `true`; `PreviewCard` and standard voices pass the flag correctly.
- [x] `reasampler_processor`: output bus permanently stereo; `channelModeExplicit_` member added;
`channelModeFor()` called on `reloadFromBank` when not explicit; `ComponentState` v8→v9
(`channelModeExplicit` byte); pre-v9 lift treats stored mode as explicit.
- [x] `instrument_drop`: `.vstpreset` image builder replacing `vst_chunk` base64 path; `vstClassIdHex()`
sourced from `reasampler_uid.h`; `instrument_drop_tests` covers preset image structure round-trip.
- [x] `reasampler_uid.h`: new SDK-free header in `src/vst/` owning the frozen class-UID macros;
`reasampler_vst.h` and `instrument_drop` both source from it.
- [x] `instrument_drop_win`: FX hotspot prefix-set extended (`tcp.fx*`/`mcp.fx*`/`fx_*`); transient
`.vstpreset` write + `TrackFX_SetPreset` call replaces `TrackFX_SetNamedConfigParm` "vst_chunk".
- [x] `bank_panel`: `SetCapture` moved to drag-arm branch; `bankPanelInvalidate()` called from
`actions.cpp` after mode-toggle actions.