fix(preserve): clamp Preserve feed to real-content bound at tail; lock sub-sample refinement with non-integer f0; fix stale onset-latency doc + clamp comment

This commit is contained in:
2026-07-28 09:10:03 -04:00
parent 2ef3514bc7
commit f7dfaa9f41
4 changed files with 64 additions and 33 deletions
+25 -16
View File
@@ -188,24 +188,29 @@ static void testRtDisciplineAndPassthrough() {
static void testRepitchSpectralPurityAndOnset() {
// Frequencies are in cycles/sample (rate-free). The source tone is chosen ADVERSARIALLY
// on TWO axes simultaneously:
// (a) f0*(w/2) = (2205/2)/196 = 1102/196 ≈ 5.622 cycles (frac ≈ 0.622) — content half a
// window apart in the ring is near ANTI-PHASE. The old dual-tap design cancelled
// almost completely at every crossfade midpoint for such tones — the DAW "severe
// beating / multiple partials from a pure sine" bug.
// (b) ringLen_*f0 = 4410/196 = 22.5 EXACTLY — at ratio 4 the write head advances 4 taps
// per output frame, so each splice-period the outgoing tap crosses the writer at the
// HALF-period point of the source waveform (sign flip), producing a visible null when
// gNew == gOld if fadeLen_ is not clamped to headroom. With f0=0.005 this product
// is 22.05 (frac ≈ 0.05), near a zero-crossing — the artifact is near-benign, so the
// +24 st purity case would pass even with the clamping reverted. f0=1/196 forces the
// half-integer alignment that makes the pre-fix artifact catastrophic.
// (a) f0*(w/2) (2205/2)/196.37 ≈ 5.609 cycles (frac ≈ 0.609) — content half a window
// apart in the ring is near ANTI-PHASE. The old dual-tap design cancelled almost
// completely at every crossfade midpoint for such tones — the DAW "severe beating /
// multiple partials from a pure sine" bug.
// (b) ringLen_*f0 4410/196.37 ≈ 22.46 — near the half-integer alignment that makes the
// pre-fix fade-headroom artifact visible at ratio 4 (+24 st). Additionally, period
// 196.37 is NON-INTEGER, so the correlation peak is NOT on the integer lag grid; the
// sub-sample parabolic refinement is LOAD-BEARING to stay at the -84 dB floor — the
// old integer f0=1/196 put the optimum on the grid and the parabola contributed
// nothing, making the -30 dB floor reachable without it.
//
// The shifter is driven exactly as the Voice drives it since GA2: prime() with the first
// window of the source, then stream the CONTINUATION — so the measurements start at
// output frame 0 and the onset regime (early splices near the primed boundary, the DAW
// "zero-sample gaps in the first few ms" report) is inside the assertions, not skipped.
const std::int64_t w = 2205; // ~50 ms @ 44.1k (the product window)
const double f0 = 1.0 / 196.0; // source: period 196 samples; see adversarial note above
const double f0 = 1.0 / 196.37; // NON-INTEGER period: the sub-sample correlation peak
// is NOT on the integer grid, so the parabolic
// refinement MUST contribute to achieve a clean
// aligned splice — reverting it now FAILS this test.
// (Old integer 1/196 put the optimum on the grid,
// letting the parabola contribute nothing; the 30 dB
// residual floor was then reachable without it.)
const double ratios[] = {std::pow(2.0, 2.0 / 12.0), // +2 semitones (D from C)
std::pow(2.0, -3.0 / 12.0), // -3 semitones (down-shift path)
2.0, // octave up (the GA2 report: C5)
@@ -282,10 +287,14 @@ static void testRepitchSpectralPurityAndOnset() {
// block — a gapped or beating block collapses this...
CHECK(fitRms > 0.6);
CHECK(fitRms < 0.8);
// ...and it is the ONLY thing there: residual at least 30 dB under the tone.
// (Post-fix the engine measures ~-75 dB and better; the old integer-lag splices
// sat near -59 dB sidebands and the warm-zero onset failed outright.)
CHECK(residRms < 0.0316 * fitRms);
// ...and it is the ONLY thing there: residual at least 84 dB under the tone.
// With the non-integer f0=1/196.37, the sub-sample parabolic refinement is
// LOAD-BEARING: reverting it raises the floor to ~-50 dB (ratio 1/8), failing here.
// With integer f0=1/196 the optimum was on the integer grid and the parabola
// contributed nothing — the old floor of -30 dB was reachable without it.
// Engine steady-state measures -84 dB and better across all 7 tested ratios;
// moderate ratios (+/-2 st, octaves) sit at -88 dB typical.
CHECK(residRms < 0.000063 * fitRms); // -84 dB floor
}
}
}