PitchShift: Fix streaming silence when reset=False#486
Open
codyjhsieh wants to merge 1 commit into
Open
Conversation
Problem PitchShift produces all-zero output when processing audio in streaming mode (reset=False). Three interacting bugs cause this: 1. PrimeWithSilence::prepare() calls setMaximumDelayInSamples() on every call, which unconditionally resets the JUCE delay buffer. Stored audio is wiped between streaming calls, so the pitch shifter only receives silence as input. 2. RubberbandPlugin::getLatencyHint() ratchets upward via std::max on a member variable that never decreases, inflating the latency estimate on every call. 3. processFloat32() trims output by the latency estimate even in streaming mode, reducing the output to a zero-length array when the plugin's startup latency exceeds the chunk size. Solution - Guard setMaximumDelayInSamples() with a value-changed check so the delay buffer is preserved across streaming calls. - Replace the ratcheting getLatencyHint() with a constant structural latency: getLatency() + maximumBlockSize. - In streaming mode (reset=False), return the full buffer instead of trimming by latency. Result Streaming produces audio after the expected priming period at all chunk sizes. Single-shot reset=True latency compensation is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Fixes #415.
Three interacting bugs cause
PitchShiftto produce all-zero output when processing audio in streaming mode (reset=False). A single-shot call withreset=Trueworks correctly, but any streaming use — voice chat, DJ apps, chunked file processing — gets permanent silence.Problem
PrimeWithSilence::prepare()clears the delay line buffer on every call. It calls JUCE'ssetMaximumDelayInSamples()unconditionally, which internally callsreset()→bufferData.clear(). SinceprocessFloat32callsprepare()before everyprocess(), the 44100-sample delay line loses all stored audio between streaming calls. The pitch shifter only ever receives silence as input.RubberbandPlugin::getLatencyHint()ratchets upward viastd::max. TheinitialSamplesRequiredmember variable can only grow, inflating the latency estimate on each call. The pipeline uses this to decide how many output samples to trim.processFloat32trims output by latency even in streaming mode. Whenreset=False, the pipeline passesisProbablyLastProcessCall=false, so it never extends the buffer to accommodate latency. The latency trimming then reduces the output to a zero-length array.Solution
PrimeWithSilence.h: GuardsetMaximumDelayInSamples()with a check — only call it when the value actually changes. This preserves the delay buffer across streaming calls.RubberbandPlugin.h: Replace the ratchetinggetLatencyHint()with a constant:rbPtr->getLatency() + lastSpec.maximumBlockSize. Remove theinitialSamplesRequiredmember.process.h: In streaming mode (reset=False), settotalOutputLatencySamples = 0so the full buffer is returned, including any leading silence from plugin priming.Result
reset=Truelatency compensation is unchanged (PitchShift(0)identity error < 1e-6).🤖 Generated with Claude Code