Conversation
A bursty stretch stage refills the output buffer one hop at a time while the render thread drains one block per quantum, so the buffer's trough rides at exactly one render block. Wherever the stage's production schedule comes up a few frames short, the block is zero-filled — an audible click of up to full signal amplitude (measured: 1-8 sample dropouts). SoundTouchProcessorBase now supports holding extraction for startupHoldBlocks render blocks after the output buffer first fills a block. Held blocks are emitted before any real output, so the added silence is inaudible, and the unconsumed frames become a permanent cushion under the trough. The phase vocoder worklet holds one block: a 128-frame cushion (16x the worst measured shortfall) for one render block (~2.9 ms) of added latency. Warmup blocks no longer count as underruns, so the metric now reports only real faults. Measured A/B (real pipeline, gate vs none) across the full fftSize/overlapFactor grid at 44.1/48/96 kHz: group delay shifts by exactly 128 frames with output otherwise bit-identical, and hop-aligned pitch ratios drop from 9-21 underruns per 20 s to zero at every functional configuration. Arbitrary (unaligned) ratios are a sustained stretch/transposer rate mismatch that outruns any fixed cushion — the gate only delays onset there; matching the transposer to the stage's realized tempo is the actual fix for that case. Configs with hop <= 128 starve with or without the gate because PhaseVocoder.process() handles at most one hop per call (unlike Stretch, which loops until input is exhausted) — a pre-existing defect to fix separately. The default of 0 leaves the other worklets' timing unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
A data point from the WSOLA worklet ( It does. Feeding a constant stereo signal (0.5 / 0.25) through the processor built from
Same mechanism as the description: the transposer emits a fractional frame count per block ( With one held block (a local patch that holds extraction for the first block that has output, i.e. So I'd suggest either overriding Repro script (Node; point it at a built
|
Hey again :)
This came up while trying to switch my bespoke phase vocoder implementation over to v2.1.1. Can't say I noticed the transients myself, but it's plausible. It does add ~3ms of latency which seemed like a reasonable tradeoff for correctness.
Model used: Anthropic Fable 5
Highlighting the two other issues the model called out:
Already a PR for this with #85
I'll look at creating a separate PR for this - not sure how invasive it may end up being.