From 2dcb27d3ddfd77a5300ca989e37610134c8d0c75 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Mon, 20 Mar 2023 10:08:01 +0000 Subject: [PATCH 1/8] Toward properly testing reset --- src/finer/R3Stretcher.cpp | 11 ++++-- src/test/TestStretcher.cpp | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index 6cb6ae9..3e1b9c8 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -545,9 +545,6 @@ R3Stretcher::reset() cd->reset(); } - m_prevInhop = m_inhop; - m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); - m_studyInputDuration = 0; m_suppliedInputDuration = 0; m_totalTargetDuration = 0; @@ -557,6 +554,14 @@ R3Stretcher::reset() m_keyFrameMap.clear(); m_mode = ProcessMode::JustCreated; + + m_prevInhop = 1; + m_prevOuthop = 1; + + calculateHop(); + + m_prevInhop = m_inhop; + m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); } void diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index 9e63d2a..6954cb0 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -1251,5 +1251,77 @@ BOOST_AUTO_TEST_CASE(final_fast_lower_realtime_finer_after) false); } +BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_reset_finer) +{ + int n = 10000; + int rate = 44100; + RubberBandStretcher stretcher + (rate, 1, RubberBandStretcher::OptionEngineFiner); + + stretcher.setTimeRatio(2.0); + stretcher.setPitchScale(1.5); + + vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); + + in[100] = 1.f; + in[101] = -1.f; + + in[5000] = 1.f; + in[5001] = -1.f; + + in[9900] = 1.f; + in[9901] = -1.f; + + float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + size_t got = stretcher.retrieve(&outp1, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + stretcher.reset(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + got = stretcher.retrieve(&outp2, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + for (int i = 0; i < n * 2; ++i) { + BOOST_TEST(outp1[i] == outp2[i]); + if (outp1[i] != outp2[i]) { + std::cerr << "Failure at index " << i << std::endl; + break; + } + } + +/* + std::cout << "ms\tV" << std::endl; + for (int i = 0; i < n*2; ++i) { + std::cout << i << "\t" << out[i] << std::endl; + } +*/ +} BOOST_AUTO_TEST_SUITE_END() From 6c71159593b4626ec4f6cd1a3a0c3e878d5daa05 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Wed, 22 Mar 2023 13:26:15 +0000 Subject: [PATCH 2/8] More reset tests, tighten up reset logic --- src/finer/BinClassifier.h | 11 ++++ src/finer/R3Stretcher.cpp | 2 + src/finer/R3Stretcher.h | 6 +- src/test/TestStretcher.cpp | 122 +++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 1 deletion(-) diff --git a/src/finer/BinClassifier.h b/src/finer/BinClassifier.h index 88a3d0d..d489946 100644 --- a/src/finer/BinClassifier.h +++ b/src/finer/BinClassifier.h @@ -92,6 +92,17 @@ public: void reset() { + while (m_vfQueue.getReadSpace() > 0) { + process_t *entry = m_vfQueue.readOne(); + deallocate(entry); + } + + for (int i = 0; i < m_parameters.horizontalFilterLag; ++i) { + process_t *entry = + allocate_and_zero(m_parameters.binCount); + m_vfQueue.write(&entry, 1); + } + m_hFilters->reset(); } diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index bfbbbde..d99b17c 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -533,6 +533,7 @@ void R3Stretcher::reset() { m_calculator->reset(); + if (m_resampler) { m_resampler->reset(); } @@ -545,6 +546,7 @@ R3Stretcher::reset() cd->reset(); } + m_unityCount = 0; m_studyInputDuration = 0; m_suppliedInputDuration = 0; m_totalTargetDuration = 0; diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index 88660f1..f8f39a6 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -172,6 +172,7 @@ protected: void reset() { v_zero(prevMag.data(), prevMag.size()); + v_zero(pendingKick.data(), pendingKick.size()); v_zero(accumulator.data(), accumulator.size()); accumulatorFill = 0; } @@ -226,7 +227,7 @@ protected: std::unique_ptr formant; ChannelData(BinSegmenter::Parameters segmenterParameters, BinClassifier::Parameters classifierParameters, - int longestFftSize, + int /*!!! longestFftSize */, int windowSourceSize, int inRingBufferSize, int outRingBufferSize) : @@ -252,6 +253,9 @@ protected: segmentation = BinSegmenter::Segmentation(); prevSegmentation = BinSegmenter::Segmentation(); nextSegmentation = BinSegmenter::Segmentation(); + for (size_t i = 0; i < nextClassification.size(); ++i) { + nextClassification[i] = BinClassifier::Classification::Residual; + } inbuf->reset(); outbuf->reset(); for (auto &s : scales) { diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index 6954cb0..b003486 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -1251,6 +1251,79 @@ BOOST_AUTO_TEST_CASE(final_fast_lower_realtime_finer_after) false); } +BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer) +{ + int n = 10000; + int rate = 44100; + RubberBandStretcher stretcher + (rate, 1, RubberBandStretcher::OptionEngineFiner); + + stretcher.setTimeRatio(2.0); + stretcher.setPitchScale(1.0); + + vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); + + in[100] = 1.f; + in[101] = -1.f; + + in[5000] = 1.f; + in[5001] = -1.f; + + in[9900] = 1.f; + in[9901] = -1.f; + + float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + size_t got = stretcher.retrieve(&outp1, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + stretcher.reset(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + got = stretcher.retrieve(&outp2, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + for (int i = 0; i < n * 2; ++i) { + BOOST_TEST(outp1[i] == outp2[i]); + if (outp1[i] != outp2[i]) { + std::cerr << "Failure at index " << i << std::endl; + break; + } + } + +/* + std::cout << "ms\tV" << std::endl; + for (int i = 0; i < n*2; ++i) { + std::cout << i << "\t" << out[i] << std::endl; + } +*/ +} + BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_reset_finer) { int n = 10000; @@ -1324,4 +1397,53 @@ BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_reset_finer) */ } +BOOST_AUTO_TEST_CASE(impulses_2x_5up_realtime_reset_finer) +{ + int n = 10000; + int rate = 44100; + RubberBandStretcher stretcher + (rate, 1, RubberBandStretcher::OptionEngineFiner); + + stretcher.setTimeRatio(2.0); + stretcher.setPitchScale(1.5); + + vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); + + in[100] = 1.f; + in[101] = -1.f; + + in[5000] = 1.f; + in[5001] = -1.f; + + in[9900] = 1.f; + in[9901] = -1.f; + + float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); + + stretcher.process(&inp, n, true); + size_t got1 = stretcher.retrieve(&outp1, n * 2); + BOOST_TEST(got1 <= n * 2); + + stretcher.reset(); + + stretcher.process(&inp, n, true); + size_t got2 = stretcher.retrieve(&outp2, n * 2); + BOOST_TEST(got2 == got1); + + for (size_t i = 0; i < got1; ++i) { + BOOST_TEST(outp1[i] == outp2[i]); + if (outp1[i] != outp2[i]) { + std::cerr << "Failure at index " << i << std::endl; + break; + } + } + +/* + std::cout << "ms\tV" << std::endl; + for (int i = 0; i < n*2; ++i) { + std::cout << i << "\t" << out[i] << std::endl; + } +*/ +} + BOOST_AUTO_TEST_SUITE_END() From 99d2d4a080d15d9385c86a8fd5794b8540e2bd26 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 10:25:18 +0000 Subject: [PATCH 3/8] Further adjustments to reset, and ensure initial prev in/out hops are set the same way if ratios set after construction as they are if ratios set on construction. Plus tests --- src/finer/R3Stretcher.cpp | 52 +++++--- src/finer/R3Stretcher.h | 1 + src/test/TestStretcher.cpp | 267 ++++++++++++++++++++++++++++++++++++- 3 files changed, 297 insertions(+), 23 deletions(-) diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index d99b17c..05ef5c6 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -61,7 +61,13 @@ R3Stretcher::R3Stretcher(Parameters parameters, m_mode(ProcessMode::JustCreated) { Profiler profiler("R3Stretcher::R3Stretcher"); - + + initialise(); +} + +void +R3Stretcher::initialise() +{ m_log.log(1, "R3Stretcher::R3Stretcher: rate, options", m_parameters.sampleRate, m_parameters.options); m_log.log(1, "R3Stretcher::R3Stretcher: initial time ratio and pitch scale", @@ -99,6 +105,8 @@ R3Stretcher::R3Stretcher(Parameters parameters, int inRingBufferSize = getWindowSourceSize() * 16; int outRingBufferSize = getWindowSourceSize() * 16; + m_channelData.clear(); + for (int c = 0; c < m_parameters.channels; ++c) { m_channelData.push_back(std::make_shared (segmenterParameters, @@ -115,6 +123,8 @@ R3Stretcher::R3Stretcher(Parameters parameters, (fftSize, m_guideConfiguration.longestFftSize); } } + + m_scaleData.clear(); for (int b = 0; b < m_guideConfiguration.fftBandLimitCount; ++b) { const auto &band = m_guideConfiguration.fftBandLimits[b]; @@ -141,9 +151,6 @@ R3Stretcher::R3Stretcher(Parameters parameters, calculateHop(); - m_prevInhop = m_inhop; - m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); - if (!m_inhop.is_lock_free()) { m_log.log(0, "R3Stretcher: WARNING: std::atomic is not lock-free"); } @@ -388,6 +395,11 @@ R3Stretcher::calculateHop() m_log.log(1, "calculateHop: not using readahead, inhop too long for buffer in current configuration"); m_useReadahead = false; } + + if (m_mode == ProcessMode::JustCreated) { + m_prevInhop = m_inhop; + m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); + } } void @@ -532,6 +544,21 @@ R3Stretcher::getChannelCount() const void R3Stretcher::reset() { + m_inhop = 1; + m_prevInhop = 1; + m_prevOuthop = 1; + m_unityCount = 0; + m_startSkip = 0; + m_studyInputDuration = 0; + m_suppliedInputDuration = 0; + m_totalTargetDuration = 0; + m_consumedInputDuration = 0; + m_lastKeyFrameSurpassed = 0; + m_totalOutputDuration = 0; + m_keyFrameMap.clear(); + + m_mode = ProcessMode::JustCreated; + m_calculator->reset(); if (m_resampler) { @@ -546,24 +573,7 @@ R3Stretcher::reset() cd->reset(); } - m_unityCount = 0; - m_studyInputDuration = 0; - m_suppliedInputDuration = 0; - m_totalTargetDuration = 0; - m_consumedInputDuration = 0; - m_lastKeyFrameSurpassed = 0; - m_totalOutputDuration = 0; - m_keyFrameMap.clear(); - - m_mode = ProcessMode::JustCreated; - - m_prevInhop = 1; - m_prevOuthop = 1; - calculateHop(); - - m_prevInhop = m_inhop; - m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); } void diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index f8f39a6..77ee3d0 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -356,6 +356,7 @@ protected: }; ProcessMode m_mode; + void initialise(); void prepareInput(const float *const *input, int ix, int n); void consume(); void createResampler(); diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index b003486..e596efb 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -1251,12 +1251,275 @@ BOOST_AUTO_TEST_CASE(final_fast_lower_realtime_finer_after) false); } -BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer) +static void with_resets(RubberBandStretcher::Options options, + double timeRatio, + double pitchScale) +{ + const int n = 10000; + const int nOut = int(round(n * timeRatio)); + const int rate = 44100; + const bool realtime = + (options & RubberBandStretcher::OptionProcessRealTime); + + vector in(n, 0.f), outRef(nOut, 0.f), out(nOut, 0.f); + + in[100] = 1.f; + in[101] = -1.f; + + in[5000] = 1.f; + in[5001] = -1.f; + + in[9900] = 1.f; + in[9901] = -1.f; + + int nExpected = 0; + + RubberBandStretcher *stretcher = nullptr; + + // Combinations we need to ensure produce identical outputs: + // 1. With timeRatio and pitchScale passed to constructor + // 2. Then reset called and run again + // 3. New instance, no ratios passed to ctor, timeRatio and + // pitchScale set after construction + // 4. Then reset called and run again + + for (int run = 1; run <= 4; ++run) { // run being index into list above + + float *inp = in.data(), *outRefp = outRef.data(), *outp = out.data(); + + if (run == 1 || run == 3) { + delete stretcher; + if (run == 1) { + stretcher = new RubberBandStretcher(rate, 1, options, + timeRatio, pitchScale); + } else { + stretcher = new RubberBandStretcher(rate, 1, options); + stretcher->setTimeRatio(timeRatio); + stretcher->setPitchScale(pitchScale); + } + } + + if (run == 2 || run == 4) { + stretcher->reset(); + } + + // In every case we request nOut samples into out, and nActual + // records how many we actually get + int nActual = 0; + + if (realtime) { + + int blocksize = 1024; + int nIn = 0; + + while (nActual < nOut) { + int bsHere = blocksize; + bool final = false; + if (nIn + blocksize > n) { + bsHere = n - nIn; + final = true; + } + stretcher->process(&inp, bsHere, final); + nIn += bsHere; + inp += bsHere; + int avail = stretcher->available(); + if (avail < 0) break; + int toGet = avail; + if (nActual + toGet > nOut) { + toGet = nOut - nActual; + } + int got = (int)stretcher->retrieve(&outp, toGet); + nActual += got; + outp += got; + if (final) break; + } + + BOOST_TEST(nActual <= nOut); + + } else { + + stretcher->setMaxProcessSize(n); + stretcher->setExpectedInputDuration(n); + BOOST_TEST(stretcher->available() == 0); + + stretcher->study(&inp, n, true); + BOOST_TEST(stretcher->available() == 0); + + stretcher->process(&inp, n, true); + BOOST_TEST(stretcher->available() == nOut); + + BOOST_TEST(stretcher->getStartDelay() == 0); // offline mode + + nActual = (int)stretcher->retrieve(&outp, nOut); + BOOST_TEST(nActual == nOut); + BOOST_TEST(stretcher->available() == -1); + } + + if (run == 1) { // set up expectations for subsequent runs + + for (int i = 0; i < nActual; ++i) { + outRef[i] = out[i]; + } + nExpected = nActual; + + } else { // check expectations + + BOOST_TEST(nActual == nExpected); + + for (int i = 0; i < nActual; ++i) { + BOOST_TEST(out[i] == outRef[i]); + if (out[i] != outRef[i]) { + std::cerr << "Failure at index " << i << " in run " + << run << std::endl; + break; + } + } + } + } + + delete stretcher; +} + +BOOST_AUTO_TEST_CASE(with_resets_1x_0up_offline_finer) +{ + with_resets(RubberBandStretcher::OptionEngineFiner, 1.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_0up_offline_finer) +{ + with_resets(RubberBandStretcher::OptionEngineFiner, 2.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_5up_offline_finer) +{ + with_resets(RubberBandStretcher::OptionEngineFiner, 2.0, 1.5); +} + +BOOST_AUTO_TEST_CASE(with_resets_1x_0up_offline_faster) +{ + with_resets(RubberBandStretcher::OptionEngineFaster, 1.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_0up_offline_faster) +{ + with_resets(RubberBandStretcher::OptionEngineFaster, 2.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_5up_offline_faster) +{ + with_resets(RubberBandStretcher::OptionEngineFaster, 2.0, 1.5); +} + +BOOST_AUTO_TEST_CASE(with_resets_1x_0up_realtime_finer) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFiner, 1.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_0up_realtime_finer) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFiner, 2.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_5up_realtime_finer) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFiner, 2.0, 1.5); +} + +BOOST_AUTO_TEST_CASE(with_resets_1x_0up_realtime_faster) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFaster, 1.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_0up_realtime_faster) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFaster, 2.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(with_resets_2x_5up_realtime_faster) +{ + with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFaster, 2.0, 1.5); +} + + + +BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer_initialparams) { int n = 10000; int rate = 44100; RubberBandStretcher stretcher - (rate, 1, RubberBandStretcher::OptionEngineFiner); + (rate, 1, RubberBandStretcher::OptionEngineFiner, + 2.0, 1.0); + + vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); + + in[100] = 1.f; + in[101] = -1.f; + + in[5000] = 1.f; + in[5001] = -1.f; + + in[9900] = 1.f; + in[9901] = -1.f; + + float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + size_t got = stretcher.retrieve(&outp1, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + stretcher.reset(); + + stretcher.setMaxProcessSize(n); + stretcher.setExpectedInputDuration(n); + BOOST_TEST(stretcher.available() == 0); + + stretcher.study(&inp, n, true); + BOOST_TEST(stretcher.available() == 0); + + stretcher.process(&inp, n, true); + BOOST_TEST(stretcher.available() == n * 2); + + BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode + + got = stretcher.retrieve(&outp2, n * 2); + BOOST_TEST(got == n * 2); + BOOST_TEST(stretcher.available() == -1); + + for (int i = 0; i < n * 2; ++i) { + BOOST_TEST(outp1[i] == outp2[i]); + if (outp1[i] != outp2[i]) { + std::cerr << "Failure at index " << i << std::endl; + break; + } + } + +/* + std::cout << "ms\tV" << std::endl; + for (int i = 0; i < n*2; ++i) { + std::cout << i << "\t" << out[i] << std::endl; + } +*/ +} + +BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer_postparams) +{ + int n = 10000; + int rate = 44100; + RubberBandStretcher stretcher + (rate, 1, RubberBandStretcher::OptionEngineFiner, + 2.0, 1.0); stretcher.setTimeRatio(2.0); stretcher.setPitchScale(1.0); From 47f884548621a8975e6da5ed19ccf90112aa505c Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 10:26:57 +0000 Subject: [PATCH 4/8] Remove duplicate tests --- src/test/TestStretcher.cpp | 269 ------------------------------------- 1 file changed, 269 deletions(-) diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index e596efb..54999bf 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -1440,273 +1440,4 @@ BOOST_AUTO_TEST_CASE(with_resets_2x_5up_realtime_faster) with_resets(RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFaster, 2.0, 1.5); } - - -BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer_initialparams) -{ - int n = 10000; - int rate = 44100; - RubberBandStretcher stretcher - (rate, 1, RubberBandStretcher::OptionEngineFiner, - 2.0, 1.0); - - vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); - - in[100] = 1.f; - in[101] = -1.f; - - in[5000] = 1.f; - in[5001] = -1.f; - - in[9900] = 1.f; - in[9901] = -1.f; - - float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - size_t got = stretcher.retrieve(&outp1, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - stretcher.reset(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - got = stretcher.retrieve(&outp2, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - for (int i = 0; i < n * 2; ++i) { - BOOST_TEST(outp1[i] == outp2[i]); - if (outp1[i] != outp2[i]) { - std::cerr << "Failure at index " << i << std::endl; - break; - } - } - -/* - std::cout << "ms\tV" << std::endl; - for (int i = 0; i < n*2; ++i) { - std::cout << i << "\t" << out[i] << std::endl; - } -*/ -} - -BOOST_AUTO_TEST_CASE(impulses_2x_0up_offline_reset_finer_postparams) -{ - int n = 10000; - int rate = 44100; - RubberBandStretcher stretcher - (rate, 1, RubberBandStretcher::OptionEngineFiner, - 2.0, 1.0); - - stretcher.setTimeRatio(2.0); - stretcher.setPitchScale(1.0); - - vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); - - in[100] = 1.f; - in[101] = -1.f; - - in[5000] = 1.f; - in[5001] = -1.f; - - in[9900] = 1.f; - in[9901] = -1.f; - - float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - size_t got = stretcher.retrieve(&outp1, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - stretcher.reset(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - got = stretcher.retrieve(&outp2, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - for (int i = 0; i < n * 2; ++i) { - BOOST_TEST(outp1[i] == outp2[i]); - if (outp1[i] != outp2[i]) { - std::cerr << "Failure at index " << i << std::endl; - break; - } - } - -/* - std::cout << "ms\tV" << std::endl; - for (int i = 0; i < n*2; ++i) { - std::cout << i << "\t" << out[i] << std::endl; - } -*/ -} - -BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_reset_finer) -{ - int n = 10000; - int rate = 44100; - RubberBandStretcher stretcher - (rate, 1, RubberBandStretcher::OptionEngineFiner); - - stretcher.setTimeRatio(2.0); - stretcher.setPitchScale(1.5); - - vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); - - in[100] = 1.f; - in[101] = -1.f; - - in[5000] = 1.f; - in[5001] = -1.f; - - in[9900] = 1.f; - in[9901] = -1.f; - - float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - size_t got = stretcher.retrieve(&outp1, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - stretcher.reset(); - - stretcher.setMaxProcessSize(n); - stretcher.setExpectedInputDuration(n); - BOOST_TEST(stretcher.available() == 0); - - stretcher.study(&inp, n, true); - BOOST_TEST(stretcher.available() == 0); - - stretcher.process(&inp, n, true); - BOOST_TEST(stretcher.available() == n * 2); - - BOOST_TEST(stretcher.getStartDelay() == 0); // offline mode - - got = stretcher.retrieve(&outp2, n * 2); - BOOST_TEST(got == n * 2); - BOOST_TEST(stretcher.available() == -1); - - for (int i = 0; i < n * 2; ++i) { - BOOST_TEST(outp1[i] == outp2[i]); - if (outp1[i] != outp2[i]) { - std::cerr << "Failure at index " << i << std::endl; - break; - } - } - -/* - std::cout << "ms\tV" << std::endl; - for (int i = 0; i < n*2; ++i) { - std::cout << i << "\t" << out[i] << std::endl; - } -*/ -} - -BOOST_AUTO_TEST_CASE(impulses_2x_5up_realtime_reset_finer) -{ - int n = 10000; - int rate = 44100; - RubberBandStretcher stretcher - (rate, 1, RubberBandStretcher::OptionEngineFiner); - - stretcher.setTimeRatio(2.0); - stretcher.setPitchScale(1.5); - - vector in(n, 0.f), out1(n * 2, 0.f), out2(n * 2, 0.f); - - in[100] = 1.f; - in[101] = -1.f; - - in[5000] = 1.f; - in[5001] = -1.f; - - in[9900] = 1.f; - in[9901] = -1.f; - - float *inp = in.data(), *outp1 = out1.data(), *outp2 = out2.data(); - - stretcher.process(&inp, n, true); - size_t got1 = stretcher.retrieve(&outp1, n * 2); - BOOST_TEST(got1 <= n * 2); - - stretcher.reset(); - - stretcher.process(&inp, n, true); - size_t got2 = stretcher.retrieve(&outp2, n * 2); - BOOST_TEST(got2 == got1); - - for (size_t i = 0; i < got1; ++i) { - BOOST_TEST(outp1[i] == outp2[i]); - if (outp1[i] != outp2[i]) { - std::cerr << "Failure at index " << i << std::endl; - break; - } - } - -/* - std::cout << "ms\tV" << std::endl; - for (int i = 0; i < n*2; ++i) { - std::cout << i << "\t" << out[i] << std::endl; - } -*/ -} - BOOST_AUTO_TEST_SUITE_END() From d063f851b47454992ef01d243d51ffe2bdbdf940 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 13:01:19 +0000 Subject: [PATCH 5/8] Further test --- src/test/TestStretcher.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index 54999bf..a6db469 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -881,7 +881,7 @@ BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_finer) if (out[i] > max) { max = out[i]; peak2 = i; } } - BOOST_TEST(peak0 < 100); + BOOST_TEST(peak0 < 250); BOOST_TEST(peak1 > n - 400); BOOST_TEST(peak1 < n + 50); BOOST_TEST(peak2 > n*2 - 600); @@ -1282,6 +1282,9 @@ static void with_resets(RubberBandStretcher::Options options, // 3. New instance, no ratios passed to ctor, timeRatio and // pitchScale set after construction // 4. Then reset called and run again + // 5. Reset called again, timeRatio and pitchScale set again (to + // the same things, just in case the act of setting them + // changes anything) and run again for (int run = 1; run <= 4; ++run) { // run being index into list above @@ -1299,8 +1302,12 @@ static void with_resets(RubberBandStretcher::Options options, } } - if (run == 2 || run == 4) { + if (run == 2 || run == 4 || run == 5) { stretcher->reset(); + if (run == 5) { + stretcher->setTimeRatio(timeRatio); + stretcher->setPitchScale(pitchScale); + } } // In every case we request nOut samples into out, and nActual From adfe1ff2cf039277d139a121d9cb740b28f0d72d Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 17:26:11 +0000 Subject: [PATCH 6/8] Further resets --- src/faster/R2Stretcher.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/faster/R2Stretcher.cpp b/src/faster/R2Stretcher.cpp index 996d195..4c44bc8 100644 --- a/src/faster/R2Stretcher.cpp +++ b/src/faster/R2Stretcher.cpp @@ -223,6 +223,8 @@ R2Stretcher::reset() m_mode = JustCreated; if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset(); if (m_silentAudioCurve) m_silentAudioCurve->reset(); + m_expectedInputDuration = 0; + m_maxProcessSize = 0; m_inputDuration = 0; m_silentHistory = 0; From 963752951d858a905b6478c09cf8a550fa55e4f3 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 17:26:28 +0000 Subject: [PATCH 7/8] Fix erroneous limits calculations --- src/finer/R3Stretcher.cpp | 4 ++-- src/finer/R3Stretcher.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index 05ef5c6..2608585 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -389,10 +389,10 @@ R3Stretcher::calculateHop() m_log.log(1, "calculateHop: inhop and mean outhop", m_inhop, m_inhop * ratio); if (m_inhop < m_limits.maxInhopWithReadahead) { - m_log.log(1, "calculateHop: using readahead"); + m_log.log(1, "calculateHop: using readahead; maxInhopWithReadahead", m_limits.maxInhopWithReadahead); m_useReadahead = true; } else { - m_log.log(1, "calculateHop: not using readahead, inhop too long for buffer in current configuration"); + m_log.log(1, "calculateHop: not using readahead; maxInhopWithReadahead", m_limits.maxInhopWithReadahead); m_useReadahead = false; } diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index 77ee3d0..1e25cf2 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -114,8 +114,8 @@ protected: minPreferredOuthop(roundUpDiv(rate, 512)), // 128 maxPreferredOuthop(roundUpDiv(rate, 128)), // 512 minInhop(1), - maxInhopWithReadahead(roundUpDiv(rate, 32)), // 1024 - maxInhop(roundUpDiv(rate, 32)) { // 1024 + maxInhopWithReadahead(roundUpDiv(rate, 64)), // 1024 + maxInhop(roundUpDiv(rate, 32)) { // 2048 if (options & RubberBandStretcher::OptionWindowShort) { // See note in calculateHop minPreferredOuthop = roundUpDiv(rate, 256); // 256 From fbb4979f876e659c926c1ff432461d92f02e366c Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 23 Mar 2023 17:26:36 +0000 Subject: [PATCH 8/8] Further reset tests --- src/test/TestStretcher.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index a6db469..5b2352e 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -1068,7 +1068,7 @@ static void final_realtime(RubberBandStretcher::Options options, BOOST_TEST(stretcher.available() == 0); int toSkip = stretcher.getStartDelay(); - + int incount = 0, outcount = 0; while (true) { @@ -1285,10 +1285,12 @@ static void with_resets(RubberBandStretcher::Options options, // 5. Reset called again, timeRatio and pitchScale set again (to // the same things, just in case the act of setting them // changes anything) and run again + // 6. More input supplied and left in stretcher (output not + // retrieved) - then reset called and run again - for (int run = 1; run <= 4; ++run) { // run being index into list above + for (int run = 1; run <= 6; ++run) { // run being index into list above - float *inp = in.data(), *outRefp = outRef.data(), *outp = out.data(); + float *inp = in.data(), *outp = out.data(); if (run == 1 || run == 3) { delete stretcher; @@ -1302,7 +1304,7 @@ static void with_resets(RubberBandStretcher::Options options, } } - if (run == 2 || run == 4 || run == 5) { + if (run == 2 || run > 3) { stretcher->reset(); if (run == 5) { stretcher->setTimeRatio(timeRatio); @@ -1310,6 +1312,16 @@ static void with_resets(RubberBandStretcher::Options options, } } + if (run == 6) { + if (realtime) { + stretcher->process(&inp, n / 2, false); + } else { + stretcher->study(&inp, n / 2, true); + stretcher->process(&inp, n / 2, false); + } + stretcher->reset(); + } + // In every case we request nOut samples into out, and nActual // records how many we actually get int nActual = 0;