From 4c20eba91caf638394185b2b8f0015fc3360c912 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Tue, 3 Dec 2024 00:14:38 -0800 Subject: [PATCH] Smooth out gaps in audio caused by how soxr works. --- src/pipeline/ResampleStep.cpp | 39 +++++++++++++++++++++++------------ src/pipeline/ResampleStep.h | 4 +++- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/pipeline/ResampleStep.cpp b/src/pipeline/ResampleStep.cpp index a793bee5..088e86bd 100644 --- a/src/pipeline/ResampleStep.cpp +++ b/src/pipeline/ResampleStep.cpp @@ -48,11 +48,15 @@ ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate) &runtimeSpec ); assert(resampleState_ != nullptr); + + outputFifo_ = codec2_fifo_create(std::max(inputSampleRate_, outputSampleRate_)); + assert(outputFifo_ != nullptr); } ResampleStep::~ResampleStep() { soxr_delete(resampleState_); + codec2_fifo_free(outputFifo_); } int ResampleStep::getInputSampleRate() const @@ -68,25 +72,34 @@ int ResampleStep::getOutputSampleRate() const std::shared_ptr ResampleStep::execute(std::shared_ptr inputSamples, int numInputSamples, int* numOutputSamples) { short* outputSamples = nullptr; + *numOutputSamples = 0; + if (numInputSamples > 0) { - double scaleFactor = ((double)outputSampleRate_)/((double)inputSampleRate_); - int outputArraySize = std::max(numInputSamples, (int)(scaleFactor*numInputSamples)); - assert(outputArraySize > 0); - - outputSamples = new short[outputArraySize]; - assert(outputSamples != nullptr); - + short outputBuffer[std::max(inputSampleRate_, outputSampleRate_)]; + int expectedNumOutputSamples = (double)numInputSamples * ((double)outputSampleRate_ / (double)inputSampleRate_); size_t inputUsed = 0; size_t outputUsed = 0; soxr_process( resampleState_, inputSamples.get(), numInputSamples, &inputUsed, - outputSamples, outputArraySize, &outputUsed); - *numOutputSamples = outputUsed; - } - else - { - *numOutputSamples = 0; + outputBuffer, sizeof(outputBuffer) / sizeof(short), &outputUsed); + + if (outputUsed > 0) + { + codec2_fifo_write(outputFifo_, outputBuffer, outputUsed); + } + + // Because of how soxr works, we may get outputUsed == 0 for a significant amount of time + // before getting a huge batch of samples at once. This logic is intended to smooth that out + // and improve playback further down the line. + if (codec2_fifo_used(outputFifo_) >= expectedNumOutputSamples) + { + outputSamples = new short[expectedNumOutputSamples]; + assert(outputSamples != nullptr); + + codec2_fifo_read(outputFifo_, outputSamples, expectedNumOutputSamples); + *numOutputSamples = expectedNumOutputSamples; + } } return std::shared_ptr(outputSamples, std::default_delete()); diff --git a/src/pipeline/ResampleStep.h b/src/pipeline/ResampleStep.h index 9ac7a96f..24403dc8 100644 --- a/src/pipeline/ResampleStep.h +++ b/src/pipeline/ResampleStep.h @@ -26,6 +26,7 @@ #include "IPipelineStep.h" #include +#include "codec2_fifo.h" class ResampleStep : public IPipelineStep { @@ -41,6 +42,7 @@ private: int inputSampleRate_; int outputSampleRate_; soxr_t resampleState_; + FIFO* outputFifo_; }; -#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H \ No newline at end of file +#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H