Fix: phase vocoder worklet#84
Open
bhj wants to merge 3 commits into
Open
Conversation
…and exact OLA normalization Four defects in the PhaseVocoder stretch stage combined to collapse the stereo center and shift output level whenever tempo != 1: - Inter-channel incoherence: L/R were processed with fully independent phase accumulators, destroying the inter-channel phase relationship that forms the stereo center. The recursion now runs once on the mid (L+R) spectrum — by FFT linearity the sum of the channel spectra, so no third FFT — and each channel resynthesizes as the shared mid synthesis phase plus its instantaneous offset from the mid, preserving the inter-channel difference exactly. - Unbounded phase accumulation: synthesis phase grew without wrapping in float32 storage; high bins lose phase resolution within minutes of playback. The accumulator is now wrapped to (-pi, pi] every frame. - Incorrect OLA normalization: the constant 2/overlapFactor assumed single Hann coverage, but the pipeline windows twice (analysis and synthesis), and the synthesis hop varies with tempo. Overlap-add is now normalized per sample by the accumulated squared-window sum (WOLA), exact for any hop including mid-stream tempo changes. - Warmup phase poisoning: the recursion was seeded from the very first hop, when the analysis window is still mostly zeros, freezing the startup transient's arbitrary inter-bin phase relationships into the accumulators permanently — a constant, tempo-dependent level loss (e.g. -1.4 dB at tempo 2.0) even after the fixes above. Frames now pass through untouched until the analysis window is fully primed; the first fully-valid frame seeds the recursion. Measured on stationary tones (fftSize 512, overlap 4): steady-state gain is now 1.0000 at tempos 0.5 through 4.0 for bin-aligned and non-aligned frequencies (previously 0.68-0.97, and 0.75 at identity). First-frame output is now exactly normalized rather than attenuated by w^2/2; those samples are analysis-priming zeros either way. New DSP-correctness specs cover level at multiple tempos, DC reproduction, inter-channel identity and fixed-offset preservation, synthesis-phase boundedness over long runs, and mid-stream tempo changes. Seven of them fail against the previous implementation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…revent broadband level loss With the phase recursion running independently per bin, any Hs != Ha re-randomizes the local phase structure that makes overlapping frames of noise-like content sum consistently. The overlap-add then combines incoherently, which for a Hann window at 75% overlap costs ~3.1 dB on broadband material (consonants, drums, cymbals, reverb) while pure tones pass at unity — measured -2.9 to -3.4 dB on white noise through the stretch stage, matching listener reports of a ~3 dB drop on music. This applies identity phase locking (Puckette 1995; Laroche & Dolson 1999) on the mid-channel reference: the recursion runs only at spectral peaks of the mid magnitude, and every bin in a peak's region of influence (bounded by midpoints between adjacent peaks) rotates rigidly by that peak's synthesis rotation. Rigid rotation preserves the analysis frame's local phase structure, keeping noise coherent under overlap-add, and rotating both channels by the same angle preserves the inter-channel phase difference exactly. Phase state is now carried as complex spectra (previous analysis mid and previous synthesized mid) instead of accumulated angles — complex storage is inherently wrapped, so unbounded accumulation is impossible by construction, and atan2/cos/sin run only at peak bins instead of every bin. Measured on white noise through the stretch stage at +/-2 and +5 semitone-equivalent tempos: -0.4 to -1.0 dB (previously -2.9 to -3.4). Tones and harmonic stacks remain at 0.00 dB. New regression specs assert broadband noise level within 1.5 dB in both stretch directions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…phase reference A mid-only (L+R) phase reference is degenerate for anti-phase content: the mid spectrum vanishes, its phase turns noisy, and the recursion's rotation decoheres the overlap-add — measured -6 dB on an anti-phase sine and -1.8 to -2.7 dB on anti-phase noise. Exactly out-of-phase layers occur in real material (stereo-widening and phase tricks in backing tracks), and the previous per-channel recursion handled them coherently, so this was a regression of the mid-reference design. The side (L-R) spectrum is as free as the mid by FFT linearity. Peak finding now runs on per-bin energy (|mid|^2 + |side|^2, phase-agnostic) and each peak's recursion uses whichever of mid/side is stronger at that bin, keeping the reference well-conditioned for any inter-channel correlation. Rigid region rotation is unchanged — rotating L and R by the same angle rotates mid and side identically — so the exact inter-channel phase guarantee is untouched. Measured after the change: anti-phase sine 0.00 dB (was -6.03), anti-phase noise -0.4 to -0.6 dB (was -1.8 to -2.7), identical to regular noise; all previous levels unchanged. New spec asserts level and exact polarity preservation for purely anti-phase channels. 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.
Hi, thanks for all your work. This fixes the issues I heard with the phase vocoder worklet, namely stereo image collapse and lowered volume when engaged. Results sound much better, more-or-less matching the previous best implementation I've heard (https://github.com/olvb/phaze)
Let me know if I missed anything.
Model used: Anthropic Fable