50b2a22ae6b7 — Chris Cannam 2 months ago
Further tests
2 files changed, 126 insertions(+), 26 deletions(-)

M src/finer/R3LiveShifter.cpp
M src/test/TestLiveShifter.cpp
M src/finer/R3LiveShifter.cpp +2 -1
@@ 184,6 184,7 @@ R3LiveShifter::setPitchScale(double scal
     m_log.log(2, "R3LiveShifter::setPitchScale", scale);
     if (scale == m_pitchScale) return;
     m_pitchScale = scale;
+    measureResamplerDelay();
 }
 
 void

          
@@ 242,7 243,7 @@ R3LiveShifter::measureResamplerDelay()
     auto outbuf = inbuf;
 
     int outcount = m_inResampler->resampleInterleaved
-        (outbuf.data(), bs, inbuf.data(), bs, 1.0, false);
+        (outbuf.data(), bs, inbuf.data(), bs, m_pitchScale, false);
 
     m_inResampler->reset();
 

          
M src/test/TestLiveShifter.cpp +124 -25
@@ 42,6 42,41 @@ namespace tt = boost::test_tools;
 
 BOOST_AUTO_TEST_SUITE(TestLiveShifter)
 
+static void dump(const vector<float> &in,
+                 const vector<float> &out,
+                 const vector<float> &expected,
+                 int delay)
+{
+    std::cerr << "dump: delay reported as " << delay << 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 << "OUT," << i << "," << out[i] << std::endl;
+    }
+
+    std::cout << "SHIFTED,sample,V" << std::endl;
+    for (int i = 0; i + delay < int(out.size()); ++i) {
+        std::cout << "SHIFTED," << i << "," << out[i + delay] << std::endl;
+    }
+    
+    std::cout << "EXPECTED,sample,V" << std::endl;
+    for (int i = 0; i < int(expected.size()); ++i) {
+        std::cout << "EXPECTED," << i << "," << expected[i] << std::endl;
+    }
+    
+    std::cout << "DIFF,sample,V" << std::endl;
+    for (int i = 0; i + delay < int(expected.size()); ++i) {
+        std::cout << "DIFF," << i << "," << out[i + delay] - expected[i] << std::endl;
+    }
+}
+
 static void check_sinusoid_unchanged(int n, int rate, float freq,
                                      RubberBandLiveShifter::Options options,
                                      bool printDebug)

          
@@ 51,8 86,6 @@ static void check_sinusoid_unchanged(int
     }
     
     RubberBandLiveShifter shifter(rate, 1, options);
-
-//    shifter.setPitchScale(2.66968);
     
     int blocksize = shifter.getBlockSize();
     BOOST_TEST(blocksize == 512);

          
@@ 71,8 104,6 @@ static void check_sinusoid_unchanged(int
     }
 
     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

          
@@ 116,28 147,86 @@ static void check_sinusoid_unchanged(int
 
     if (printDebug) {
         RubberBandLiveShifter::setDefaultDebugLevel(0);
+        dump(in, out, in, delay);
+    }
+}
 
-        // 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;
+static void check_sinusoid_shifted(int n, int rate, float freq, float shift,
+                                   RubberBandLiveShifter::Options options,
+                                   bool printDebug)
+{
+    if (printDebug) {
+        RubberBandLiveShifter::setDefaultDebugLevel(2);
+    }
+    
+    RubberBandLiveShifter shifter(rate, 1, options);
+
+    shifter.setPitchScale(shift);
+    
+    int blocksize = shifter.getBlockSize();
+    BOOST_TEST(blocksize == 512);
+
+    n = (n / blocksize + 1) * blocksize;
+    
+    vector<float> in(n), out(n), expected(n);
+    for (int i = 0; i < n; ++i) {
+        in[i] = 0.5f * sinf(float(i) * freq * M_PI * 2.f / float(rate));
+        expected[i] = 0.5f * sinf(float(i) * freq * shift * M_PI * 2.f / float(rate));
+    }
+
+    for (int i = 0; i < n; i += blocksize) {
+        float *inp = in.data() + i;
+        float *outp = out.data() + i;
+        shifter.shift(&inp, &outp);
+    }
+
+    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
+    // thing. It will have lower precision for a while at the start,
+    // so we check that with a threshold of 0.1; after that we expect
+    // better precision.
+
+    int slackpart = 2048;
+    float slackeps = 1.0e-1f;
+    float eps = 1.0e-3f;
+
+#ifdef USE_BQRESAMPLER
+    eps = 1.0e-2f;
+#endif
+    
+    for (int i = 0; i < slackpart; ++i) {
+        float fin = expected[i];
+        float fout = out[delay + i];
+        float err = fabsf(fin - fout);
+        if (err > slackeps) {
+            std::cerr << "Error at index " << i << " exceeds slack eps "
+                      << slackeps << ": output " << fout << " - expected "
+                      << fin << " = " << fout - fin << std::endl;
+            BOOST_TEST(err < eps);
+            break;
         }
-        
-        std::cout << "OUT,sample,V" << std::endl;
-        for (int i = 0; i < int(out.size()); ++i) {
-            std::cout << "OUT," << i << "," << out[i] << std::endl;
+    }
+    
+    for (int i = slackpart; i < n - delay; ++i) {
+        float fin = expected[i];
+        float fout = out[delay + i];
+        float err = fabsf(fin - fout);
+        if (err > eps) {
+            std::cerr << "Error at index " << i << " exceeds tight eps "
+                      << eps << ": output " << fout << " - expected "
+                      << fin << " = " << fout - fin << std::endl;
+            BOOST_TEST(err < eps);
+            break;
         }
-        
-        std::cout << "SHIFTED,sample,V" << std::endl;
-        for (int i = 0; i + delay < int(out.size()); ++i) {
-            std::cout << "SHIFTED," << i << "," << out[i + delay] << std::endl;
-        }
+    }
 
-        std::cout << "DIFF,sample,V" << std::endl;
-        for (int i = 0; i + delay < int(in.size()); ++i) {
-            std::cout << "DIFF," << i << "," << out[i + delay] - in[i] << std::endl;
-        }
+    if (printDebug) {
+        RubberBandLiveShifter::setDefaultDebugLevel(0);
+        dump(in, out, expected, delay);
     }
 }
 

          
@@ 145,7 234,7 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged_
 {
     RubberBandLiveShifter::Options options =
         RubberBandLiveShifter::OptionPitchMethodStandard;
-    int n = 100000;
+    int n = 20000;
 
     check_sinusoid_unchanged(n, 44100, 440.f, options, false);
     check_sinusoid_unchanged(n, 48000, 260.f, options, false);

          
@@ 155,10 244,20 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged_
 {
     RubberBandLiveShifter::Options options =
         RubberBandLiveShifter::OptionPitchMethodAlternate;
-    int n = 100000;
+    int n = 20000;
 
-    check_sinusoid_unchanged(n, 44100, 440.f, options, true);
+    check_sinusoid_unchanged(n, 44100, 440.f, options, false);
     check_sinusoid_unchanged(n, 48000, 260.f, options, false);
 }
 
+BOOST_AUTO_TEST_CASE(sinusoid_down_octave_mode_a)
+{
+    RubberBandLiveShifter::Options options =
+        RubberBandLiveShifter::OptionPitchMethodStandard;
+    int n = 20000;
+
+    check_sinusoid_shifted(n, 44100, 440.f, 0.5f, options, true);
+//    check_sinusoid_shifted(n, 48000, 260.f, 0.5f, options, false);
+}
+
 BOOST_AUTO_TEST_SUITE_END()