From a9d78f033150e9e2421decdf1c83011a316fcfb1 Mon Sep 17 00:00:00 2001 From: Geraint Date: Mon, 19 Feb 2024 10:20:40 +0000 Subject: [PATCH] Add `.flush()` for getting the final bits of output without any input --- signalsmith-stretch.h | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/signalsmith-stretch.h b/signalsmith-stretch.h index f2374f1..1af7061 100644 --- a/signalsmith-stretch.h +++ b/signalsmith-stretch.h @@ -38,6 +38,7 @@ struct SignalsmithStretch { channelBands.assign(channelBands.size(), Band()); silenceCounter = 2*stft.windowSize(); didSeek = false; + flushed = true; } // Configures using a default preset @@ -183,6 +184,7 @@ struct SignalsmithStretch { } stft.analyse(c, timeBuffer); } + flushed = false; // TODO: first block after a flush should be gain-compensated for (int c = 0; c < channels; ++c) { auto channelBands = bandsForChannel(c); @@ -250,7 +252,37 @@ struct SignalsmithStretch { stft += outputSamples; prevInputOffset -= inputSamples; } - + + // Read the remaining output, providing no further input. `outputSamples` should ideally be at least `.outputLatency()` + template + void flush(Outputs &&outputs, int outputSamples) { + int plainOutput = std::min(outputSamples, stft.windowSize()); + int foldedBackOutput = std::min(outputSamples, stft.windowSize() - plainOutput); + for (int c = 0; c < channels; ++c) { + auto &&outputChannel = outputs[c]; + auto &&stftChannel = stft[c]; + for (int i = 0; i < plainOutput; ++i) { + // TODO: plain output should be gain- + outputChannel[i] = stftChannel[i]; + } + for (int i = 0; i < foldedBackOutput; ++i) { + outputChannel[outputSamples - 1 - i] -= stftChannel[plainOutput + i]; + } + for (int i = 0; i < plainOutput + foldedBackOutput; ++i) { + stftChannel[i] = 0; + } + } + // Skip the output we just used/cleared + stft += plainOutput + foldedBackOutput; + // Reset the phase-vocoder stuff, so the next block gets a fresh start + for (int c = 0; c < channels; ++c) { + auto channelBands = bandsForChannel(c); + for (int b = 0; b < bands; ++b) { + channelBands[b].prevInput = channelBands[b].prevOutput = 0; + } + } + flushed = true; + } private: using Complex = std::complex; static constexpr Sample noiseFloor{1e-15}; @@ -266,7 +298,7 @@ private: int channels = 0, bands = 0; int prevInputOffset = -1; std::vector timeBuffer; - bool didSeek = false; + bool didSeek = false, flushed = true; Sample seekTimeFactor = 1; std::vector rotCentreSpectrum, rotPrevInterval;