Improved ResampleAudio
* filterindex2 was off-by-one * Generate ResamplerFilter using doubles * Transpose ResamplerFilter to improve access patternsmain
parent
cdaa19869d
commit
b9541b9eab
|
@ -41,23 +41,27 @@ gcc -o genfilter build-scripts/gen_audio_resampler_filter.c -lm && ./genfilter >
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define RESAMPLER_ZERO_CROSSINGS 5
|
||||
#define RESAMPLER_BITS_PER_SAMPLE 16
|
||||
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
|
||||
#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
|
||||
#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)
|
||||
|
||||
/* This is a "modified" bessel function, so you can't use POSIX j0() */
|
||||
static double
|
||||
bessel(const double x)
|
||||
{
|
||||
const double xdiv2 = x / 2.0;
|
||||
double i0 = 1.0f;
|
||||
double f = 1.0f;
|
||||
double i0 = 1.0;
|
||||
double f = 1.0;
|
||||
int i = 1;
|
||||
|
||||
while (1) {
|
||||
const double diff = pow(xdiv2, i * 2) / pow(f, 2);
|
||||
if (diff < 1.0e-21f) {
|
||||
if (diff < 1.0e-21) {
|
||||
break;
|
||||
}
|
||||
i0 += diff;
|
||||
|
@ -70,30 +74,25 @@ bessel(const double x)
|
|||
|
||||
/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
|
||||
static void
|
||||
kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
|
||||
kaiser_and_sinc(double *table, double *diffs, const int tablelen, const double beta)
|
||||
{
|
||||
const int lenm1 = tablelen - 1;
|
||||
const int lenm1div2 = lenm1 / 2;
|
||||
const double bessel_beta = bessel(beta);
|
||||
int i;
|
||||
|
||||
table[0] = 1.0f;
|
||||
for (i = 1; i < tablelen; i++) {
|
||||
const double kaiser = bessel(beta * sqrt(1.0 - pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel_beta;
|
||||
table[tablelen - i] = (float) kaiser;
|
||||
}
|
||||
table[0] = 1.0;
|
||||
diffs[tablelen - 1] = 0.0;
|
||||
|
||||
for (i = 1; i < tablelen; i++) {
|
||||
const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
|
||||
table[i] *= sinf(x) / x;
|
||||
const double kaiser = bessel(beta * sqrt(1.0 - pow((double)i / (double)(tablelen - 1), 2.0))) / bessel_beta;
|
||||
const double x = (((double) i) / ((double) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * M_PI;
|
||||
table[i] = kaiser * (sin(x) / x);
|
||||
diffs[i - 1] = table[i] - table[i - 1];
|
||||
}
|
||||
diffs[lenm1] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
static float ResamplerFilter[RESAMPLER_FILTER_SIZE];
|
||||
static float ResamplerFilterDifference[RESAMPLER_FILTER_SIZE];
|
||||
static double ResamplerFilter[RESAMPLER_FILTER_SIZE + 1];
|
||||
static double ResamplerFilterDifference[RESAMPLER_FILTER_SIZE + 1];
|
||||
|
||||
static void
|
||||
PrepareResampleFilter(void)
|
||||
|
@ -101,12 +100,12 @@ PrepareResampleFilter(void)
|
|||
/* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
|
||||
const double dB = 80.0;
|
||||
const double beta = 0.1102 * (dB - 8.7);
|
||||
kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
|
||||
kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE + 1, beta);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
PrepareResampleFilter();
|
||||
|
||||
|
@ -137,21 +136,21 @@ int main(void)
|
|||
"#define RESAMPLER_ZERO_CROSSINGS %d\n"
|
||||
"#define RESAMPLER_BITS_PER_SAMPLE %d\n"
|
||||
"#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))\n"
|
||||
"#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)\n"
|
||||
"#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)\n"
|
||||
"\n", RESAMPLER_ZERO_CROSSINGS, RESAMPLER_BITS_PER_SAMPLE
|
||||
);
|
||||
|
||||
printf("static const float ResamplerFilter[RESAMPLER_FILTER_SIZE] = {\n");
|
||||
printf(" %.9ff", ResamplerFilter[0]);
|
||||
for (i = 0; i < RESAMPLER_FILTER_SIZE-1; i++) {
|
||||
printf("%s%.9ff", ((i % 5) == 4) ? ",\n " : ", ", ResamplerFilter[i+1]);
|
||||
printf("static const float ResamplerFilter[RESAMPLER_FILTER_SIZE] = {");
|
||||
for (i = 0; i < RESAMPLER_FILTER_SIZE; i++) {
|
||||
j = (i % RESAMPLER_ZERO_CROSSINGS) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING + (i / RESAMPLER_ZERO_CROSSINGS);
|
||||
printf("%s%12.9ff,", (i % RESAMPLER_ZERO_CROSSINGS) ? "" : "\n ", ResamplerFilter[j]);
|
||||
}
|
||||
printf("\n};\n\n");
|
||||
|
||||
printf("static const float ResamplerFilterDifference[RESAMPLER_FILTER_SIZE] = {\n");
|
||||
printf(" %.9ff", ResamplerFilterDifference[0]);
|
||||
for (i = 0; i < RESAMPLER_FILTER_SIZE-1; i++) {
|
||||
printf("%s%.9ff", ((i % 5) == 4) ? ",\n " : ", ", ResamplerFilterDifference[i+1]);
|
||||
printf("static const float ResamplerFilterDifference[RESAMPLER_FILTER_SIZE] = {");
|
||||
for (i = 0; i < RESAMPLER_FILTER_SIZE; i++) {
|
||||
j = (i % RESAMPLER_ZERO_CROSSINGS) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING + (i / RESAMPLER_ZERO_CROSSINGS);
|
||||
printf("%s%12.9ff,", (i % RESAMPLER_ZERO_CROSSINGS) ? "" : "\n ", ResamplerFilterDifference[j]);
|
||||
}
|
||||
printf("\n};\n\n");
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -95,16 +95,16 @@ static void ResampleAudio(const int chans, const int inrate, const int outrate,
|
|||
* = mod(i * inrate, outrate) / outrate */
|
||||
const int srcfraction = (int)(srcpos % outrate);
|
||||
const float interpolation1 = ((float)srcfraction) / ((float)outrate);
|
||||
const int filterindex1 = ((Sint32)srcfraction) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING / outrate;
|
||||
const int filterindex1 = (((Sint32)srcfraction) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING / outrate) * RESAMPLER_ZERO_CROSSINGS;
|
||||
const float interpolation2 = 1.0f - interpolation1;
|
||||
const int filterindex2 = ((Sint32)(outrate - srcfraction)) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING / outrate;
|
||||
const int filterindex2 = RESAMPLER_FILTER_SIZE - filterindex1 - RESAMPLER_ZERO_CROSSINGS;
|
||||
|
||||
for (chan = 0; chan < chans; chan++) {
|
||||
float outsample = 0.0f;
|
||||
|
||||
// do this twice to calculate the sample, once for the "left wing" and then same for the right.
|
||||
for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
|
||||
const int filt_ind = filterindex1 + j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
||||
for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
|
||||
const int filt_ind = j + filterindex1;
|
||||
const int srcframe = srcindex - j;
|
||||
SDL_assert(paddinglen + srcframe >= 0);
|
||||
/* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
|
||||
|
@ -113,8 +113,8 @@ static void ResampleAudio(const int chans, const int inrate, const int outrate,
|
|||
}
|
||||
|
||||
// Do the right wing!
|
||||
for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
|
||||
const int filt_ind = filterindex2 + j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
||||
for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
|
||||
const int filt_ind = j + filterindex2;
|
||||
const int srcframe = srcindex + 1 + j;
|
||||
SDL_assert(srcframe - inframes < paddinglen);
|
||||
// !!! FIXME: we can bubble this conditional out of here by doing a post loop.
|
||||
|
|
|
@ -794,9 +794,10 @@ static int audio_resampleLoss(void *arg)
|
|||
double signal_to_noise;
|
||||
double max_error;
|
||||
} test_specs[] = {
|
||||
{ 50, 440, 0, 44100, 48000, 60, 0.0025 },
|
||||
{ 50, 5000, SDL_PI_D / 2, 20000, 10000, 65, 0.0010 },
|
||||
{ 50, 440, 0, 22050, 96000, 60, 0.0120 }, /* I have no idea how to tune these values */
|
||||
{ 50, 440, 0, 44100, 48000, 79, 0.0008 },
|
||||
{ 50, 5000, SDL_PI_D / 2, 20000, 10000, 999, 0.0001 },
|
||||
{ 50, 440, 0, 22050, 96000, 76, 0.0120 }, /* I have no idea how to tune these values */
|
||||
{ 50, 440, 0, 96000, 22050, 80, 0.0014 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue