Γ-W1-T2 review: one restart funnel, tighter ceiling proof, effective-gain meter

Fold setLimiterEnabled's restart request into setInstrumentParams so every writer
keeps the host's latency report in sync. Pin the window-sizing identity, drop the
per-sample modulo, tighten the ceiling tolerance, publish the blended gain.
This commit is contained in:
2026-08-01 19:34:08 -04:00
parent 3baf4ee50b
commit 0612abbddb
5 changed files with 77 additions and 26 deletions
+34 -3
View File
@@ -108,8 +108,10 @@ static void testEngagedHoldsTheCeilingOnProgramTwelveDbOver() {
for (std::size_t i = static_cast<std::size_t>(latency); i < out.size(); ++i) {
worst = std::max(worst, std::fabs(out[i]));
}
// Sample peak, so the true-peak ceiling is the bound with room to spare for float rounding.
CHECK(worst <= ceiling * 1.0001f);
// Sample peak, so the true-peak ceiling is the bound with room to spare for float rounding
// (ceiling/peak then x*gain admits at most ~2.4e-7 relative overshoot; 1e-6 stays a hard
// bound without hiding a systematic error the way a much wider tolerance would).
CHECK(worst <= ceiling * (1.f + 1e-6f));
}
static void testTruePeakDetectionEngagesWhereSamplePeakWouldNot() {
@@ -161,7 +163,7 @@ static void testStereoLinkedGainKeepsDualMonoCenteredAcrossAToggle() {
for (std::size_t i = l.size() / 2; i < (l.size() * 3) / 4; ++i) {
worstEngaged = std::max(worstEngaged, std::fabs(l[i]));
}
CHECK(worstEngaged <= ceiling * 1.0001f);
CHECK(worstEngaged <= ceiling * (1.f + 1e-6f));
CHECK(worstEngaged > 0.f);
}
@@ -253,6 +255,34 @@ static void testGainNeverRisesAboveUnity() {
CHECK(outPeak <= inPeak);
}
static void testAlignmentIdentityHoldsAtTheExactWindowEdge() {
// Pins the alignment identity window_ = latency_ - kLimiterOsDelay + 1 (limiter.h's
// comment on window_, otherwise asserted nowhere): a single isolated over-ceiling impulse
// is reduced to EXACTLY the ceiling at the one output sample the identity predicts
// (impulseAt + latency), because that is the unique push index where the sliding
// min-then-average has folded in nothing but this impulse's own detected peak. Shifting
// the identity by +-1 either lets the impulse's own excess slip just outside the window
// (undershoots the reduction, sample overshoots the ceiling) or applies the full reduction
// one sample late (same overshoot at this index) — confirmed by hand-mutating window_'s
// formula in both directions and observing this assertion fail before restoring it.
Limiter lim;
lim.setEnabled(true);
lim.prepare(kRate);
const int latency = limiterLookaheadSamples(kRate);
const float ceiling = static_cast<float>(limiterCeilingLinear());
const int impulseAt = 500;
std::vector<float> in(static_cast<std::size_t>(impulseAt + latency + 200), 0.f);
in[static_cast<std::size_t>(impulseAt)] = ceiling * 4.f; // isolated, well over
float minGain = 0.f;
const std::vector<float> out = runMono(lim, in, 37, &minGain); // odd block: crosses the edge
CHECK(minGain > 0.24f && minGain < 0.26f); // ceiling/peak == 0.25 for this impulse
const float atEdge = out[static_cast<std::size_t>(impulseAt + latency)];
CHECK(std::fabs(atEdge - ceiling) <= ceiling * 1e-6f);
// Every neighbor stays exactly silent — the reduction lands on this one sample, not smeared.
CHECK(out[static_cast<std::size_t>(impulseAt + latency - 1)] == 0.f);
CHECK(out[static_cast<std::size_t>(impulseAt + latency + 1)] == 0.f);
}
static void testBakedConstants() {
CHECK(kLimiterCeilingDbTp == -0.3);
CHECK(std::fabs(limiterCeilingLinear() - std::pow(10.0, -0.3 / 20.0)) < 1e-12);
@@ -275,6 +305,7 @@ int main() {
testToggleEmitsNoStepLargerThanTheSignalsOwn();
testCrossfadeSettlesToTheExactEngagedAndBypassedPaths();
testGainNeverRisesAboveUnity();
testAlignmentIdentityHoldsAtTheExactWindowEdge();
testBakedConstants();
if (g_fail) {
std::printf("%d FAILURE(S)\n", g_fail);