Skip to content

Phase-vocoder phase hygiene (ROADMAP Stage 13) - #36

Merged
robmorgan merged 1 commit into
mainfrom
fix/pv-phase-hygiene
Aug 6, 2026
Merged

Phase-vocoder phase hygiene (ROADMAP Stage 13)#36
robmorgan merged 1 commit into
mainfrom
fix/pv-phase-hygiene

Conversation

@robmorgan

Copy link
Copy Markdown
Owner

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

  • Wrap phase_accum to (−π, π] after every accumulation. It is only consumed via from_polar and 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).
  • 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π apart lands on a meaningless intermediate angle.
  • Hold DC and Nyquist at their analysis phases and project them real 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 (A/B vs pre-fix via stash)

Metric Before After
PV-direct null @ ratio 1.0 59.3 dB SER 139.3 dB
5 kHz purity @ ratio 1.5 ~25 dB ~57 dB, flat over 30 s

New tests/pv_null.rs gates both (>100 dB / >45 dB — pre-fix fails by 40+ dB). The tests/identity.rs suite only ever exercised the lib.rs ratio-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)

  • Wide-falsification sidecar re-run
  • Owner listen at ±50% including the Rubber Band A/B re-baseline (the accepted wide-rate gap was measured against the pre-fix vocoder)

🤖 Generated with Claude Code

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>
@robmorgan
robmorgan merged commit 80a964e into main Aug 6, 2026
10 checks passed
@robmorgan
robmorgan deleted the fix/pv-phase-hygiene branch August 6, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant