Close Γ-W1-T7 re-review: pitch-sync cadence math, floor-model regression check, evidence-count fix, one-home comments

New cadence-collapse-band test at P=1470 shows PSOLA eliminates the corner rather than regressing it (18.52% -> 0.00%).
This commit is contained in:
2026-08-02 05:34:43 -04:00
parent ef59265e7a
commit f1168e16eb
9 changed files with 249 additions and 40 deletions
+50
View File
@@ -42,6 +42,7 @@
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <vector>
using namespace reasampler;
@@ -920,6 +921,9 @@ static void testThirtyHertzSplicesAlignOnceTheSourcePeriodIsKnown() {
{"34 Hz rate 2.0", 34.0, 2.0, 0.0},
};
double controlWorst = 0.0, subjectWorst = 0.0, subjectOffWorst = 0.0;
// std::max alone floors a NEGATIVE floor-relative excess to 0 — but a negative excess means
// the floor model mismatches the render, not a clean one, so track the signed minimum too.
double subjectWorstMin = std::numeric_limits<double>::infinity();
for (const Row& r : rows) {
const double period = 44100.0 / r.freq;
std::vector<AudioSample> src(srcLen);
@@ -943,6 +947,7 @@ static void testThirtyHertzSplicesAlignOnceTheSourcePeriodIsKnown() {
controlWorst = std::max(controlWorst, pctOn);
} else {
subjectWorst = std::max(subjectWorst, pctOn);
subjectWorstMin = std::min(subjectWorstMin, pctOn);
subjectOffWorst = std::max(subjectOffWorst, pctOff);
}
}
@@ -953,6 +958,8 @@ static void testThirtyHertzSplicesAlignOnceTheSourcePeriodIsKnown() {
std::printf(" [30 Hz] worst subject excess %.2f%% vs worst control excess %.2f%%\n",
subjectWorst, controlWorst);
CHECK(subjectWorst < 0.10);
CHECK(subjectWorstMin > -0.10); // a negative excess this large is a model
// mismatch, not a clean render — catch it too
CHECK(subjectWorst <= controlWorst + 0.05); // 0.05 absorbs the floor subtraction's sign noise
// Vacuity guard, matching testTwentyNineHertzAtRateTwoKeepsItsPitch's sibling check: the
// FIXED-WINDOW (no period set) arm is asserted too, so a setSourcePeriod that silently did
@@ -1029,6 +1036,48 @@ static void testCadenceCornerIsUnmovedByAPitchSynchronousSplice() {
}
}
// M1 (Gamma-W1-T7 re-review): the corner above sits where periodAlignedJump narrows the jump
// by only ~10% (2205 -> 2000/2400/2100 at P=500/600/700), never reaching the collapse band
// (jump_->0.63-0.67*window) time_stretch.h's own derivation flags as where the recurrence
// interval shrinks hardest. P=1470 (30 Hz at 44.1k) is the case that track exists for: n=2
// overshoots jumpMax_ (2*1470=2940 > 2756), forcing n=1 and jump_=1470=0.667*window — 1.5x the
// splice rate of the fixed-window fallback.
//
// MEASURED (Debug, this machine): metric floor 55.86% (P=1470's want-period of 5880 fr under a
// 32768-frame segment leaks a lot of mainlobe, same effect as the P=500-700 rows, just larger),
// fixed-window excess 18.52%, pitch-synchronous excess 0.00%. The faster cadence does NOT
// regress this corner — every splice at n=1 lands exactly one source period away, so despite
// firing 1.5x as often each one is phase-perfect rather than merely aligned-on-average, and the
// corner clears rather than worsens. Recorded as read, not tuned: if a future change moves
// these numbers, update this comment to match, don't loosen the bounds to hide it.
static void testCadenceCollapseBandAtThirtyHertzUnderPitchSynchronousSplice() {
using reasampler::test_support::energyOutsideFundamentalPercent;
const std::int64_t w = 2205;
const double rate = 2.0;
const double shift = std::pow(2.0, -24.0 / 12.0); // -24 st, the same corner as above
const double period = 1470.0; // 30 Hz at 44.1k
const std::size_t outFrames = 60000, from = 20000, len = 32768;
const std::size_t srcLen = 400000;
std::vector<AudioSample> src(srcLen);
for (std::size_t i = 0; i < srcLen; ++i) {
src[i] = static_cast<AudioSample>(std::sin(2.0 * kPi * static_cast<double>(i) / period));
}
const std::vector<double> off = runStretch(src, w, rate, shift, outFrames, nullptr);
const std::vector<double> on = runStretch(src, w, rate, shift, outFrames, nullptr, period);
for (double v : on) CHECK(std::isfinite(v));
const double want = period / shift;
const double floor = idealToneFloorPercent(want, from, len);
const double pctOff = energyOutsideFundamentalPercent(off, from, len, want);
const double pctOn = energyOutsideFundamentalPercent(on, from, len, want);
std::printf(" [cadence collapse band, PSOLA] period %.0f (want %.0f, metric floor %.2f%%): "
"excess %.2f%% -> %.2f%%\n", period, want, floor, pctOff - floor, pctOn - floor);
CHECK(pctOn - floor < 1.0); // measured 0.00%: phase-perfect at n=1, not merely aligned
// Vacuity guard (shape of testThirtyHertzSplicesAlignOnceTheSourcePeriodIsKnown's :961): the
// FIXED-WINDOW arm is asserted too (measured 18.52% excess), so a setSourcePeriod that
// silently did nothing would render both arms identically and pass the bound above by luck.
CHECK(pctOff - floor > pctOn - floor + 1.0);
}
// The two new entry points on a shifter that was never configured (a Varispeed voice's) —
// neither may touch the empty ring.
static void testStretchEntryPointsOnPassThrough() {
@@ -1056,6 +1105,7 @@ int main() {
testThirtyHertzSplicesAlignOnceTheSourcePeriodIsKnown();
testTwentyNineHertzAtRateTwoKeepsItsPitch();
testCadenceCornerIsUnmovedByAPitchSynchronousSplice();
testCadenceCollapseBandAtThirtyHertzUnderPitchSynchronousSplice();
testStretchEntryPointsOnPassThrough();
if (g_fail == 0) {