Phase-vocoder phase hygiene (ROADMAP Stage 13) - #36
Merged
Conversation
Four confirmed correctness fixes from the 2026-08-05 quality review (LEARNINGS.md), all wide-path only — the DJ keylock chain is untouched: - Wrap phase_accum to (-PI, PI] after every accumulation. It is only consumed via from_polar and differences, and unwrapped it grew without bound, so the per-frame f32 downcast lost radians of precision within minutes on long renders (HF phase degraded to noise). - Blend phases along the wrapped difference in the gradient and IF coherence blends. A linear mix of raw phase values sitting different multiples of 2*PI apart lands on a meaningless intermediate angle. - Hold DC and Nyquist at their analysis phases and project them onto the real axis in reconstruct_spectrum, so the mirrored spectrum is exactly Hermitian instead of scaling those bins by cos(accumulated phase). - Offline wide path: hop = FFT/8, matching the live wide stage's mandatory overlap (FFT/4 is the documented -75% level/click blowup). stretch_into() also gains stretch()'s exact ratio-1.0 passthrough. Measured: PV-direct null at ratio 1.0 went 59 -> 139 dB SER; 5 kHz tone purity at ratio 1.5 went ~25 -> ~57 dB, flat over a 30 s render. New tests/pv_null.rs gates both (the tests/identity.rs suite only ever exercised the lib.rs ratio-1.0 bypass, never the vocoder). Re-pinned two wide-path baselines in stretch_quality_regressions.rs: the ratio-2.0 pitch check now measures the steady-state middle (edge ramp reads low at the new hop), and the two-tone balance bands track the smaller low-band loss at ratio 0.5 / the pinned rigid sub-bass attenuation at ratio 2.0 (trait of the live hop/8 configuration, recorded in LEARNINGS.md). ROADMAP Stage 13 status note updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four confirmed correctness fixes from the 2026-08-05 quality review (evidence in LEARNINGS.md), all wide-path only — the DJ keylock chain is untouched.
Fixes
phase_accumto (−π, π] after every accumulation. It is only consumed viafrom_polarand phase differences; unwrapped it grew without bound, so the per-frame f32 downcast lost radians of precision within minutes on long renders (HF phase degraded to noise on sustained material, which gets no rescue from onset resets).reconstruct_spectrum, so the mirrored spectrum is exactly Hermitian instead of scaling those bins by cos(accumulated phase).stretch_into()also gainsstretch()'s exact ratio-1.0 passthrough.Measured (A/B vs pre-fix via stash)
New
tests/pv_null.rsgates both (>100 dB / >45 dB — pre-fix fails by 40+ dB). Thetests/identity.rssuite only ever exercised thelib.rsratio-1.0 bypass, never the vocoder.Re-pinned baselines
Two wide-path baselines in
stretch_quality_regressions.rs, both investigated before touching: the ratio-2.0 pitch check now measures the steady-state middle (edge ramp reads low at the new hop; steady state verified 440.97–441.18 Hz by zero-crossing sweep), and the two-tone balance bands track the smaller low-band loss at ratio 0.5 plus the pinned rigid sub-bass attenuation at ratio 2.0 (a trait of the live hop/8 configuration, recorded in LEARNINGS.md as Stage 14/16 material).Remaining Stage 13 exit criteria (manual)
🤖 Generated with Claude Code