Γ-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:
+34
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user