fix(zone-view): Add Zone seeds narrow octave range so new zones survive reconcile

This commit is contained in:
2026-07-27 19:38:03 -04:00
parent 7fd812bd34
commit 88c122fcb4
3 changed files with 17 additions and 7 deletions
+15 -5
View File
@@ -1943,10 +1943,13 @@ void ReaSamplerEditor::onMouseDown(int x, int y) {
Rect addR{content.left + pad, content.top + 4, content.left + pad + 96, Rect addR{content.left + pad, content.top + 4, content.left + pad + 96,
content.top + 4 + 20}; content.top + 4 + 20};
if (contains(addR, x, y)) { 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 // 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 // already exists (pre-fix bleed survivor), select it rather than appending a duplicate
// root-marker drag path already performs, preventing overlapping identical zones). // (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_ std::string seed = !selectedId_.empty() ? selectedId_
: (!visible_.empty() ? visible_.front().id : std::string()); : (!visible_.empty() ? visible_.front().id : std::string());
if (seed.empty()) return; if (seed.empty()) return;
@@ -1958,10 +1961,17 @@ void ReaSamplerEditor::onMouseDown(int x, int y) {
return; 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; PerformanceZone z;
z.sampleId = seed; z.sampleId = seed;
z.lowNote = 0; z.lowNote = lo;
z.highNote = 127; z.highNote = hi;
map_.zones.push_back(z); map_.zones.push_back(z);
selectedZone_ = static_cast<int>(map_.zones.size()) - 1; selectedZone_ = static_cast<int>(map_.zones.size()) - 1;
commitAndReload(); commitAndReload();
+1 -1
View File
@@ -188,7 +188,7 @@ tresult PLUGIN_API ReaSamplerProcessor::setState(IBStream* state) {
// editor shows is the sample the engine plays" for already-affected projects; authored // editor shows is the sample the engine plays" for already-affected projects; authored
// Zone-view maps (any narrow key range) pass through untouched. // Zone-view maps (any narrow key range) pass through untouched.
PerformanceMap restored = cs.map; PerformanceMap restored = cs.map;
reconcileSingleCaptureZones(restored, cs.selectionId); reconcileSingleCaptureZones(restored, cs.selectionId); // bool return ignored: setPerformanceMap + reloadFromBank run unconditionally on load
setPerformanceMap(restored); setPerformanceMap(restored);
// S8: restore the last-consumed assignment generation so a re-open does not re-apply a // 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). // stale assign_request (the user may have manually changed the selection after the assign).
+1 -1
View File
@@ -252,7 +252,7 @@ struct PerformanceMap {
// authorship; first-match order is load-bearing there — untouched, false. The Sample // 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. // 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 // * 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 // 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). // selection via the Tier-0 fast path with product defaults).
// Returns true iff the map changed (the caller republishes + reloads on true). // Returns true iff the map changed (the caller republishes + reloads on true).