From 88c122fcb4b5a81fc3659f516628686a34898d3c Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Mon, 27 Jul 2026 19:38:03 -0400 Subject: [PATCH] fix(zone-view): Add Zone seeds narrow octave range so new zones survive reconcile --- src/vst/reasampler_editor.cpp | 20 +++++++++++++++----- src/vst/reasampler_processor.cpp | 2 +- src/vst/sample_map.h | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/vst/reasampler_editor.cpp b/src/vst/reasampler_editor.cpp index 91ee7e1..a4b3b8a 100644 --- a/src/vst/reasampler_editor.cpp +++ b/src/vst/reasampler_editor.cpp @@ -1943,10 +1943,13 @@ void ReaSamplerEditor::onMouseDown(int x, int y) { Rect addR{content.left + pad, content.top + 4, content.left + pad + 96, content.top + 4 + 20}; if (contains(addR, x, y)) { - // Add a full-keyboard zone for the picked capture (or the first visible sample as a + // Add a narrow default zone for the picked capture (or the first visible sample as a // sensible seed). No pick -> nothing to add. If a full-keyboard zone for the seed id - // already exists, select it rather than appending a duplicate (mirrors the upsert the - // root-marker drag path already performs, preventing overlapping identical zones). + // already exists (pre-fix bleed survivor), select it rather than appending a duplicate + // (mirrors the upsert the root-marker drag path already performs). + // NARROW DEFAULT: seed [root-6, root+5] (one octave centred on the bank root, clamped + // to [0,127]) so the new zone is immediately "authored" (narrow) and survives + // reconcileSingleCaptureZones without being treated as a Sample-face full-range zone. std::string seed = !selectedId_.empty() ? selectedId_ : (!visible_.empty() ? visible_.front().id : std::string()); if (seed.empty()) return; @@ -1958,10 +1961,17 @@ void ReaSamplerEditor::onMouseDown(int x, int y) { return; } } + // Look up the seed's root note from the browser list (absent root defaults to 60). + int seedRoot = 60; + for (const SampleChoice& sc : samples_) { + if (sc.id == seed) { if (sc.rootNote.has_value()) seedRoot = *sc.rootNote; break; } + } + const int lo = (std::max)(0, seedRoot - 6); + const int hi = (std::min)(127, seedRoot + 5); PerformanceZone z; z.sampleId = seed; - z.lowNote = 0; - z.highNote = 127; + z.lowNote = lo; + z.highNote = hi; map_.zones.push_back(z); selectedZone_ = static_cast(map_.zones.size()) - 1; commitAndReload(); diff --git a/src/vst/reasampler_processor.cpp b/src/vst/reasampler_processor.cpp index 0f2fff2..d5801bf 100644 --- a/src/vst/reasampler_processor.cpp +++ b/src/vst/reasampler_processor.cpp @@ -188,7 +188,7 @@ tresult PLUGIN_API ReaSamplerProcessor::setState(IBStream* state) { // editor shows is the sample the engine plays" for already-affected projects; authored // Zone-view maps (any narrow key range) pass through untouched. PerformanceMap restored = cs.map; - reconcileSingleCaptureZones(restored, cs.selectionId); + reconcileSingleCaptureZones(restored, cs.selectionId); // bool return ignored: setPerformanceMap + reloadFromBank run unconditionally on load setPerformanceMap(restored); // S8: restore the last-consumed assignment generation so a re-open does not re-apply a // stale assign_request (the user may have manually changed the selection after the assign). diff --git a/src/vst/sample_map.h b/src/vst/sample_map.h index 28eedf0..14980eb 100644 --- a/src/vst/sample_map.h +++ b/src/vst/sample_map.h @@ -252,7 +252,7 @@ struct PerformanceMap { // authorship; first-match order is load-bearing there — untouched, false. The Sample // face never creates a narrow zone, so a narrow zone proves deliberate multi-zone intent. // * else (every zone full-range — the map is purely Sample-face-shaped): keep only the -// first zone bound to `selectedId` (its params survive a return to that sample); drop +// first zone bound to `selectedId` (the selection's own params are not reset); drop // the rest. A selection with no zone yet empties the map (the shell then plays the // selection via the Tier-0 fast path with product defaults). // Returns true iff the map changed (the caller republishes + reloads on true).