instrument: fix AHD node-tracking/tie-break/live-latch defects and close staged-envelope-curve test gaps

This commit is contained in:
2026-07-31 09:52:17 -04:00
parent d60ab1524a
commit 2fa1405b06
27 changed files with 360 additions and 86 deletions
+26 -2
View File
@@ -54,6 +54,29 @@ namespace {
constexpr double kEnvTimeMaxSeconds = instrument::ui::kGateStageMaxSeconds;
constexpr double kPitchDepthMaxSemis = 24.0; // pitch depth throw: +/-24 st, centered
constexpr double kKeyTrackMax = 2.0; // key-track slider ceiling (0..200%)
// The raw stored curve exponent for a curve-dial control id, read DIRECTLY off the field —
// never round-tripped through curveFromKnobNorm(knobNormFromCurve(x)): the knob-norm law's
// centre detent (curve_law.h) snaps anything near-neutral back to exactly 1.0, so a round trip
// can misreport a stored exponent that isn't neutral as "^1.00".
double curveExponentFor(int id, const PlaySeconds& play) {
using DeckParam = instrument::ui::DeckParam; // ReaSamplerEditor::ParamControl is an alias
switch (static_cast<DeckParam>(id)) {
case DeckParam::kAttackCurve: return play.adsr.attackCurve;
case DeckParam::kDecayCurve: return play.adsr.decayCurve;
case DeckParam::kReleaseCurve: return play.adsr.releaseCurve;
case DeckParam::kTrigAttackCurve: return play.trigAhd.attackCurve;
case DeckParam::kTrigDecayCurve: return play.trigAhd.decayCurve;
case DeckParam::kPitchEnvAttackCurve: return play.pitchEnv.shape.attackCurve;
case DeckParam::kPitchEnvDecayCurve: return play.pitchEnv.shape.decayCurve;
case DeckParam::kFilterEnvAttackCurve: return play.filter.env.attackCurve;
case DeckParam::kFilterEnvDecayCurve: return play.filter.env.decayCurve;
case DeckParam::kFilterEnvReleaseCurve: return play.filter.env.releaseCurve;
case DeckParam::kFilterTrigAttackCurve: return play.filter.trigEnv.attackCurve;
case DeckParam::kFilterTrigDecayCurve: return play.filter.trigEnv.decayCurve;
default: return util::kCurveNeutral;
}
}
} // namespace
ReaSamplerEditor::FaceLayout ReaSamplerEditor::faceLayout(int w, int h) const {
@@ -373,7 +396,7 @@ std::string ReaSamplerEditor::deckValueLabel(int id) const {
case ParamControl::kFilterEnvReleaseCurve:
case ParamControl::kFilterTrigAttackCurve:
case ParamControl::kFilterTrigDecayCurve:
snprintf(buf, sizeof(buf), "^%.2f", util::curveFromKnobNorm(controlValue(id, play)));
snprintf(buf, sizeof(buf), "^%.2f", curveExponentFor(id, play));
break;
default:
// -2 (preview velocity) is labeled at its chrome call site; nothing else here.
@@ -461,10 +484,11 @@ StageEnvelope ReaSamplerEditor::packEnvelope(OverlayEnv which, const PlaySeconds
else packAhdsr(play.filter.env, env);
break;
case OverlayEnv::kAmp:
case OverlayEnv::kNone:
if (trigger) packAhd(play.trigAhd, t0, playSpan, env);
else packAhdsr(play.adsr, env);
break;
case OverlayEnv::kNone:
break; // nothing is overlay-active; a default-constructed StageEnvelope, not amp
}
return env;
}