Rebuild full ResamplerFilter (left wing + right wing) at runtime

main
Brick 2023-08-24 00:18:52 +01:00 committed by Ryan C. Gordon
parent 0c15ce0060
commit 6a73f74b6b
4 changed files with 53 additions and 33 deletions

View File

@ -50,7 +50,6 @@ gcc -o genfilter build-scripts/gen_audio_resampler_filter.c -lm && ./genfilter >
#define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1) #define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1)
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING) #define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING)
#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) #define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)
#define RESAMPLER_TABLE_SIZE (RESAMPLER_FILTER_SIZE + RESAMPLER_ZERO_CROSSINGS)
/* This is a "modified" bessel function, so you can't use POSIX j0() */ /* This is a "modified" bessel function, so you can't use POSIX j0() */
static double static double
@ -136,18 +135,13 @@ int main(void)
"#define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1)\n" "#define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1)\n"
"#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING)\n" "#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING)\n"
"#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)\n" "#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)\n"
"#define RESAMPLER_TABLE_SIZE (RESAMPLER_FILTER_SIZE + RESAMPLER_ZERO_CROSSINGS)\n"
"\n", RESAMPLER_ZERO_CROSSINGS, RESAMPLER_BITS_PER_SAMPLE "\n", RESAMPLER_ZERO_CROSSINGS, RESAMPLER_BITS_PER_SAMPLE
); );
printf("static const float ResamplerFilter[RESAMPLER_TABLE_SIZE] = {"); printf("static const float ResamplerFilter[RESAMPLER_FILTER_SIZE] = {");
for (i = 0; i < RESAMPLER_TABLE_SIZE; i++) { for (i = 0; i < RESAMPLER_FILTER_SIZE; i++) {
double v = 0.0; j = (i % RESAMPLER_ZERO_CROSSINGS) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING + (i / RESAMPLER_ZERO_CROSSINGS);
if (i < RESAMPLER_FILTER_SIZE) { printf("%s%12.9ff,", (i % RESAMPLER_ZERO_CROSSINGS) ? "" : "\n ", ResamplerFilter[j]);
j = (i % RESAMPLER_ZERO_CROSSINGS) * RESAMPLER_SAMPLES_PER_ZERO_CROSSING + (i / RESAMPLER_ZERO_CROSSINGS);
v = ResamplerFilter[j];
}
printf("%s%12.9ff,", (i % RESAMPLER_ZERO_CROSSINGS) ? "" : "\n ", v);
} }
printf("\n};\n\n"); printf("\n};\n\n");

View File

@ -26,9 +26,8 @@
#define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1) #define RESAMPLER_BITS_PER_ZERO_CROSSING ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1)
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING) #define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING)
#define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) #define RESAMPLER_FILTER_SIZE (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS)
#define RESAMPLER_TABLE_SIZE (RESAMPLER_FILTER_SIZE + RESAMPLER_ZERO_CROSSINGS)
static const float ResamplerFilter[RESAMPLER_TABLE_SIZE] = { static const float ResamplerFilter[RESAMPLER_FILTER_SIZE] = {
1.000000000f, 0.000000000f,-0.000000000f, 0.000000000f,-0.000000000f, 1.000000000f, 0.000000000f,-0.000000000f, 0.000000000f,-0.000000000f,
0.999993165f,-0.001679888f, 0.000529080f,-0.000151513f, 0.000027455f, 0.999993165f,-0.001679888f, 0.000529080f,-0.000151513f, 0.000027455f,
0.999972661f,-0.003351212f, 0.001055794f,-0.000302183f, 0.000054683f, 0.999972661f,-0.003351212f, 0.001055794f,-0.000302183f, 0.000054683f,
@ -541,6 +540,5 @@ static const float ResamplerFilter[RESAMPLER_TABLE_SIZE] = {
0.005090874f,-0.001601309f, 0.000459559f,-0.000083727f, 0.000003250f, 0.005090874f,-0.001601309f, 0.000459559f,-0.000083727f, 0.000003250f,
0.003385399f,-0.001065208f, 0.000305539f,-0.000055591f, 0.000002140f, 0.003385399f,-0.001065208f, 0.000305539f,-0.000055591f, 0.000002140f,
0.001688435f,-0.000531434f, 0.000152351f,-0.000027682f, 0.000001057f, 0.001688435f,-0.000531434f, 0.000152351f,-0.000027682f, 0.000001057f,
0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f,
}; };

View File

@ -84,11 +84,20 @@ static int GetHistoryBufferSampleFrames(const int required_resampler_frames)
#define RESAMPLER_SAMPLES_PER_FRAME (RESAMPLER_ZERO_CROSSINGS * 2) #define RESAMPLER_SAMPLES_PER_FRAME (RESAMPLER_ZERO_CROSSINGS * 2)
#define RESAMPLER_FULL_FILTER_SIZE RESAMPLER_SAMPLES_PER_FRAME * (RESAMPLER_SAMPLES_PER_ZERO_CROSSING + 1)
// TODO: Add SIMD-accelerated versions // TODO: Add SIMD-accelerated versions
static void ResampleFrame(const float* src, float* dst, const float* filter, const int chans) static void ResampleFrame(const float* src, float* dst, const float* raw_filter, const float interp, const int chans)
{ {
int i, chan; int i, chan;
float filter[RESAMPLER_SAMPLES_PER_FRAME];
// Interpolate between the nearest two filters
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
filter[i] = (raw_filter[i] * (1.0f - interp)) + (raw_filter[i + RESAMPLER_SAMPLES_PER_FRAME] * interp);
}
if (chans == 2) { if (chans == 2) {
float v0 = 0.0f; float v0 = 0.0f;
float v1 = 0.0f; float v1 = 0.0f;
@ -136,12 +145,40 @@ static void ResampleFrame(const float* src, float* dst, const float* filter, con
} }
} }
static float FullResamplerFilter[RESAMPLER_FULL_FILTER_SIZE];
void SDL_SetupAudioResampler()
{
// Build a table combining the left and right wings, for faster access
int i, j;
for (i = 0; i < RESAMPLER_SAMPLES_PER_ZERO_CROSSING; ++i) {
for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
int lwing = (i * RESAMPLER_SAMPLES_PER_FRAME) + (RESAMPLER_ZERO_CROSSINGS - 1) - j;
int rwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - lwing;
float value = ResamplerFilter[(i * RESAMPLER_ZERO_CROSSINGS) + j];
FullResamplerFilter[lwing] = value;
FullResamplerFilter[rwing] = value;
}
}
for (i = 0; i < RESAMPLER_ZERO_CROSSINGS; ++i) {
int rwing = i + RESAMPLER_ZERO_CROSSINGS;
int lwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - rwing;
FullResamplerFilter[lwing] = 0.0f;
FullResamplerFilter[rwing] = 0.0f;
}
}
static void ResampleAudio(const int chans, const float *inbuf, const int inframes, float *outbuf, const int outframes, static void ResampleAudio(const int chans, const float *inbuf, const int inframes, float *outbuf, const int outframes,
const Sint64 resample_rate, Sint64* resample_offset) const Sint64 resample_rate, Sint64* resample_offset)
{ {
SDL_assert(resample_rate > 0); SDL_assert(resample_rate > 0);
float *dst = outbuf; float *dst = outbuf;
int i, j; int i;
Sint64 srcpos = *resample_offset; Sint64 srcpos = *resample_offset;
@ -152,26 +189,12 @@ static void ResampleAudio(const int chans, const float *inbuf, const int inframe
SDL_assert(srcindex >= -1 && srcindex < inframes); SDL_assert(srcindex >= -1 && srcindex < inframes);
const int filterindex = (int)(srcfraction >> RESAMPLER_FILTER_INTERP_BITS) * RESAMPLER_ZERO_CROSSINGS; const float* filter = &FullResamplerFilter[(srcfraction >> RESAMPLER_FILTER_INTERP_BITS) * RESAMPLER_SAMPLES_PER_FRAME];
const float interp = (float)(srcfraction & (RESAMPLER_FILTER_INTERP_RANGE - 1)) * (1.0f / RESAMPLER_FILTER_INTERP_RANGE);
const float interpolation1 = (float)(srcfraction & (RESAMPLER_FILTER_INTERP_RANGE - 1)) * (1.0f / RESAMPLER_FILTER_INTERP_RANGE);
const float interpolation2 = 1.0f - interpolation1;
float filter[RESAMPLER_SAMPLES_PER_FRAME];
for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
const int filt_ind1 = filterindex + (RESAMPLER_ZERO_CROSSINGS - 1) - j;
const int filt_ind2 = (RESAMPLER_FILTER_SIZE - 1) - filt_ind1;
const float scale1 = (ResamplerFilter[filt_ind1] * interpolation2) + (ResamplerFilter[filt_ind1 + RESAMPLER_ZERO_CROSSINGS] * interpolation1);
const float scale2 = (ResamplerFilter[filt_ind2] * interpolation1) + (ResamplerFilter[filt_ind2 + RESAMPLER_ZERO_CROSSINGS] * interpolation2);
filter[j] = scale1;
filter[j + RESAMPLER_ZERO_CROSSINGS] = scale2;
}
const float* src = &inbuf[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans]; const float* src = &inbuf[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans];
ResampleFrame(src, dst, filter, chans); ResampleFrame(src, dst, filter, interp, chans);
dst += chans; dst += chans;
} }

View File

@ -962,6 +962,8 @@ void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples) = N
void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples) = NULL; void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples) = NULL;
void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples) = NULL; void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples) = NULL;
extern void SDL_SetupAudioResampler(void);
void SDL_ChooseAudioConverters(void) void SDL_ChooseAudioConverters(void)
{ {
static SDL_bool converters_chosen = SDL_FALSE; static SDL_bool converters_chosen = SDL_FALSE;
@ -969,6 +971,9 @@ void SDL_ChooseAudioConverters(void)
return; return;
} }
// FIXME: Hacks on top of hacks.
SDL_SetupAudioResampler();
#define SET_CONVERTER_FUNCS(fntype) \ #define SET_CONVERTER_FUNCS(fntype) \
SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \ SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \
SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \ SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \