deck: filter mod moves to FILTER ENV, cell runs centre in their reserves, two-segment toggles become single buttons, deck focuses its overlay

This commit is contained in:
2026-08-03 13:12:28 -04:00
parent 0eb2c67875
commit 450559f155
22 changed files with 885 additions and 504 deletions
+51
View File
@@ -400,8 +400,59 @@ static void testTheFilterFourKeepTheirIdentityTaper() {
}
}
// The single-button commit seam. A one-button toggle carries no segment, so the commit derives
// the NEXT state from the parameter set and hands it to setDeckParam's unchanged segment
// contract. Driven end-to-end — derive, apply, re-derive — because the property that matters is
// that repeated clicks alternate the stored field rather than latching it.
static void testASingleButtonsDerivedSegmentFlipsTheFieldItNames() {
PlaySeconds p;
// Enables: off by default, so the first derived segment must be ON.
CHECK(!p.pitchEnv.enabled);
CHECK(nextToggleSegment(DeckParam::kPitchEnvEnable, p) == 1);
setDeckParam(DeckParam::kPitchEnvEnable, p, 0.0,
nextToggleSegment(DeckParam::kPitchEnvEnable, p));
CHECK(p.pitchEnv.enabled);
CHECK(nextToggleSegment(DeckParam::kPitchEnvEnable, p) == 0);
setDeckParam(DeckParam::kPitchEnvEnable, p, 0.0,
nextToggleSegment(DeckParam::kPitchEnvEnable, p));
CHECK(!p.pitchEnv.enabled);
CHECK(!p.filter.enabled);
CHECK(nextToggleSegment(DeckParam::kFilterEnable, p) == 1);
setDeckParam(DeckParam::kFilterEnable, p, 0.0,
nextToggleSegment(DeckParam::kFilterEnable, p));
CHECK(p.filter.enabled);
// Mode selectors: Staged by default, so the first derived segment is Spline. Flipping the
// amp to Spline also forces Trigger (the drawn-EG rule), which is setDeckParam's own job
// and must survive the derived segment reaching it unchanged.
CHECK(p.ampSpline.mode == EnvMode::Staged);
CHECK(nextToggleSegment(DeckParam::kAmpEnvMode, p) == 1);
setDeckParam(DeckParam::kAmpEnvMode, p, 0.0, nextToggleSegment(DeckParam::kAmpEnvMode, p));
CHECK(p.ampSpline.mode == EnvMode::Spline);
CHECK(p.playMode == PlayMode::Trigger);
CHECK(nextToggleSegment(DeckParam::kAmpEnvMode, p) == 0);
setDeckParam(DeckParam::kAmpEnvMode, p, 0.0, nextToggleSegment(DeckParam::kAmpEnvMode, p));
CHECK(p.ampSpline.mode == EnvMode::Staged);
for (DeckParam id : {DeckParam::kPitchEnvMode, DeckParam::kFilterEnvMode}) {
setDeckParam(id, p, 0.0, nextToggleSegment(id, p));
}
CHECK(p.pitchSpline.mode == EnvMode::Spline);
CHECK(p.filterSpline.mode == EnvMode::Spline);
// Every control that still carries its own segment answers "not mine", so the shell can
// tell the two commit paths apart on the answer alone.
for (DeckParam id : {DeckParam::kPlayMode, DeckParam::kPitchEngine, DeckParam::kFilterLaw,
DeckParam::kVoiceMode, DeckParam::kMonoTrigger,
DeckParam::kFilterCutoff, DeckParam::kCount}) {
CHECK(nextToggleSegment(id, p) == -1);
}
}
int main() {
testTheTwoCeilingNamesAreOneNumber();
testASingleButtonsDerivedSegmentFlipsTheFieldItNames();
testNormRoundTripsThroughEveryValueDomain();
testRateKnobEndsAreTheStretchersOwnBounds();
testRateAndPitchBindTheirOwnFields();