diff options
-rw-r--r-- | Alc/effects/autowah.c | 568 |
1 files changed, 284 insertions, 284 deletions
diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index e0556cf3..298eb7f0 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -1,284 +1,284 @@ -/**
- * OpenAL cross platform audio library
- * Copyright (C) 2013 by Anis A. Hireche, Nasca Octavian Paul
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include <stdlib.h>
-
-#include "config.h"
-#include "alu.h"
-#include "alFilter.h"
-#include "alError.h"
-#include "alMain.h"
-#include "alAuxEffectSlot.h"
-
-
-/* You can tweak the octave of this dynamic filter just changing next macro
- * guitar - (default) 2.0f
- * bass - 4.0f
- */
-#define OCTAVE 2.0f
-
-
-typedef struct ALautowahStateFactory {
- DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALautowahStateFactory;
-
-static ALautowahStateFactory AutowahFactory;
-
-
-/* We use a lfo with a custom low-pass filter to generate autowah
- * effect and a high-pass filter to avoid distortion and aliasing.
- * By adding the two filters up, we obtain a dynamic bandpass filter.
- */
-
-typedef struct ALautowahState {
- DERIVE_FROM_TYPE(ALeffectState);
-
- /* Effect gains for each channel */
- ALfloat Gain[MaxChannels];
-
- /* Effect parameters */
- ALfloat AttackTime;
- ALfloat ReleaseTime;
- ALfloat Resonance;
- ALfloat PeakGain;
- ALuint Frequency;
-
- /* Samples processing */
- ALuint lfo;
- ALfilterState low_pass;
- ALfilterState high_pass;
-} ALautowahState;
-
-static ALvoid ALautowahState_Destruct(ALautowahState *state)
-{
- (void)state;
-}
-
-static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device)
-{
- return AL_TRUE;
- (void)state;
- (void)device;
-}
-
-static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *Device, const ALeffectslot *Slot)
-{
- const ALfloat cutoff = LOWPASSFREQREF / (Device->Frequency * 4.0f);
- const ALfloat bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
- ALfloat gain;
-
- /* computing high-pass filter coefficients */
- ALfilterState_setParams(&state->high_pass, ALfilterType_HighPass, 1.0f,
- cutoff, bandwidth);
-
- state->AttackTime = Slot->EffectProps.Autowah.AttackTime;
- state->ReleaseTime = Slot->EffectProps.Autowah.ReleaseTime;
- state->Frequency = Device->Frequency;
- state->PeakGain = Slot->EffectProps.Autowah.PeakGain;
- state->Resonance = Slot->EffectProps.Autowah.Resonance;
-
- state->lfo = 0;
-
- ALfilterState_clear(&state->low_pass);
-
- gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
- SetGains(Device, gain, state->Gain);
-}
-
-static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
-{
- ALuint it, kt;
- ALuint base;
-
- for(base = 0;base < SamplesToDo;)
- {
- ALfloat temps[64];
- ALuint td = minu(SamplesToDo-base, 64);
-
- for(it = 0;it < td;it++)
- {
- ALfloat smp = SamplesIn[it+base];
- ALfloat frequency, omega, alpha, peak;
-
- /* lfo for low-pass shaking */
- if((state->lfo++) % 30 == 0)
- {
- /* Using custom low-pass filter coefficients, to handle the resonance and peak-gain properties. */
- frequency = (1.0f + cosf(state->lfo * (1.0f / lerp(1.0f, 4.0f, state->AttackTime * state->ReleaseTime)) * 2.0f * F_PI / state->Frequency)) / OCTAVE;
- frequency = expf((frequency - 1.0f) * 6.0f);
-
- /* computing cutoff frequency and peak gain */
- omega = F_PI * frequency;
- alpha = sinf(omega) / (16.0f * (state->Resonance / AL_AUTOWAH_MAX_RESONANCE));
- peak = lerp(1.0f, 10.0f, state->PeakGain / AL_AUTOWAH_MAX_PEAK_GAIN);
-
- /* computing low-pass filter coefficients */
- state->low_pass.b[0] = (1.0f - cosf(omega)) / 2.0f;
- state->low_pass.b[1] = 1.0f - cosf(omega);
- state->low_pass.b[2] = (1.0f - cosf(omega)) / 2.0f;
- state->low_pass.a[0] = 1.0f + alpha / peak;
- state->low_pass.a[1] = -2.0f * cosf(omega);
- state->low_pass.a[2] = 1.0f - alpha / peak;
-
- state->low_pass.b[2] /= state->low_pass.a[0];
- state->low_pass.b[1] /= state->low_pass.a[0];
- state->low_pass.b[0] /= state->low_pass.a[0];
- state->low_pass.a[2] /= state->low_pass.a[0];
- state->low_pass.a[1] /= state->low_pass.a[0];
- state->low_pass.a[0] /= state->low_pass.a[0];
- }
-
- /* do high-pass filter */
- smp = ALfilterState_processSingle(&state->high_pass, smp);
-
- /* do low-pass filter */
- temps[it] = ALfilterState_processSingle(&state->low_pass, smp);
- }
-
- for(kt = 0;kt < MaxChannels;kt++)
- {
- ALfloat gain = state->Gain[kt];
- if(!(gain > 0.00001f))
- continue;
-
- for(it = 0;it < td;it++)
- SamplesOut[kt][base+it] += gain * temps[it];
- }
-
- base += td;
- }
-}
-
-static void ALautowahState_Delete(ALautowahState *state)
-{
- free(state);
-}
-
-DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState);
-
-
-static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *factory)
-{
- ALautowahState *state;
- (void)factory;
-
- state = malloc(sizeof(*state));
- if(!state) return NULL;
- SET_VTABLE2(ALautowahState, ALeffectState, state);
-
- ALfilterState_clear(&state->low_pass);
- ALfilterState_clear(&state->high_pass);
-
- return STATIC_CAST(ALeffectState, state);
-}
-
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALautowahStateFactory);
-
-ALeffectStateFactory *ALautowahStateFactory_getFactory(void)
-{
- SET_VTABLE2(ALautowahStateFactory, ALeffectStateFactory, &AutowahFactory);
- return STATIC_CAST(ALeffectStateFactory, &AutowahFactory);
-}
-
-
-void ALautowah_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val; }
-void ALautowah_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- ALautowah_setParami(effect, context, param, vals[0]);
-}
-
-void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- ALeffectProps *props = &effect->Props;
- switch(param)
- {
- case AL_AUTOWAH_ATTACK_TIME:
- if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- props->Autowah.AttackTime = val;
- break;
-
- case AL_AUTOWAH_RELEASE_TIME:
- if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- props->Autowah.ReleaseTime = val;
- break;
-
- case AL_AUTOWAH_RESONANCE:
- if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- props->Autowah.Resonance = val;
- break;
-
- case AL_AUTOWAH_PEAK_GAIN:
- if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- props->Autowah.PeakGain = val;
- break;
-
- default:
- SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
- }
-}
-
-void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- ALautowah_setParamf(effect, context, param, vals[0]);
-}
-
-void ALautowah_getParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val; }
-void ALautowah_getParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- ALautowah_getParami(effect, context, param, vals);
-}
-void ALautowah_getParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- const ALeffectProps *props = &effect->Props;
- switch(param)
- {
- case AL_AUTOWAH_ATTACK_TIME:
- *val = props->Autowah.AttackTime;
- break;
-
- case AL_AUTOWAH_RELEASE_TIME:
- *val = props->Autowah.ReleaseTime;
- break;
-
- case AL_AUTOWAH_RESONANCE:
- *val = props->Autowah.Resonance;
- break;
-
- case AL_AUTOWAH_PEAK_GAIN:
- *val = props->Autowah.PeakGain;
- break;
-
- default:
- SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
- }
-}
-
-void ALautowah_getParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- ALautowah_getParamf(effect, context, param, vals);
-}
-
-DEFINE_ALEFFECT_VTABLE(ALautowah);
+/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Anis A. Hireche, Nasca Octavian Paul + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include <stdlib.h> + +#include "config.h" +#include "alu.h" +#include "alFilter.h" +#include "alError.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" + + +/* You can tweak the octave of this dynamic filter just changing next macro + * guitar - (default) 2.0f + * bass - 4.0f + */ +#define OCTAVE 2.0f + + +typedef struct ALautowahStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALautowahStateFactory; + +static ALautowahStateFactory AutowahFactory; + + +/* We use a lfo with a custom low-pass filter to generate autowah + * effect and a high-pass filter to avoid distortion and aliasing. + * By adding the two filters up, we obtain a dynamic bandpass filter. + */ + +typedef struct ALautowahState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MaxChannels]; + + /* Effect parameters */ + ALfloat AttackTime; + ALfloat ReleaseTime; + ALfloat Resonance; + ALfloat PeakGain; + ALuint Frequency; + + /* Samples processing */ + ALuint lfo; + ALfilterState low_pass; + ALfilterState high_pass; +} ALautowahState; + +static ALvoid ALautowahState_Destruct(ALautowahState *state) +{ + (void)state; +} + +static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device) +{ + return AL_TRUE; + (void)state; + (void)device; +} + +static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + const ALfloat cutoff = LOWPASSFREQREF / (Device->Frequency * 4.0f); + const ALfloat bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); + ALfloat gain; + + /* computing high-pass filter coefficients */ + ALfilterState_setParams(&state->high_pass, ALfilterType_HighPass, 1.0f, + cutoff, bandwidth); + + state->AttackTime = Slot->EffectProps.Autowah.AttackTime; + state->ReleaseTime = Slot->EffectProps.Autowah.ReleaseTime; + state->Frequency = Device->Frequency; + state->PeakGain = Slot->EffectProps.Autowah.PeakGain; + state->Resonance = Slot->EffectProps.Autowah.Resonance; + + state->lfo = 0; + + ALfilterState_clear(&state->low_pass); + + gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; + SetGains(Device, gain, state->Gain); +} + +static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE]) +{ + ALuint it, kt; + ALuint base; + + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); + + for(it = 0;it < td;it++) + { + ALfloat smp = SamplesIn[it+base]; + ALfloat frequency, omega, alpha, peak; + + /* lfo for low-pass shaking */ + if((state->lfo++) % 30 == 0) + { + /* Using custom low-pass filter coefficients, to handle the resonance and peak-gain properties. */ + frequency = (1.0f + cosf(state->lfo * (1.0f / lerp(1.0f, 4.0f, state->AttackTime * state->ReleaseTime)) * 2.0f * F_PI / state->Frequency)) / OCTAVE; + frequency = expf((frequency - 1.0f) * 6.0f); + + /* computing cutoff frequency and peak gain */ + omega = F_PI * frequency; + alpha = sinf(omega) / (16.0f * (state->Resonance / AL_AUTOWAH_MAX_RESONANCE)); + peak = lerp(1.0f, 10.0f, state->PeakGain / AL_AUTOWAH_MAX_PEAK_GAIN); + + /* computing low-pass filter coefficients */ + state->low_pass.b[0] = (1.0f - cosf(omega)) / 2.0f; + state->low_pass.b[1] = 1.0f - cosf(omega); + state->low_pass.b[2] = (1.0f - cosf(omega)) / 2.0f; + state->low_pass.a[0] = 1.0f + alpha / peak; + state->low_pass.a[1] = -2.0f * cosf(omega); + state->low_pass.a[2] = 1.0f - alpha / peak; + + state->low_pass.b[2] /= state->low_pass.a[0]; + state->low_pass.b[1] /= state->low_pass.a[0]; + state->low_pass.b[0] /= state->low_pass.a[0]; + state->low_pass.a[2] /= state->low_pass.a[0]; + state->low_pass.a[1] /= state->low_pass.a[0]; + state->low_pass.a[0] /= state->low_pass.a[0]; + } + + /* do high-pass filter */ + smp = ALfilterState_processSingle(&state->high_pass, smp); + + /* do low-pass filter */ + temps[it] = ALfilterState_processSingle(&state->low_pass, smp); + } + + for(kt = 0;kt < MaxChannels;kt++) + { + ALfloat gain = state->Gain[kt]; + if(!(gain > 0.00001f)) + continue; + + for(it = 0;it < td;it++) + SamplesOut[kt][base+it] += gain * temps[it]; + } + + base += td; + } +} + +static void ALautowahState_Delete(ALautowahState *state) +{ + free(state); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); + + +static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *factory) +{ + ALautowahState *state; + (void)factory; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALautowahState, ALeffectState, state); + + ALfilterState_clear(&state->low_pass); + ALfilterState_clear(&state->high_pass); + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALautowahStateFactory); + +ALeffectStateFactory *ALautowahStateFactory_getFactory(void) +{ + SET_VTABLE2(ALautowahStateFactory, ALeffectStateFactory, &AutowahFactory); + return STATIC_CAST(ALeffectStateFactory, &AutowahFactory); +} + + +void ALautowah_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val; } +void ALautowah_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALautowah_setParami(effect, context, param, vals[0]); +} + +void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) + SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + props->Autowah.AttackTime = val; + break; + + case AL_AUTOWAH_RELEASE_TIME: + if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) + SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + props->Autowah.ReleaseTime = val; + break; + + case AL_AUTOWAH_RESONANCE: + if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) + SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + props->Autowah.Resonance = val; + break; + + case AL_AUTOWAH_PEAK_GAIN: + if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) + SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + props->Autowah.PeakGain = val; + break; + + default: + SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + } +} + +void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALautowah_setParamf(effect, context, param, vals[0]); +} + +void ALautowah_getParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val; } +void ALautowah_getParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALautowah_getParami(effect, context, param, vals); +} +void ALautowah_getParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + *val = props->Autowah.AttackTime; + break; + + case AL_AUTOWAH_RELEASE_TIME: + *val = props->Autowah.ReleaseTime; + break; + + case AL_AUTOWAH_RESONANCE: + *val = props->Autowah.Resonance; + break; + + case AL_AUTOWAH_PEAK_GAIN: + *val = props->Autowah.PeakGain; + break; + + default: + SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + } +} + +void ALautowah_getParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALautowah_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALautowah); |