ref: 84ac89922d6fed2d363254965111a0c3222811f1
parent: fa1413c69747f35c396fce8bbd8d2fba005bb11e
author: Chris Moeller <kode54@gmail.com>
date: Fri Apr 4 12:50:51 EDT 2014
Resampler now adds input delay and subtracts output delay according to whichever quality is selected, rather than being fixed for sinc only. This fixes blep synthesis mode defeating note on and off volume ramping.
--- a/dumb/src/helpers/resampler.c
+++ b/dumb/src/helpers/resampler.c
@@ -17,7 +17,7 @@
#define M_PI 3.14159265358979323846
#endif
-#include "internal/resampler.h"
+#include "resampler.h"
enum { RESAMPLER_SHIFT = 13 };
enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT };
@@ -114,6 +114,8 @@
unsigned int inv_phase;
unsigned int inv_phase_inc;
unsigned char quality;
+ signed char delay_added;
+ signed char delay_removed;
float last_amp;
float accumulator;
float buffer_in[resampler_buffer_size * 2];
@@ -126,7 +128,7 @@
if ( !r ) return 0;
r->write_pos = SINC_WIDTH - 1;
- r->write_filled = SINC_WIDTH - 1;
+ r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
@@ -134,6 +136,8 @@
r->inv_phase = 0;
r->inv_phase_inc = 0;
r->quality = RESAMPLER_QUALITY_MAX;
+ r->delay_added = -1;
+ r->delay_removed = -1;
r->last_amp = 0;
r->accumulator = 0;
memset( r->buffer_in, 0, sizeof(r->buffer_in) );
@@ -162,6 +166,8 @@
r_out->inv_phase = r_in->inv_phase;
r_out->inv_phase_inc = r_in->inv_phase_inc;
r_out->quality = r_in->quality;
+ r_out->delay_added = r_in->delay_added;
+ r_out->delay_removed = r_in->delay_removed;
r_out->last_amp = r_in->last_amp;
r_out->accumulator = r_in->accumulator;
memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
@@ -184,6 +190,8 @@
r_out->inv_phase = r_in->inv_phase;
r_out->inv_phase_inc = r_in->inv_phase_inc;
r_out->quality = r_in->quality;
+ r_out->delay_added = r_in->delay_added;
+ r_out->delay_removed = r_in->delay_removed;
r_out->last_amp = r_in->last_amp;
r_out->accumulator = r_in->accumulator;
memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) );
@@ -207,6 +215,8 @@
r->accumulator = 0;
memset( r->buffer_out, 0, sizeof(r->buffer_out) );
}
+ r->delay_added = -1;
+ r->delay_removed = -1;
}
r->quality = (unsigned char)quality;
}
@@ -237,6 +247,40 @@
}
}
+static int resampler_input_delay(resampler *r)
+{
+ switch (r->quality)
+ {
+ default:
+ case RESAMPLER_QUALITY_ZOH:
+ case RESAMPLER_QUALITY_BLEP:
+ case RESAMPLER_QUALITY_LINEAR:
+ return 0;
+
+ case RESAMPLER_QUALITY_CUBIC:
+ return 1;
+
+ case RESAMPLER_QUALITY_SINC:
+ return SINC_WIDTH - 1;
+ }
+}
+
+static int resampler_output_delay(resampler *r)
+{
+ switch (r->quality)
+ {
+ default:
+ case RESAMPLER_QUALITY_ZOH:
+ case RESAMPLER_QUALITY_LINEAR:
+ case RESAMPLER_QUALITY_CUBIC:
+ case RESAMPLER_QUALITY_SINC:
+ return 0;
+
+ case RESAMPLER_QUALITY_BLEP:
+ return SINC_WIDTH - 1;
+ }
+}
+
int resampler_ready(void *_r)
{
resampler * r = ( resampler * ) _r;
@@ -247,10 +291,12 @@
{
resampler * r = ( resampler * ) _r;
r->write_pos = SINC_WIDTH - 1;
- r->write_filled = SINC_WIDTH - 1;
+ r->write_filled = 0;
r->read_pos = 0;
r->read_filled = 0;
r->phase = 0;
+ r->delay_added = -1;
+ r->delay_removed = -1;
memset(r->buffer_in, 0, (SINC_WIDTH - 1) * sizeof(r->buffer_in[0]));
memset(r->buffer_in + resampler_buffer_size, 0, (SINC_WIDTH - 1) * sizeof(r->buffer_in[0]));
if (r->quality == RESAMPLER_QUALITY_BLEP)
@@ -269,10 +315,16 @@
{
resampler * r = ( resampler * ) _r;
+ if ( r->delay_added < 0 )
+ {
+ r->delay_added = 0;
+ r->write_filled = resampler_input_delay( r );
+ }
+
if ( r->write_filled < resampler_buffer_size )
{
float s32 = s;
- s32 *= (1.0 / 32768.0);
+ s32 *= 256.0;
r->buffer_in[ r->write_pos ] = s32;
r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32;
@@ -791,11 +843,23 @@
}
}
+static void resampler_fill_and_remove_delay(resampler * r)
+{
+ resampler_fill( r );
+ if ( r->delay_removed < 0 )
+ {
+ int delay = resampler_output_delay( r );
+ r->delay_removed = 0;
+ while ( delay-- )
+ resampler_remove_sample( r );
+ }
+}
+
int resampler_get_sample_count(void *_r)
{
resampler * r = ( resampler * ) _r;
- if ( r->read_filled < 1 )
- resampler_fill( r );
+ if ( r->read_filled < 1 && (r->quality != RESAMPLER_QUALITY_BLEP || r->inv_phase_inc))
+ resampler_fill_and_remove_delay( r );
return r->read_filled;
}
@@ -803,13 +867,13 @@
{
resampler * r = ( resampler * ) _r;
if ( r->read_filled < 1 && r->phase_inc)
- resampler_fill( r );
+ 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) * 8388608.0;
+ return (int)(r->buffer_out[ r->read_pos ] + r->accumulator);
else
- return r->buffer_out[ r->read_pos ] * 8388608.0;
+ return (int)r->buffer_out[ r->read_pos ];
}
void resampler_remove_sample(void *_r)
@@ -822,6 +886,8 @@
r->accumulator += r->buffer_out[ r->read_pos ];
r->buffer_out[ r->read_pos ] = 0;
r->accumulator -= r->accumulator * (1.0 / 8192.0);
+ if (fabs(r->accumulator) < 1e-20)
+ r->accumulator = 0;
}
--r->read_filled;
r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size;