From d5dd0e573a42422c605a4bf6221ece217d41744b Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Mon, 20 Feb 2023 17:46:10 +0000 Subject: [PATCH] Further timing tests --- src/test/TestStretcher.cpp | 444 ++++++++++++++++++++++++++++--------- 1 file changed, 338 insertions(+), 106 deletions(-) diff --git a/src/test/TestStretcher.cpp b/src/test/TestStretcher.cpp index 3bd96aa..a389f60 100644 --- a/src/test/TestStretcher.cpp +++ b/src/test/TestStretcher.cpp @@ -229,40 +229,13 @@ BOOST_AUTO_TEST_CASE(sinusoid_2x_offline_finer) BOOST_TEST(rms < 0.1); } -static void sinusoid_realtime(RubberBandStretcher::Options options, - double timeRatio, - double pitchScale, - bool printDebug) +static vector process_realtime(RubberBandStretcher &stretcher, + const vector &in, + int nOut, + int bs, + bool printDebug) { - int n = (timeRatio < 1.0 ? 80000 : 40000); - int nOut = int(ceil(n * timeRatio)); - float freq = 441.f; - int rate = 44100; - int bs = 512; - - // This test simulates block-by-block realtime processing with - // latency compensation, and checks that the output is all in the - // expected place - - RubberBandStretcher stretcher(rate, 1, options, timeRatio, pitchScale); - stretcher.setMaxProcessSize(bs); - - if (printDebug) { - stretcher.setDebugLevel(2); - } - - // The input signal is a fixed frequency sinusoid that steps up in - // amplitude every 1/10 of the total duration - from 0.1 at the - // start, via increments of 0.1, to 1.0 at the end - - vector in(n); - for (int i = 0; i < n; ++i) { - float amplitude = float((i / (n/10)) + 1) / 10.f; - float sample = amplitude * - sinf(float(i) * freq * M_PI * 2.f / float(rate)); - in[i] = sample; - } - + int n = in.size(); vector out(nOut, 0.f); // Prime the start @@ -298,7 +271,7 @@ static void sinusoid_realtime(RubberBandStretcher::Options options, int required = stretcher.getSamplesRequired(); BOOST_TEST(required > 0); // because available == 0 int toProcess = std::min(required, n - inOffset); - float *source = in.data() + inOffset; + const float *const source = in.data() + inOffset; bool final = (toProcess < required); stretcher.process(&source, toProcess, final); inOffset += toProcess; @@ -330,6 +303,45 @@ static void sinusoid_realtime(RubberBandStretcher::Options options, std::cout << "#" << i << "\t" << out[i] << std::endl; } } + + return out; +} + +static void sinusoid_realtime(RubberBandStretcher::Options options, + double timeRatio, + double pitchScale, + bool printDebug) +{ + int n = (timeRatio < 1.0 ? 80000 : 40000); + int nOut = int(ceil(n * timeRatio)); + float freq = 441.f; + int rate = 44100; + int bs = 512; + + // This test simulates block-by-block realtime processing with + // latency compensation, and checks that the output is all in the + // expected place + + RubberBandStretcher stretcher(rate, 1, options, timeRatio, pitchScale); + stretcher.setMaxProcessSize(bs); + + if (printDebug) { + stretcher.setDebugLevel(2); + } + + // The input signal is a fixed frequency sinusoid that steps up in + // amplitude every 1/10 of the total duration - from 0.1 at the + // start, via increments of 0.1, to 1.0 at the end + + vector in(n); + for (int i = 0; i < n; ++i) { + float amplitude = float((i / (n/10)) + 1) / 10.f; + float sample = amplitude * + sinf(float(i) * freq * M_PI * 2.f / float(rate)); + in[i] = sample; + } + + vector out = process_realtime(stretcher, in, nOut, bs, printDebug); // Step through the output signal in chunk of 1/20 of its duration // (i.e. a rather arbitrary two per expected 0.1 increment in @@ -368,7 +380,9 @@ static void sinusoid_realtime(RubberBandStretcher::Options options, int slack = 0; if (options & RubberBandStretcher::OptionEngineFiner) { - if (chunk == 0 || chunk == 19 || highSpeedPitch) { + if (options & RubberBandStretcher::OptionWindowShort) { + slack = 2; + } else if (chunk == 0 || chunk == 19 || highSpeedPitch) { slack = 1; } } else { @@ -399,7 +413,8 @@ static void sinusoid_realtime(RubberBandStretcher::Options options, double maxOver = 0.01; double maxUnder = 0.1; - if (!(options & RubberBandStretcher::OptionEngineFiner)) { + if (!(options & RubberBandStretcher::OptionEngineFiner) || + (options & RubberBandStretcher::OptionWindowShort)) { maxUnder = 0.2; } @@ -416,14 +431,6 @@ BOOST_AUTO_TEST_CASE(sinusoid_slow_samepitch_realtime_finer) false); } -BOOST_AUTO_TEST_CASE(sinusoid_slow_samepitch_realtime_faster) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime, - 8.0, 1.0, - false); -} - BOOST_AUTO_TEST_CASE(sinusoid_fast_samepitch_realtime_finer) { sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | @@ -432,14 +439,6 @@ BOOST_AUTO_TEST_CASE(sinusoid_fast_samepitch_realtime_finer) false); } -BOOST_AUTO_TEST_CASE(sinusoid_fast_samepitch_realtime_faster) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime, - 0.5, 1.0, - false); -} - BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_finer) { sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | @@ -466,32 +465,6 @@ BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_finer_hcpitch) false); } -BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime, - 4.0, 1.5, - false); -} - -BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster_hqpitch) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime | - RubberBandStretcher::OptionPitchHighQuality, - 4.0, 1.5, - false); -} - -BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster_hcpitch) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime | - RubberBandStretcher::OptionPitchHighConsistency, - 4.0, 1.5, - false); -} - BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_finer) { sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | @@ -518,32 +491,6 @@ BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_finer_hcpitch) false); } -BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime, - 0.5, 1.5, - false); -} - -BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster_hqpitch) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime | - RubberBandStretcher::OptionPitchHighQuality, - 0.5, 1.5, - false); -} - -BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster_hcpitch) -{ - sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | - RubberBandStretcher::OptionProcessRealTime | - RubberBandStretcher::OptionPitchHighConsistency, - 0.5, 1.5, - false); -} - BOOST_AUTO_TEST_CASE(sinusoid_slow_lower_realtime_finer) { sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | @@ -570,6 +517,149 @@ BOOST_AUTO_TEST_CASE(sinusoid_slow_lower_realtime_finer_hcpitch) false); } +BOOST_AUTO_TEST_CASE(sinusoid_slow_samepitch_realtime_finer_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort, + 8.0, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_samepitch_realtime_finer_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort, + 0.5, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_finer_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_finer_short_hcpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort | + RubberBandStretcher::OptionPitchHighConsistency, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_finer_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort, + 0.5, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_finer_hcpitch_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort | + RubberBandStretcher::OptionPitchHighConsistency, + 0.5, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_lower_realtime_finer_short) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort, + 8.0, 0.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_lower_realtime_finer_short_hcpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionWindowShort | + RubberBandStretcher::OptionPitchHighConsistency, + 8.0, 0.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_samepitch_realtime_faster) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime, + 8.0, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_samepitch_realtime_faster) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime, + 0.5, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster_hqpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighQuality, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_slow_higher_realtime_faster_hcpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighConsistency, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime, + 0.5, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster_hqpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighQuality, + 0.5, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(sinusoid_fast_higher_realtime_faster_hcpitch) +{ + sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighConsistency, + 0.5, 1.5, + false); +} + BOOST_AUTO_TEST_CASE(sinusoid_slow_lower_realtime_faster) { sinusoid_realtime(RubberBandStretcher::OptionEngineFaster | @@ -803,7 +893,142 @@ BOOST_AUTO_TEST_CASE(impulses_2x_5up_offline_finer) } */ } + +static void impulses_realtime(RubberBandStretcher::Options options, + double timeRatio, + double pitchScale, + bool printDebug) +{ + int n = 10000; + int nOut = int(ceil(n * timeRatio)); + int rate = 48000; + int bs = 1024; + + RubberBandStretcher stretcher(rate, 1, options, timeRatio, pitchScale); + + if (printDebug) { + stretcher.setDebugLevel(2); + } + + vector in(n, 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; + + vector out = process_realtime(stretcher, in, nOut, bs, printDebug); + + int peak0 = -1, peak1 = -1, peak2 = -1; + float max; + + max = -2.f; + for (int i = 0; i < nOut/4; ++i) { + if (out[i] > max) { max = out[i]; peak0 = i; } + } + + max = -2.f; + for (int i = nOut/4; i < (nOut*3)/4; ++i) { + if (out[i] > max) { max = out[i]; peak1 = i; } + } + + max = -2.f; + for (int i = (nOut*3)/4; i < nOut; ++i) { + if (out[i] > max) { max = out[i]; peak2 = i; } + } + + // These limits aren't alarming, but it be worth tightening them + // and and taking a look at the waveforms + + BOOST_TEST(peak0 < int(ceil(200 * timeRatio))); + BOOST_TEST(peak0 > int(ceil(50 * timeRatio))); + + BOOST_TEST(peak1 < int(ceil(5070 * timeRatio))); + BOOST_TEST(peak1 > int(ceil(4840 * timeRatio))); + + BOOST_TEST(peak2 < int(ceil(9970 * timeRatio))); + BOOST_TEST(peak2 > int(ceil(9770 * timeRatio))); + /* + 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_slow_samepitch_realtime_finer) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime, + 8.0, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_fast_samepitch_realtime_finer) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime, + 0.5, 1.0, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_higher_realtime_finer) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_higher_realtime_finer_hqpitch) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighQuality, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_higher_realtime_finer_hcpitch) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighConsistency, + 4.0, 1.5, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_lower_realtime_finer) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime, + 8.0, 0.5, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_lower_realtime_finer_hqpitch) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighQuality, + 8.0, 0.5, + false); +} + +BOOST_AUTO_TEST_CASE(impulses_slow_lower_realtime_finer_hcpitch) +{ + impulses_realtime(RubberBandStretcher::OptionEngineFiner | + RubberBandStretcher::OptionProcessRealTime | + RubberBandStretcher::OptionPitchHighConsistency, + 8.0, 0.5, + false); +} + BOOST_AUTO_TEST_CASE(final_realtime_faster) { int n = 10000; @@ -845,11 +1070,18 @@ BOOST_AUTO_TEST_CASE(final_realtime_faster) float *out = outp + outcount; size_t got = stretcher.retrieve(&out, avail); BOOST_TEST(got == size_t(avail)); - BOOST_TEST(stretcher.available() == 0); incount += inbs; outcount += got; + + cerr << "outcount = " << outcount << ", n = " << n << endl; + + if (outcount >= n * 2) { + BOOST_TEST(stretcher.available() == -1); + } else { + BOOST_TEST(stretcher.available() == 0); + } } } -*/ + BOOST_AUTO_TEST_SUITE_END()