instrument: latch the note done at the read-head run-off, fit the migrated fades, and lift the curve dial and overlay selection into pure modules

This commit is contained in:
2026-07-31 09:17:04 -04:00
parent 13e8c5c4d9
commit d60ab1524a
18 changed files with 575 additions and 129 deletions
+26
View File
@@ -191,6 +191,32 @@ bool isLiveDeckParam(DeckParam id) {
return false; // unreachable for a valid enumerator; silences a warning.
}
OverlayEnv overlayEnvForRadio(int radioId) {
switch (static_cast<DeckParam>(radioId)) {
case DeckParam::kAmpEnvSelect: return OverlayEnv::kAmp;
case DeckParam::kPitchEnvSelect: return OverlayEnv::kPitch;
case DeckParam::kFilterEnvSelect: return OverlayEnv::kFilter;
default: return OverlayEnv::kNone;
}
}
OverlayEnv nextOverlaySelection(OverlayEnv current, int radioId) {
const OverlayEnv picked = overlayEnvForRadio(radioId);
if (picked == OverlayEnv::kNone) return current; // not a radio: nothing selects
return (current == picked) ? OverlayEnv::kNone : picked;
}
bool overlayEnvInert(OverlayEnv env, bool pitchEnvEnabled, bool filterEnabled) {
switch (env) {
case OverlayEnv::kPitch: return !pitchEnvEnabled;
case OverlayEnv::kFilter: return !filterEnabled;
case OverlayEnv::kAmp:
case OverlayEnv::kNone:
return false;
}
return false; // unreachable for a valid enumerator; silences a warning.
}
bool liveCommitFor(LiveDragKind kind, int paramId) {
switch (kind) {
case LiveDragKind::kDeckKnob:
+19
View File
@@ -133,6 +133,25 @@ enum class LiveDragKind { kOther, kDeckKnob, kEnvNode };
// can reach — AHDSR or AHD, on any of the three envelopes — is itself live.
bool liveCommitFor(LiveDragKind kind, int paramId);
// Which envelope the waveform overlay draws and edits. Exclusive across the three envelope
// decks, and kNone is a valid resting state — the editor opens there. Transient view state:
// never persisted, never a parameter.
enum class OverlayEnv { kNone, kAmp, kPitch, kFilter };
// The envelope a deck's overlay-select radio picks; kNone for any other control id.
OverlayEnv overlayEnvForRadio(int radioId);
// The selection a click on `radioId` produces from `current`. Two rules, provable here rather
// than in the shell: picking another deck's radio switches to it (exclusivity), and clicking
// the ACTIVE one clears back to kNone — "no envelope shown" is a state the user can get back
// to, not an error. A non-radio id leaves the selection alone.
OverlayEnv nextOverlaySelection(OverlayEnv current, int radioId);
// Whether the overlay for `env` is INERT: its deck group's enable toggle is off, so its knobs
// are drawn-but-dead and a node drag on the same params must be too — otherwise a drag reaches
// a param a knob couldn't (envelope_edit.h). Amp has no enable toggle and is never inert.
bool overlayEnvInert(OverlayEnv env, bool pitchEnvEnabled, bool filterEnabled);
// The deck's BIPOLAR knob law: 0.5 of the knob's travel is zero depth, the ends are -1 and
// +1. Exact inverses, and exact at the centre detent (0.5 -> 0 -> 0.5), so a knob parked at
// centre can never persist a hair of modulation. Out-of-range norm clamps to the endpoints.