From 03fa21464ff025fcd5d7be2c10a187df019816a4 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 4 Apr 2014 20:41:46 -0700 Subject: [PATCH] Updated sinc resampler with unscaled windowing, which improves resampling quality significantly when downsampling --- Frameworks/Dumb/dumb/src/helpers/resampler.c | 46 ++++++++++++++++--- Frameworks/modplay/modplay/resampler.c | 20 +++++--- .../vio2sf/src/vio2sf/desmume/resampler.c | 28 +++++++---- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/Frameworks/Dumb/dumb/src/helpers/resampler.c b/Frameworks/Dumb/dumb/src/helpers/resampler.c index 77764de30..475c30d8e 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resampler.c +++ b/Frameworks/Dumb/dumb/src/helpers/resampler.c @@ -17,9 +17,9 @@ #define M_PI 3.14159265358979323846 #endif -#include "resampler.h" +#include "internal/resampler.h" -enum { RESAMPLER_SHIFT = 13 }; +enum { RESAMPLER_SHIFT = 10 }; enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; enum { SINC_WIDTH = 16 }; enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; @@ -28,6 +28,7 @@ enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; ALIGNED static float cubic_lut[CUBIC_SAMPLES]; static float sinc_lut[SINC_SAMPLES + 1]; +static float window_lut[SINC_SAMPLES + 1]; enum { resampler_buffer_size = SINC_WIDTH * 4 }; @@ -89,7 +90,8 @@ void resampler_init(void) // Lanczos float window = sinc(y); #endif - sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) : 0.0; + window_lut[i] = window; } dx = 1.0 / (float)(RESAMPLER_RESOLUTION); x = 0.0; @@ -335,6 +337,30 @@ void resampler_write_sample(void *_r, short s) } } +void resampler_write_sample_fixed(void *_r, int s, unsigned char depth) +{ + 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 /= (double)(1 << (depth - 1)); + + 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; @@ -407,7 +433,8 @@ static int resampler_run_blep(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -470,7 +497,8 @@ static int resampler_run_blep_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -667,6 +695,7 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -681,7 +710,8 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) sample += in[i] * kernel[i]; @@ -722,6 +752,7 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -740,7 +771,8 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (i = 0; i < SINC_WIDTH / 2; ++i) { diff --git a/Frameworks/modplay/modplay/resampler.c b/Frameworks/modplay/modplay/resampler.c index 88dd75f08..368d91d18 100644 --- a/Frameworks/modplay/modplay/resampler.c +++ b/Frameworks/modplay/modplay/resampler.c @@ -19,7 +19,7 @@ #include "resampler.h" -enum { RESAMPLER_SHIFT = 13 }; +enum { RESAMPLER_SHIFT = 10 }; enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; enum { SINC_WIDTH = 16 }; enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; @@ -28,6 +28,7 @@ enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; ALIGNED static float cubic_lut[CUBIC_SAMPLES]; static float sinc_lut[SINC_SAMPLES + 1]; +static float window_lut[SINC_SAMPLES + 1]; enum { resampler_buffer_size = SINC_WIDTH * 4 }; @@ -89,7 +90,8 @@ void resampler_init(void) // Lanczos float window = sinc(y); #endif - sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) : 0.0; + window_lut[i] = window; } dx = 1.0 / (float)(RESAMPLER_RESOLUTION); x = 0.0; @@ -431,7 +433,8 @@ static int resampler_run_blep(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -494,7 +497,8 @@ static int resampler_run_blep_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -691,6 +695,7 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -705,7 +710,8 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) sample += in[i] * kernel[i]; @@ -746,6 +752,7 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -764,7 +771,8 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (i = 0; i < SINC_WIDTH / 2; ++i) { diff --git a/Frameworks/vio2sf/vio2sf/src/vio2sf/desmume/resampler.c b/Frameworks/vio2sf/vio2sf/src/vio2sf/desmume/resampler.c index eac6bf830..d383e80fd 100644 --- a/Frameworks/vio2sf/vio2sf/src/vio2sf/desmume/resampler.c +++ b/Frameworks/vio2sf/vio2sf/src/vio2sf/desmume/resampler.c @@ -19,7 +19,7 @@ #include "resampler.h" -enum { RESAMPLER_SHIFT = 13 }; +enum { RESAMPLER_SHIFT = 10 }; enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; enum { SINC_WIDTH = 16 }; enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; @@ -28,6 +28,7 @@ enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; ALIGNED static float cubic_lut[CUBIC_SAMPLES]; static float sinc_lut[SINC_SAMPLES + 1]; +static float window_lut[SINC_SAMPLES + 1]; enum { resampler_buffer_size = SINC_WIDTH * 4 }; @@ -89,7 +90,8 @@ void resampler_init(void) // Lanczos float window = sinc(y); #endif - sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) : 0.0; + window_lut[i] = window; } dx = 1.0 / (float)(RESAMPLER_RESOLUTION); x = 0.0; @@ -311,7 +313,7 @@ void resampler_set_rate(void *_r, double new_factor) r->inv_phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION ); } -void resampler_write_sample(void *_r, short s) +void resampler_write_sample(void *_r, int s) { resampler * r = ( resampler * ) _r; @@ -430,7 +432,8 @@ static int resampler_run_blep(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -493,7 +496,8 @@ static int resampler_run_blep_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(inv_phase - pos)]; + int abs_pos = abs(inv_phase - pos); + kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs_pos] * window_lut[abs_pos]; } sample = *in++ - last_amp; last_amp += sample; @@ -690,6 +694,7 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -704,7 +709,8 @@ static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) sample += in[i] * kernel[i]; @@ -745,6 +751,7 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) int phase_inc = r->phase_inc; int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + int window_step = RESAMPLER_RESOLUTION; do { @@ -763,7 +770,8 @@ static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) for (; i >= -SINC_WIDTH + 1; --i) { int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + 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)]; } for (i = 0; i < SINC_WIDTH / 2; ++i) { @@ -886,7 +894,7 @@ int resampler_get_sample_count(void *_r) return r->read_filled; } -float resampler_get_sample(void *_r) +int resampler_get_sample(void *_r) { resampler * r = ( resampler * ) _r; if ( r->read_filled < 1 && r->phase_inc) @@ -894,9 +902,9 @@ float resampler_get_sample(void *_r) if ( r->read_filled < 1 ) return 0; if ( r->quality == RESAMPLER_QUALITY_BLEP ) - return r->buffer_out[ r->read_pos ] + r->accumulator; + return (int)(r->buffer_out[ r->read_pos ] + r->accumulator); else - return r->buffer_out[ r->read_pos ]; + return (int)r->buffer_out[ r->read_pos ]; } void resampler_remove_sample(void *_r)