7f48814edf3a — Chris Cannam 10 days ago
Delay calculations
3 files changed, 66 insertions(+), 37 deletions(-)

M src/finer/R3LiveShifter.cpp
M src/finer/R3LiveShifter.h
M src/test/TestLiveShifter.cpp
M src/finer/R3LiveShifter.cpp +27 -33
@@ 41,7 41,7 @@ R3LiveShifter::R3LiveShifter(Parameters 
             m_log),
     m_guideConfiguration(m_guide.getConfiguration()),
     m_channelAssembly(m_parameters.channels),
-    m_resamplerDelay(32),
+    m_initialResamplerDelays(32, 32),
     m_useReadahead(false),
     m_prevInhop(m_limits.maxInhopWithReadahead / 2),
     m_prevOuthop(m_prevInhop),

          
@@ 240,19 240,18 @@ R3LiveShifter::measureResamplerDelay()
     std::vector<float> inbuf(bs * m_parameters.channels, 0.f);
     auto outbuf = inbuf;
     
-    double inRatio = 1.0;
-    if (m_pitchScale > 1.0) {
-        inRatio = 1.0 / m_pitchScale;
-    }
-
-    int outcount = m_inResampler->resampleInterleaved
-        (outbuf.data(), bs, inbuf.data(), bs, inRatio, false);
-
+    int incount = m_inResampler->resampleInterleaved
+        (outbuf.data(), bs, inbuf.data(), bs, getInRatio(), false);
     m_inResampler->reset();
 
-    m_resamplerDelay = bs - outcount;
+    int outcount = m_outResampler->resampleInterleaved
+        (outbuf.data(), bs, inbuf.data(), bs, getOutRatio(), false);
+    m_outResampler->reset();
+    
+    m_initialResamplerDelays = { bs - incount, bs - outcount };
 
-    m_log.log(1, "R3LiveShifter::measureResamplerDelay: measured delay and outcount ", m_resamplerDelay, outcount);
+    m_log.log(1, "R3LiveShifter::measureResamplerDelay: inRatio, outRatio ", getInRatio(), getOutRatio());
+    m_log.log(1, "R3LiveShifter::measureResamplerDelay: measured delays ", m_initialResamplerDelays.first, m_initialResamplerDelays.second);
 }
 
 double

          
@@ 276,13 275,21 @@ R3LiveShifter::getPreferredStartPad() co
 size_t
 R3LiveShifter::getStartDelay() const
 {
-    int fixed = getWindowSourceSize() / 2 + m_resamplerDelay * 2;
-    int variable = getWindowSourceSize() / 2;
-    if (m_pitchScale < 1.0) {
-        return size_t(fixed + ceil(variable / m_pitchScale));
-    } else {
-        return size_t(fixed + ceil(variable * m_pitchScale));
+    int inDelay = getWindowSourceSize() + m_initialResamplerDelays.first;
+    int outDelay = int(floor(inDelay * getOutRatio())) + m_initialResamplerDelays.second;
+
+    int total = outDelay;
+    int bs = getBlockSize();
+    if (m_pitchScale > 1.0) {
+        total += bs - 1;
+    } else if (m_pitchScale < 1.0) {
+        int scaled = int(ceil(bs / m_pitchScale));
+        total -= bs * (scaled - bs) / bs;
     }
+
+    m_log.log(2, "R3LiveShifter::getStartDelay: inDelay, outDelay", inDelay, outDelay);
+    m_log.log(1, "R3LiveShifter::getStartDelay", total);
+    return total;
 }
 
 size_t

          
@@ 345,12 352,7 @@ R3LiveShifter::shift(const float *const 
     
     readIn(input);
 
-    double outRatio = 1.0;
-
-    if (m_pitchScale < 1.0) {
-        outRatio = 1.0 / m_pitchScale;
-    }
-    
+    double outRatio = getOutRatio();
     int requiredInOutbuf = int(ceil(incount / outRatio));
     generate(requiredInOutbuf);
     

          
@@ 409,11 411,7 @@ R3LiveShifter::readIn(const float *const
         }
     }
     
-    double inRatio = 1.0;
-    if (m_pitchScale > 1.0) {
-        inRatio = 1.0 / m_pitchScale;
-    }
-
+    double inRatio = getInRatio();
     m_log.log(2, "R3LiveShifter::readIn: ratio", inRatio);
     
     int resampleBufSize = int(m_channelData.at(0)->resampled.size());

          
@@ 601,11 599,7 @@ R3LiveShifter::generate(int requiredInOu
 int
 R3LiveShifter::readOut(float *const *output, int outcount)
 {
-    double outRatio = 1.0;
-    if (m_pitchScale < 1.0) {
-        outRatio = 1.0 / m_pitchScale;
-    }
-    
+    double outRatio = getOutRatio();
     m_log.log(2, "R3LiveShifter::readOut: outcount and ratio", outcount, outRatio);
 
     int resampledCount = 0;

          
M src/finer/R3LiveShifter.h +17 -1
@@ 311,7 311,7 @@ protected:
     ChannelAssembly m_channelAssembly;
     std::unique_ptr<Resampler> m_inResampler;
     std::unique_ptr<Resampler> m_outResampler;
-    int m_resamplerDelay;
+    std::pair<int, int> m_initialResamplerDelays;
     bool m_useReadahead;
     int m_prevInhop;
     int m_prevOuthop;

          
@@ 387,6 387,22 @@ protected:
         return true;
     }
 
+    double getInRatio() const {
+        if (m_pitchScale > 1.0) {
+            return 1.0 / m_pitchScale;
+        } else {
+            return 1.0;
+        }
+    }
+
+    double getOutRatio() const {
+        if (m_pitchScale < 1.0) {
+            return 1.0 / m_pitchScale;
+        } else {
+            return 1.0;
+        }
+    }
+    
     int getWindowSourceSize() const {
         if (m_useReadahead) {
             int sz = m_guideConfiguration.classificationFftSize +

          
M src/test/TestLiveShifter.cpp +22 -3
@@ 182,8 182,6 @@ static void check_sinusoid_shifted(int n
 
     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,

          
@@ 240,7 238,28 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged)
 BOOST_AUTO_TEST_CASE(sinusoid_down_octave)
 {
     int n = 20000;
-    check_sinusoid_shifted(n, 44100, 440.f, 0.5f, 0, true);
+    check_sinusoid_shifted(n, 44100, 440.f, 0.5f, 0, false);
+//    check_sinusoid_shifted(n, 48000, 260.f, 0.5f, 0, false);
+}
+
+BOOST_AUTO_TEST_CASE(sinusoid_down_2octave)
+{
+    int n = 20000;
+    check_sinusoid_shifted(n, 44100, 440.f, 0.25f, 0, false);
+//    check_sinusoid_shifted(n, 48000, 260.f, 0.5f, 0, false);
+}
+
+BOOST_AUTO_TEST_CASE(sinusoid_up_octave)
+{
+    int n = 20000;
+    check_sinusoid_shifted(n, 44100, 440.f, 2.0f, 0, false);
+//    check_sinusoid_shifted(n, 48000, 260.f, 0.5f, 0, false);
+}
+
+BOOST_AUTO_TEST_CASE(sinusoid_up_2octave)
+{
+    int n = 20000;
+    check_sinusoid_shifted(n, 44100, 440.f, 4.0f, 0, false);
 //    check_sinusoid_shifted(n, 48000, 260.f, 0.5f, 0, false);
 }