shithub: dumb

Download patch

ref: 6937b61cc57d839278f6ee73bc9471eaa07c7f87
parent: a8d9baafc008bc851bce7b0aef799b74b9732a76
author: Chris Moeller <[email protected]>
date: Sat Mar 22 21:28:04 EDT 2014

Replaced built-in linear and cubic resamplers with new routines

--- a/dumb/cmake/CMakeLists.txt
+++ b/dumb/cmake/CMakeLists.txt
@@ -101,7 +101,7 @@
     ../src/it/loadany2.c
     ../src/it/loadany.c
     ../src/it/readany2.c
-    ../src/helpers/sinc_resampler.c
+    ../src/helpers/resampler.c
     ../src/helpers/lpc.c
 )
 
--- /dev/null
+++ b/dumb/include/internal/resampler.h
@@ -1,0 +1,39 @@
+#ifndef _SINC_RESAMPLER_H_
+#define _SINC_RESAMPLER_H_
+
+// Ugglay
+#ifdef SINC_DECORATE
+#define PASTE(a,b) a ## b
+#define EVALUATE(a,b) PASTE(a,b)
+#define sinc_init EVALUATE(SINC_DECORATE,_sinc_init)
+#define sinc_resampler_create EVALUATE(SINC_DECORATE,_sinc_resampler_create)
+#define sinc_resampler_delete EVALUATE(SINC_DECORATE,_sinc_resampler_delete)
+#define sinc_resampler_dup EVALUATE(SINC_DECORATE,_sinc_resampler_dup)
+#define sinc_resampler_dup_inplace EVALUATE(SINC_DECORATE,_sinc_resampler_dup_inplace)
+#define sinc_resampler_get_free_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_free_count)
+#define sinc_resampler_write_sample EVALUATE(SINC_DECORATE,_sinc_resampler_write_sample)
+#define sinc_resampler_set_rate EVALUATE(SINC_DECORATE,_sinc_resampler_set_rate)
+#define sinc_resampler_ready EVALUATE(SINC_DECORATE,_sinc_resampler_ready)
+#define sinc_resampler_clear EVALUATE(SINC_DECORATE,_sinc_resampler_clear)
+#define sinc_resampler_get_sample_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample_count)
+#define sinc_resampler_get_sample EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample)
+#define sinc_resampler_remove_sample EVALUATE(SINC_DECORATE,_sinc_resampler_remove_sample)
+#endif
+
+void sinc_init(void);
+
+void * sinc_resampler_create(void);
+void sinc_resampler_delete(void *);
+void * sinc_resampler_dup(const void *);
+void sinc_resampler_dup_inplace(void *, const void *);
+
+int sinc_resampler_get_free_count(void *);
+void sinc_resampler_write_sample(void *, short sample);
+void sinc_resampler_set_rate( void *, double new_factor );
+int sinc_resampler_ready(void *);
+void sinc_resampler_clear(void *);
+int sinc_resampler_get_sample_count(void *);
+int sinc_resampler_get_sample(void *);
+void sinc_resampler_remove_sample(void *);
+
+#endif
--- a/dumb/include/internal/sinc_resampler.h
+++ /dev/null
@@ -1,39 +1,0 @@
-#ifndef _SINC_RESAMPLER_H_
-#define _SINC_RESAMPLER_H_
-
-// Ugglay
-#ifdef SINC_DECORATE
-#define PASTE(a,b) a ## b
-#define EVALUATE(a,b) PASTE(a,b)
-#define sinc_init EVALUATE(SINC_DECORATE,_sinc_init)
-#define sinc_resampler_create EVALUATE(SINC_DECORATE,_sinc_resampler_create)
-#define sinc_resampler_delete EVALUATE(SINC_DECORATE,_sinc_resampler_delete)
-#define sinc_resampler_dup EVALUATE(SINC_DECORATE,_sinc_resampler_dup)
-#define sinc_resampler_dup_inplace EVALUATE(SINC_DECORATE,_sinc_resampler_dup_inplace)
-#define sinc_resampler_get_free_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_free_count)
-#define sinc_resampler_write_sample EVALUATE(SINC_DECORATE,_sinc_resampler_write_sample)
-#define sinc_resampler_set_rate EVALUATE(SINC_DECORATE,_sinc_resampler_set_rate)
-#define sinc_resampler_ready EVALUATE(SINC_DECORATE,_sinc_resampler_ready)
-#define sinc_resampler_clear EVALUATE(SINC_DECORATE,_sinc_resampler_clear)
-#define sinc_resampler_get_sample_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample_count)
-#define sinc_resampler_get_sample EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample)
-#define sinc_resampler_remove_sample EVALUATE(SINC_DECORATE,_sinc_resampler_remove_sample)
-#endif
-
-void sinc_init(void);
-
-void * sinc_resampler_create(void);
-void sinc_resampler_delete(void *);
-void * sinc_resampler_dup(const void *);
-void sinc_resampler_dup_inplace(void *, const void *);
-
-int sinc_resampler_get_free_count(void *);
-void sinc_resampler_write_sample(void *, short sample);
-void sinc_resampler_set_rate( void *, double new_factor );
-int sinc_resampler_ready(void *);
-void sinc_resampler_clear(void *);
-int sinc_resampler_get_sample_count(void *);
-int sinc_resampler_get_sample(void *);
-void sinc_resampler_remove_sample(void *);
-
-#endif
--- a/dumb/src/helpers/resamp3.inc
+++ b/dumb/src/helpers/resamp3.inc
@@ -140,71 +140,17 @@
 						MIX_ALIAS( todo );
 						done -= check;
 					}
-				} else if (quality <= DUMB_RQ_LINEAR) {
-					/* Linear interpolation, backwards */
-					SRCTYPE xbuf[3*SRC_CHANNELS];
-					SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
-					COPYSRC(xbuf, 0, resampler->X, 1);
-					COPYSRC(xbuf, 1, resampler->X, 2);
-					COPYSRC(xbuf, 2, src, pos);
-					while (todo && x < &xbuf[3*SRC_CHANNELS]) {
-						HEAVYASSERT(pos >= resampler->start);
-						MIX_LINEAR(+=, 1, 0, -1);
-						subpos += dt;
-						pos += subpos >> 16;
-						x -= (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-						todo--;
-					}
-					// TODO: use xstart for others too
-					x = &src[pos*SRC_CHANNELS];
-					LOOP4(todo,
-						HEAVYASSERT(pos >= resampler->start);
-						MIX_LINEAR(+=, 1, 1, 2);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-					);
-                                } else if (quality <= DUMB_RQ_CUBIC) {
-					/* Cubic interpolation, backwards */
-					SRCTYPE xbuf[6*SRC_CHANNELS];
-					SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
-					COPYSRC(xbuf, 0, resampler->X, 0);
-					COPYSRC(xbuf, 1, resampler->X, 1);
-					COPYSRC(xbuf, 2, resampler->X, 2);
-					COPYSRC(xbuf, 3, src, pos);
-					if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1);
-					if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2);
-					while (todo && x < &xbuf[6*SRC_CHANNELS]) {
-						HEAVYASSERT(pos >= resampler->start);
-						MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3);
-						subpos += dt;
-						pos += subpos >> 16;
-						x -= (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-						todo--;
-					}
-					x = &src[pos*SRC_CHANNELS];
-					LOOP4(todo,
-						HEAVYASSERT(pos >= resampler->start);
-						MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-					);
                                 } else {
                                     /* FIR resampling, backwards */
                                     SRCTYPE *x;
                                     if ( resampler->fir_resampler_ratio != delta ) {
-                                        sinc_resampler_set_rate( resampler->fir_resampler[0], delta );
-                                        sinc_resampler_set_rate( resampler->fir_resampler[1], delta );
+                                        resampler_set_rate( resampler->fir_resampler[0], delta );
+                                        resampler_set_rate( resampler->fir_resampler[1], delta );
                                         resampler->fir_resampler_ratio = delta;
                                     }
                                     x = &src[pos*SRC_CHANNELS];
                                     while ( todo ) {
-                                            while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) &&
+                                            while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
                                                     pos >= resampler->start )
                                             {
                                                     POKE_FIR(0);
@@ -211,7 +157,7 @@
                                                     pos--;
                                                     x -= SRC_CHANNELS;
                                             }
-                                            if ( !sinc_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
+                                            if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
                                             MIX_FIR;
                                             ADVANCE_FIR;
                                             --todo;
@@ -273,70 +219,17 @@
 						MIX_ALIAS( todo );
 						done -= check;
 					}
-				} else if (quality <= DUMB_RQ_LINEAR) {
-					/* Linear interpolation, forwards */
-					SRCTYPE xbuf[3*SRC_CHANNELS];
-					SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
-					COPYSRC(xbuf, 0, resampler->X, 1);
-					COPYSRC(xbuf, 1, resampler->X, 2);
-					COPYSRC(xbuf, 2, src, pos);
-					while (todo && x < &xbuf[3*SRC_CHANNELS]) {
-						HEAVYASSERT(pos < resampler->end);
-						MIX_LINEAR(+=, 1, -1, 0);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-						todo--;
-					}
-					x = &src[pos*SRC_CHANNELS];
-					LOOP4(todo,
-						HEAVYASSERT(pos < resampler->end);
-						MIX_LINEAR(+=, 1, -2, -1);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-					);
-                                } else if (quality <= DUMB_RQ_CUBIC) {
-					/* Cubic interpolation, forwards */
-					SRCTYPE xbuf[6*SRC_CHANNELS];
-					SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
-					COPYSRC(xbuf, 0, resampler->X, 0);
-					COPYSRC(xbuf, 1, resampler->X, 1);
-					COPYSRC(xbuf, 2, resampler->X, 2);
-					COPYSRC(xbuf, 3, src, pos);
-					if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1);
-					if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2);
-					while (todo && x < &xbuf[6*SRC_CHANNELS]) {
-						HEAVYASSERT(pos < resampler->end);
-						MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-						todo--;
-					}
-					x = &src[pos*SRC_CHANNELS];
-					LOOP4(todo,
-						HEAVYASSERT(pos < resampler->end);
-						MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += (subpos >> 16) * SRC_CHANNELS;
-						subpos &= 65535;
-					);
                                 } else {
                                     /* FIR resampling, forwards */
                                     SRCTYPE *x;
                                     if ( resampler->fir_resampler_ratio != delta ) {
-                                        sinc_resampler_set_rate( resampler->fir_resampler[0], delta );
-                                        sinc_resampler_set_rate( resampler->fir_resampler[1], delta );
+                                        resampler_set_rate( resampler->fir_resampler[0], delta );
+                                        resampler_set_rate( resampler->fir_resampler[1], delta );
                                         resampler->fir_resampler_ratio = delta;
                                     }
                                     x = &src[pos*SRC_CHANNELS];
                                     while ( todo ) {
-                                            while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) &&
+                                            while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
                                                     pos < resampler->end )
                                             {
                                                     POKE_FIR(0);
@@ -343,7 +236,7 @@
                                                     pos++;
                                                     x += SRC_CHANNELS;
                                             }
-                                            if ( !sinc_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
+                                            if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break;
                                             MIX_FIR;
                                             ADVANCE_FIR;
                                             --todo;
--- a/dumb/src/helpers/resample.c
+++ b/dumb/src/helpers/resample.c
@@ -46,7 +46,7 @@
 #include "dumb.h"
 
 #include "internal/blip_buf.h"
-#include "internal/sinc_resampler.h"
+#include "internal/resampler.h"
 
 
 
@@ -158,20 +158,12 @@
  * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution?
  */
 
-static short cubicA0[1025], cubicA1[1025];
-
 void _dumb_init_cubic(void)
 {
-	unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */
 	static int done = 0;
 	if (done) return;
-	for (t = 0; t < 1025; t++) {
-		/* int casts to pacify warnings about negating unsigned values */
-		cubicA0[t] = -(int)(  t*t*t >> 17) + (int)(  t*t >> 6) - (int)(t << 3);
-		cubicA1[t] =  (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7)                 + (int)(1 << 14);
-	}
 
-	sinc_init();
+	resampler_init();
 
 	done = 1;
 }
--- a/dumb/src/helpers/resample.inc
+++ b/dumb/src/helpers/resample.inc
@@ -75,8 +75,10 @@
 	blip_clear(resampler->blip_buffer[0]);
 	blip_clear(resampler->blip_buffer[1]);
         resampler->fir_resampler_ratio = 0;
-        sinc_resampler_clear(resampler->fir_resampler[0]);
-        sinc_resampler_clear(resampler->fir_resampler[1]);
+        resampler_clear(resampler->fir_resampler[0]);
+        resampler_clear(resampler->fir_resampler[1]);
+        resampler_set_quality(resampler->fir_resampler[0], resampler->quality);
+        resampler_set_quality(resampler->fir_resampler[1], resampler->quality);
 }
 
 
@@ -158,15 +160,15 @@
 	resampler->last_clock += inv_dt; \
 }
 #define POKE_FIR(offset) { \
-        sinc_resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \
+        resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \
 }
 #define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol )
-#define MONO_DEST_PEEK_FIR *dst = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), vol )
+#define MONO_DEST_PEEK_FIR *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol )
 #define MONO_DEST_MIX_FIR { \
-        *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), vol ); \
+        *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ); \
         UPDATE_VOLUME( volume, vol ); \
 }
-#define ADVANCE_FIR sinc_resampler_remove_sample( resampler->fir_resampler[0] )
+#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0] )
 #define MONO_DEST_MIX_ALIAS(count) { \
 	int n = 0; \
 	resampler->last_clock -= count * 65536; \
@@ -184,12 +186,12 @@
 	*dst++ = MULSC( sample, rvol ); \
 }
 #define STEREO_DEST_PEEK_FIR { \
-        int sample = sinc_resampler_get_sample( resampler->fir_resampler[0] ); \
+        int sample = resampler_get_sample( resampler->fir_resampler[0] ); \
         *dst++ = MULSC( sample, lvol ); \
         *dst++ = MULSC( sample, rvol ); \
 }
 #define STEREO_DEST_MIX_FIR { \
-        int sample = sinc_resampler_get_sample( resampler->fir_resampler[0] ); \
+        int sample = resampler_get_sample( resampler->fir_resampler[0] ); \
         *dst++ += MULSC( sample, lvol ); \
         *dst++ += MULSC( sample, rvol ); \
         UPDATE_VOLUME( volume_left, lvol ); \
@@ -296,8 +298,8 @@
 	resampler->last_clock += inv_dt; \
 }
 #define POKE_FIR(offset) { \
-        sinc_resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \
-        sinc_resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \
+        resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \
+        resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \
 }
 #define MONO_DEST_PEEK_ALIAS { \
 	*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
@@ -304,18 +306,18 @@
 		MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
 }
 #define MONO_DEST_PEEK_FIR { \
-        *dst = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
-                MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
+        *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
+                MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
 }
 #define MONO_DEST_MIX_FIR { \
-        *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
-                MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
+        *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
+                MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
         UPDATE_VOLUME( volume_left, lvol ); \
         UPDATE_VOLUME( volume_right, rvol ); \
 }
 #define ADVANCE_FIR { \
-        sinc_resampler_remove_sample( resampler->fir_resampler[0] ); \
-        sinc_resampler_remove_sample( resampler->fir_resampler[1] ); \
+        resampler_remove_sample( resampler->fir_resampler[0] ); \
+        resampler_remove_sample( resampler->fir_resampler[1] ); \
 }
 #define MONO_DEST_MIX_ALIAS(count) { \
 	int n = 0; \
@@ -336,12 +338,12 @@
 	*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
 }
 #define STEREO_DEST_PEEK_FIR { \
-        *dst++ = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
-        *dst++ = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
+        *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
+        *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
 }
 #define STEREO_DEST_MIX_FIR { \
-        *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
-        *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
+        *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
+        *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
         UPDATE_VOLUME( volume_left, lvol ); \
         UPDATE_VOLUME( volume_right, rvol ); \
 }
--- /dev/null
+++ b/dumb/src/helpers/resampler.c
@@ -1,0 +1,636 @@
+#include <stdlib.h>
+#include <string.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
+#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
+#include <xmmintrin.h>
+#define RESAMPLER_SSE
+#endif
+
+#ifdef _MSC_VER
+#define ALIGNED     _declspec(align(16))
+#else
+#define ALIGNED     __attribute__((aligned(16)))
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "resampler.h"
+
+enum { RESAMPLER_SHIFT = 13 };
+enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT };
+enum { SINC_WIDTH = 16 };
+enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH };
+enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 };
+
+ALIGNED static float cubic_lut[CUBIC_SAMPLES];
+
+static float sinc_lut[SINC_SAMPLES + 1];
+
+enum { resampler_buffer_size = SINC_WIDTH * 4 };
+
+static int fEqual(const float b, const float a)
+{
+    return fabs(a - b) < 1.0e-6;
+}
+
+static float sinc(float x)
+{
+    return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI);
+}
+
+#ifdef RESAMPLER_SSE
+#ifdef _MSC_VER
+#include <intrin.h>
+#elif defined(__clang__) || defined(__GNUC__)
+static inline void
+__cpuid(int *data, int selector)
+{
+    asm("cpuid"
+        : "=a" (data[0]),
+        "=b" (data[1]),
+        "=c" (data[2]),
+        "=d" (data[3])
+        : "a"(selector));
+}
+#else
+#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4)
+#endif
+
+static int query_cpu_feature_sse() {
+	int buffer[4];
+	__cpuid(buffer,1);
+	if ((buffer[3]&(1<<25)) == 0) return 0;
+	return 1;
+}
+
+static int resampler_has_sse = 0;
+#endif
+
+void resampler_init(void)
+{
+    unsigned i;
+    double dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0;
+    for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx)
+    {
+        float y = x / SINC_WIDTH;
+#if 1
+        // Blackman
+        float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y);
+#elif 0
+        // C.R.Helmrich's 2 term window
+        float window = 0.79445 * cos(0.5 * M_PI * y) + 0.20555 * cos(1.5 * M_PI * y);
+#elif 0
+        // Lanczos
+        float window = sinc(y);
+#endif
+        sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0;
+    }
+    dx = 1.0 / (float)(RESAMPLER_RESOLUTION);
+    x = 0.0;
+    for (i = 0; i < RESAMPLER_RESOLUTION; ++i, x += dx)
+    {
+        cubic_lut[i*4]   = (float)(-0.5 * x * x * x +       x * x - 0.5 * x);
+        cubic_lut[i*4+1] = (float)( 1.5 * x * x * x - 2.5 * x * x           + 1.0);
+        cubic_lut[i*4+2] = (float)(-1.5 * x * x * x + 2.0 * x * x + 0.5 * x);
+        cubic_lut[i*4+3] = (float)( 0.5 * x * x * x - 0.5 * x * x);
+    }
+#ifdef RESAMPLER_SSE
+    resampler_has_sse = query_cpu_feature_sse();
+#endif
+}
+
+typedef struct resampler
+{
+    int write_pos, write_filled;
+    int read_pos, read_filled;
+    unsigned short phase;
+    unsigned short phase_inc;
+    unsigned char quality;
+    float buffer_in[resampler_buffer_size * 2];
+    float buffer_out[resampler_buffer_size + SINC_WIDTH * 2 - 1];
+} resampler;
+
+void * resampler_create(void)
+{
+    resampler * r = ( resampler * ) malloc( sizeof(resampler) );
+    if ( !r ) return 0;
+
+    r->write_pos = 0;
+    r->write_filled = 0;
+    r->read_pos = 0;
+    r->read_filled = 0;
+    r->phase = 0;
+    r->phase_inc = 0;
+    r->quality = RESAMPLER_QUALITY_MAX;
+    memset( r->buffer_in, 0, sizeof(r->buffer_in) );
+    memset( r->buffer_out, 0, sizeof(r->buffer_out) );
+
+    return r;
+}
+
+void resampler_delete(void * _r)
+{
+    free( _r );
+}
+
+void * resampler_dup(const void * _r)
+{
+    const resampler * r_in = ( const resampler * ) _r;
+    resampler * r_out = ( resampler * ) malloc( sizeof(resampler) );
+    if ( !r_out ) return 0;
+
+    r_out->write_pos = r_in->write_pos;
+    r_out->write_filled = r_in->write_filled;
+    r_out->read_pos = r_in->read_pos;
+    r_out->read_filled = r_in->read_filled;
+    r_out->phase = r_in->phase;
+    r_out->phase_inc = r_in->phase_inc;
+    r_out->quality = r_in->quality;
+    memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
+    memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
+
+    return r_out;
+}
+
+void resampler_dup_inplace(void *_d, const void *_s)
+{
+    const resampler * r_in = ( const resampler * ) _s;
+    resampler * r_out = ( resampler * ) _d;
+
+    r_out->write_pos = r_in->write_pos;
+    r_out->write_filled = r_in->write_filled;
+    r_out->read_pos = r_in->read_pos;
+    r_out->read_filled = r_in->read_filled;
+    r_out->phase = r_in->phase;
+    r_out->phase_inc = r_in->phase_inc;
+    r_out->quality = r_in->quality;
+    memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
+    memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
+}
+
+void resampler_set_quality(void *_r, int quality)
+{
+    resampler * r = ( resampler * ) _r;
+    if (quality < RESAMPLER_QUALITY_MIN)
+        quality = RESAMPLER_QUALITY_MIN;
+    else if (quality > RESAMPLER_QUALITY_MAX)
+        quality = RESAMPLER_QUALITY_MAX;
+    r->quality = (unsigned char)quality;
+}
+
+int resampler_get_free_count(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    return resampler_buffer_size - r->write_filled;
+}
+
+static int resampler_min_filled(resampler *r)
+{
+    switch (r->quality)
+    {
+    default:
+    case RESAMPLER_QUALITY_ZOH:
+        return 1;
+            
+    case RESAMPLER_QUALITY_LINEAR:
+        return 2;
+            
+    case RESAMPLER_QUALITY_CUBIC:
+        return 4;
+            
+    case RESAMPLER_QUALITY_SINC:
+        return SINC_WIDTH * 2;
+    }
+}
+
+int resampler_ready(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    return r->write_filled > resampler_min_filled(r);
+}
+
+void resampler_clear(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    r->write_pos = 0;
+    r->write_filled = 0;
+    r->read_pos = 0;
+    r->read_filled = 0;
+    r->phase = 0;
+}
+
+void resampler_set_rate(void *_r, double new_factor)
+{
+    resampler * r = ( resampler * ) _r;
+    r->phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION );
+}
+
+void resampler_write_sample(void *_r, short s)
+{
+    resampler * r = ( resampler * ) _r;
+
+    if ( r->write_filled < resampler_buffer_size )
+    {
+        float s32 = s;
+        s32 *= (1.0 / 32768.0);
+
+        r->buffer_in[ r->write_pos ] = s32;
+        r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32;
+
+        ++r->write_filled;
+
+        r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size;
+    }
+}
+
+static int resampler_run_zoh(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= 1;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+        
+        do
+        {
+            float sample;
+            
+            if ( out >= out_end )
+                break;
+
+            sample = *in;
+            *out++ = sample;
+            
+            phase += phase_inc;
+            
+            in += phase >> RESAMPLER_SHIFT;
+            
+            phase &= RESAMPLER_RESOLUTION-1;
+        }
+        while ( in < in_end );
+        
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+        
+        used = (int)(in - in_);
+        
+        r->write_filled -= used;
+    }
+    
+    return used;
+}
+
+static int resampler_run_linear(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= 2;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+        
+        do
+        {
+            float sample;
+            
+            if ( out >= out_end )
+                break;
+            
+            sample = in[0] + (in[1] - in[0]) * ((float)phase / RESAMPLER_RESOLUTION);
+            *out++ = sample;
+            
+            phase += phase_inc;
+            
+            in += phase >> RESAMPLER_SHIFT;
+            
+            phase &= RESAMPLER_RESOLUTION-1;
+        }
+        while ( in < in_end );
+        
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+        
+        used = (int)(in - in_);
+        
+        r->write_filled -= used;
+    }
+    
+    return used;
+}
+
+static int resampler_run_cubic(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= 4;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+        
+        do
+        {
+            float * kernel;
+            int i;
+            float sample;
+            
+            if ( out >= out_end )
+                break;
+            
+            kernel = cubic_lut + phase * 4;
+            
+            for (sample = 0, i = 0; i < 4; ++i)
+                sample += in[i] * kernel[i];
+            *out++ = sample;
+            
+            phase += phase_inc;
+            
+            in += phase >> RESAMPLER_SHIFT;
+            
+            phase &= RESAMPLER_RESOLUTION-1;
+        }
+        while ( in < in_end );
+        
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+        
+        used = (int)(in - in_);
+        
+        r->write_filled -= used;
+    }
+    
+    return used;
+}
+
+#ifdef RESAMPLER_SSE
+static int resampler_run_cubic_sse(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= 4;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+        
+        do
+        {
+            __m128 temp1, temp2;
+            __m128 samplex = _mm_setzero_ps();
+            
+            if ( out >= out_end )
+                break;
+            
+            temp1 = _mm_loadu_ps( (const float *)( in ) );
+            temp2 = _mm_load_ps( (const float *)( cubic_lut + phase * 4 ) );
+            temp1 = _mm_mul_ps( temp1, temp2 );
+            samplex = _mm_add_ps( samplex, temp1 );
+            temp1 = _mm_movehl_ps( temp1, samplex );
+            samplex = _mm_add_ps( samplex, temp1 );
+            temp1 = samplex;
+            temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) );
+            samplex = _mm_add_ps( samplex, temp1 );
+            _mm_store_ss( out, samplex );
+            ++out;
+            
+            phase += phase_inc;
+            
+            in += phase >> RESAMPLER_SHIFT;
+            
+            phase &= RESAMPLER_RESOLUTION - 1;
+        }
+        while ( in < in_end );
+        
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+        
+        used = (int)(in - in_);
+        
+        r->write_filled -= used;
+    }
+    
+    return used;
+}
+#endif
+
+static int resampler_run_sinc(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= SINC_WIDTH * 2;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+
+        int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION;
+
+        do
+        {
+            float kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
+            int i = SINC_WIDTH;
+            int phase_adj = phase * step / RESAMPLER_RESOLUTION;
+            float sample;
+
+            if ( out >= out_end )
+                break;
+
+            for (; i >= -SINC_WIDTH + 1; --i)
+            {
+                int pos = i * step;
+                kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)];
+            }
+            for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i)
+                sample += in[i] * kernel[i];
+            *out++ = (float)(sample / kernel_sum);
+
+            phase += phase_inc;
+
+            in += phase >> RESAMPLER_SHIFT;
+
+            phase &= RESAMPLER_RESOLUTION-1;
+        }
+        while ( in < in_end );
+
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+
+        used = (int)(in - in_);
+
+        r->write_filled -= used;
+    }
+
+    return used;
+}
+
+#ifdef RESAMPLER_SSE
+static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end)
+{
+    int in_size = r->write_filled;
+    float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled;
+    int used = 0;
+    in_size -= SINC_WIDTH * 2;
+    if ( in_size > 0 )
+    {
+        float* out = *out_;
+        float const* in = in_;
+        float const* const in_end = in + in_size;
+        int phase = r->phase;
+        int phase_inc = r->phase_inc;
+        
+        int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION;
+        
+        do
+        {
+            // accumulate in extended precision
+            float kernel_sum = 0.0;
+            __m128 kernel[SINC_WIDTH / 2];
+            __m128 temp1, temp2;
+            __m128 samplex = _mm_setzero_ps();
+            float *kernelf = (float*)(&kernel);
+            int i = SINC_WIDTH;
+            int phase_adj = phase * step / RESAMPLER_RESOLUTION;
+            
+            if ( out >= out_end )
+                break;
+            
+            for (; i >= -SINC_WIDTH + 1; --i)
+            {
+                int pos = i * step;
+                kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)];
+            }
+            for (i = 0; i < SINC_WIDTH / 2; ++i)
+            {
+                temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) );
+                temp2 = _mm_load_ps( (const float *)( kernel + i ) );
+                temp1 = _mm_mul_ps( temp1, temp2 );
+                samplex = _mm_add_ps( samplex, temp1 );
+            }
+            kernel_sum = 1.0 / kernel_sum;
+            temp1 = _mm_movehl_ps( temp1, samplex );
+            samplex = _mm_add_ps( samplex, temp1 );
+            temp1 = samplex;
+            temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) );
+            samplex = _mm_add_ps( samplex, temp1 );
+            temp1 = _mm_set_ss( kernel_sum );
+            samplex = _mm_mul_ps( samplex, temp1 );
+            _mm_store_ss( out, samplex );
+            ++out;
+            
+            phase += phase_inc;
+            
+            in += phase >> RESAMPLER_SHIFT;
+            
+            phase &= RESAMPLER_RESOLUTION - 1;
+        }
+        while ( in < in_end );
+        
+        r->phase = (unsigned short) phase;
+        *out_ = out;
+        
+        used = (int)(in - in_);
+        
+        r->write_filled -= used;
+    }
+    
+    return used;
+}
+#endif
+
+static void resampler_fill(resampler * r)
+{
+    int min_filled = resampler_min_filled(r);
+    int quality = r->quality;
+    while ( r->write_filled > min_filled &&
+            r->read_filled < resampler_buffer_size )
+    {
+        int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size;
+        int write_size = resampler_buffer_size - write_pos;
+        float * out = r->buffer_out + write_pos;
+        if ( write_size > ( resampler_buffer_size - r->read_filled ) )
+            write_size = resampler_buffer_size - r->read_filled;
+        switch (quality)
+        {
+        case RESAMPLER_QUALITY_ZOH:
+            resampler_run_zoh( r, &out, out + write_size );
+            break;
+                
+        case RESAMPLER_QUALITY_LINEAR:
+            resampler_run_linear( r, &out, out + write_size );
+            break;
+                
+        case RESAMPLER_QUALITY_CUBIC:
+#ifdef RESAMPLER_SSE
+            if ( resampler_has_sse )
+                resampler_run_cubic_sse( r, &out, out + write_size );
+            else
+#endif
+                resampler_run_cubic( r, &out, out + write_size );
+            break;
+                
+        case RESAMPLER_QUALITY_SINC:
+#ifdef RESAMPLER_SSE
+            if ( resampler_has_sse )
+                resampler_run_sinc_sse( r, &out, out + write_size );
+            else
+#endif
+                resampler_run_sinc( r, &out, out + write_size );
+            break;
+        }
+        r->read_filled += out - r->buffer_out - write_pos;
+    }
+}
+
+int resampler_get_sample_count(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    if ( r->read_filled < 1 )
+        resampler_fill( r );
+    return r->read_filled;
+}
+
+int resampler_get_sample(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    if ( r->read_filled < 1 )
+        resampler_fill( r );
+    if ( r->read_filled < 1 )
+        return 0;
+    return (int)(r->buffer_out[ r->read_pos ] * 16777216.0);
+}
+
+void resampler_remove_sample(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    if ( r->read_filled > 0 )
+    {
+        --r->read_filled;
+        r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size;
+    }
+}
--- a/dumb/src/helpers/sinc_resampler.c
+++ /dev/null
@@ -1,361 +1,0 @@
-#include <stdlib.h>
-#include <string.h>
-#define _USE_MATH_DEFINES
-#include <math.h>
-#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
-#include <xmmintrin.h>
-#define SINC_SSE
-#endif
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-#include "sinc_resampler.h"
-
-enum { SINC_RESOLUTION = 8192 };
-enum { SINC_WIDTH = 16 };
-enum { SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH };
-
-static float sinc_lut[SINC_SAMPLES + 1];
-
-enum { sinc_buffer_size = SINC_WIDTH * 4 };
-
-static int fEqual(const float b, const float a)
-{
-    return fabs(a - b) < 1.0e-6;
-}
-
-static float sinc(float x)
-{
-    return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI);
-}
-
-#ifdef SINC_SSE
-#ifdef _MSC_VER
-#include <intrin.h>
-#elif defined(__clang__) || defined(__GNUC__)
-static inline void
-__cpuid(int *data, int selector)
-{
-    asm("cpuid"
-        : "=a" (data[0]),
-        "=b" (data[1]),
-        "=c" (data[2]),
-        "=d" (data[3])
-        : "a"(selector));
-}
-#else
-#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4)
-#endif
-
-static int query_cpu_feature_sse() {
-	int buffer[4];
-	__cpuid(buffer,1);
-	if ((buffer[3]&(1<<25)) == 0) return 0;
-	return 1;
-}
-
-static int sinc_has_sse = 0;
-#endif
-
-void sinc_init(void)
-{
-    unsigned i;
-    float dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0;
-    for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx)
-    {
-        float y = x / SINC_WIDTH;
-        float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y);
-        sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0;
-    }
-#ifdef SINC_SSE
-    sinc_has_sse = query_cpu_feature_sse();
-#endif
-}
-
-typedef struct sinc_resampler
-{
-    int write_pos, write_filled;
-    int read_pos, read_filled;
-    unsigned short phase;
-    unsigned int phase_inc;
-    float buffer_in[sinc_buffer_size * 2];
-    int buffer_out[sinc_buffer_size];
-} sinc_resampler;
-
-void * sinc_resampler_create(void)
-{
-    sinc_resampler * r = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) );
-    if ( !r ) return 0;
-
-    r->write_pos = 0;
-    r->write_filled = 0;
-    r->read_pos = 0;
-    r->read_filled = 0;
-    r->phase = 0;
-    r->phase_inc = 0;
-    memset( r->buffer_in, 0, sizeof(r->buffer_in) );
-    memset( r->buffer_out, 0, sizeof(r->buffer_out) );
-
-    return r;
-}
-
-void sinc_resampler_delete(void * _r)
-{
-    free( _r );
-}
-
-void * sinc_resampler_dup(const void * _r)
-{
-    const sinc_resampler * r_in = ( const sinc_resampler * ) _r;
-    sinc_resampler * r_out = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) );
-    if ( !r_out ) return 0;
-
-    r_out->write_pos = r_in->write_pos;
-    r_out->write_filled = r_in->write_filled;
-    r_out->read_pos = r_in->read_pos;
-    r_out->read_filled = r_in->read_filled;
-    r_out->phase = r_in->phase;
-    r_out->phase_inc = r_in->phase_inc;
-    memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
-    memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
-
-    return r_out;
-}
-
-void sinc_resampler_dup_inplace(void *_d, const void *_s)
-{
-    const sinc_resampler * r_in = ( const sinc_resampler * ) _s;
-    sinc_resampler * r_out = ( sinc_resampler * ) _d;
-
-    r_out->write_pos = r_in->write_pos;
-    r_out->write_filled = r_in->write_filled;
-    r_out->read_pos = r_in->read_pos;
-    r_out->read_filled = r_in->read_filled;
-    r_out->phase = r_in->phase;
-    r_out->phase_inc = r_in->phase_inc;
-    memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
-    memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) );
-}
-
-int sinc_resampler_get_free_count(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    return sinc_buffer_size - r->write_filled;
-}
-
-int sinc_resampler_ready(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    return r->write_filled > (SINC_WIDTH * 2);
-}
-
-void sinc_resampler_clear(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    r->write_pos = 0;
-    r->write_filled = 0;
-    r->read_pos = 0;
-    r->read_filled = 0;
-    r->phase = 0;
-}
-
-void sinc_resampler_set_rate(void *_r, double new_factor)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    r->phase_inc = (int)( new_factor * SINC_RESOLUTION );
-}
-
-void sinc_resampler_write_sample(void *_r, short s)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-
-    if ( r->write_filled < sinc_buffer_size )
-    {
-        float s32 = s;
-
-        r->buffer_in[ r->write_pos ] = s32;
-        r->buffer_in[ r->write_pos + sinc_buffer_size ] = s32;
-
-        ++r->write_filled;
-
-        r->write_pos = ( r->write_pos + 1 ) % sinc_buffer_size;
-    }
-}
-
-static int sinc_resampler_run(sinc_resampler * r, int ** out_, int * out_end)
-{
-    int in_size = r->write_filled;
-    float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled;
-    int used = 0;
-    in_size -= SINC_WIDTH * 2;
-    if ( in_size > 0 )
-    {
-        int* out = *out_;
-        float const* in = in_;
-        float const* const in_end = in + in_size;
-        int phase = r->phase;
-        int phase_inc = r->phase_inc;
-
-        int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION;
-
-        do
-        {
-            // accumulate in extended precision
-            float kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
-            int i = SINC_WIDTH;
-            int phase_adj = phase * step / SINC_RESOLUTION;
-            float sample;
-
-            if ( out >= out_end )
-                break;
-
-            for (; i >= -SINC_WIDTH + 1; --i)
-            {
-                int pos = i * step;
-                kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)];
-            }
-            for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i)
-                sample += in[i] * kernel[i];
-            *out++ = (int)(sample / kernel_sum * 256.0);
-
-            phase += phase_inc;
-
-            in += phase >> 13;
-
-            phase &= 8191;
-        }
-        while ( in < in_end );
-
-        r->phase = (unsigned short) phase;
-        *out_ = out;
-
-        used = (int)(in - in_);
-
-        r->write_filled -= used;
-    }
-
-    return used;
-}
-
-#ifdef SINC_SSE
-static int sinc_resampler_run_sse(sinc_resampler * r, int ** out_, int * out_end)
-{
-    int in_size = r->write_filled;
-    float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled;
-    int used = 0;
-    in_size -= SINC_WIDTH * 2;
-    if ( in_size > 0 )
-    {
-        int* out = *out_;
-        float const* in = in_;
-        float const* const in_end = in + in_size;
-        int phase = r->phase;
-        int phase_inc = r->phase_inc;
-        
-        int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION;
-        
-        do
-        {
-            // accumulate in extended precision
-            float kernel_sum = 0.0;
-            __m128 kernel[SINC_WIDTH / 2];
-            __m128 temp1, temp2;
-            __m128 samplex = _mm_setzero_ps();
-            float *kernelf = (float*)(&kernel);
-            int i = SINC_WIDTH;
-            int phase_adj = phase * step / SINC_RESOLUTION;
-            
-            if ( out >= out_end )
-                break;
-            
-            for (; i >= -SINC_WIDTH + 1; --i)
-            {
-                int pos = i * step;
-                kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)];
-            }
-            for (i = 0; i < SINC_WIDTH / 2; ++i)
-            {
-                temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) );
-                temp2 = _mm_load_ps( (const float *)( kernel + i ) );
-                temp1 = _mm_mul_ps( temp1, temp2 );
-                samplex = _mm_add_ps( samplex, temp1 );
-            }
-            kernel_sum = 1.0 / kernel_sum * 256.0;
-            temp1 = _mm_movehl_ps( temp1, samplex );
-            samplex = _mm_add_ps( samplex, temp1 );
-            temp1 = samplex;
-            temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) );
-            samplex = _mm_add_ps( samplex, temp1 );
-            temp1 = _mm_set_ss( kernel_sum );
-            samplex = _mm_mul_ps( samplex, temp1 );
-            *out++ = _mm_cvtss_si32( samplex );
-            
-            phase += phase_inc;
-            
-            in += phase >> 13;
-            
-            phase &= 8191;
-        }
-        while ( in < in_end );
-        
-        r->phase = (unsigned short) phase;
-        *out_ = out;
-        
-        used = (int)(in - in_);
-        
-        r->write_filled -= used;
-    }
-    
-    return used;
-}
-#endif
-
-static void sinc_resampler_fill(sinc_resampler * r)
-{
-    while ( r->write_filled > (SINC_WIDTH * 2) &&
-            r->read_filled < sinc_buffer_size )
-    {
-        int write_pos = ( r->read_pos + r->read_filled ) % sinc_buffer_size;
-        int write_size = sinc_buffer_size - write_pos;
-        int * out = r->buffer_out + write_pos;
-        if ( write_size > ( sinc_buffer_size - r->read_filled ) )
-            write_size = sinc_buffer_size - r->read_filled;
-#ifdef SINC_SSE
-        if ( sinc_has_sse )
-            sinc_resampler_run_sse( r, &out, out + write_size );
-        else
-#endif
-            sinc_resampler_run( r, &out, out + write_size );
-        r->read_filled += out - r->buffer_out - write_pos;
-    }
-}
-
-int sinc_resampler_get_sample_count(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    if ( r->read_filled < 1 )
-        sinc_resampler_fill( r );
-    return r->read_filled;
-}
-
-int sinc_resampler_get_sample(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    if ( r->read_filled < 1 )
-        sinc_resampler_fill( r );
-    if ( r->read_filled < 1 )
-        return 0;
-    return r->buffer_out[ r->read_pos ];
-}
-
-void sinc_resampler_remove_sample(void *_r)
-{
-    sinc_resampler * r = ( sinc_resampler * ) _r;
-    if ( r->read_filled > 0 )
-    {
-        --r->read_filled;
-        r->read_pos = ( r->read_pos + 1 ) % sinc_buffer_size;
-    }
-}
--- a/dumb/src/it/itrender.c
+++ b/dumb/src/it/itrender.c
@@ -27,7 +27,7 @@
 #include "internal/lpc.h"
 
 #include "internal/blip_buf.h"
-#include "internal/sinc_resampler.h"
+#include "internal/resampler.h"
 
 // #define BIT_ARRAY_BULLSHIT
 
@@ -52,7 +52,7 @@
 		blip_set_rates(r->resampler.blip_buffer[0], 65536, 1);
 		blip_set_rates(r->resampler.blip_buffer[1], 65536, 1);
 		r->resampler.fir_resampler_ratio = 0.0;
-		r->resampler.fir_resampler[0] = sinc_resampler_create();
+		r->resampler.fir_resampler[0] = resampler_create();
 		if ( !r->resampler.fir_resampler[0] ) {
 			free( r->resampler.blip_buffer[1] );
 			free( r->resampler.blip_buffer[0] );
@@ -59,9 +59,9 @@
 			free( r );
 			return NULL;
 		}
-		r->resampler.fir_resampler[1] = sinc_resampler_create();
+		r->resampler.fir_resampler[1] = resampler_create();
 		if ( !r->resampler.fir_resampler[1] ) {
-			sinc_resampler_delete( r->resampler.fir_resampler[0] );
+			resampler_delete( r->resampler.fir_resampler[0] );
 			free( r->resampler.blip_buffer[1] );
 			free( r->resampler.blip_buffer[0] );
 			free( r );
@@ -73,8 +73,8 @@
 
 static void free_playing(IT_PLAYING * r)
 {
-	sinc_resampler_delete( r->resampler.fir_resampler[1] );
-	sinc_resampler_delete( r->resampler.fir_resampler[0] );
+	resampler_delete( r->resampler.fir_resampler[1] );
+	resampler_delete( r->resampler.fir_resampler[0] );
 	blip_delete( r->resampler.blip_buffer[1] );
 	blip_delete( r->resampler.blip_buffer[0] );
 	free( r );
@@ -180,7 +180,7 @@
 		return NULL;
 	}
 	dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio;
-	dst->resampler.fir_resampler[0] = sinc_resampler_dup( src->resampler.fir_resampler[0] );
+	dst->resampler.fir_resampler[0] = resampler_dup( src->resampler.fir_resampler[0] );
 	if ( !dst->resampler.fir_resampler[0] ) {
 		blip_delete( dst->resampler.blip_buffer[1] );
 		blip_delete( dst->resampler.blip_buffer[0] );
@@ -187,9 +187,9 @@
 		free( dst );
 		return NULL;
 	}
-	dst->resampler.fir_resampler[1] = sinc_resampler_dup( src->resampler.fir_resampler[1] );
+	dst->resampler.fir_resampler[1] = resampler_dup( src->resampler.fir_resampler[1] );
 	if ( !dst->resampler.fir_resampler[1] ) {
-		sinc_resampler_delete( dst->resampler.fir_resampler[0] );
+		resampler_delete( dst->resampler.fir_resampler[0] );
 		blip_delete( dst->resampler.blip_buffer[1] );
 		blip_delete( dst->resampler.blip_buffer[0] );
 		free( dst );
@@ -4660,6 +4660,8 @@
 		if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
 			quality = playing->sample->max_resampling_quality;
 		playing->resampler.quality = quality;
+                resampler_set_quality(playing->resampler.fir_resampler[0], quality);
+                resampler_set_quality(playing->resampler.fir_resampler[1], quality);
 	}
 
 	bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
@@ -5335,6 +5337,8 @@
 				IT_PLAYING * playing = sigrenderer->channel[i].playing;
 				playing->resampling_quality = quality;
 				playing->resampler.quality = quality;
+                                resampler_set_quality(playing->resampler.fir_resampler[0], quality);
+                                resampler_set_quality(playing->resampler.fir_resampler[1], quality);
 			}
 		}
 		for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
@@ -5342,6 +5346,8 @@
 				IT_PLAYING * playing = sigrenderer->playing[i];
 				playing->resampling_quality = quality;
 				playing->resampler.quality = quality;
+                                resampler_set_quality(playing->resampler.fir_resampler[0], quality);
+                                resampler_set_quality(playing->resampler.fir_resampler[1], quality);
 			}
 		}
 	}
--- a/dumb/vc6/dumb/dumb.vcxproj
+++ b/dumb/vc6/dumb/dumb.vcxproj
@@ -112,7 +112,7 @@
     <ClCompile Include="..\..\src\helpers\blip_buf.c" />
     <ClCompile Include="..\..\src\helpers\clickrem.c" />
     <ClCompile Include="..\..\src\helpers\fir_resampler.c" />
-    <ClCompile Include="..\..\src\helpers\sinc_resampler.c" />
+    <ClCompile Include="..\..\src\helpers\resampler.c" />
     <ClCompile Include="..\..\src\helpers\lpc.c" />
     <ClCompile Include="..\..\src\helpers\memfile.c" />
     <ClCompile Include="..\..\src\helpers\resample.c" />
@@ -209,7 +209,7 @@
     <ClInclude Include="..\..\include\internal\dumbfile.h" />
     <ClInclude Include="..\..\include\internal\fir_resampler.h" />
     <ClInclude Include="..\..\include\internal\it.h" />
-    <ClInclude Include="..\..\include\internal\sinc_resampler.h" />
+    <ClInclude Include="..\..\include\internal\resampler.h" />
     <ClInclude Include="..\..\include\internal\lpc.h" />
     <ClInclude Include="..\..\include\internal\riff.h" />
     <ClInclude Include="..\..\include\internal\stack_alloc.h" />
--- a/dumb/vc6/dumb/dumb.vcxproj.filters
+++ b/dumb/vc6/dumb/dumb.vcxproj.filters
@@ -282,7 +282,7 @@
     <ClCompile Include="..\..\src\it\readany2.c">
       <Filter>src\it\readers</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\helpers\sinc_resampler.c">
+    <ClCompile Include="..\..\src\helpers\resampler.c">
       <Filter>src\helpers</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\helpers\tarray.c">
@@ -320,7 +320,7 @@
     <ClInclude Include="..\..\include\internal\blip_buf.h">
       <Filter>include\internal</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\include\internal\sinc_resampler.h">
+    <ClInclude Include="..\..\include\internal\resampler.h">
       <Filter>include\internal</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\internal\tarray.h">