7f8c02147225 — Chris Cannam 3 months ago
Rework output resampler handling to deal with case where fewer samples are consumed than available
M src/common/BQResampler.cpp +0 -7
@@ 201,13 201,6 @@ BQResampler::resampleInterleaved(float *
         }
     }
 
-    if (i < incount_samples) {
-        std::cerr << "only used " << i << " of " << incount_samples
-                  << " samples to generate output count " << o
-                  << " (outspace_samples was " << outspace_samples << ")"
-                  << std::endl;
-    }
-
     int fbufsize = m_fade->buffer.size();
     int fi = 0, fo = 0;
     while (fo < o && m_fade_count > 0) {

          
M src/finer/R3LiveShifter.cpp +53 -46
@@ 344,7 344,7 @@ R3LiveShifter::shift(const float *const 
     int requiredInOutbuf = 1 + int(ceil(incount / outRatio));
     generate(requiredInOutbuf);
     
-    int got = readOut(output, incount, 0);
+    int got = readOut(output, incount);
 
     if (got < incount) {
         m_log.log(0, "R3LiveShifter::shift: ERROR: internal error: insufficient data at output (wanted, got)", incount, got);

          
@@ 597,7 597,7 @@ R3LiveShifter::generate(int requiredInOu
 }
 
 int
-R3LiveShifter::readOut(float *const *output, int outcount, int origin)
+R3LiveShifter::readOut(float *const *output, int outcount)
 {
     double outRatio = 1.0;
 

          
@@ 613,79 613,86 @@ R3LiveShifter::readOut(float *const *out
     
     m_log.log(2, "R3LiveShifter::readOut: outcount and ratio", outcount, outRatio);
 
-    int fromOutbuf = int(floor(outcount / outRatio));
+    int resampledCount = 0;
+    bool fillingTail = true;
 
-    m_log.log(2, "R3LiveShifter::readOut: origin and fromOutbuf", origin, fromOutbuf);
-    
-    if (fromOutbuf == 0) {
-        fromOutbuf = 1;
-    }
+    while (resampledCount < outcount) {
+
+        int fromOutbuf;
 
-    int got = fromOutbuf;
+        if (fillingTail) {
+            fromOutbuf = 1;
+        } else {
+            fromOutbuf = int(floor(outcount / outRatio));
+            if (fromOutbuf == 0) {
+                fromOutbuf = 1;
+            }
+        }
+        
+        m_log.log(2, "R3LiveShifter::readOut: fromOutbuf", fromOutbuf);
+
+        int got = fromOutbuf;
     
-    for (int c = 0; c < m_parameters.channels; ++c) {
-        auto &cd = m_channelData.at(c);
-        int gotHere = cd->outbuf->read(cd->resampled.data(), got);
-        if (gotHere < got) {
-            if (c > 0) {
-                m_log.log(0, "R3LiveShifter::readOut: WARNING: channel imbalance detected");
+        for (int c = 0; c < m_parameters.channels; ++c) {
+            auto &cd = m_channelData.at(c);
+            int gotHere = cd->outbuf->read(cd->resampled.data(), got);
+            if (gotHere < got) {
+                if (c > 0) {
+                    m_log.log(0, "R3LiveShifter::readOut: WARNING: channel imbalance detected");
+                }
             }
             got = std::min(got, std::max(gotHere, 0));
         }
-    }
 
-    m_log.log(2, "R3LiveShifter::readOut: requested and got from outbufs", fromOutbuf, got);
-    m_log.log(2, "R3LiveShifter::readOut: leaving behind", m_channelData.at(0)->outbuf->getReadSpace());
-
-    int resampledCount = 0;
-
-    if (got > 0) {
+        m_log.log(2, "R3LiveShifter::readOut: requested and got from outbufs", fromOutbuf, got);
+        m_log.log(2, "R3LiveShifter::readOut: leaving behind", m_channelData.at(0)->outbuf->getReadSpace());
 
         for (int c = 0; c < m_parameters.channels; ++c) {
             auto &cd = m_channelData.at(c);
             m_channelAssembly.resampled[c] = cd->resampled.data();
-            m_channelAssembly.mixdown[c] = output[c] + origin;
+            m_channelAssembly.mixdown[c] = output[c] + resampledCount;
         }
             
-        resampledCount = m_outResampler->resample
+        auto resampledHere = m_outResampler->resample
             (m_channelAssembly.mixdown.data(),
-             outcount,
+             outcount - resampledCount,
              m_channelAssembly.resampled.data(),
              got,
              outRatio,
              false);
+
+        m_log.log(2, "R3LiveShifter::readOut: resampledHere", resampledHere);
+
+        if (got == 0 && resampledHere == 0) {
+            m_log.log(2, "R3LiveShifter::readOut: made no progress, finishing");
+            break;
+        }            
+        
+        resampledCount += resampledHere;
+
+        fillingTail = true;
+    }
     
-        if (useMidSide()) {
-            for (int i = 0; i < resampledCount; ++i) {
-                float m = output[0][origin + i];
-                float s = output[1][origin + i];
-                float l = m + s;
-                float r = m - s;
-                output[0][origin + i] = l;
-                output[1][origin + i] = r;
-            }
+    if (useMidSide()) {
+        for (int i = 0; i < resampledCount; ++i) {
+            float m = output[0][i];
+            float s = output[1][i];
+            float l = m + s;
+            float r = m - s;
+            output[0][i] = l;
+            output[1][i] = r;
         }
     }
 
     m_log.log(2, "R3LiveShifter::readOut: resampled to", resampledCount);
 
-    if (resampledCount < outcount &&
-        m_channelData.at(0)->outbuf->getReadSpace() > 0) {
-        int remaining = outcount - resampledCount;
-        m_log.log(2, "R3LiveShifter::readOut: recursing to try to get the remaining",
-                  remaining);
-        resampledCount += readOut(output, remaining, origin + resampledCount);
-    }
-
     if (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(output[c] + origin + prepad,
-                       output[c] + origin,
-                       resampledCount);
-                v_zero(output[c] + origin, prepad);
+                v_move(output[c] + prepad, output[c], resampledCount);
+                v_zero(output[c], prepad);
             }
             resampledCount = outcount;
         } else {

          
M src/finer/R3LiveShifter.h +1 -1
@@ 328,7 328,7 @@ protected:
 
     void readIn(const float *const *input);
     void generate(int required);
-    int readOut(float *const *output, int outcount, int origin);
+    int readOut(float *const *output, int outcount);
     
     void createResamplers();
     void analyseChannel(int channel, int inhop, int prevInhop, int prevOuthop);

          
M src/test/TestLiveShifter.cpp +2 -2
@@ 52,7 52,7 @@ static void check_sinusoid_unchanged(int
     
     RubberBandLiveShifter shifter(rate, 1, options);
 
-    shifter.setPitchScale(2.66968);
+//    shifter.setPitchScale(2.66968);
     
     int blocksize = shifter.getBlockSize();
     BOOST_TEST(blocksize == 512);

          
@@ 120,7 120,7 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged_
         RubberBandLiveShifter::OptionPitchModeA;
     int n = 100000;
 
-    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);
 }