fix: S12 R2 — marker-drag sets selectedZone_, ADSR rate-resolve, gateAdsr doc

Marker drag now sets selectedZone_ so single-capture controls stay reachable. Lifted/default ADSR rescales nominal 44100-Hz frame counts by sampleRate/44100 via adsrNeedsRateResolve; v4-authored zones skip rescale. gateAdsr documented vestigial.
This commit is contained in:
2026-07-27 02:01:43 -04:00
parent 7fb778206c
commit 1d338318e7
7 changed files with 192 additions and 41 deletions
+37 -18
View File
@@ -269,32 +269,31 @@ ReaSamplerEditor::SetupMarkers ReaSamplerEditor::pickedMarkers(std::int64_t fram
return m;
}
void ReaSamplerEditor::upsertPickedOverride(const SetupMarkers& m) {
int ReaSamplerEditor::upsertPickedOverride(const SetupMarkers& m) {
// Find-or-append the zone for selectedId_ and write the loop/start override fields.
// The bank intrinsic is NEVER written (read-only bank consumer, D-B). selectedId_ must
// be non-empty; callers are responsible for that guard.
// Returns the zone index (0-based) so callers can update selectedZone_.
SampleLoop loop;
loop.hasLoop = m.hasLoop;
loop.start = m.loopStart;
loop.end = m.loopEnd;
bool found = false;
for (PerformanceZone& z : map_.zones) {
for (int i = 0; i < static_cast<int>(map_.zones.size()); ++i) {
PerformanceZone& z = map_.zones[static_cast<std::size_t>(i)];
if (z.sampleId == selectedId_) {
z.loopOverride = loop;
z.startPoint = m.start;
found = true;
break;
return i;
}
}
if (!found) {
PerformanceZone z;
z.sampleId = selectedId_;
z.lowNote = 0;
z.highNote = 127;
z.loopOverride = loop;
z.startPoint = m.start;
map_.zones.push_back(z);
}
PerformanceZone z;
z.sampleId = selectedId_;
z.lowNote = 0;
z.highNote = 127;
z.loopOverride = loop;
z.startPoint = m.start;
map_.zones.push_back(z);
return static_cast<int>(map_.zones.size()) - 1;
}
namespace {
@@ -1322,6 +1321,14 @@ void ReaSamplerEditor::onMouseDown(int x, int y) {
dragParamPanel_ = panel;
dragStartMap_ = map_;
applyControl(id, z.play, valueAtPoint(r.control, x), 0);
// An explicit ADSR slider touch commits a rate-resolved value (the slider
// maps 0..1 -> editor-domain frames at kEnvTimeMaxFrames, not nominal 44100-Hz
// counts). Mark the zone as no longer needing rate-resolve so buildZonedKeymap
// does not re-rescale the value at reload time.
if (id >= static_cast<int>(ParamControl::kAttack) &&
id <= static_cast<int>(ParamControl::kRelease)) {
z.adsrNeedsRateResolve = false;
}
invalidate(); // live feedback; commit on WM_LBUTTONUP
}
break;
@@ -1352,9 +1359,18 @@ void ReaSamplerEditor::onMouseMove(int x, int y) {
// zone over the whole keyboard) and round-trips through the v3 component state; the
// zone becomes visible if the user opens the Zones panel. Upsert by the picked id so a
// repeated drag edits the same zone rather than stacking duplicates.
// Upsert the root override on the picked id; track the zone index so the control panel
// stays visible after the zone is materialized on the single-capture face (fix: without
// setting selectedZone_ here, selectedZone_==-1 with a non-empty map hides controls).
bool found = false;
for (PerformanceZone& z : map_.zones) {
if (z.sampleId == selectedId_) { z.rootOverride = note; found = true; break; }
for (int i = 0; i < static_cast<int>(map_.zones.size()); ++i) {
PerformanceZone& z = map_.zones[static_cast<std::size_t>(i)];
if (z.sampleId == selectedId_) {
z.rootOverride = note;
selectedZone_ = i;
found = true;
break;
}
}
if (!found) {
PerformanceZone z;
@@ -1363,6 +1379,7 @@ void ReaSamplerEditor::onMouseMove(int x, int y) {
z.highNote = 127;
z.rootOverride = note;
map_.zones.push_back(z);
selectedZone_ = static_cast<int>(map_.zones.size()) - 1;
}
invalidate(); // live feedback; the commit lands on WM_LBUTTONUP
return;
@@ -1407,8 +1424,10 @@ void ReaSamplerEditor::onMouseMove(int x, int y) {
if (m.start > frames - 1) m.start = frames - 1;
// Upsert the override on the picked id (mirror of the root-marker path); commit lands on
// release, this is live feedback.
upsertPickedOverride(m);
// release, this is live feedback. Set selectedZone_ so the control panel stays visible
// after the zone is materialized (fix: without this, selectedZone_==-1 with a non-empty
// map hides controls after the first marker drag on the single-capture face).
selectedZone_ = upsertPickedOverride(m);
invalidate();
return;
}