From dc10e56babf61b62c6cc779414103d7183100c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Sep 2015 18:27:11 -0700 Subject: Implement a 6-point sinc-lanczos filter --- Alc/ALc.c | 4 +++- Alc/ALu.c | 1 + Alc/mixer.c | 38 ++++++++++++++++++++++++++------------ Alc/mixer_c.c | 3 +++ Alc/mixer_defs.h | 1 + Alc/mixer_sse2.c | 8 ++++---- Alc/mixer_sse41.c | 8 ++++---- ChangeLog | 4 +++- OpenAL32/Include/alMain.h | 1 + OpenAL32/Include/alu.h | 13 +++++++++++-- OpenAL32/alSource.c | 2 ++ alsoftrc.sample | 1 + utils/alsoft-config/mainwindow.cpp | 5 +++-- 13 files changed, 63 insertions(+), 26 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fcb6504b..b9c01128 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1011,9 +1011,11 @@ static void alc_initconfig(void) DefaultResampler = LinearResampler; else if(strcasecmp(str, "sinc4") == 0) DefaultResampler = FIR4Resampler; + else if(strcasecmp(str, "sinc6") == 0) + DefaultResampler = FIR6Resampler; else if(strcasecmp(str, "cubic") == 0) { - ERR("Resampler option \"cubic\" is deprecated, using sinc4\n"); + WARN("Resampler option \"cubic\" is deprecated, using sinc4\n"); DefaultResampler = FIR4Resampler; } else diff --git a/Alc/ALu.c b/Alc/ALu.c index 3ffe2e63..d8d41e2b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -80,6 +80,7 @@ extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac); +extern inline ALfloat resample_fir6(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALuint frac); extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); diff --git a/Alc/mixer.c b/Alc/mixer.c index b2bd1dce..dedcb5b9 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -43,7 +43,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size); -alignas(16) ALfloat ResampleCoeffs[FRACTIONONE][4]; +alignas(16) union ResamplerCoeffs ResampleCoeffs; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; @@ -104,6 +104,8 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) return Resample_fir4_32_SSE2; #endif return Resample_fir4_32_C; + case FIR6Resampler: + return Resample_fir6_32_C; case ResamplerMax: /* Shouldn't happen */ break; @@ -113,27 +115,39 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) } -static float lanc2(float x) +static float lanc(float r, float x) { if(x == 0.0f) return 1.0f; - if(fabsf(x) >= 2.0f) + if(fabsf(x) >= r) return 0.0f; - return 2.0f*sinf(x*F_PI)*sinf(x*F_PI/2.0f) / + return r*sinf(x*F_PI)*sinf(x*F_PI/r) / (F_PI*F_PI * x*x); } void aluInitMixer(void) { ALuint i; - for(i = 0;i < FRACTIONONE;i++) - { - ALfloat mu = (ALfloat)i / FRACTIONONE; - ResampleCoeffs[i][0] = lanc2(mu - -1.0f); - ResampleCoeffs[i][1] = lanc2(mu - 0.0f); - ResampleCoeffs[i][2] = lanc2(mu - 1.0f); - ResampleCoeffs[i][3] = lanc2(mu - 2.0f); - } + if(DefaultResampler == FIR6Resampler) + for(i = 0;i < FRACTIONONE;i++) + { + ALfloat mu = (ALfloat)i / FRACTIONONE; + ResampleCoeffs.FIR6[i][0] = lanc(3.0f, mu - -2.0f); + ResampleCoeffs.FIR6[i][1] = lanc(3.0f, mu - -1.0f); + ResampleCoeffs.FIR6[i][2] = lanc(3.0f, mu - 0.0f); + ResampleCoeffs.FIR6[i][3] = lanc(3.0f, mu - 1.0f); + ResampleCoeffs.FIR6[i][4] = lanc(3.0f, mu - 2.0f); + ResampleCoeffs.FIR6[i][5] = lanc(3.0f, mu - 3.0f); + } + else if(DefaultResampler == FIR4Resampler) + for(i = 0;i < FRACTIONONE;i++) + { + ALfloat mu = (ALfloat)i / FRACTIONONE; + ResampleCoeffs.FIR4[i][0] = lanc(2.0f, mu - -1.0f); + ResampleCoeffs.FIR4[i][1] = lanc(2.0f, mu - 0.0f); + ResampleCoeffs.FIR4[i][2] = lanc(2.0f, mu - 1.0f); + ResampleCoeffs.FIR4[i][3] = lanc(2.0f, mu - 2.0f); + } MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 6164eb00..59ee5ebf 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -14,6 +14,8 @@ static inline ALfloat lerp32(const ALfloat *vals, ALuint frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac) { return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); } +static inline ALfloat fir6_32(const ALfloat *vals, ALuint frac) +{ return resample_fir6(vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], frac); } const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac), ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples) @@ -46,6 +48,7 @@ const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \ DECL_TEMPLATE(point32) DECL_TEMPLATE(lerp32) DECL_TEMPLATE(fir4_32) +DECL_TEMPLATE(fir6_32) #undef DECL_TEMPLATE diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index e577fafc..4c94954f 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -16,6 +16,7 @@ const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increme const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); const ALfloat *Resample_fir4_32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_fir6_32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); /* C mixers */ diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index 09a797c3..a6f2bb4e 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -100,10 +100,10 @@ const ALfloat *Resample_fir4_32_SSE2(const ALfloat *src, ALuint frac, ALuint inc const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs[frac_.i[3]]); + __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]); + __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]); + __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]); + __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index c85a733d..b9ef608a 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -104,10 +104,10 @@ const ALfloat *Resample_fir4_32_SSE41(const ALfloat *src, ALuint frac, ALuint in const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs[frac_.i[3]]); + __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]); + __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]); + __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]); + __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); diff --git a/ChangeLog b/ChangeLog index fb35d599..eacfeba0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,9 @@ openal-soft-1.17.0: Implemented the ALC_SOFT_HRTF extension. - Implemented C, SSE2, and SSE4.1 based Sinc-Lanczos 4-point resamplers. + Implemented C, SSE2, and SSE4.1 based 4-point Sinc-Lanczos resamplers. + + Implemented a C based 6-point Sinc-Lanczos resampler. Implemented B-Format output support for the wave file writer. This creates FuMa-style first-order Ambisonics wave files (AMB format). diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7d508721..9703a9cf 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -529,6 +529,7 @@ enum Resampler { PointResampler, LinearResampler, FIR4Resampler, + FIR6Resampler, ResamplerMax, }; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 16b3e1ab..c37ebb9f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -202,7 +202,11 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) { return minu64(max, maxu64(min, val)); } -extern alignas(16) ALfloat ResampleCoeffs[FRACTIONONE][4]; +union ResamplerCoeffs { + ALfloat FIR4[FRACTIONONE][4]; + ALfloat FIR6[FRACTIONONE][6]; +}; +extern alignas(16) union ResamplerCoeffs ResampleCoeffs; inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) @@ -211,9 +215,14 @@ inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) } inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac) { - const ALfloat *k = ResampleCoeffs[frac]; + const ALfloat *k = ResampleCoeffs.FIR4[frac]; return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3; } +inline ALfloat resample_fir6(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALuint frac) +{ + const ALfloat *k = ResampleCoeffs.FIR6[frac]; + return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 + k[4]*val4 + k[5]*val5; +} void aluInitMixer(void); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index aff82b5f..24e5874d 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -43,11 +43,13 @@ const ALsizei ResamplerPadding[ResamplerMax] = { 0, /* Point */ 1, /* Linear */ 2, /* FIR4 */ + 3, /* FIR6 */ }; const ALsizei ResamplerPrePadding[ResamplerMax] = { 0, /* Point */ 0, /* Linear */ 1, /* FIR4 */ + 2, /* FIR6 */ }; diff --git a/alsoftrc.sample b/alsoftrc.sample index c05841b4..e1ab22e4 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -130,6 +130,7 @@ # point - nearest sample, no interpolation # linear - extrapolates samples using a linear slope between samples # sinc4 - extrapolates samples using a 4-point Sinc-Lanczos filter +# sinc6 - extrapolates samples using a 6-point Sinc-Lanczos filter # Specifying other values will result in using the default (linear). #resampler = linear diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 310d9260..24372688 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -35,7 +35,7 @@ static const struct { }; static const struct { - const char name[32]; + const char name[48]; const char value[16]; } speakerModeList[] = { { "Autodetect", "" }, @@ -63,7 +63,8 @@ static const struct { { "Default", "" }, { "Point (low quality, fast)", "point" }, { "Linear (basic quality, fast)", "linear" }, - { "Sinc-Lanczos (good quality)", "sinc4" }, + { "Sinc-Lanczos 4pt (good quality)", "sinc4" }, + { "Sinc-Lanczos 6pt (high quality, slow)", "sinc6" }, { "", "" } }, stereoModeList[] = { -- cgit v1.2.3