Smooth out gaps in audio caused by how soxr works.
parent
dc37633328
commit
4c20eba91c
|
@ -48,11 +48,15 @@ ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate)
|
||||||
&runtimeSpec
|
&runtimeSpec
|
||||||
);
|
);
|
||||||
assert(resampleState_ != nullptr);
|
assert(resampleState_ != nullptr);
|
||||||
|
|
||||||
|
outputFifo_ = codec2_fifo_create(std::max(inputSampleRate_, outputSampleRate_));
|
||||||
|
assert(outputFifo_ != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResampleStep::~ResampleStep()
|
ResampleStep::~ResampleStep()
|
||||||
{
|
{
|
||||||
soxr_delete(resampleState_);
|
soxr_delete(resampleState_);
|
||||||
|
codec2_fifo_free(outputFifo_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ResampleStep::getInputSampleRate() const
|
int ResampleStep::getInputSampleRate() const
|
||||||
|
@ -68,25 +72,34 @@ int ResampleStep::getOutputSampleRate() const
|
||||||
std::shared_ptr<short> ResampleStep::execute(std::shared_ptr<short> inputSamples, int numInputSamples, int* numOutputSamples)
|
std::shared_ptr<short> ResampleStep::execute(std::shared_ptr<short> inputSamples, int numInputSamples, int* numOutputSamples)
|
||||||
{
|
{
|
||||||
short* outputSamples = nullptr;
|
short* outputSamples = nullptr;
|
||||||
|
*numOutputSamples = 0;
|
||||||
|
|
||||||
if (numInputSamples > 0)
|
if (numInputSamples > 0)
|
||||||
{
|
{
|
||||||
double scaleFactor = ((double)outputSampleRate_)/((double)inputSampleRate_);
|
short outputBuffer[std::max(inputSampleRate_, outputSampleRate_)];
|
||||||
int outputArraySize = std::max(numInputSamples, (int)(scaleFactor*numInputSamples));
|
int expectedNumOutputSamples = (double)numInputSamples * ((double)outputSampleRate_ / (double)inputSampleRate_);
|
||||||
assert(outputArraySize > 0);
|
|
||||||
|
|
||||||
outputSamples = new short[outputArraySize];
|
|
||||||
assert(outputSamples != nullptr);
|
|
||||||
|
|
||||||
size_t inputUsed = 0;
|
size_t inputUsed = 0;
|
||||||
size_t outputUsed = 0;
|
size_t outputUsed = 0;
|
||||||
soxr_process(
|
soxr_process(
|
||||||
resampleState_, inputSamples.get(), numInputSamples, &inputUsed,
|
resampleState_, inputSamples.get(), numInputSamples, &inputUsed,
|
||||||
outputSamples, outputArraySize, &outputUsed);
|
outputBuffer, sizeof(outputBuffer) / sizeof(short), &outputUsed);
|
||||||
*numOutputSamples = outputUsed;
|
|
||||||
}
|
if (outputUsed > 0)
|
||||||
else
|
{
|
||||||
{
|
codec2_fifo_write(outputFifo_, outputBuffer, outputUsed);
|
||||||
*numOutputSamples = 0;
|
}
|
||||||
|
|
||||||
|
// 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<short>(outputSamples, std::default_delete<short[]>());
|
return std::shared_ptr<short>(outputSamples, std::default_delete<short[]>());
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "IPipelineStep.h"
|
#include "IPipelineStep.h"
|
||||||
|
|
||||||
#include <soxr.h>
|
#include <soxr.h>
|
||||||
|
#include "codec2_fifo.h"
|
||||||
|
|
||||||
class ResampleStep : public IPipelineStep
|
class ResampleStep : public IPipelineStep
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,7 @@ private:
|
||||||
int inputSampleRate_;
|
int inputSampleRate_;
|
||||||
int outputSampleRate_;
|
int outputSampleRate_;
|
||||||
soxr_t resampleState_;
|
soxr_t resampleState_;
|
||||||
|
FIFO* outputFifo_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H
|
#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H
|
Loading…
Reference in New Issue