From c2fbd6f2151d21864059e8f13ee6c7599063649d Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Fri, 23 Feb 2024 13:21:28 +0000 Subject: [PATCH] Some work on resampler delay --- src/finer/R3LiveShifter.cpp | 40 +++++++++++++++++++++++++++++------- src/finer/R3Stretcher.cpp | 4 ++++ src/test/TestLiveShifter.cpp | 34 +++++++++++++++++------------- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/finer/R3LiveShifter.cpp b/src/finer/R3LiveShifter.cpp index faaacf96..ed002899 100644 --- a/src/finer/R3LiveShifter.cpp +++ b/src/finer/R3LiveShifter.cpp @@ -212,6 +212,10 @@ R3LiveShifter::createResamplers() resamplerParameters.maxBufferSize = m_guideConfiguration.longestFftSize; resamplerParameters.dynamism = Resampler::RatioOftenChanging; resamplerParameters.ratioChange = Resampler::SmoothRatioChange; + + int debug = m_log.getDebugLevel(); + if (debug > 0) --debug; + resamplerParameters.debugLevel = debug; m_inResampler = std::unique_ptr (new Resampler(resamplerParameters, m_parameters.channels)); @@ -235,15 +239,18 @@ R3LiveShifter::getFormantScale() const size_t R3LiveShifter::getPreferredStartPad() const { - //!!!??? return 0; } size_t R3LiveShifter::getStartDelay() const { + //!!! need a principled way - measure it in ctor perhaps int resamplerDelay = 32; - int fixed = getWindowSourceSize() / 2 + resamplerDelay; +#ifdef HAVE_LIBSAMPLERATE + resamplerDelay = 47; +#endif + int fixed = getWindowSourceSize() / 2 + resamplerDelay * 2; int variable = getWindowSourceSize() / 2; if (m_contractThenExpand) { if (m_pitchScale < 1.0) { @@ -305,7 +312,6 @@ R3LiveShifter::shift(const float *const *input, float *const *output) m_log.log(2, "R3LiveShifter::shift: initially in outbuf", m_channelData[0]->outbuf->getReadSpace()); int pad = 0; - int resamplerDelay = 32; if (m_firstProcess) { if (m_contractThenExpand) { pad = getWindowSourceSize(); @@ -315,7 +321,6 @@ R3LiveShifter::shift(const float *const *input, float *const *output) } else { pad = getWindowSourceSize() / 2; } - pad += resamplerDelay; m_log.log(2, "R3LiveShifter::shift: extending input with pre-pad", incount, pad); for (int c = 0; c < m_parameters.channels; ++c) { m_channelData[c]->inbuf->zero(pad); @@ -336,7 +341,7 @@ R3LiveShifter::shift(const float *const *input, float *const *output) } } - int requiredInOutbuf = int(ceil(incount / outRatio)) + resamplerDelay; + int requiredInOutbuf = int(ceil(incount / outRatio)); generate(requiredInOutbuf); int got = readOut(output, incount, 0); @@ -417,8 +422,18 @@ R3LiveShifter::readIn(const float *const *input) incount, inRatio, false); - + m_log.log(2, "R3LiveShifter::readIn: writing to inbuf from resampled data, former read space and samples being added", m_channelData[0]->inbuf->getReadSpace(), resampleOutput); + + if (m_firstProcess) { + int expected = floor(incount * inRatio); + if (resampleOutput < expected) { + m_log.log(2, "R3LiveShifter::readIn: resampler left us short on first process, pre-padding output: expected and obtained", expected, resampleOutput); + for (int c = 0; c < m_parameters.channels; ++c) { + m_channelData[c]->inbuf->zero(expected - resampleOutput); + } + } + } for (int c = 0; c < m_parameters.channels; ++c) { m_channelData[c]->inbuf->write @@ -646,7 +661,18 @@ R3LiveShifter::readOut(float *const *output, int outcount, int origin) } if (resampledCount < outcount) { - m_log.log(0, "R3LiveShifter::readOut: WARNING: Failed to obtain enough samples from resampler", resampledCount, outcount); + if (m_firstProcess) { + m_log.log(2, "R3LiveShifter::readOut: resampler left us short on first process, pre-padding output: expected and obtained", outcount, resampledCount); + int prepad = outcount - resampledCount; + for (int c = 0; c < m_parameters.channels; ++c) { + v_move(m_channelAssembly.mixdown.data()[c] + prepad, + m_channelAssembly.mixdown.data()[c], resampledCount); + v_zero(m_channelAssembly.mixdown.data()[c], prepad); + } + resampledCount = outcount; + } else { + m_log.log(0, "R3LiveShifter::readOut: WARNING: Failed to obtain enough samples from resampler", resampledCount, outcount); + } } if (useMidSide()) { diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index 81524b95..224038be 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -299,6 +299,10 @@ R3Stretcher::createResampler() resamplerParameters.dynamism = Resampler::RatioMostlyFixed; resamplerParameters.ratioChange = Resampler::SuddenRatioChange; } + + int debug = m_log.getDebugLevel(); + if (debug > 0) --debug; + resamplerParameters.debugLevel = debug; m_resampler = std::unique_ptr (new Resampler(resamplerParameters, m_parameters.channels)); diff --git a/src/test/TestLiveShifter.cpp b/src/test/TestLiveShifter.cpp index 80969c84..359a25bc 100644 --- a/src/test/TestLiveShifter.cpp +++ b/src/test/TestLiveShifter.cpp @@ -52,18 +52,19 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged) int n = 100000; float freq = 440.f; int rate = 44100; + + if (printDebug) { + RubberBandLiveShifter::setDefaultDebugLevel(2); + } + RubberBandLiveShifter shifter (rate, 1, RubberBandLiveShifter::OptionPitchModeB); //!!! - shifter.setPitchScale(2.0); - - if (printDebug) { - shifter.setDebugLevel(2); - } +// shifter.setPitchScale(2.0); int blocksize = shifter.getBlockSize(); - BOOST_TEST(blocksize == 2560); + BOOST_TEST(blocksize == 512); n = (n / blocksize + 1) * blocksize; @@ -79,6 +80,8 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged) } int delay = shifter.getStartDelay(); + + std::cerr << "delay reported as " << delay << std::endl; // We now have n samples of a simple sinusoid with stretch factor // 1.0; obviously we expect the output to be essentially the same @@ -106,18 +109,21 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged) tt::tolerance(0.001f) << tt::per_element()); if (printDebug) { - // The initial # is to allow grep on the test output - std::cout << "#sample\tV" << std::endl; + // The prefix is to allow grep on the test output + + std::cout << "IN,sample,V" << std::endl; + for (int i = 0; i < int(in.size()); ++i) { + std::cout << "IN," << i << "," << in[i] << std::endl; + } + + std::cout << "OUT,sample,V" << std::endl; for (int i = 0; i < int(out.size()); ++i) { - std::cout << "#" << i << "\t" << out[i] << std::endl; + std::cout << "OUT," << i << "," << out[i] << std::endl; } - } - if (printDebug) { - // The initial @ is to allow grep on the test output - std::cout << "@sample\tV" << std::endl; + std::cout << "DIFF,V" << std::endl; for (int i = 0; i + delay < int(in.size()); ++i) { - std::cout << "@" << i << "\t" << out[i + delay] - in[i] << std::endl; + std::cout << "DIFF," << i << "," << out[i + delay] - in[i] << std::endl; } } #endif