shithub: dumb

Download patch

ref: 2c21da52cbd096f3d7409b58b47d8cddcad6b84b
parent: 9aa0dc277e1360b918aa62f87c92841f25f141ab
author: Chris Moeller <kode54@gmail.com>
date: Sun May 11 13:29:13 EDT 2014

Increased precision of resampler phase variable, greatly reducing the incidence of sample rate rounding errors

--- a/dumb/include/internal/resampler.h
+++ b/dumb/include/internal/resampler.h
@@ -13,11 +13,13 @@
 #define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality)
 #define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count)
 #define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample)
+#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed)
 #define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate)
 #define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready)
 #define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear)
 #define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count)
 #define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample)
+#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float)
 #define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample)
 #endif
 
@@ -43,11 +45,13 @@
 
 int resampler_get_free_count(void *);
 void resampler_write_sample(void *, short sample);
+void resampler_write_sample_fixed(void *, int sample, unsigned char depth);
 void resampler_set_rate( void *, double new_factor );
 int resampler_ready(void *);
 void resampler_clear(void *);
 int resampler_get_sample_count(void *);
 int resampler_get_sample(void *);
+float resampler_get_sample_float(void *);
 void resampler_remove_sample(void *);
 
 #endif
--- a/dumb/src/helpers/resampler.c
+++ b/dumb/src/helpers/resampler.c
@@ -20,7 +20,9 @@
 #include "internal/resampler.h"
 
 enum { RESAMPLER_SHIFT = 10 };
+enum { RESAMPLER_SHIFT_EXTRA = 8 };
 enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT };
+enum { RESAMPLER_RESOLUTION_EXTRA = 1 << (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA) };
 enum { SINC_WIDTH = 16 };
 enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH };
 enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 };
@@ -324,9 +326,9 @@
 void resampler_set_rate(void *_r, double new_factor)
 {
     resampler * r = ( resampler * ) _r;
-    r->phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION );
+    r->phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION_EXTRA );
     new_factor = 1.0 / new_factor;
-    r->inv_phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION );
+    r->inv_phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION_EXTRA );
 }
 
 void resampler_write_sample(void *_r, short s)
@@ -403,13 +405,13 @@
             
             phase += phase_inc;
             
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            phase &= RESAMPLER_RESOLUTION-1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
-        r->phase = (unsigned short) phase;
+        r->phase = phase;
         *out_ = out;
         
         used = (int)(in - in_);
@@ -440,6 +442,7 @@
         do
         {
             float kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
+            int phase_reduced = inv_phase >> RESAMPLER_SHIFT_EXTRA;
             int i = SINC_WIDTH;
             float sample;
             
@@ -449,7 +452,7 @@
             for (; i >= -SINC_WIDTH + 1; --i)
             {
                 int pos = i * step;
-                int abs_pos = abs(inv_phase - pos);
+                int abs_pos = abs(phase_reduced - pos);
                 kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos];
             }
             sample = *in++ - last_amp;
@@ -460,9 +463,9 @@
             
             inv_phase += inv_phase_inc;
             
-            out += inv_phase >> RESAMPLER_SHIFT;
+            out += inv_phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            inv_phase &= RESAMPLER_RESOLUTION-1;
+            inv_phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -505,6 +508,7 @@
             __m128 samplex;
             float sample;
             float *kernelf = (float*)(&kernel);
+            int phase_reduced = inv_phase >> RESAMPLER_SHIFT_EXTRA;
             int i = SINC_WIDTH;
             
             if ( out + SINC_WIDTH * 2 > out_end )
@@ -513,7 +517,7 @@
             for (; i >= -SINC_WIDTH + 1; --i)
             {
                 int pos = i * step;
-                int abs_pos = abs(inv_phase - pos);
+                int abs_pos = abs(phase_reduced - pos);
                 kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos];
             }
             sample = *in++ - last_amp;
@@ -531,9 +535,9 @@
             
             inv_phase += inv_phase_inc;
             
-            out += inv_phase >> RESAMPLER_SHIFT;
+            out += inv_phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            inv_phase &= RESAMPLER_RESOLUTION - 1;
+            inv_phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -571,14 +575,14 @@
             if ( out >= out_end )
                 break;
             
-            sample = in[0] + (in[1] - in[0]) * ((float)phase / RESAMPLER_RESOLUTION);
+            sample = in[0] + (in[1] - in[0]) * ((float)phase / RESAMPLER_RESOLUTION_EXTRA);
             *out++ = sample;
             
             phase += phase_inc;
             
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            phase &= RESAMPLER_RESOLUTION-1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -616,7 +620,7 @@
             if ( out >= out_end )
                 break;
             
-            kernel = cubic_lut + phase * 4;
+            kernel = cubic_lut + (phase >> RESAMPLER_SHIFT_EXTRA) * 4;
             
             for (sample = 0, i = 0; i < 4; ++i)
                 sample += in[i] * kernel[i];
@@ -624,9 +628,9 @@
             
             phase += phase_inc;
             
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            phase &= RESAMPLER_RESOLUTION-1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -665,7 +669,7 @@
                 break;
             
             temp1 = _mm_loadu_ps( (const float *)( in ) );
-            temp2 = _mm_load_ps( (const float *)( cubic_lut + phase * 4 ) );
+            temp2 = _mm_load_ps( (const float *)( cubic_lut + (phase >> RESAMPLER_SHIFT_EXTRA) * 4 ) );
             temp1 = _mm_mul_ps( temp1, temp2 );
             samplex = _mm_add_ps( samplex, temp1 );
             temp1 = _mm_movehl_ps( temp1, samplex );
@@ -678,9 +682,9 @@
             
             phase += phase_inc;
             
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            phase &= RESAMPLER_RESOLUTION - 1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -710,7 +714,7 @@
         int phase = r->phase;
         int phase_inc = r->phase_inc;
 
-        int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION;
+        int step = phase_inc > RESAMPLER_RESOLUTION_EXTRA ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION_EXTRA / phase_inc : RESAMPLER_RESOLUTION;
         int window_step = RESAMPLER_RESOLUTION;
 
         do
@@ -717,7 +721,8 @@
         {
             float kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
             int i = SINC_WIDTH;
-            int phase_adj = phase * step / RESAMPLER_RESOLUTION;
+            int phase_reduced = phase >> RESAMPLER_SHIFT_EXTRA;
+            int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION;
             float sample;
 
             if ( out >= out_end )
@@ -727,7 +732,7 @@
             {
                 int pos = i * step;
                 int window_pos = i * window_step;
-                kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase - window_pos)];
+                kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)];
             }
             for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i)
                 sample += in[i] * kernel[i];
@@ -735,9 +740,9 @@
 
             phase += phase_inc;
 
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
 
-            phase &= RESAMPLER_RESOLUTION-1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
 
@@ -767,7 +772,7 @@
         int phase = r->phase;
         int phase_inc = r->phase_inc;
         
-        int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION;
+        int step = phase_inc > RESAMPLER_RESOLUTION_EXTRA ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION_EXTRA / phase_inc : RESAMPLER_RESOLUTION;
         int window_step = RESAMPLER_RESOLUTION;
         
         do
@@ -779,7 +784,8 @@
             __m128 samplex = _mm_setzero_ps();
             float *kernelf = (float*)(&kernel);
             int i = SINC_WIDTH;
-            int phase_adj = phase * step / RESAMPLER_RESOLUTION;
+            int phase_reduced = phase >> RESAMPLER_SHIFT_EXTRA;
+            int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION;
             
             if ( out >= out_end )
                 break;
@@ -788,7 +794,7 @@
             {
                 int pos = i * step;
                 int window_pos = i * window_step;
-                kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase - window_pos)];
+                kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)];
             }
             for (i = 0; i < SINC_WIDTH / 2; ++i)
             {
@@ -810,9 +816,9 @@
             
             phase += phase_inc;
             
-            in += phase >> RESAMPLER_SHIFT;
+            in += phase >> (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA);
             
-            phase &= RESAMPLER_RESOLUTION - 1;
+            phase &= RESAMPLER_RESOLUTION_EXTRA - 1;
         }
         while ( in < in_end );
         
@@ -922,6 +928,19 @@
         return (int)(r->buffer_out[ r->read_pos ] + r->accumulator);
     else
         return (int)r->buffer_out[ r->read_pos ];
+}
+
+float resampler_get_sample_float(void *_r)
+{
+    resampler * r = ( resampler * ) _r;
+    if ( r->read_filled < 1 && r->phase_inc)
+        resampler_fill_and_remove_delay( r );
+    if ( r->read_filled < 1 )
+        return 0;
+    if ( r->quality == RESAMPLER_QUALITY_BLEP )
+        return r->buffer_out[ r->read_pos ] + r->accumulator;
+    else
+        return r->buffer_out[ r->read_pos ];
 }
 
 void resampler_remove_sample(void *_r)