Updated sinc resampler with unscaled windowing, which improves resampling quality significantly when downsampling
parent
01f086aa65
commit
03fa21464f
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue