diff options
author | Chris Robinson <[email protected]> | 2018-01-09 23:21:16 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2018-01-09 23:21:16 -0800 |
commit | de8c5b18248ee5d121cbd4b34b9af94f5e16df35 (patch) | |
tree | 76e4fb32c7ca5cb795c09dbe2d612377a32b8f2d /Alc/effects/flanger.c | |
parent | 9e2eb5dc231d835bf78a7225b6b0def74d0220ef (diff) |
Combine the chorus and flanger processing functions
Given that they're nearly identical, it should be relatively simple to use the
same effect state to process either of them, similar to the reverbs. The big
differences seem to be the delay range (much shorter with flanger) and the
defaults.
Diffstat (limited to 'Alc/effects/flanger.c')
-rw-r--r-- | Alc/effects/flanger.c | 420 |
1 files changed, 0 insertions, 420 deletions
diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c deleted file mode 100644 index b1fd2fda..00000000 --- a/Alc/effects/flanger.c +++ /dev/null @@ -1,420 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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 "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -enum FlangerWaveForm { - FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE, - FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID -}; - -typedef struct ALflangerState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBuffer; - ALsizei BufferLength; - ALsizei offset; - - ALsizei lfo_offset; - ALsizei lfo_range; - ALfloat lfo_scale; - ALint lfo_disp; - - /* Gains for left and right sides */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; - - /* effect parameters */ - enum FlangerWaveForm waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; -} ALflangerState; - -static ALvoid ALflangerState_Destruct(ALflangerState *state); -static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device); -static ALvoid ALflangerState_update(ALflangerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALflangerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); - - -static void ALflangerState_Construct(ALflangerState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALflangerState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - state->offset = 0; - state->lfo_offset = 0; - state->lfo_range = 1; - state->waveform = FWF_Triangle; -} - -static ALvoid ALflangerState_Destruct(ALflangerState *state) -{ - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; - - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device) -{ - ALsizei maxlen; - - maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 2.0f * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); - - if(maxlen != state->BufferLength) - { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->SampleBuffer); - state->SampleBuffer = temp; - - state->BufferLength = maxlen; - } - - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); - - return AL_TRUE; -} - -static ALvoid ALflangerState_update(ALflangerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALsizei mindelay = maxi(MAX_PRE_SAMPLES, MAX_POST_SAMPLES) << FRACTIONBITS; - const ALCdevice *device = context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat rate; - ALint phase; - - switch(props->Flanger.Waveform) - { - case AL_FLANGER_WAVEFORM_TRIANGLE: - state->waveform = FWF_Triangle; - break; - case AL_FLANGER_WAVEFORM_SINUSOID: - state->waveform = FWF_Sinusoid; - break; - } - - /* The LFO depth is scaled to be relative to the sample delay. Clamp the - * delay and depth to allow enough padding for resampling. - */ - state->delay = maxi(fastf2i(props->Flanger.Delay*frequency*FRACTIONONE + 0.5f), - mindelay); - state->depth = minf(props->Flanger.Depth * state->delay, state->delay - mindelay); - - state->feedback = props->Flanger.Feedback; - - /* Gains for left and right sides */ - CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); - CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); - - phase = props->Flanger.Phase; - rate = props->Flanger.Rate; - if(!(rate > 0.0f)) - { - state->lfo_offset = 0; - state->lfo_range = 1; - state->lfo_scale = 0.0f; - state->lfo_disp = 0; - } - else - { - /* Calculate LFO coefficient (number of samples per cycle). Limit the - * max range to avoid overflow when calculating the displacement. - */ - ALsizei lfo_range = mini(fastf2i(frequency/rate + 0.5f), INT_MAX/360 - 180); - - state->lfo_offset = fastf2i((ALfloat)state->lfo_offset/state->lfo_range* - lfo_range + 0.5f) % lfo_range; - state->lfo_range = lfo_range; - switch(state->waveform) - { - case FWF_Triangle: - state->lfo_scale = 4.0f / state->lfo_range; - break; - case FWF_Sinusoid: - state->lfo_scale = F_TAU / state->lfo_range; - break; - } - - /* Calculate lfo phase displacement */ - if(phase < 0) phase = 360 + phase; - state->lfo_disp = (state->lfo_range*phase + 180) / 360; - } -} - -static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALsizei bufmask = state->BufferLength-1; - const ALfloat feedback = state->feedback; - const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *restrict delaybuf = state->SampleBuffer; - ALsizei offset = state->offset; - ALsizei i, c; - ALsizei base; - - for(base = 0;base < SamplesToDo;) - { - const ALsizei todo = mini(256, SamplesToDo-base); - ALint moddelays[2][256]; - ALfloat temps[2][256]; - - if(state->waveform == FWF_Triangle) - { - GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - else /*if(state->waveform == FWF_Sinusoid)*/ - { - GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range; - - for(i = 0;i < todo;i++) - { - ALint delay; - ALfloat mu; - - // Feed the buffer's input first (necessary for delays < 1). - delaybuf[offset&bufmask] = SamplesIn[0][base+i]; - - // Tap for the left output. - delay = offset - (moddelays[0][i]>>FRACTIONBITS); - mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Tap for the right output. - delay = offset - (moddelays[1][i]>>FRACTIONBITS); - mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Accumulate feedback from the average delay. - delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; - offset++; - } - - for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, 0, base, todo); - - base += todo; - } - - state->offset = offset; -} - - -typedef struct ALflangerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALflangerStateFactory; - -ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory)) -{ - ALflangerState *state; - - NEW_OBJ0(state, ALflangerState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory); - -ALeffectStateFactory *ALflangerStateFactory_getFactory(void) -{ - static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } }; - - return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); -} - - -void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_WAVEFORM: - if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Waveform = val; - break; - - case AL_FLANGER_PHASE: - if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Phase = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALflanger_setParami(effect, context, param, vals[0]); -} -void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_RATE: - if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Rate = val; - break; - - case AL_FLANGER_DEPTH: - if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Depth = val; - break; - - case AL_FLANGER_FEEDBACK: - if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Feedback = val; - break; - - case AL_FLANGER_DELAY: - if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Flanger.Delay = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALflanger_setParamf(effect, context, param, vals[0]); -} - -void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_WAVEFORM: - *val = props->Flanger.Waveform; - break; - - case AL_FLANGER_PHASE: - *val = props->Flanger.Phase; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALflanger_getParami(effect, context, param, vals); -} -void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_RATE: - *val = props->Flanger.Rate; - break; - - case AL_FLANGER_DEPTH: - *val = props->Flanger.Depth; - break; - - case AL_FLANGER_FEEDBACK: - *val = props->Flanger.Feedback; - break; - - case AL_FLANGER_DELAY: - *val = props->Flanger.Delay; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALflanger_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALflanger); |