4b5d980c766b — Chris Cannam 4 months ago
Fixes for libsamplerate and ipp, brought back from rb code
3 files changed, 80 insertions(+), 82 deletions(-)

M Makefile
M bqresample/Resampler.h
M src/Resampler.cpp
M Makefile +2 -2
@@ 4,9 4,9 @@ 
 #
 # Available options are
 #
+#  -DHAVE_LIBSAMPLERATE  The libsamplerate library is available (recommended)
 #  -DHAVE_IPP            Intel's Integrated Performance Primitives are available
 #  -DHAVE_LIBRESAMPLE    The libresample library is available
-#  -DHAVE_LIBSAMPLERATE  The libsamplerate library is available
 #  -DUSE_SPEEX           Compile the built-in Speex-derived resampler
 #
 # You may define more than one of these. If you define USE_SPEEX, the

          
@@ 14,7 14,7 @@ 
 # the best available option for a given quality setting. If no flags
 # are supplied, the code will refuse to compile.
 
-RESAMPLE_DEFINES	:= -DUSE_SPEEX
+RESAMPLE_DEFINES	:= -DHAVE_LIBSAMPLERATE
 
 
 # Add to VECTOR_DEFINES and ALLOCATOR_DEFINES any options desired for

          
M bqresample/Resampler.h +3 -1
@@ 65,7 65,9 @@ public:
         /** 
          * Bound on the maximum incount size that may be passed to the
          * resample function before the resampler needs to reallocate
-         * its internal buffers.
+         * its internal buffers. Default is zero, so that buffer
+         * allocation will happen on the first call and any subsequent
+         * call with a greater incount.
          */
         int maxBufferSize;
 

          
M src/Resampler.cpp +75 -79
@@ 47,9 47,7 @@ 
 #ifdef HAVE_IPP
 #include <ippversion.h>
 #if (IPP_VERSION_MAJOR < 7)
-#include <ipps.h>
-#include <ippsr.h>
-#include <ippac.h>
+#error Unsupported IPP version, must be >= 7
 #else
 #include <ipps.h>
 #endif

          
@@ 160,7 158,8 @@ protected:
     void setBufSize(int);
 };
 
-D_IPP::D_IPP(Resampler::Quality quality, int channels, double initialSampleRate,
+D_IPP::D_IPP(Resampler::Quality /* quality */,
+             int channels, double initialSampleRate,
              int maxBufferSize, int debugLevel) :
     m_state(0),
     m_initialSampleRate(initialSampleRate),

          
@@ 168,36 167,12 @@ D_IPP::D_IPP(Resampler::Quality quality,
     m_debugLevel(debugLevel)
 {
     if (m_debugLevel > 0) {
-        cerr << "Resampler::Resampler: using IPP implementation"
-                  << endl;
+        cerr << "Resampler::Resampler: using IPP implementation" << endl;
     }
 
-    int nStep = 16;
+    m_window = 32;
+    int nStep = 64;
     IppHintAlgorithm hint = ippAlgHintFast;
-
-    //!!! todo: make use of initialSampleRate to calculate parameters
-    
-    switch (quality) {
-
-    case Resampler::Best:
-        m_window = 64;
-        nStep = 80;
-        hint = ippAlgHintAccurate;
-        break;
-
-    case Resampler::FastestTolerable:
-        nStep = 16;
-        m_window = 16;
-        hint = ippAlgHintFast;
-        break;
-
-    case Resampler::Fastest:
-        m_window = 24;
-        nStep = 64;
-        hint = ippAlgHintFast;
-        break;
-    }
-
     m_factor = 8; // initial upper bound on m_ratio, may be amended later
 
     // This is largely based on the IPP docs and examples. Adapted

          
@@ 233,7 208,6 @@ D_IPP::D_IPP(Resampler::Quality quality,
         cerr << "bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl;
     }
 
-#if (IPP_VERSION_MAJOR >= 7)
     int specSize = 0;
     ippsResamplePolyphaseGetSize_32f(float(m_window),
                                      nStep,

          
@@ 246,17 220,8 @@ D_IPP::D_IPP(Resampler::Quality quality,
         abort();
 #endif
     }
-#endif
 
     for (int c = 0; c < m_channels; ++c) {
-#if (IPP_VERSION_MAJOR < 7)
-        ippsResamplePolyphaseInitAlloc_32f(&m_state[c],
-                                           float(m_window),
-                                           nStep,
-                                           0.95f,
-                                           9.0f,
-                                           hint);
-#else
         m_state[c] = (IppsResamplingPolyphase_32f *)ippsMalloc_8u(specSize);
         ippsResamplePolyphaseInit_32f(float(m_window),
                                       nStep,

          
@@ 264,7 229,6 @@ D_IPP::D_IPP(Resampler::Quality quality,
                                       9.0f,
                                       m_state[c],
                                       hint);
-#endif
         
         m_lastread[c] = m_history;
         m_time[c] = m_history;

          
@@ 277,15 241,9 @@ D_IPP::D_IPP(Resampler::Quality quality,
 
 D_IPP::~D_IPP()
 {
-#if (IPP_VERSION_MAJOR < 7)
-    for (int c = 0; c < m_channels; ++c) {
-        ippsResamplePolyphaseFree_32f(m_state[c]);
-    }
-#else
     for (int c = 0; c < m_channels; ++c) {
         ippsFree(m_state[c]);
     }
-#endif
 
     deallocate_channels(m_inbuf, m_channels);
     deallocate_channels(m_outbuf, m_channels);

          
@@ 458,16 416,6 @@ D_IPP::doResample(int outspace, double r
             n = limit;
         }
         
-#if (IPP_VERSION_MAJOR < 7)
-        ippsResamplePolyphase_32f(m_state[c],
-                                  m_inbuf[c],
-                                  n,
-                                  m_outbuf[c],
-                                  ratio,
-                                  1.0f,
-                                  &m_time[c],
-                                  &outcount);
-#else
         ippsResamplePolyphase_32f(m_inbuf[c],
                                   n,
                                   m_outbuf[c],

          
@@ 476,24 424,39 @@ D_IPP::doResample(int outspace, double r
                                   &m_time[c],
                                   &outcount,
                                   m_state[c]);
-#endif
 
-        int t = int(round(m_time[c]));
+        int t = int(floor(m_time[c]));
+        
+        int moveFrom = t - m_history;
         
         if (c == 0 && m_debugLevel > 2) {
             cerr << "converted " << n << " samples to " << outcount
-                 << ", time advanced to " << t << endl;
-            cerr << "will move " << m_lastread[c] + m_history - t
-                 << " unconverted samples back from index " << t - m_history
+                 << " (nb outbufsz = " << m_outbufsz
+                 << "), time advanced to " << m_time[c] << endl;
+            cerr << "rounding time to " << t << ", lastread = "
+                 << m_lastread[c] << ", history = " << m_history << endl;
+            cerr << "will move " << m_lastread[c] - moveFrom
+                 << " unconverted samples back from index " << moveFrom
                  << " to 0" << endl;
         }
 
-        v_move(m_inbuf[c],
-               m_inbuf[c] + t - m_history,
-               m_lastread[c] + m_history - t);
+        if (moveFrom >= m_lastread[c]) {
+
+            moveFrom = m_lastread[c];
 
-        m_lastread[c] -= t - m_history;
-        m_time[c] -= t - m_history;
+            if (c == 0 && m_debugLevel > 2) {
+                cerr << "number of samples to move is <= 0, "
+                     << "not actually moving any" << endl;
+            }
+        } else {
+        
+            v_move(m_inbuf[c],
+                   m_inbuf[c] + moveFrom,
+                   m_lastread[c] - moveFrom);
+        }
+
+        m_lastread[c] -= moveFrom;
+        m_time[c] -= moveFrom;
 
         if (c == 0 && m_debugLevel > 2) {
             cerr << "lastread reduced to " << m_lastread[c]

          
@@ 539,16 502,6 @@ D_IPP::doResample(int outspace, double r
                 nAdditional = limit - n;
             }
             
-#if (IPP_VERSION_MAJOR < 7)
-            ippsResamplePolyphase_32f(m_state[c],
-                                      m_inbuf[c],
-                                      nAdditional,
-                                      m_outbuf[c],
-                                      ratio,
-                                      1.0f,
-                                      &m_time[c],
-                                      &additionalcount);
-#else
             ippsResamplePolyphase_32f(m_inbuf[c],
                                       nAdditional,
                                       m_outbuf[c],

          
@@ 557,7 510,6 @@ D_IPP::doResample(int outspace, double r
                                       &m_time[c],
                                       &additionalcount,
                                       m_state[c]);
-#endif
         
             if (c == 0 && m_debugLevel > 2) {
                 cerr << "converted " << n << " samples to " << additionalcount

          
@@ 620,6 572,7 @@ protected:
     int m_channels;
     int m_iinsize;
     int m_ioutsize;
+    double m_prevRatio;
     int m_debugLevel;
 };
 

          
@@ 631,6 584,7 @@ D_SRC::D_SRC(Resampler::Quality quality,
     m_channels(channels),
     m_iinsize(0),
     m_ioutsize(0),
+    m_prevRatio(1.0),
     m_debugLevel(debugLevel)
 {
     if (m_debugLevel > 0) {

          
@@ 709,6 663,48 @@ D_SRC::resampleInterleaved(float *const 
 {
     SRC_DATA data;
 
+    // libsamplerate smooths the filter change over the duration of
+    // the processing block to avoid artifacts due to sudden changes,
+    // and it uses outcount to determine how long to smooth the change
+    // over. This is a good thing, but it does mean (a) we should
+    // never pass outcount significantly longer than the actual
+    // expected output, and (b) when the ratio has just changed, we
+    // should aim to supply a shortish block next
+    
+    if (outcount > int(ceil(incount * ratio) + 5)) {
+        outcount = int(ceil(incount * ratio) + 5);
+    }
+
+    if (ratio != m_prevRatio) {
+
+        // If we are processing a block of appreciable length, turn it
+        // into two recursive calls, one for the short smoothing block
+        // and the other for the rest. Update m_prevRatio before doing
+        // this so that the calls don't themselves recurse!
+        m_prevRatio = ratio;
+
+        int shortBlock = 200;
+        if (outcount > shortBlock * 2) {
+            int shortIn = int(floor(shortBlock / ratio));
+            if (shortIn >= 10) {
+                int shortOut =
+                    resampleInterleaved(out, shortBlock,
+                                        in, shortIn,
+                                        ratio, false);
+                int remainingOut = 0;
+                if (shortOut < outcount) {
+                    remainingOut =
+                        resampleInterleaved(out + shortOut * m_channels,
+                                            outcount - shortOut,
+                                            in + shortIn * m_channels,
+                                            incount - shortIn,
+                                            ratio, final);
+                }
+                return shortOut + remainingOut;
+            }
+        }
+    }
+
     data.data_in = const_cast<float *>(in);
     data.data_out = out;