From 5e7513d0a0b3248f8f5bdba1ebc1d96fd7724a39 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 May 2018 18:59:27 -0700 Subject: Accumulate ambisonic upsampler gains using double-precision --- Alc/bformatdec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index dcde7d70..58898083 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -450,11 +450,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat { for(j = 0;j < device->Dry.NumChannels;j++) { - ALfloat gain=0.0f; + ALdouble gain = 0.0; for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - gain += Ambi3DDecoder[k][i] * encgains[k][j]; - ambiup->Gains[i][j][HF_BAND] = gain * Ambi3DDecoderHFScale[i]; - ambiup->Gains[i][j][LF_BAND] = gain; + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; + ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; } } } -- cgit v1.2.3 From 7501c8b48317ee2c09bf928fc1d4bf52c98dce5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 May 2018 08:18:08 -0700 Subject: Simplify counting for the bsinc FIR loop --- Alc/mixer/mixer_neon.c | 12 ++++++++---- Alc/mixer/mixer_sse.c | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 0af977e6..9aa279a2 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -101,16 +101,20 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, // Apply the scale and phase interpolated filter. r4 = vdupq_n_f32(0.0f); { + const ALsizei count = m >> 2; const float32x4_t pf4 = vdupq_n_f32(pf); - for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++) + + ASSUME(count > 0); + + for(j = 0;j < count;j++) { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const float32x4_t f4 = vmlaq_f32( - vmlaq_f32(*fil, sf4, *scd), - pf4, vmlaq_f32(*phd, sf4, *spd) + vmlaq_f32(fil[j], sf4, scd[j]), + pf4, vmlaq_f32(phd[j], sf4, spd[j]) ); /* r += f*src */ - r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); } } r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 5b4208f9..d7d54993 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -45,17 +45,21 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr // Apply the scale and phase interpolated filter. r4 = _mm_setzero_ps(); { + const ALsizei count = m >> 2; const __m128 pf4 = _mm_set1_ps(pf); + + ASSUME(count > 0); + #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++) + for(j = 0;j < count;j++) { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const __m128 f4 = MLA4( - MLA4(*fil, sf4, *scd), - pf4, MLA4(*phd, sf4, *spd) + MLA4(fil[j], sf4, scd[j]), + pf4, MLA4(phd[j], sf4, spd[j]) ); /* r += f*src */ - r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j])); + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); } #undef MLA4 } -- cgit v1.2.3 From dd51ba396babac675846f14d9159e32c1c864cb8 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:21:50 +0200 Subject: Common: Implement discrete Hilbert transform --- common/alcomplex.c | 35 +++++++++++++++++++++++++++++++++++ common/alcomplex.h | 9 +++++++++ 2 files changed, 44 insertions(+) diff --git a/common/alcomplex.c b/common/alcomplex.c index d68277e3..8a0786e9 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -59,3 +59,38 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) } } } + +/*Discrete Hilbert Transform (analytic signal form)*/ +void hilbert(ALsizei size, ALcomplex *InOutBuffer ) +{ + ALsizei k; + const ALdouble inverse_size = 1.0/(ALfloat)size; + + for ( k = 0; k < size;k++ ) + InOutBuffer[k].Imag = 0.0; + + complex_fft( InOutBuffer, size, 1.0 ); + + for( k = 0; k < size; k++ ) + { + if( k == 0 || k == size/2 ) + { + InOutBuffer[k].Real *= inverse_size; + InOutBuffer[k].Imag *= inverse_size; + } + + else if ( k >=1 && k < size/2 ) + { + InOutBuffer[k].Real *= 2.0*inverse_size; + InOutBuffer[k].Imag *= 2.0*inverse_size; + } + + else + { + InOutBuffer[k].Real = 0.0; + InOutBuffer[k].Imag = 0.0; + } + } + + complex_fft( InOutBuffer, size,-1.0 ); +} diff --git a/common/alcomplex.h b/common/alcomplex.h index cf4683fa..cfd164b6 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -55,6 +55,15 @@ inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) */ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); +/** + *Calculate the complex helical sequence (or discrete-time analytical signal) + *of the given input using the discrete Hilbert transform (In-place algorithm). + *Fills InOutBuffer[0...size-1] with the discrete-time analytical signal stored + *in InOutBuffer[0...size-1]. InOutBuffer is an array of complex numbers, + *size MUST BE power of two. + */ +void hilbert(ALsizei size, ALcomplex *InOutBuffer ); + #ifdef __cplusplus } // extern "C" #endif -- cgit v1.2.3 From d3a81f4f28484b246084a5ec5cac5619adcfa819 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:23:03 +0200 Subject: EFX: Frequency Shifter implementation Add frequency shifter effect using discrete Hilbert transform. Only mono signal processing by now (LEFT_DIRECTION). --- Alc/ALc.c | 6 +- Alc/effects/fshifter.c | 323 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/Include/alEffect.h | 10 +- OpenAL32/alAuxEffectSlot.c | 1 + OpenAL32/alEffect.c | 7 + 7 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 Alc/effects/fshifter.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 597cc890..1d001a55 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -550,8 +550,8 @@ static const struct { DECL(AL_EFFECT_ECHO), DECL(AL_EFFECT_FLANGER), DECL(AL_EFFECT_PITCH_SHIFTER), -#if 0 DECL(AL_EFFECT_FREQUENCY_SHIFTER), +#if 0 DECL(AL_EFFECT_VOCAL_MORPHER), #endif DECL(AL_EFFECT_RING_MODULATOR), @@ -632,6 +632,10 @@ static const struct { DECL(AL_FLANGER_FEEDBACK), DECL(AL_FLANGER_DELAY), + DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), + DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), + DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), + DECL(AL_RING_MODULATOR_FREQUENCY), DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c new file mode 100644 index 00000000..2d1b64fe --- /dev/null +++ b/Alc/effects/fshifter.c @@ -0,0 +1,323 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + + +typedef struct ALfshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect parameters */ + ALsizei count; + ALdouble frac_freq; + ALdouble inc; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex Analytic[HIL_SIZE]; + ALcomplex Outdata[BUFFERSIZE]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + +} ALfshifterState; + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state); +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + +/* Define a Hann window, used to filter the HIL input and output. */ +alignas(16) static ALdouble HannWindow[HIL_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(i = 0;i < HIL_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; + } +} + +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + +static void ALfshifterState_Construct(ALfshifterState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALfshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->frac_freq = 0.0; + state->inc = 0.0; + state->ld_sign = -1.0; + + memset(state->InFIFO , 0, HIL_SIZE*sizeof(ALfloat)); + memset(state->OutFIFO , 0, HIL_SIZE*sizeof(ALcomplex)); + memset(state->OutputAccum, 0, 2*HIL_SIZE*sizeof(ALcomplex)); + memset(state->Analytic , 0, HIL_SIZE*sizeof(ALcomplex)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + + state->frac_freq = props->Fshifter.Frequency/device->Frequency; + + switch (props->Fshifter.Left_direction) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + state->ld_sign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + state->ld_sign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + state->frac_freq = 0.0; + break; + } + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALsizei i,k; + ALfloat *restrict BufferOut = state->BufferOut; + + for (i = 0; i < SamplesToDo; i++){ + + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; + + state->count++; + + /* Check whether FIFO buffer is filled */ + if (state->count >= HIL_SIZE ) + { + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for (k = 0; k < HIL_SIZE;k++) + { + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0f; + } + /*Processing signal by Discrete Hilbert Transform (analytical signal)*/ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k=0; k < HIL_SIZE; k++) + { + state->OutputAccum[k].Real += 2.0f*HannWindow[k]*state->Analytic[k].Real / OVERSAMP; + state->OutputAccum[k].Imag += 2.0f*HannWindow[k]*state->Analytic[k].Imag / OVERSAMP; + } + for (k = 0; k < HIL_STEP; k++) + { + state->OutFIFO[k] = state->OutputAccum[k]; + } + + /* shift accumulator */ + memmove(state->OutputAccum, state->OutputAccum + HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); + + /* move input FIFO */ + for (k = 0; k < FIFO_LATENCY; k++) state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + } + } + /*Process frequency shifter using the analytic signal obtained*/ + for ( k = 0; k < SamplesToDo; k++, state->inc += state->frac_freq ) + { + ALdouble phase; + + if( state->inc >= 1.0 ) state->inc -= 1.0; + + phase = (2.0*M_PI*state->inc); + + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->ld_sign*state->Outdata[k].Imag*sin(phase)); + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); + +} + +typedef struct FshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} FshifterStateFactory; + +static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +{ + ALfshifterState *state; + + NEW_OBJ0(state, ALfshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); + +EffectStateFactory *FshifterStateFactory_getFactory(void) +{ + static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &FshifterFactory); +} + +void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = (ALfloat) val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} + +void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALfshifter_setParamf(effect, context, param, vals[0]); +} + +void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.Left_direction = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.Right_direction = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALfshifter_setParami(effect, context, param, vals[0]); +} + +void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = (ALint)props->Fshifter.Left_direction; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = (ALint)props->Fshifter.Right_direction; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALfshifter_getParami(effect, context, param, vals); +} + +void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = (ALfloat)props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } + +} + +void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALfshifter_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALfshifter); diff --git a/CMakeLists.txt b/CMakeLists.txt index cd3ecbed..a6024bf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,6 +761,7 @@ SET(ALC_OBJS Alc/effects/distortion.c Alc/effects/echo.c Alc/effects/equalizer.c + Alc/effects/fshifter.c Alc/effects/modulator.c Alc/effects/null.c Alc/effects/pshifter.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index bb9aef59..c1eae443 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -166,6 +166,7 @@ EffectStateFactory *DistortionStateFactory_getFactory(void); EffectStateFactory *EchoStateFactory_getFactory(void); EffectStateFactory *EqualizerStateFactory_getFactory(void); EffectStateFactory *FlangerStateFactory_getFactory(void); +EffectStateFactory *FshifterStateFactory_getFactory(void); EffectStateFactory *ModulatorStateFactory_getFactory(void); EffectStateFactory *PshifterStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 50b64ee1..206c495b 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -18,6 +18,7 @@ enum { ECHO_EFFECT, EQUALIZER_EFFECT, FLANGER_EFFECT, + FSHIFTER_EFFECT, MODULATOR_EFFECT, PSHIFTER_EFFECT, DEDICATED_EFFECT, @@ -33,7 +34,7 @@ struct EffectList { int type; ALenum val; }; -#define EFFECTLIST_SIZE 12 +#define EFFECTLIST_SIZE 13 extern const struct EffectList EffectList[EFFECTLIST_SIZE]; @@ -65,6 +66,7 @@ extern const struct ALeffectVtable ALdistortion_vtable; extern const struct ALeffectVtable ALecho_vtable; extern const struct ALeffectVtable ALequalizer_vtable; extern const struct ALeffectVtable ALflanger_vtable; +extern const struct ALeffectVtable ALfshifter_vtable; extern const struct ALeffectVtable ALmodulator_vtable; extern const struct ALeffectVtable ALnull_vtable; extern const struct ALeffectVtable ALpshifter_vtable; @@ -145,6 +147,12 @@ typedef union ALeffectProps { ALfloat HighGain; } Equalizer; + struct { + ALfloat Frequency; + ALint Left_direction; + ALint Right_direction; + } Fshifter; + struct { ALfloat Frequency; ALfloat HighPassCutoff; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index d04fc4a7..6f6ef163 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -54,6 +54,7 @@ static const struct { { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index e7dc6ace..a69bf70c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -44,6 +44,7 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, @@ -584,6 +585,12 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; effect->vtab = &ALflanger_vtable; break; + case AL_EFFECT_FREQUENCY_SHIFTER: + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.Left_direction = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.Right_direction = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->vtab = &ALfshifter_vtable; + break; case AL_EFFECT_RING_MODULATOR: effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; -- cgit v1.2.3 From da6f32a1c0fd89e19a09f24f03cae23df65ac91e Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:27:37 +0200 Subject: Alsoft-config: Add frequency shifter effect --- alsoftrc.sample | 2 +- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 2b7093a9..04dd72f6 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -220,7 +220,7 @@ # Sets which effects to exclude, preventing apps from using them. This can # help for apps that try to use effects which are too CPU intensive for the # system to handle. Available effects are: eaxreverb,reverb,chorus,compressor, -# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter +# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter,fshifter #excludefx = ## default-reverb: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index dbd359d8..07b5992b 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -378,6 +378,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableFrequencyShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enablePitchShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -844,6 +845,7 @@ void MainWindow::loadConfig(const QString &fname) ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive)); ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive)); ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); + ui->enableFrequencyShifterCheck->setChecked(!excludefx.contains("fshifter", Qt::CaseInsensitive)); ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); @@ -1056,6 +1058,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("equalizer"); if(!ui->enableFlangerCheck->isChecked()) strlist.append("flanger"); + if(!ui->enableFrequencyShifterCheck->isChecked()) + strlist.append("fshifter"); if(!ui->enableModulatorCheck->isChecked()) strlist.append("modulator"); if(!ui->enableDedicatedCheck->isChecked()) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index ef886ba4..bc112157 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -2124,6 +2124,22 @@ added by the ALC_EXT_DEDICATED extension. true + + + + 320 + 180 + 131 + 21 + + + + Frequency Shifter + + + true + + -- cgit v1.2.3 From 97c165b9518bfdad0fc0506820f32f706488c75e Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 18:44:24 +0200 Subject: Add correct cast --- common/alcomplex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/alcomplex.c b/common/alcomplex.c index 8a0786e9..9cf9d9bd 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -64,7 +64,7 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) void hilbert(ALsizei size, ALcomplex *InOutBuffer ) { ALsizei k; - const ALdouble inverse_size = 1.0/(ALfloat)size; + const ALdouble inverse_size = 1.0/(ALdouble)size; for ( k = 0; k < size;k++ ) InOutBuffer[k].Imag = 0.0; -- cgit v1.2.3 From a235259b5e7788b6e5f77b15ca0f26370914fbc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 06:16:03 -0700 Subject: Further clarify a comment about float precision --- Alc/ALu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9d7fcdd5..3c36cbc6 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1674,9 +1674,9 @@ static inline ALfloat Conv_ALfloat(ALfloat val) { return val; } static inline ALint Conv_ALint(ALfloat val) { - /* Floats have a 23-bit mantissa. A bit of the exponent helps out along - * with the sign bit, giving 25 bits. So [-16777216, +16777216] is the max - * integer range normalized floats can be converted to before losing + /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa + * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] + * is the max value a normalized float can be scaled to before losing * precision. */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; -- cgit v1.2.3 From 720ec2beea665c6098753e13713b165fc3729162 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 17:51:57 -0700 Subject: Use the __BYTE_ORDER__ macro when available --- OpenAL32/Include/alMain.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 886f3ab1..093f7950 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -184,11 +184,15 @@ inline int fallback_ctz64(ALuint64 value) #define CTZ64 fallback_ctz64 #endif +#if defined(__BYTE_ORDER__) && defined(__LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __LITTLE_ENDIAN__) +#else static const union { ALuint u; ALubyte b[sizeof(ALuint)]; } EndianTest = { 1 }; #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) +#endif #define COUNTOF(x) (sizeof(x) / sizeof(0[x])) -- cgit v1.2.3 From 4e315353c82adf7c65fed52e2d99c355e52fc821 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 23:25:56 -0700 Subject: Add a method to queue multiple buffer layers onto a source --- Alc/inprogext.h | 8 ++++ OpenAL32/alSource.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/Alc/inprogext.h b/Alc/inprogext.h index 619b604f..3025abe2 100644 --- a/Alc/inprogext.h +++ b/Alc/inprogext.h @@ -72,6 +72,14 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); #endif #endif +#ifndef AL_SOFT_buffer_layers +#define AL_SOFT_buffer_layers +typedef void (AL_APIENTRY*LPALSOURCEQUEUEBUFFERLAYERSSOFT)(ALuint src, ALsizei nb, const ALuint *buffers); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers); +#endif +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index ed6bd8ee..5ce439c7 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2826,6 +2826,121 @@ done: ALCcontext_DecRef(context); } +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +{ + ALCdevice *device; + ALCcontext *context; + ALbufferlistitem *BufferListStart; + ALbufferlistitem *BufferList; + ALbuffer *BufferFmt = NULL; + ALsource *source; + ALsizei i; + + if(nb == 0) + return; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + + LockSourceList(context); + if(!(nb >= 0 && nb < 16)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb); + if((source=LookupSource(context, src)) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + + if(source->SourceType == AL_STATIC) + { + /* Can't queue on a Static Source */ + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + } + + /* Check for a valid Buffer, for its frequency and format */ + BufferList = source->queue; + while(BufferList) + { + for(i = 0;i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != NULL) + break; + } + if(BufferFmt) break; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } + + LockBufferList(device); + BufferListStart = al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb)); + BufferList = BufferListStart; + ATOMIC_INIT(&BufferList->next, NULL); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; + for(i = 0;i < nb;i++) + { + ALbuffer *buffer = NULL; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", + buffers[i]); + + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + "Queueing non-persistently mapped buffer %u", buffer->id); + + if(BufferFmt == NULL) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, + almemory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != NULL) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + UnlockBufferList(device); + goto done; + } + } + /* All buffers good. */ + UnlockBufferList(device); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + BufferList = next; + ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) { ALCcontext *context; -- cgit v1.2.3 From ecdc58c1c9c4dcd1d7f685d423f7712a48f8a983 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 05:59:03 -0700 Subject: Fix formatting and line endings --- Alc/effects/fshifter.c | 649 +++++++++++++++++++++++++------------------------ 1 file changed, 326 insertions(+), 323 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 2d1b64fe..16710ac2 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -1,323 +1,326 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - -#include "alcomplex.h" - -#define HIL_SIZE 1024 -#define OVERSAMP (1<<2) - -#define HIL_STEP (HIL_SIZE / OVERSAMP) -#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) - - -typedef struct ALfshifterState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect parameters */ - ALsizei count; - ALdouble frac_freq; - ALdouble inc; - ALdouble ld_sign; - - /*Effects buffers*/ - ALfloat InFIFO[HIL_SIZE]; - ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[2*HIL_SIZE]; - ALcomplex Analytic[HIL_SIZE]; - ALcomplex Outdata[BUFFERSIZE]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - -} ALfshifterState; - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state); -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); - -/* Define a Hann window, used to filter the HIL input and output. */ -alignas(16) static ALdouble HannWindow[HIL_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(i = 0;i < HIL_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); - HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; - } -} - -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - -static void ALfshifterState_Construct(ALfshifterState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALfshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); -} - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device) -{ - /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->frac_freq = 0.0; - state->inc = 0.0; - state->ld_sign = -1.0; - - memset(state->InFIFO , 0, HIL_SIZE*sizeof(ALfloat)); - memset(state->OutFIFO , 0, HIL_SIZE*sizeof(ALcomplex)); - memset(state->OutputAccum, 0, 2*HIL_SIZE*sizeof(ALcomplex)); - memset(state->Analytic , 0, HIL_SIZE*sizeof(ALcomplex)); - - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); - - return AL_TRUE; -} - -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - - state->frac_freq = props->Fshifter.Frequency/device->Frequency; - - switch (props->Fshifter.Left_direction) - { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - state->ld_sign = -1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->frac_freq = 0.0; - break; - } - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); -} - -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALsizei i,k; - ALfloat *restrict BufferOut = state->BufferOut; - - for (i = 0; i < SamplesToDo; i++){ - - /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; - - state->count++; - - /* Check whether FIFO buffer is filled */ - if (state->count >= HIL_SIZE ) - { - state->count = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for (k = 0; k < HIL_SIZE;k++) - { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0f; - } - /*Processing signal by Discrete Hilbert Transform (analytical signal)*/ - hilbert(HIL_SIZE, state->Analytic); - - /* Windowing and add to output accumulator */ - for(k=0; k < HIL_SIZE; k++) - { - state->OutputAccum[k].Real += 2.0f*HannWindow[k]*state->Analytic[k].Real / OVERSAMP; - state->OutputAccum[k].Imag += 2.0f*HannWindow[k]*state->Analytic[k].Imag / OVERSAMP; - } - for (k = 0; k < HIL_STEP; k++) - { - state->OutFIFO[k] = state->OutputAccum[k]; - } - - /* shift accumulator */ - memmove(state->OutputAccum, state->OutputAccum + HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); - - /* move input FIFO */ - for (k = 0; k < FIFO_LATENCY; k++) state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; - } - } - /*Process frequency shifter using the analytic signal obtained*/ - for ( k = 0; k < SamplesToDo; k++, state->inc += state->frac_freq ) - { - ALdouble phase; - - if( state->inc >= 1.0 ) state->inc -= 1.0; - - phase = (2.0*M_PI*state->inc); - - BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->ld_sign*state->Outdata[k].Imag*sin(phase)); - } - - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, - maxi(SamplesToDo, 512), 0, SamplesToDo); - -} - -typedef struct FshifterStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} FshifterStateFactory; - -static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) -{ - ALfshifterState *state; - - NEW_OBJ0(state, ALfshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); - -EffectStateFactory *FshifterStateFactory_getFactory(void) -{ - static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &FshifterFactory); -} - -void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = (ALfloat) val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } -} - -void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALfshifter_setParamf(effect, context, param, vals[0]); -} - -void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.Left_direction = val; - break; - - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.Right_direction = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALfshifter_setParami(effect, context, param, vals[0]); -} - -void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = (ALint)props->Fshifter.Left_direction; - break; - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = (ALint)props->Fshifter.Right_direction; - break; - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALfshifter_getParami(effect, context, param, vals); -} - -void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = (ALfloat)props->Fshifter.Frequency; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } - -} - -void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALfshifter_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALfshifter); +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + + +typedef struct ALfshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect parameters */ + ALsizei count; + ALdouble frac_freq; + ALdouble inc; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex Analytic[HIL_SIZE]; + ALcomplex Outdata[BUFFERSIZE]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +} ALfshifterState; + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state); +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + +/* Define a Hann window, used to filter the HIL input and output. */ +alignas(16) static ALdouble HannWindow[HIL_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(i = 0;i < HIL_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; + } +} + +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + +static void ALfshifterState_Construct(ALfshifterState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALfshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->frac_freq = 0.0; + state->inc = 0.0; + state->ld_sign = 1.0; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analytic, 0, sizeof(state->Analytic)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + + state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; + + switch(props->Fshifter.Left_direction) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + state->ld_sign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + state->ld_sign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + state->inc = 0.0; + state->frac_freq = 0.0; + break; + } + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat *restrict BufferOut = state->BufferOut; + ALsizei i, k; + + for(i = 0; i < SamplesToDo;i++) + { + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; + state->count++; + + /* Check whether FIFO buffer is filled */ + if(state->count >= HIL_SIZE) + { + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) + { + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0; + } + + /* Processing signal by Discrete Hilbert Transform (analytical + * signal). + */ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + { + state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; + state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; + } + for(k = 0;k < HIL_STEP;k++) + state->OutFIFO[k] = state->OutputAccum[k]; + + /* Shift accumulator */ + memmove(state->OutputAccum, state->OutputAccum+HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); + + /* Move input FIFO */ + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + } + } + + /* Process frequency shifter using the analytic signal obtained. */ + for(k = 0;k < SamplesToDo;k++) + { + ALdouble phase; + + if(state->inc >= 1.0) + state->inc -= 1.0; + + phase = 2.0*M_PI * state->inc; + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->ld_sign*state->Outdata[k].Imag*sin(phase)); + + state->inc += state->frac_freq; + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); +} + +typedef struct FshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} FshifterStateFactory; + +static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +{ + ALfshifterState *state; + + NEW_OBJ0(state, ALfshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); + +EffectStateFactory *FshifterStateFactory_getFactory(void) +{ + static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &FshifterFactory); +} + +void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = (ALfloat) val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} + +void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALfshifter_setParamf(effect, context, param, vals[0]); +} + +void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.Left_direction = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.Right_direction = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALfshifter_setParami(effect, context, param, vals[0]); +} + +void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = (ALint)props->Fshifter.Left_direction; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = (ALint)props->Fshifter.Right_direction; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALfshifter_getParami(effect, context, param, vals); +} + +void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = (ALfloat)props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } + +} + +void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALfshifter_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALfshifter); -- cgit v1.2.3 From 80df89d0db7805a5661a72b07dd3961b4f5aa836 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 06:12:55 -0700 Subject: Improve the frequency shifter output accum handling --- Alc/effects/fshifter.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 16710ac2..2e1a6c45 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -50,7 +50,7 @@ typedef struct ALfshifterState { /*Effects buffers*/ ALfloat InFIFO[HIL_SIZE]; ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex OutputAccum[HIL_SIZE]; ALcomplex Analytic[HIL_SIZE]; ALcomplex Outdata[BUFFERSIZE]; @@ -147,8 +147,9 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { + static const ALcomplex complex_zero = { 0.0, 0.0 }; ALfloat *restrict BufferOut = state->BufferOut; - ALsizei i, k; + ALsizei i, j, k; for(i = 0; i < SamplesToDo;i++) { @@ -180,15 +181,13 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; } - for(k = 0;k < HIL_STEP;k++) - state->OutFIFO[k] = state->OutputAccum[k]; - /* Shift accumulator */ - memmove(state->OutputAccum, state->OutputAccum+HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); - - /* Move input FIFO */ + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; } } -- cgit v1.2.3 From 8219bb374df7412edb6359ddeb5f45fffafb47a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 06:19:59 -0700 Subject: Fix a couple property variable names --- Alc/effects/fshifter.c | 14 +++++++------- OpenAL32/Include/alEffect.h | 6 +++--- OpenAL32/alEffect.c | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 2e1a6c45..fd229f3f 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -125,7 +125,7 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; - switch(props->Fshifter.Left_direction) + switch(props->Fshifter.LeftDirection) { case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: state->ld_sign = -1.0; @@ -242,7 +242,7 @@ void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, A case AL_FREQUENCY_SHIFTER_FREQUENCY: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = (ALfloat) val; + props->Fshifter.Frequency = val; break; default: @@ -263,13 +263,13 @@ void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, A case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.Left_direction = val; + props->Fshifter.LeftDirection = val; break; case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.Right_direction = val; + props->Fshifter.RightDirection = val; break; default: @@ -287,10 +287,10 @@ void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum pa switch(param) { case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = (ALint)props->Fshifter.Left_direction; + *val = props->Fshifter.LeftDirection; break; case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = (ALint)props->Fshifter.Right_direction; + *val = props->Fshifter.RightDirection; break; default: alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); @@ -308,7 +308,7 @@ void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum pa switch(param) { case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = (ALfloat)props->Fshifter.Frequency; + *val = props->Fshifter.Frequency; break; default: diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 206c495b..4d28a708 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -147,10 +147,10 @@ typedef union ALeffectProps { ALfloat HighGain; } Equalizer; - struct { + struct { ALfloat Frequency; - ALint Left_direction; - ALint Right_direction; + ALint LeftDirection; + ALint RightDirection; } Fshifter; struct { diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index a69bf70c..aacddd4c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -586,9 +586,9 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->vtab = &ALflanger_vtable; break; case AL_EFFECT_FREQUENCY_SHIFTER: - effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - effect->Props.Fshifter.Left_direction = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; - effect->Props.Fshifter.Right_direction = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; effect->vtab = &ALfshifter_vtable; break; case AL_EFFECT_RING_MODULATOR: -- cgit v1.2.3 From f3d4220cab368428e04b8c3fcfec7078e34bd2c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 07:02:14 -0700 Subject: Use fixed point for the frequency shifter's phase --- Alc/effects/fshifter.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index fd229f3f..66ec7124 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -43,8 +43,8 @@ typedef struct ALfshifterState { /* Effect parameters */ ALsizei count; - ALdouble frac_freq; - ALdouble inc; + ALsizei PhaseStep; + ALsizei Phase; ALdouble ld_sign; /*Effects buffers*/ @@ -103,8 +103,8 @@ static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice { /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; - state->frac_freq = 0.0; - state->inc = 0.0; + state->PhaseStep = 0; + state->Phase = 0; state->ld_sign = 1.0; memset(state->InFIFO, 0, sizeof(state->InFIFO)); @@ -122,8 +122,10 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat step; - state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; + step = props->Fshifter.Frequency / (ALfloat)device->Frequency; + state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { @@ -132,12 +134,12 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c break; case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; + state->ld_sign = 1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->inc = 0.0; - state->frac_freq = 0.0; + state->Phase = 0; + state->PhaseStep = 0; break; } @@ -194,16 +196,12 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD /* Process frequency shifter using the analytic signal obtained. */ for(k = 0;k < SamplesToDo;k++) { - ALdouble phase; - - if(state->inc >= 1.0) - state->inc -= 1.0; - - phase = 2.0*M_PI * state->inc; + ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->ld_sign*state->Outdata[k].Imag*sin(phase)); + state->Outdata[k].Imag*sin(phase)*state->ld_sign); - state->inc += state->frac_freq; + state->Phase += state->PhaseStep; + state->Phase &= FRACTIONMASK; } /* Now, mix the processed sound data to the output. */ -- cgit v1.2.3 From c2a4a35c2e3d9959f6a0f20881a7d7dc2ef2c4b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 07:28:53 -0700 Subject: Use a tighter loop to handle the frequency shifter's fifo --- Alc/effects/fshifter.c | 72 +++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 66ec7124..3a58f087 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -151,46 +151,52 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD { static const ALcomplex complex_zero = { 0.0, 0.0 }; ALfloat *restrict BufferOut = state->BufferOut; - ALsizei i, j, k; + ALsizei j, k, base; - for(i = 0; i < SamplesToDo;i++) + for(base = 0;base < SamplesToDo;) { + ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); + + ASSUME(todo > 0); + /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; - state->count++; + k = state->count; + for(j = 0;j < todo;j++,k++) + { + state->InFIFO[k] = SamplesIn[0][base+j]; + state->Outdata[base+j] = state->OutFIFO[k-FIFO_LATENCY]; + } + state->count += todo; + base += todo; /* Check whether FIFO buffer is filled */ - if(state->count >= HIL_SIZE) + if(state->count < HIL_SIZE) continue; + + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) { - state->count = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for(k = 0;k < HIL_SIZE;k++) - { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0; - } - - /* Processing signal by Discrete Hilbert Transform (analytical - * signal). - */ - hilbert(HIL_SIZE, state->Analytic); - - /* Windowing and add to output accumulator */ - for(k = 0;k < HIL_SIZE;k++) - { - state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; - state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; - } - - /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; - for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0; } + + /* Processing signal by Discrete Hilbert Transform (analytical signal). */ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + { + state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; + state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; + } + + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; } /* Process frequency shifter using the analytic signal obtained. */ -- cgit v1.2.3 From 84a94a61098ea6bf1ede1d93ace00b5e2dcaf625 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 01:04:52 -0700 Subject: Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a7aec638..80a55df7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,7 @@ openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. - Implemented the Pitch Shifter effect. + Implemented the Pitch Shifter and Frequency Shifter effects. Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. -- cgit v1.2.3 From 1782208fde4352e4e40a3f3ec9102fb136e1f5e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 05:58:06 -0700 Subject: Remove unused function --- Alc/ALu.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3c36cbc6..acd5de06 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -145,16 +145,6 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) } -/* Prior to VS2013, MSVC lacks the round() family of functions. */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -static float roundf(float val) -{ - if(val < 0.0f) - return ceilf(val-0.5f); - return floorf(val+0.5f); -} -#endif - /* This RNG method was created based on the math found in opusdec. It's quick, * and starting with a seed value of 22222, is suitable for generating * whitenoise. -- cgit v1.2.3 From 9bf3ee722c338f367a65a75ec4d2353f259bc2af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 06:10:09 -0700 Subject: Fix a function comment about a return value --- Alc/ALu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index acd5de06..72c3dd60 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -332,9 +332,7 @@ void aluSelectPostProcess(ALCdevice *device) } -/* Prepares the interpolator for a given rate (determined by increment). A - * result of AL_FALSE indicates that the filter output will completely cut - * the input signal. +/* Prepares the interpolator for a given rate (determined by increment). * * With a bit of work, and a trade of memory for CPU cost, this could be * modified for use with an interpolated increment for buttery-smooth pitch -- cgit v1.2.3 From 93de5350b9d41c4106bc6a6ccfc23e1bc5f48482 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 19:22:21 -0700 Subject: Add some LIKELY and ASSUME statements --- Alc/ALu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 72c3dd60..3cd8ed5c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1610,7 +1610,7 @@ static void ApplyDistanceComp(ALfloat (*restrict Samples)[BUFFERSIZE], DistanceC continue; } - if(SamplesToDo >= base) + if(LIKELY(SamplesToDo >= base)) { for(i = 0;i < base;i++) Values[i] = distbuf[i]; @@ -1638,6 +1638,9 @@ static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_ ALuint seed = *dither_seed; ALsizei c, i; + ASSUME(numchans > 0); + ASSUME(SamplesToDo > 0); + /* Dithering. Step 1, generate whitenoise (uniform distribution of random * values between -1 and +1). Step 2 is to add the noise to the samples, * before rounding and after scaling up to the desired quantization depth. @@ -1690,6 +1693,10 @@ static void Write##A(const ALfloat (*restrict InBuffer)[BUFFERSIZE], \ ALsizei numchans) \ { \ ALsizei i, j; \ + \ + ASSUME(numchans > 0); \ + ASSUME(SamplesToDo > 0); \ + \ for(j = 0;j < numchans;j++) \ { \ const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \ -- cgit v1.2.3 From 422cf429e61c610f271a05c9b5ac44c60b7e58fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 19:49:49 -0700 Subject: Clamp the dither depth between 2 and 20 bits --- Alc/ALc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1d001a55..1858c29b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2217,9 +2217,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; } } - else if(depth > 24) - depth = 24; - device->DitherDepth = (depth > 0) ? powf(2.0f, (ALfloat)(depth-1)) : 0.0f; + + if(depth > 0) + { + depth = clampi(depth, 2, 20); + device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); + } } if(!(device->DitherDepth > 0.0f)) TRACE("Dithering disabled\n"); -- cgit v1.2.3 From 803d331711cf5c0ecd0796bf28e9c95cf3724198 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 May 2018 00:16:50 -0700 Subject: Improve formatting of the hilbert function --- Alc/effects/fshifter.c | 2 +- common/alcomplex.c | 62 +++++++++++++++++++++++--------------------------- common/alcomplex.h | 12 +++++----- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 3a58f087..5aa08453 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -182,7 +182,7 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - hilbert(HIL_SIZE, state->Analytic); + complex_hilbert(state->Analytic, HIL_SIZE); /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) diff --git a/common/alcomplex.c b/common/alcomplex.c index 9cf9d9bd..d4045aeb 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -60,37 +60,33 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) } } -/*Discrete Hilbert Transform (analytic signal form)*/ -void hilbert(ALsizei size, ALcomplex *InOutBuffer ) -{ - ALsizei k; - const ALdouble inverse_size = 1.0/(ALdouble)size; - - for ( k = 0; k < size;k++ ) - InOutBuffer[k].Imag = 0.0; - - complex_fft( InOutBuffer, size, 1.0 ); - - for( k = 0; k < size; k++ ) - { - if( k == 0 || k == size/2 ) - { - InOutBuffer[k].Real *= inverse_size; - InOutBuffer[k].Imag *= inverse_size; - } - - else if ( k >=1 && k < size/2 ) - { - InOutBuffer[k].Real *= 2.0*inverse_size; - InOutBuffer[k].Imag *= 2.0*inverse_size; - } - - else - { - InOutBuffer[k].Real = 0.0; - InOutBuffer[k].Imag = 0.0; - } - } - - complex_fft( InOutBuffer, size,-1.0 ); +void complex_hilbert(ALcomplex *Buffer, ALsizei size) +{ + const ALdouble inverse_size = 1.0/(ALdouble)size; + ALsizei todo, i; + + for(i = 0;i < size;i++) + Buffer[i].Imag = 0.0; + + complex_fft(Buffer, size, 1.0); + + todo = size >> 1; + Buffer[0].Real *= inverse_size; + Buffer[0].Imag *= inverse_size; + for(i = 1;i < todo;i++) + { + Buffer[i].Real *= 2.0*inverse_size; + Buffer[i].Imag *= 2.0*inverse_size; + } + Buffer[i].Real *= inverse_size; + Buffer[i].Imag *= inverse_size; + i++; + + for(;i < size;i++) + { + Buffer[i].Real = 0.0; + Buffer[i].Imag = 0.0; + } + + complex_fft(Buffer, size, -1.0); } diff --git a/common/alcomplex.h b/common/alcomplex.h index cfd164b6..2418ce78 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -56,13 +56,13 @@ inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); /** - *Calculate the complex helical sequence (or discrete-time analytical signal) - *of the given input using the discrete Hilbert transform (In-place algorithm). - *Fills InOutBuffer[0...size-1] with the discrete-time analytical signal stored - *in InOutBuffer[0...size-1]. InOutBuffer is an array of complex numbers, - *size MUST BE power of two. + * Calculate the complex helical sequence (discrete-time analytical signal) of + * the given input using the discrete Hilbert transform (In-place algorithm). + * Fills Buffer[0...size-1] with the discrete-time analytical signal stored in + * Buffer[0...size-1]. Buffer is an array of complex numbers, size MUST BE + * power of two. */ -void hilbert(ALsizei size, ALcomplex *InOutBuffer ); +void complex_hilbert(ALcomplex *Buffer, ALsizei size); #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From ec84a107a4e0d26fa6a528940a40405d1fd1ce65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 00:26:11 -0700 Subject: Don't hardcode the max channels for HRTF B-Format decoding --- Alc/hrtf.c | 6 +++++- Alc/hrtf.h | 6 ------ Alc/panning.c | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 376c849f..ddbd3a28 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -202,13 +202,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N #define NUM_BANDS 2 BandSplitter splitter; ALdouble (*tmpres)[HRIR_LENGTH][2]; - ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; + ALsizei *restrict idx; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length; ALsizei i, c, b; + idx = al_calloc(DEF_ALIGN, AmbiCount*sizeof(*idx)); + for(c = 0;c < AmbiCount;c++) { ALuint evidx, azidx; @@ -312,6 +314,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } al_free(tmpres); tmpres = NULL; + al_free(idx); + idx = NULL; if(NUM_BANDS == 1) max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index aaffa904..ab68929b 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -9,12 +9,6 @@ #include "atomic.h" -/* The maximum number of virtual speakers used to generate HRTF coefficients - * for decoding B-Format. - */ -#define HRTF_AMBI_MAX_CHANNELS 18 - - #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1<AmbiUp) { -- cgit v1.2.3 From ac4061b9d2f5f0994e79ebc71ec85eb69b8b9655 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 18:17:17 -0700 Subject: Better sort the effect list in alsoft-config --- utils/alsoft-config/mainwindow.ui | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index bc112157..18a00659 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ - 5 + 0 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 80 - 20 + 93 + 29 @@ -2011,8 +2011,8 @@ for the system to handle. - 320 - 30 + 70 + 180 131 21 @@ -2028,7 +2028,7 @@ for the system to handle. 320 - 60 + 30 131 21 @@ -2060,7 +2060,7 @@ for the system to handle. 320 - 120 + 150 131 21 @@ -2076,7 +2076,7 @@ for the system to handle. 320 - 150 + 180 131 21 @@ -2111,8 +2111,8 @@ added by the ALC_EXT_DEDICATED extension. - 70 - 180 + 320 + 120 131 21 @@ -2128,7 +2128,7 @@ added by the ALC_EXT_DEDICATED extension. 320 - 180 + 60 131 21 @@ -2162,8 +2162,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 108 - 20 + 125 + 29 @@ -2332,7 +2332,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 21 + 27 -- cgit v1.2.3 From 728dd5a4e05a5353795290c5d0b881883f5ecc83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 20:43:05 -0700 Subject: Avoid setting unnecessary variables --- Alc/ALu.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3cd8ed5c..dd720183 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1878,17 +1878,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) va_end(args); if(msglen < 0 || (size_t)msglen >= sizeof(evt.Message)) - { evt.Message[sizeof(evt.Message)-1] = 0; - msglen = (int)strlen(evt.Message); - } - if(msglen > 0) - msg = evt.Message; - else - { - msg = ""; - msglen = (int)strlen(msg); - } ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) -- cgit v1.2.3 From a5edf487dd1a4095ef5c022c1f254f032ff7f537 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 May 2018 01:03:18 -0700 Subject: Use a macro to handle common case formatting --- Alc/ALu.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index dd720183..dc24755d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1828,27 +1828,16 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) switch(device->FmtType) { - case DevFmtByte: - WriteI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUByte: - WriteUI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtShort: - WriteI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUShort: - WriteUI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtInt: - WriteI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUInt: - WriteUI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtFloat: - WriteF32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; +#define HANDLE_WRITE(T, S) case T: \ + Write##S(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; + HANDLE_WRITE(DevFmtByte, I8) + HANDLE_WRITE(DevFmtUByte, UI8) + HANDLE_WRITE(DevFmtShort, I16) + HANDLE_WRITE(DevFmtUShort, UI16) + HANDLE_WRITE(DevFmtInt, I32) + HANDLE_WRITE(DevFmtUInt, UI32) + HANDLE_WRITE(DevFmtFloat, F32) +#undef HANDLE_WRITE } } -- cgit v1.2.3 From 5cba81cf35ff7f8b6739b317ada82163899a3168 Mon Sep 17 00:00:00 2001 From: "Jan Chren (rindeal)" Date: Tue, 29 May 2018 18:31:41 +0200 Subject: CMake: fix SSE3 typo Closes: https://github.com/kcat/openal-soft/issues/195 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6024bf4..c27c6e4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -858,7 +858,7 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2) MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions") ENDIF() -OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF) +OPTION(ALSOFT_REQUIRE_SSE3 "Require SSE3 support" OFF) CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}") IF(HAVE_EMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) -- cgit v1.2.3 From 8854720e8a83ccb25221b085612b9a47c36bfa16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:15:49 -0700 Subject: Avoid separate in/out parameters when they're always the same --- utils/makehrtf.c | 92 +++++++++++++++++++++----------------------------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index e19c77c9..0bd36849 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -988,46 +988,30 @@ static Complex *CreateComplexes(size_t n) return a; } -/* Fast Fourier transform routines. The number of points must be a power of - * two. In-place operation is possible only if both the real and imaginary - * parts are in-place together. +/* Fast Fourier transform routines. The number of points must be a power of + * two. */ // Performs bit-reversal ordering. -static void FftArrange(const uint n, const Complex *in, Complex *out) +static void FftArrange(const uint n, Complex *inout) { uint rk, k, m; - if(in == out) + // Handle in-place arrangement. + rk = 0; + for(k = 0;k < n;k++) { - // Handle in-place arrangement. - rk = 0; - for(k = 0;k < n;k++) + if(rk > k) { - if(rk > k) - { - Complex temp = in[rk]; - out[rk] = in[k]; - out[k] = temp; - } - m = n; - while(rk&(m >>= 1)) - rk &= ~m; - rk |= m; - } - } - else - { - // Handle copy arrangement. - rk = 0; - for(k = 0;k < n;k++) - { - out[rk] = in[k]; - m = n; - while(rk&(m >>= 1)) - rk &= ~m; - rk |= m; + Complex temp = inout[rk]; + inout[rk] = inout[k]; + inout[k] = temp; } + + m = n; + while(rk&(m >>= 1)) + rk &= ~m; + rk |= m; } } @@ -1061,23 +1045,23 @@ static void FftSummation(const int n, const double s, Complex *cplx) } // Performs a forward FFT. -static void FftForward(const uint n, const Complex *in, Complex *out) +static void FftForward(const uint n, Complex *inout) { - FftArrange(n, in, out); - FftSummation(n, 1.0, out); + FftArrange(n, inout); + FftSummation(n, 1.0, inout); } // Performs an inverse FFT. -static void FftInverse(const uint n, const Complex *in, Complex *out) +static void FftInverse(const uint n, Complex *inout) { double f; uint i; - FftArrange(n, in, out); - FftSummation(n, -1.0, out); + FftArrange(n, inout); + FftSummation(n, -1.0, inout); f = 1.0 / n; for(i = 0;i < n;i++) - out[i] = c_muls(out[i], f); + inout[i] = c_muls(inout[i], f); } /* Calculate the complex helical sequence (or discrete-time analytical signal) @@ -1085,30 +1069,22 @@ static void FftInverse(const uint n, const Complex *in, Complex *out) * of a signal's magnitude response, the imaginary components can be used as * the angles for minimum-phase reconstruction. */ -static void Hilbert(const uint n, const Complex *in, Complex *out) +static void Hilbert(const uint n, Complex *inout) { uint i; - if(in == out) - { - // Handle in-place operation. - for(i = 0;i < n;i++) - out[i].Imag = 0.0; - } - else - { - // Handle copy operation. - for(i = 0;i < n;i++) - out[i] = MakeComplex(in[i].Real, 0.0); - } - FftInverse(n, out, out); + // Handle in-place operation. + for(i = 0;i < n;i++) + inout[i].Imag = 0.0; + + FftInverse(n, inout); for(i = 1;i < (n+1)/2;i++) - out[i] = c_muls(out[i], 2.0); + inout[i] = c_muls(inout[i], 2.0); /* Increment i if n is even. */ i += (n&1)^1; for(;i < n;i++) - out[i] = MakeComplex(0.0, 0.0); - FftForward(n, out, out); + inout[i] = MakeComplex(0.0, 0.0); + FftForward(n, inout); } /* Calculate the magnitude response of the given input. This is used in @@ -1175,7 +1151,7 @@ static void MinimumPhase(const uint n, const double *in, Complex *out) mags[i] = mags[n - i]; out[i] = out[n - i]; } - Hilbert(n, out, out); + Hilbert(n, out); // Remove any DC offset the filter has. mags[0] = EPSILON; for(i = 0;i < n;i++) @@ -2073,7 +2049,7 @@ static void AverageHrirMagnitude(const uint points, const uint n, const double * h[i] = MakeComplex(hrir[i], 0.0); for(;i < n;i++) h[i] = MakeComplex(0.0, 0.0); - FftForward(n, h, h); + FftForward(n, h); MagnitudeResponse(n, h, r); for(i = 0;i < m;i++) mag[i] = Lerp(mag[i], r[i], f); @@ -2243,7 +2219,7 @@ static void ReconstructHrirs(const HrirDataT *hData) for(ti = 0;ti < channels;ti++) { MinimumPhase(n, azd->mIrs[ti], h); - FftInverse(n, h, h); + FftInverse(n, h); for(i = 0;i < hData->mIrPoints;i++) azd->mIrs[ti][i] = h[i].Real; pcdone = ++count * 100 / total; -- cgit v1.2.3 From 46c59f382f5d417a8e95a58a8e2156b9c4b35f1a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:49:45 -0700 Subject: Use fastf2i instead of manual rounding in another place --- Alc/effects/modulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7f1a2cad..db771103 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -137,7 +137,8 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->GetSamples = ModulateSquare; - state->step = float2int(props->Modulator.Frequency*WAVEFORM_FRACONE/device->Frequency + 0.5f); + state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * + WAVEFORM_FRACONE); state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); /* Custom filter coeffs, which match the old version instead of a low-shelf. */ -- cgit v1.2.3 From 0b7f35b28922e2250f06d1aee1ebb60bfecf91d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:55:21 -0700 Subject: Avoid extra sample copies and storage in the modulator effect --- Alc/effects/modulator.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index db771103..7985f03e 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -40,8 +40,6 @@ typedef struct ALmodulatorState { ALsizei index; ALsizei step; - alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES]; - struct { BiquadFilter Filter; @@ -162,13 +160,12 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat *restrict modsamples = ASSUME_ALIGNED(state->ModSamples, 16); const ALsizei step = state->step; ALsizei base; for(base = 0;base < SamplesToDo;) { - alignas(16) ALfloat temps[2][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); ALsizei c, i; @@ -178,11 +175,13 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadFilter_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); + alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; + + BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td); for(i = 0;i < td;i++) - temps[1][i] = temps[0][i] * modsamples[i]; + temps[i] *= modsamples[i]; - MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[c].CurrentGains, + MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains, state->Chans[c].TargetGains, SamplesToDo-base, base, td); } -- cgit v1.2.3