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"));
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