diff options
-rw-r--r-- | Alc/ALc.c | 15 | ||||
-rw-r--r-- | Alc/ALu.c | 70 | ||||
-rw-r--r-- | Alc/bformatdec.c | 8 | ||||
-rw-r--r-- | Alc/effects/fshifter.c | 329 | ||||
-rw-r--r-- | Alc/effects/modulator.c | 16 | ||||
-rw-r--r-- | Alc/hrtf.c | 6 | ||||
-rw-r--r-- | Alc/hrtf.h | 6 | ||||
-rw-r--r-- | Alc/inprogext.h | 8 | ||||
-rw-r--r-- | Alc/mixer/mixer_neon.c | 12 | ||||
-rw-r--r-- | Alc/mixer/mixer_sse.c | 12 | ||||
-rw-r--r-- | Alc/panning.c | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alAuxEffectSlot.h | 1 | ||||
-rw-r--r-- | OpenAL32/Include/alEffect.h | 10 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 4 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 1 | ||||
-rw-r--r-- | OpenAL32/alEffect.c | 7 | ||||
-rw-r--r-- | OpenAL32/alSource.c | 115 | ||||
-rw-r--r-- | alsoftrc.sample | 2 | ||||
-rw-r--r-- | common/alcomplex.c | 31 | ||||
-rw-r--r-- | common/alcomplex.h | 9 | ||||
-rw-r--r-- | utils/alsoft-config/mainwindow.cpp | 4 | ||||
-rw-r--r-- | utils/alsoft-config/mainwindow.ui | 42 | ||||
-rw-r--r-- | utils/makehrtf.c | 92 |
25 files changed, 651 insertions, 155 deletions
@@ -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), @@ -2213,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"); @@ -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. @@ -342,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 @@ -1622,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]; @@ -1650,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. @@ -1674,9 +1665,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; @@ -1702,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); \ @@ -1833,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 } } @@ -1883,17 +1867,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 = "<internal error constructing message>"; - msglen = (int)strlen(msg); - } ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) 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; } } } diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c new file mode 100644 index 00000000..5aa08453 --- /dev/null +++ b/Alc/effects/fshifter.c @@ -0,0 +1,329 @@ +/** + * 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 <math.h> +#include <stdlib.h> + +#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; + ALsizei PhaseStep; + ALsizei Phase; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[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->PhaseStep = 0; + state->Phase = 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]; + ALfloat step; + + step = props->Fshifter.Frequency / (ALfloat)device->Frequency; + state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + + switch(props->Fshifter.LeftDirection) + { + 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->Phase = 0; + state->PhaseStep = 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) +{ + static const ALcomplex complex_zero = { 0.0, 0.0 }; + ALfloat *restrict BufferOut = state->BufferOut; + ALsizei j, k, base; + + for(base = 0;base < SamplesToDo;) + { + ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); + + ASSUME(todo > 0); + + /* Fill FIFO buffer with samples data */ + 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) continue; + + 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). */ + complex_hilbert(state->Analytic, HIL_SIZE); + + /* 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. */ + for(k = 0;k < SamplesToDo;k++) + { + ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->Outdata[k].Imag*sin(phase)*state->ld_sign); + + state->Phase += state->PhaseStep; + state->Phase &= FRACTIONMASK; + } + + /* 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 = 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.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.RightDirection = 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 = props->Fshifter.LeftDirection; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = props->Fshifter.RightDirection; + 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 = 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/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7f1a2cad..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; @@ -137,7 +135,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. */ @@ -161,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; @@ -177,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); } @@ -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); @@ -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<<HRTF_HISTORY_BITS) #define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1) 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/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 } diff --git a/Alc/panning.c b/Alc/panning.c index 4a7c592b..e4562387 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -884,7 +884,6 @@ static void InitHrtfPanning(ALCdevice *device) static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); - static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); if(device->AmbiUp) { diff --git a/CMakeLists.txt b/CMakeLists.txt index cd3ecbed..c27c6e4e 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 @@ -857,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) @@ -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. 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..4d28a708 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; @@ -147,6 +149,12 @@ typedef union ALeffectProps { struct { ALfloat Frequency; + ALint LeftDirection; + ALint RightDirection; + } Fshifter; + + struct { + ALfloat Frequency; ALfloat HighPassCutoff; ALint Waveform; } Modulator; 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])) 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..aacddd4c 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.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: effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; 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; 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/common/alcomplex.c b/common/alcomplex.c index d68277e3..d4045aeb 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -59,3 +59,34 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) } } } + +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 cf4683fa..2418ce78 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 (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 complex_hilbert(ALcomplex *Buffer, ALsizei size); + #ifdef __cplusplus } // extern "C" #endif 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..18a00659 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ </rect> </property> <property name="currentIndex"> - <number>5</number> + <number>0</number> </property> <widget class="QWidget" name="tab_3"> <attribute name="title"> @@ -131,8 +131,8 @@ to stereo output.</string> <rect> <x>380</x> <y>20</y> - <width>80</width> - <height>20</height> + <width>93</width> + <height>29</height> </rect> </property> <property name="toolTip"> @@ -2011,8 +2011,8 @@ for the system to handle.</string> <widget class="QCheckBox" name="enableEchoCheck"> <property name="geometry"> <rect> - <x>320</x> - <y>30</y> + <x>70</x> + <y>180</y> <width>131</width> <height>21</height> </rect> @@ -2028,7 +2028,7 @@ for the system to handle.</string> <property name="geometry"> <rect> <x>320</x> - <y>60</y> + <y>30</y> <width>131</width> <height>21</height> </rect> @@ -2060,7 +2060,7 @@ for the system to handle.</string> <property name="geometry"> <rect> <x>320</x> - <y>120</y> + <y>150</y> <width>131</width> <height>21</height> </rect> @@ -2076,7 +2076,7 @@ for the system to handle.</string> <property name="geometry"> <rect> <x>320</x> - <y>150</y> + <y>180</y> <width>131</width> <height>21</height> </rect> @@ -2111,8 +2111,8 @@ added by the ALC_EXT_DEDICATED extension.</string> <widget class="QCheckBox" name="enablePitchShifterCheck"> <property name="geometry"> <rect> - <x>70</x> - <y>180</y> + <x>320</x> + <y>120</y> <width>131</width> <height>21</height> </rect> @@ -2124,6 +2124,22 @@ added by the ALC_EXT_DEDICATED extension.</string> <bool>true</bool> </property> </widget> + <widget class="QCheckBox" name="enableFrequencyShifterCheck"> + <property name="geometry"> + <rect> + <x>320</x> + <y>60</y> + <width>131</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>Frequency Shifter</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> </widget> <widget class="QLabel" name="label_13"> <property name="geometry"> @@ -2146,8 +2162,8 @@ added by the ALC_EXT_DEDICATED extension.</string> <rect> <x>160</x> <y>20</y> - <width>108</width> - <height>20</height> + <width>125</width> + <height>29</height> </rect> </property> <property name="sizeAdjustPolicy"> @@ -2316,7 +2332,7 @@ added by the ALC_EXT_DEDICATED extension.</string> <x>0</x> <y>0</y> <width>564</width> - <height>21</height> + <height>27</height> </rect> </property> <widget class="QMenu" name="menuFile"> 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; |