diff --git a/build-scripts/gen_audio_resampler_filter.c b/build-scripts/gen_audio_resampler_filter.c index b2ee5083b..19991bd96 100644 --- a/build-scripts/gen_audio_resampler_filter.c +++ b/build-scripts/gen_audio_resampler_filter.c @@ -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_SAMPLES_PER_ZERO_CROSSING (1 << RESAMPLER_BITS_PER_ZERO_CROSSING) #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() */ static double @@ -136,18 +135,13 @@ int main(void) "#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_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 ); - printf("static const float ResamplerFilter[RESAMPLER_TABLE_SIZE] = {"); - for (i = 0; i < RESAMPLER_TABLE_SIZE; i++) { - double v = 0.0; - if (i < RESAMPLER_FILTER_SIZE) { - 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("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"); diff --git a/src/audio/SDL_audio_resampler_filter.h b/src/audio/SDL_audio_resampler_filter.h index b0097050a..1ea9c33dd 100644 --- a/src/audio/SDL_audio_resampler_filter.h +++ b/src/audio/SDL_audio_resampler_filter.h @@ -26,9 +26,8 @@ #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_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, 0.999993165f,-0.001679888f, 0.000529080f,-0.000151513f, 0.000027455f, 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.003385399f,-0.001065208f, 0.000305539f,-0.000055591f, 0.000002140f, 0.001688435f,-0.000531434f, 0.000152351f,-0.000027682f, 0.000001057f, - 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, }; diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index e2549d605..824e5a310 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -84,11 +84,20 @@ static int GetHistoryBufferSampleFrames(const int required_resampler_frames) #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 -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; + 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) { float v0 = 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, const Sint64 resample_rate, Sint64* resample_offset) { SDL_assert(resample_rate > 0); float *dst = outbuf; - int i, j; + int i; 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); - const int filterindex = (int)(srcfraction >> RESAMPLER_FILTER_INTERP_BITS) * RESAMPLER_ZERO_CROSSINGS; - - 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* 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* src = &inbuf[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans]; - ResampleFrame(src, dst, filter, chans); + ResampleFrame(src, dst, filter, interp, chans); + dst += chans; } diff --git a/src/audio/SDL_audiotypecvt.c b/src/audio/SDL_audiotypecvt.c index 416e9ab91..cbf19a998 100644 --- a/src/audio/SDL_audiotypecvt.c +++ b/src/audio/SDL_audiotypecvt.c @@ -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_S32)(Sint32 *dst, const float *src, int num_samples) = NULL; +extern void SDL_SetupAudioResampler(void); + void SDL_ChooseAudioConverters(void) { static SDL_bool converters_chosen = SDL_FALSE; @@ -969,6 +971,9 @@ void SDL_ChooseAudioConverters(void) return; } + // FIXME: Hacks on top of hacks. + SDL_SetupAudioResampler(); + #define SET_CONVERTER_FUNCS(fntype) \ SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \ SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \