Hi, lately I've stumbled upon an old article that sings praise of
Akai S1000 samplers and the resampling algorithm it used.
This piqued my curiosity and inspired me to try implementing a sinc
resampler into LS for comparison.

I attach my code to the message, as patch against svn trunk.
Link to the article: http://martin78.com/samplers/akai-s1000-s1100/

-- some implementation notes:
* this is a N-point sinc resampler, where N is defined in code by
  parameter SINC_NPTOTAL=SINC_NPBEFORE+SINC_NPAFTER
* code uses optimization to reduce the number of trig operations/sample
  from N sin() to 1 sin() + 1 cos()

As default I have used parameters NPBEFORE=1 NPAFTER=7, the number of
past and future samples used respectively.
This happens in some situations, with some samples of my set, to crash
LS with segfault, presumably because of out-of-bounds access by
getSample().

The question is: where in LS is defined how many past/future samples are
available to the resampling?
I note LS already has linear and cubic which require 2 and 4. How
to control this number? Akai S1000 supposedly has N=8, but I'd like to
also to try larger lengths.
Index: src/engines/common/Resampler.h
===================================================================
--- src/engines/common/Resampler.h	(revision 2878)
+++ src/engines/common/Resampler.h	(working copy)
@@ -30,10 +30,15 @@
 #include "../../common/global_private.h"
 
 // TODO: cubic interpolation is not yet supported by the MMX/SSE(1) version though
-#ifndef USE_LINEAR_INTERPOLATION
-# define USE_LINEAR_INTERPOLATION   1  ///< set to 0 if you prefer cubic interpolation (slower, better quality)
-#endif
+// # define USE_LINEAR_INTERPOLATION   1  ///< set if you prefer linear interpolation
+//# define USE_CUBIC_INTERPOLATION   1  ///< set if you prefer cubic interpolation (slower, better quality)
+# define USE_SINC_INTERPOLATION   1  ///< set if you prefer sinc interpolation (slower, better quality)
 
+/// parameters of sinc interpolation: number of points used before/after the fractional sample position
+#define SINC_NPBEFORE 1
+#define SINC_NPAFTER 7
+#define SINC_NPTOTAL (SINC_NPBEFORE+SINC_NPAFTER)
+
 namespace LinuxSampler {
 
     /** @brief Stereo sample point
@@ -165,15 +170,55 @@
                 }
             }
 
+#ifdef USE_SINC_INTERPOLATION
+
+#if 0 // given for reference
+        template <unsigned N>
+        static inline void fastsins(float (&sintab)[N], float start, float step) {
+            /// fast sin computation using identity
+            /// sin(a+b)=sin(a)cos(b)+cos(a)sin(b)
+            /// cos(a+b)=cos(a)cos(b)-sin(a)sin(b)
+            const float a = cosf(step), b = sinf(step);
+            float s = sinf(start), c = cosf(start);
+            sintab[0] = s;
+            for (unsigned i = 1; i < N; i++) {
+                const float ns = b*c + a*s, nc = a*c - b*s;
+                c = nc;
+                s = ns;
+                sintab[i] = s;
+            }
+        }
+#endif
+
+        template <unsigned N>
+        static inline void fastsincs(float (&sinctab)[N], float start) {
+            /// compute normalized sinc(x): x=0 => 1, otherwise => sin(pi*x)/(pi*x)
+            /// same tactic as fastsins using step=pi
+            const float a = -1.0f, b = 0.0f; // cos(step), sin(step)
+            start *= (float)M_PI;
+            float s = sinf(start), c = cosf(start);
+            float denom = start;
+            sinctab[0] = (denom == 0) ? 1.0f : (s / denom);
+            for (unsigned i = 1; i < N; i++) {
+                const float ns = b*c + a*s, nc = a*c - b*s;
+                c = nc;
+                s = ns;
+                denom += (float)M_PI;
+                sinctab[i] = (denom == 0) ? 1.0f : (s / denom);
+            }
+        }
+#endif // USE_SINC_INTERPOLATION
+
             inline static float Interpolate1StepMonoCPP(sample_t* __restrict pSrc, double* __restrict Pos, float& Pitch) {
                 int   pos_int   = (int) *Pos;     // integer position
                 float pos_fract = *Pos - pos_int; // fractional part of position
 
-                #if USE_LINEAR_INTERPOLATION
+                #if defined(USE_LINEAR_INTERPOLATION)
                     int x1 = getSample(pSrc, pos_int);
                     int x2 = getSample(pSrc, pos_int + 1);
                     float samplePoint  = (x1 + pos_fract * (x2 - x1));
-                #else // polynomial interpolation
+
+                #elif defined(USE_CUBIC_INTERPOLATION)
                     float xm1 = getSample(pSrc, pos_int);
                     float x0  = getSample(pSrc, pos_int + 1);
                     float x1  = getSample(pSrc, pos_int + 2);
@@ -182,8 +227,18 @@
                     float b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
                     float c   = (x1 - xm1) * 0.5f;
                     float samplePoint =  (((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0;
-                #endif // USE_LINEAR_INTERPOLATION
 
+                #elif defined(USE_SINC_INTERPOLATION)
+                    float samplePoint = 0.0f;
+                    const float sincStart = (-SINC_NPBEFORE + 1) - pos_fract;
+                    float sincValues[SINC_NPTOTAL];
+                    fastsincs(sincValues, sincStart);
+                    for (int i = 0; i < SINC_NPTOTAL; ++i) {
+                        float inputSample = getSample(pSrc, pos_int + i - SINC_NPBEFORE + 1);
+                        samplePoint += inputSample * sincValues[i];
+                    }
+                #endif
+
                 *Pos += Pitch;
                 return samplePoint;
             }
@@ -195,7 +250,7 @@
 
                 stereo_sample_t samplePoint;
 
-                #if USE_LINEAR_INTERPOLATION
+                #if defined(USE_LINEAR_INTERPOLATION)
                     // left channel
                     int x1 = getSample(pSrc, pos_int);
                     int x2 = getSample(pSrc, pos_int + 2);
@@ -204,7 +259,8 @@
                     x1 = getSample(pSrc, pos_int + 1);
                     x2 = getSample(pSrc, pos_int + 3);
                     samplePoint.right = (x1 + pos_fract * (x2 - x1));
-                #else // polynomial interpolation
+
+                #elif defined(USE_CUBIC_INTERPOLATION)
                     // calculate left channel
                     float xm1 = getSample(pSrc, pos_int);
                     float x0  = getSample(pSrc, pos_int + 2);
@@ -224,8 +280,21 @@
                     b   = 2.0f * x1 + xm1 - (5.0f * x0 + x2) * 0.5f;
                     c   = (x1 - xm1) * 0.5f;
                     samplePoint.right =  (((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0;
-                #endif // USE_LINEAR_INTERPOLATION
 
+                #elif defined(USE_SINC_INTERPOLATION)
+                    samplePoint.left = 0.0f;
+                    samplePoint.right = 0.0f;
+                    const float sincStart = (-SINC_NPBEFORE + 1) - pos_fract;
+                    float sincValues[SINC_NPTOTAL];
+                    fastsincs(sincValues, sincStart);
+                    for (int i = 0; i < SINC_NPTOTAL; ++i) {
+                        float leftSample = getSample(pSrc, 2*i*(pos_int - SINC_NPBEFORE + 1));
+                        float rightSample = getSample(pSrc, 2*i*(pos_int - SINC_NPBEFORE + 1)+1);
+                        samplePoint.left += leftSample * sincValues[i];
+                        samplePoint.right += rightSample * sincValues[i];
+                    }
+                #endif
+
                 *Pos += Pitch;
                 return samplePoint;
             }
Index: src/linuxsampler.cpp
===================================================================
--- src/linuxsampler.cpp	(revision 2878)
+++ src/linuxsampler.cpp	(working copy)
@@ -118,6 +118,7 @@
     }
 
     dmsg(1,("LinuxSampler %s\n", VERSION));
+    dmsg(1,("-- using Sinc interpolation patch (experimental)\n"));
     dmsg(1,("Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck\n"));
     dmsg(1,("Copyright (C) 2005-2016 Christian Schoenebeck\n"));
 

Attachment: pgpjBsbGOi2ix.pgp
Description: OpenPGP digital signature

------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
_______________________________________________
Linuxsampler-devel mailing list
Linuxsampler-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxsampler-devel

Reply via email to