aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaulshc <[email protected]>2018-05-31 14:17:20 +0200
committerGitHub <[email protected]>2018-05-31 14:17:20 +0200
commit5233c4aa21d01f8df3decd9b7c5746d8539094fd (patch)
treef19535db9bfafe797e3ca899fcdc86261673f1d8
parentcd2fd126c4024f43730a7c857fca223b35fe0a5b (diff)
parent0b7f35b28922e2250f06d1aee1ebb60bfecf91d6 (diff)
Merge from kcat/master
Update git repository
-rw-r--r--Alc/ALc.c15
-rw-r--r--Alc/ALu.c70
-rw-r--r--Alc/bformatdec.c8
-rw-r--r--Alc/effects/fshifter.c329
-rw-r--r--Alc/effects/modulator.c16
-rw-r--r--Alc/hrtf.c6
-rw-r--r--Alc/hrtf.h6
-rw-r--r--Alc/inprogext.h8
-rw-r--r--Alc/mixer/mixer_neon.c12
-rw-r--r--Alc/mixer/mixer_sse.c12
-rw-r--r--Alc/panning.c1
-rw-r--r--CMakeLists.txt3
-rw-r--r--ChangeLog2
-rw-r--r--OpenAL32/Include/alAuxEffectSlot.h1
-rw-r--r--OpenAL32/Include/alEffect.h10
-rw-r--r--OpenAL32/Include/alMain.h4
-rw-r--r--OpenAL32/alAuxEffectSlot.c1
-rw-r--r--OpenAL32/alEffect.c7
-rw-r--r--OpenAL32/alSource.c115
-rw-r--r--alsoftrc.sample2
-rw-r--r--common/alcomplex.c31
-rw-r--r--common/alcomplex.h9
-rw-r--r--utils/alsoft-config/mainwindow.cpp4
-rw-r--r--utils/alsoft-config/mainwindow.ui42
-rw-r--r--utils/makehrtf.c92
25 files changed, 651 insertions, 155 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 597cc890..1858c29b 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),
@@ -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");
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 9d7fcdd5..dc24755d 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.
@@ -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);
}
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<<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)
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.
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;