From 357cf72ab33ef1807da8ea6ce4633fd8e2a89553 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2013 21:33:16 -0700 Subject: Move remaining effects to the effects subdir --- Alc/alcChorus.c | 411 -------------------------------------- Alc/alcDedicated.c | 183 ----------------- Alc/alcDistortion.c | 402 -------------------------------------- Alc/alcEcho.c | 324 ------------------------------ Alc/alcEqualizer.c | 499 ----------------------------------------------- Alc/alcFlanger.c | 411 -------------------------------------- Alc/alcModulator.c | 343 -------------------------------- Alc/effects/chorus.c | 411 ++++++++++++++++++++++++++++++++++++++ Alc/effects/dedicated.c | 183 +++++++++++++++++ Alc/effects/distortion.c | 402 ++++++++++++++++++++++++++++++++++++++ Alc/effects/echo.c | 324 ++++++++++++++++++++++++++++++ Alc/effects/equalizer.c | 499 +++++++++++++++++++++++++++++++++++++++++++++++ Alc/effects/flanger.c | 411 ++++++++++++++++++++++++++++++++++++++ Alc/effects/modulator.c | 343 ++++++++++++++++++++++++++++++++ 14 files changed, 2573 insertions(+), 2573 deletions(-) delete mode 100644 Alc/alcChorus.c delete mode 100644 Alc/alcDedicated.c delete mode 100644 Alc/alcDistortion.c delete mode 100644 Alc/alcEcho.c delete mode 100644 Alc/alcEqualizer.c delete mode 100644 Alc/alcFlanger.c delete mode 100644 Alc/alcModulator.c create mode 100644 Alc/effects/chorus.c create mode 100644 Alc/effects/dedicated.c create mode 100644 Alc/effects/distortion.c create mode 100644 Alc/effects/echo.c create mode 100644 Alc/effects/equalizer.c create mode 100644 Alc/effects/flanger.c create mode 100644 Alc/effects/modulator.c (limited to 'Alc') diff --git a/Alc/alcChorus.c b/Alc/alcChorus.c deleted file mode 100644 index e5a20b5d..00000000 --- a/Alc/alcChorus.c +++ /dev/null @@ -1,411 +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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALchorusStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALchorusStateFactory; - -static ALchorusStateFactory ChorusFactory; - - -typedef struct ALchorusState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBufferLeft; - ALfloat *SampleBufferRight; - ALuint BufferLength; - ALint offset; - ALfloat lfo_coeff; - ALint lfo_disp; - - /* Gains for left and right sides */ - ALfloat Gain[2][MaxChannels]; - - /* effect parameters */ - ALint waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; -} ALchorusState; - -static ALvoid ALchorusState_Destruct(ALchorusState *state) -{ - free(state->SampleBufferLeft); - state->SampleBufferLeft = NULL; - - free(state->SampleBufferRight); - state->SampleBufferRight = NULL; -} - -static ALboolean ALchorusState_DeviceUpdate(ALchorusState *state, ALCdevice *Device) -{ - ALuint maxlen; - ALuint it; - - maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); - - if(maxlen != state->BufferLength) - { - void *temp; - - temp = realloc(state->SampleBufferLeft, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - state->SampleBufferLeft = temp; - - temp = realloc(state->SampleBufferRight, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - state->SampleBufferRight = temp; - - state->BufferLength = maxlen; - } - - for(it = 0;it < state->BufferLength;it++) - { - state->SampleBufferLeft[it] = 0.0f; - state->SampleBufferRight[it] = 0.0f; - } - - return AL_TRUE; -} - -static ALvoid ALchorusState_Update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALfloat frequency = (ALfloat)Device->Frequency; - ALfloat rate; - ALint phase; - ALuint it; - - for (it = 0; it < MaxChannels; it++) - { - state->Gain[0][it] = 0.0f; - state->Gain[1][it] = 0.0f; - } - - state->waveform = Slot->effect.Chorus.Waveform; - state->depth = Slot->effect.Chorus.Depth; - state->feedback = Slot->effect.Chorus.Feedback; - state->delay = fastf2i(Slot->effect.Chorus.Delay * frequency); - - /* Gains for left and right sides */ - ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); - ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); - - phase = Slot->effect.Chorus.Phase; - rate = Slot->effect.Chorus.Rate; - - /* Calculate LFO coefficient */ - switch (state->waveform) - { - case AL_CHORUS_WAVEFORM_TRIANGLE: - if(rate == 0.0f) - state->lfo_coeff = 0.0f; - else - state->lfo_coeff = 1.0f / (frequency / rate); - break; - case AL_CHORUS_WAVEFORM_SINUSOID: - if(rate == 0.0f) - state->lfo_coeff = 0.0f; - else - state->lfo_coeff = F_PI*2.0f / (frequency / rate); - break; - } - - /* Calculate lfo phase displacement */ - if(phase == 0 || rate == 0.0f) - state->lfo_disp = 0; - else - state->lfo_disp = fastf2i(frequency / rate / (360.0f/phase)); -} - -static __inline void Triangle(ALint *delay_left, ALint *delay_right, ALint offset, const ALchorusState *state) -{ - ALfloat lfo_value; - - lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff*offset*4.0f, 4.0f)); - lfo_value *= state->depth * state->delay; - *delay_left = fastf2i(lfo_value) + state->delay; - - lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * - (offset+state->lfo_disp)*4.0f, - 4.0f)); - lfo_value *= state->depth * state->delay; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -static __inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALint offset, const ALchorusState *state) -{ - ALfloat lfo_value; - - lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff*offset, 2.0f*F_PI)); - lfo_value *= state->depth * state->delay; - *delay_left = fastf2i(lfo_value) + state->delay; - - lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff*(offset+state->lfo_disp), - 2.0f*F_PI)); - lfo_value *= state->depth * state->delay; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -#define DECL_TEMPLATE(func) \ -static void Process##func(ALchorusState *state, ALuint SamplesToDo, \ - const ALfloat *restrict SamplesIn, \ - ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ -{ \ - const ALint mask = state->BufferLength-1; \ - ALint offset = state->offset; \ - ALuint it, kt; \ - ALuint base; \ - \ - for(base = 0;base < SamplesToDo;) \ - { \ - ALfloat temps[64][2]; \ - ALuint td = minu(SamplesToDo-base, 64); \ - \ - for(it = 0;it < td;it++,offset++) \ - { \ - ALint delay_left, delay_right; \ - (func)(&delay_left, &delay_right, offset, state); \ - \ - temps[it][0] = state->SampleBufferLeft[(offset-delay_left)&mask]; \ - state->SampleBufferLeft[offset&mask] = (temps[it][0] + \ - SamplesIn[it+base]) * \ - state->feedback; \ - \ - temps[it][1] = state->SampleBufferRight[(offset-delay_right)&mask];\ - state->SampleBufferRight[offset&mask] = (temps[it][1] + \ - SamplesIn[it+base]) * \ - state->feedback; \ - } \ - \ - for(kt = 0;kt < MaxChannels;kt++) \ - { \ - ALfloat gain = state->Gain[0][kt]; \ - if(gain > 0.00001f) \ - { \ - for(it = 0;it < td;it++) \ - SamplesOut[kt][it+base] += temps[it][0] * gain; \ - } \ - \ - gain = state->Gain[1][kt]; \ - if(gain > 0.00001f) \ - { \ - for(it = 0;it < td;it++) \ - SamplesOut[kt][it+base] += temps[it][1] * gain; \ - } \ - } \ - \ - base += td; \ - } \ - \ - state->offset = offset; \ -} - -DECL_TEMPLATE(Triangle) -DECL_TEMPLATE(Sinusoid) - -#undef DECL_TEMPLATE - -static ALvoid ALchorusState_Process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - if(state->waveform == AL_CHORUS_WAVEFORM_TRIANGLE) - ProcessTriangle(state, SamplesToDo, SamplesIn, SamplesOut); - else if(state->waveform == AL_CHORUS_WAVEFORM_SINUSOID) - ProcessSinusoid(state, SamplesToDo, SamplesIn, SamplesOut); -} - -static ALeffectStateFactory *ALchorusState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &ChorusFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); - - -static ALeffectState *ALchorusStateFactory_create(void) -{ - ALchorusState *state; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALchorusState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBufferLeft = NULL; - state->SampleBufferRight = NULL; - state->offset = 0; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALchorusStateFactory_destroy(ALeffectState *effect) -{ - ALchorusState *state = STATIC_UPCAST(ALchorusState, ALeffectState, effect); - ALchorusState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory); - - -static void init_chorus_factory(void) -{ - SET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory, &ChorusFactory); -} - -ALeffectStateFactory *ALchorusStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_chorus_factory); - return STATIC_CAST(ALeffectStateFactory, &ChorusFactory); -} - - -void chorus_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_CHORUS_WAVEFORM: - if(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM) - effect->Chorus.Waveform = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_CHORUS_PHASE: - if(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE) - effect->Chorus.Phase = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void chorus_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - chorus_SetParami(effect, context, param, vals[0]); -} -void chorus_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_CHORUS_RATE: - if(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE) - effect->Chorus.Rate = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_CHORUS_DEPTH: - if(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH) - effect->Chorus.Depth = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_CHORUS_FEEDBACK: - if(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK) - effect->Chorus.Feedback = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_CHORUS_DELAY: - if(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY) - effect->Chorus.Delay = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void chorus_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - chorus_SetParamf(effect, context, param, vals[0]); -} - -void chorus_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_CHORUS_WAVEFORM: - *val = effect->Chorus.Waveform; - break; - - case AL_CHORUS_PHASE: - *val = effect->Chorus.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void chorus_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - chorus_GetParami(effect, context, param, vals); -} -void chorus_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_CHORUS_RATE: - *val = effect->Chorus.Rate; - break; - - case AL_CHORUS_DEPTH: - *val = effect->Chorus.Depth; - break; - - case AL_CHORUS_FEEDBACK: - *val = effect->Chorus.Feedback; - break; - - case AL_CHORUS_DELAY: - *val = effect->Chorus.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void chorus_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - chorus_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcDedicated.c b/Alc/alcDedicated.c deleted file mode 100644 index bd266b0e..00000000 --- a/Alc/alcDedicated.c +++ /dev/null @@ -1,183 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson. - * 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 "config.h" - -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALdedicatedStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALdedicatedStateFactory; - -static ALdedicatedStateFactory DedicatedFactory; - - -typedef struct ALdedicatedState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat gains[MaxChannels]; -} ALdedicatedState; - - -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) -{ - (void)state; -} - -static ALboolean ALdedicatedState_DeviceUpdate(ALdedicatedState *state, ALCdevice *Device) -{ - return AL_TRUE; - (void)state; - (void)Device; -} - -static ALvoid ALdedicatedState_Update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot) -{ - ALfloat Gain; - ALsizei s; - - Gain = Slot->Gain * Slot->effect.Dedicated.Gain; - for(s = 0;s < MaxChannels;s++) - state->gains[s] = 0.0f; - - if(Slot->effect.type == AL_EFFECT_DEDICATED_DIALOGUE) - ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains); - else if(Slot->effect.type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) - state->gains[LFE] = Gain; -} - -static ALvoid ALdedicatedState_Process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - const ALfloat *gains = state->gains; - ALuint i, c; - - for(c = 0;c < MaxChannels;c++) - { - if(!(gains[c] > 0.00001f)) - continue; - - for(i = 0;i < SamplesToDo;i++) - SamplesOut[c][i] = SamplesIn[i] * gains[c]; - } -} - -static ALeffectStateFactory *ALdedicatedState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); - - -ALeffectState *ALdedicatedStateFactory_create(void) -{ - ALdedicatedState *state; - ALsizei s; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALdedicatedState, ALeffectState, state); - - for(s = 0;s < MaxChannels;s++) - state->gains[s] = 0.0f; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALdedicatedStateFactory_destroy(ALeffectState *effect) -{ - ALdedicatedState *state = STATIC_UPCAST(ALdedicatedState, ALeffectState, effect); - ALdedicatedState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory); - - -static void init_dedicated_factory(void) -{ - SET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory, &DedicatedFactory); -} - -ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_dedicated_factory); - return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory); -} - - -void ded_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } -void ded_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ded_SetParami(effect, context, param, vals[0]); -} -void ded_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_DEDICATED_GAIN: - if(val >= 0.0f && isfinite(val)) - effect->Dedicated.Gain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void ded_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ded_SetParamf(effect, context, param, vals[0]); -} - -void ded_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } -void ded_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ded_GetParami(effect, context, param, vals); -} -void ded_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_DEDICATED_GAIN: - *val = effect->Dedicated.Gain; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void ded_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ded_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcDistortion.c b/Alc/alcDistortion.c deleted file mode 100644 index 7828377c..00000000 --- a/Alc/alcDistortion.c +++ /dev/null @@ -1,402 +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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALdistortionStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALdistortionStateFactory; - -static ALdistortionStateFactory DistortionFactory; - - -/* Filters implementation is based on the "Cookbook formulae for audio * - * EQ biquad filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ - -typedef enum ALEQFilterType { - LOWPASS, - BANDPASS, -} ALEQFilterType; - -typedef struct ALEQFilter { - ALEQFilterType type; - ALfloat x[2]; /* History of two last input samples */ - ALfloat y[2]; /* History of two last output samples */ - ALfloat a[3]; /* Transfer function coefficients "a" */ - ALfloat b[3]; /* Transfer function coefficients "b" */ -} ALEQFilter; - -typedef struct ALdistortionState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; - - /* Effect parameters */ - ALEQFilter bandpass; - ALEQFilter lowpass; - ALfloat attenuation; - ALfloat edge_coeff; -} ALdistortionState; - -static ALvoid ALdistortionState_Destruct(ALdistortionState *state) -{ - (void)state; -} - -static ALboolean ALdistortionState_DeviceUpdate(ALdistortionState *state, ALCdevice *device) -{ - return AL_TRUE; - (void)state; - (void)device; -} - -static ALvoid ALdistortionState_Update(ALdistortionState *state, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALfloat gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; - ALfloat frequency = (ALfloat)Device->Frequency; - ALuint it; - ALfloat w0; - ALfloat alpha; - ALfloat bandwidth; - ALfloat cutoff; - ALfloat edge; - - for(it = 0;it < MaxChannels;it++) - state->Gain[it] = 0.0f; - for(it = 0;it < Device->NumChan;it++) - { - enum Channel chan = Device->Speaker2Chan[it]; - state->Gain[chan] = gain; - } - - /* Store distorted signal attenuation settings */ - state->attenuation = Slot->effect.Distortion.Gain; - - /* Store waveshaper edge settings */ - edge = sinf(Slot->effect.Distortion.Edge * (F_PI/2.0f)); - state->edge_coeff = 2.0f * edge / (1.0f-edge); - - /* Lowpass filter */ - cutoff = Slot->effect.Distortion.LowpassCutoff; - /* Bandwidth value is constant in octaves */ - bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); - w0 = 2.0f*F_PI * cutoff / (frequency*4.0f); - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); - state->lowpass.b[0] = (1.0f - cosf(w0)) / 2.0f; - state->lowpass.b[1] = 1.0f - cosf(w0); - state->lowpass.b[2] = (1.0f - cosf(w0)) / 2.0f; - state->lowpass.a[0] = 1.0f + alpha; - state->lowpass.a[1] = -2.0f * cosf(w0); - state->lowpass.a[2] = 1.0f - alpha; - - /* Bandpass filter */ - cutoff = Slot->effect.Distortion.EQCenter; - /* Convert bandwidth in Hz to octaves */ - bandwidth = Slot->effect.Distortion.EQBandwidth / (cutoff * 0.67f); - w0 = 2.0f*F_PI * cutoff / (frequency*4.0f); - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); - state->bandpass.b[0] = alpha; - state->bandpass.b[1] = 0; - state->bandpass.b[2] = -alpha; - state->bandpass.a[0] = 1.0f + alpha; - state->bandpass.a[1] = -2.0f * cosf(w0); - state->bandpass.a[2] = 1.0f - alpha; -} - -static ALvoid ALdistortionState_Process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - const ALfloat fc = state->edge_coeff; - float oversample_buffer[64][4]; - ALfloat tempsmp; - ALuint base; - ALuint it; - ALuint ot; - ALuint kt; - - for(base = 0;base < SamplesToDo;) - { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); - - /* Perform 4x oversampling to avoid aliasing. */ - /* Oversampling greatly improves distortion */ - /* quality and allows to implement lowpass and */ - /* bandpass filters using high frequencies, at */ - /* which classic IIR filters became unstable. */ - - /* Fill oversample buffer using zero stuffing */ - for(it = 0;it < td;it++) - { - oversample_buffer[it][0] = SamplesIn[it+base]; - oversample_buffer[it][1] = 0.0f; - oversample_buffer[it][2] = 0.0f; - oversample_buffer[it][3] = 0.0f; - } - - /* First step, do lowpass filtering of original signal, */ - /* additionally perform buffer interpolation and lowpass */ - /* cutoff for oversampling (which is fortunately first */ - /* step of distortion). So combine three operations into */ - /* the one. */ - for(it = 0;it < td;it++) - { - for(ot = 0;ot < 4;ot++) - { - tempsmp = state->lowpass.b[0] / state->lowpass.a[0] * oversample_buffer[it][ot] + - state->lowpass.b[1] / state->lowpass.a[0] * state->lowpass.x[0] + - state->lowpass.b[2] / state->lowpass.a[0] * state->lowpass.x[1] - - state->lowpass.a[1] / state->lowpass.a[0] * state->lowpass.y[0] - - state->lowpass.a[2] / state->lowpass.a[0] * state->lowpass.y[1]; - - state->lowpass.x[1] = state->lowpass.x[0]; - state->lowpass.x[0] = oversample_buffer[it][ot]; - state->lowpass.y[1] = state->lowpass.y[0]; - state->lowpass.y[0] = tempsmp; - /* Restore signal power by multiplying sample by amount of oversampling */ - oversample_buffer[it][ot] = tempsmp * 4.0f; - } - } - - for(it = 0;it < td;it++) - { - /* Second step, do distortion using waveshaper function */ - /* to emulate signal processing during tube overdriving. */ - /* Three steps of waveshaping are intended to modify */ - /* waveform without boost/clipping/attenuation process. */ - for(ot = 0;ot < 4;ot++) - { - ALfloat smp = oversample_buffer[it][ot]; - - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - - /* Third step, do bandpass filtering of distorted signal */ - tempsmp = state->bandpass.b[0] / state->bandpass.a[0] * smp + - state->bandpass.b[1] / state->bandpass.a[0] * state->bandpass.x[0] + - state->bandpass.b[2] / state->bandpass.a[0] * state->bandpass.x[1] - - state->bandpass.a[1] / state->bandpass.a[0] * state->bandpass.y[0] - - state->bandpass.a[2] / state->bandpass.a[0] * state->bandpass.y[1]; - - state->bandpass.x[1] = state->bandpass.x[0]; - state->bandpass.x[0] = smp; - state->bandpass.y[1] = state->bandpass.y[0]; - state->bandpass.y[0] = tempsmp; - - oversample_buffer[it][ot] = tempsmp; - } - - /* Fourth step, final, do attenuation and perform decimation, */ - /* store only one sample out of 4. */ - temps[it] = oversample_buffer[it][0] * state->attenuation; - } - - 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 ALeffectStateFactory *ALdistortionState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &DistortionFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); - - -static ALeffectState *ALdistortionStateFactory_create(void) -{ - ALdistortionState *state; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALdistortionState, ALeffectState, state); - - state->bandpass.type = BANDPASS; - state->lowpass.type = LOWPASS; - - /* Initialize sample history only on filter creation to avoid */ - /* sound clicks if filter settings were changed in runtime. */ - state->bandpass.x[0] = 0.0f; - state->bandpass.x[1] = 0.0f; - state->lowpass.y[0] = 0.0f; - state->lowpass.y[1] = 0.0f; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALdistortionStateFactory_destroy(ALeffectState *effect) -{ - ALdistortionState *state = STATIC_UPCAST(ALdistortionState, ALeffectState, effect); - ALdistortionState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory); - - -static void init_distortion_factory(void) -{ - SET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory, &DistortionFactory); -} - -ALeffectStateFactory *ALdistortionStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_distortion_factory); - return STATIC_CAST(ALeffectStateFactory, &DistortionFactory); -} - - -void distortion_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - effect=effect; - val=val; - - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void distortion_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - distortion_SetParami(effect, context, param, vals[0]); -} -void distortion_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_DISTORTION_EDGE: - if(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE) - effect->Distortion.Edge = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_DISTORTION_GAIN: - if(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN) - effect->Distortion.Gain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - if(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF) - effect->Distortion.LowpassCutoff = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_DISTORTION_EQCENTER: - if(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER) - effect->Distortion.EQCenter = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_DISTORTION_EQBANDWIDTH: - if(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH) - effect->Distortion.EQBandwidth = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void distortion_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - distortion_SetParamf(effect, context, param, vals[0]); -} - -void distortion_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - effect=effect; - val=val; - - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void distortion_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - distortion_GetParami(effect, context, param, vals); -} -void distortion_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_DISTORTION_EDGE: - *val = effect->Distortion.Edge; - break; - - case AL_DISTORTION_GAIN: - *val = effect->Distortion.Gain; - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - *val = effect->Distortion.LowpassCutoff; - break; - - case AL_DISTORTION_EQCENTER: - *val = effect->Distortion.EQCenter; - break; - - case AL_DISTORTION_EQBANDWIDTH: - *val = effect->Distortion.EQBandwidth; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void distortion_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - distortion_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c deleted file mode 100644 index d5915295..00000000 --- a/Alc/alcEcho.c +++ /dev/null @@ -1,324 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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 "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALechoStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALechoStateFactory; - -static ALechoStateFactory EchoFactory; - - -typedef struct ALechoState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBuffer; - ALuint BufferLength; - - // The echo is two tap. The delay is the number of samples from before the - // current offset - struct { - ALuint delay; - } Tap[2]; - ALuint Offset; - /* The panning gains for the two taps */ - ALfloat Gain[2][MaxChannels]; - - ALfloat FeedGain; - - FILTER iirFilter; -} ALechoState; - -static ALvoid ALechoState_Destruct(ALechoState *state) -{ - free(state->SampleBuffer); - state->SampleBuffer = NULL; -} - -static ALboolean ALechoState_DeviceUpdate(ALechoState *state, ALCdevice *Device) -{ - ALuint maxlen, i; - - // Use the next power of 2 for the buffer length, so the tap offsets can be - // wrapped using a mask instead of a modulo - maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; - maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); - - if(maxlen != state->BufferLength) - { - void *temp; - - temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); - if(!temp) - return AL_FALSE; - state->SampleBuffer = temp; - state->BufferLength = maxlen; - } - for(i = 0;i < state->BufferLength;i++) - state->SampleBuffer[i] = 0.0f; - - return AL_TRUE; -} - -static ALvoid ALechoState_Update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALuint frequency = Device->Frequency; - ALfloat lrpan, cw, g, gain; - ALfloat dirGain; - ALuint i; - - state->Tap[0].delay = fastf2u(Slot->effect.Echo.Delay * frequency) + 1; - state->Tap[1].delay = fastf2u(Slot->effect.Echo.LRDelay * frequency); - state->Tap[1].delay += state->Tap[0].delay; - - lrpan = Slot->effect.Echo.Spread; - - state->FeedGain = Slot->effect.Echo.Feedback; - - cw = cosf(F_PI*2.0f * LOWPASSFREQREF / frequency); - g = 1.0f - Slot->effect.Echo.Damping; - state->iirFilter.coeff = lpCoeffCalc(g, cw); - - gain = Slot->Gain; - for(i = 0;i < MaxChannels;i++) - { - state->Gain[0][i] = 0.0f; - state->Gain[1][i] = 0.0f; - } - - dirGain = fabsf(lrpan); - - /* First tap panning */ - ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]); - - /* Second tap panning */ - ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]); -} - -static ALvoid ALechoState_Process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - const ALuint mask = state->BufferLength-1; - const ALuint tap1 = state->Tap[0].delay; - const ALuint tap2 = state->Tap[1].delay; - ALuint offset = state->Offset; - ALfloat smp; - ALuint base; - ALuint i, k; - - for(base = 0;base < SamplesToDo;) - { - ALfloat temps[64][2]; - ALuint td = minu(SamplesToDo-base, 64); - - for(i = 0;i < td;i++) - { - /* First tap */ - temps[i][0] = state->SampleBuffer[(offset-tap1) & mask]; - /* Second tap */ - temps[i][1] = state->SampleBuffer[(offset-tap2) & mask]; - - // Apply damping and feedback gain to the second tap, and mix in the - // new sample - smp = lpFilter2P(&state->iirFilter, temps[i][1]+SamplesIn[i]); - state->SampleBuffer[offset&mask] = smp * state->FeedGain; - } - - for(k = 0;k < MaxChannels;k++) - { - ALfloat gain = state->Gain[0][k]; - if(gain > 0.00001f) - { - for(i = 0;i < td;i++) - SamplesOut[k][i+base] += temps[i][0] * gain; - } - - gain = state->Gain[1][k]; - if(gain > 0.00001f) - { - for(i = 0;i < td;i++) - SamplesOut[k][i+base] += temps[i][1] * gain; - } - } - - base += td; - } - - state->Offset = offset; -} - -static ALeffectStateFactory *ALechoState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &EchoFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); - - -ALeffectState *ALechoStateFactory_create(void) -{ - ALechoState *state; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALechoState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - - state->Tap[0].delay = 0; - state->Tap[1].delay = 0; - state->Offset = 0; - - state->iirFilter.coeff = 0.0f; - state->iirFilter.history[0] = 0.0f; - state->iirFilter.history[1] = 0.0f; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALechoStateFactory_destroy(ALeffectState *effect) -{ - ALechoState *state = STATIC_UPCAST(ALechoState, ALeffectState, effect); - ALechoState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory); - - -static void init_echo_factory(void) -{ - SET_VTABLE2(ALechoStateFactory, ALeffectStateFactory, &EchoFactory); -} - -ALeffectStateFactory *ALechoStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_echo_factory); - return STATIC_CAST(ALeffectStateFactory, &EchoFactory); -} - - -void echo_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } -void echo_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - echo_SetParami(effect, context, param, vals[0]); -} -void echo_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_ECHO_DELAY: - if(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY) - effect->Echo.Delay = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_ECHO_LRDELAY: - if(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY) - effect->Echo.LRDelay = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_ECHO_DAMPING: - if(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING) - effect->Echo.Damping = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_ECHO_FEEDBACK: - if(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK) - effect->Echo.Feedback = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_ECHO_SPREAD: - if(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD) - effect->Echo.Spread = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void echo_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - echo_SetParamf(effect, context, param, vals[0]); -} - -void echo_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } -void echo_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - echo_GetParami(effect, context, param, vals); -} -void echo_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_ECHO_DELAY: - *val = effect->Echo.Delay; - break; - - case AL_ECHO_LRDELAY: - *val = effect->Echo.LRDelay; - break; - - case AL_ECHO_DAMPING: - *val = effect->Echo.Damping; - break; - - case AL_ECHO_FEEDBACK: - *val = effect->Echo.Feedback; - break; - - case AL_ECHO_SPREAD: - *val = effect->Echo.Spread; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void echo_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - echo_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcEqualizer.c b/Alc/alcEqualizer.c deleted file mode 100644 index d397a9ba..00000000 --- a/Alc/alcEqualizer.c +++ /dev/null @@ -1,499 +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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALequalizerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALequalizerStateFactory; - -static ALequalizerStateFactory EqualizerFactory; - - -/* The document "Effects Extension Guide.pdf" says that low and high * - * frequencies are cutoff frequencies. This is not fully correct, they * - * are corner frequencies for low and high shelf filters. If they were * - * just cutoff frequencies, there would be no need in cutoff frequency * - * gains, which are present. Documentation for "Creative Proteus X2" * - * software describes 4-band equalizer functionality in a much better * - * way. This equalizer seems to be a predecessor of OpenAL 4-band * - * equalizer. With low and high shelf filters we are able to cutoff * - * frequencies below and/or above corner frequencies using attenuation * - * gains (below 1.0) and amplify all low and/or high frequencies using * - * gains above 1.0. * - * * - * Low-shelf Low Mid Band High Mid Band High-shelf * - * corner center center corner * - * frequency frequency frequency frequency * - * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * - * * - * | | | | * - * | | | | * - * B -----+ /--+--\ /--+--\ +----- * - * O |\ | | | | | | /| * - * O | \ - | - - | - / | * - * S + | \ | | | | | | / | * - * T | | | | | | | | | | * - * ---------+---------------+------------------+---------------+-------- * - * C | | | | | | | | | | * - * U - | / | | | | | | \ | * - * T | / - | - - | - \ | * - * O |/ | | | | | | \| * - * F -----+ \--+--/ \--+--/ +----- * - * F | | | | * - * | | | | * - * * - * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * - * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * - * octaves for two mid bands. * - * * - * Implementation is based on the "Cookbook formulae for audio EQ biquad * - * filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ - -typedef enum ALEQFilterType { - LOW_SHELF, - HIGH_SHELF, - PEAKING -} ALEQFilterType; - -typedef struct ALEQFilter { - ALEQFilterType type; - ALfloat x[2]; /* History of two last input samples */ - ALfloat y[2]; /* History of two last output samples */ - ALfloat a[3]; /* Transfer function coefficients "a" */ - ALfloat b[3]; /* Transfer function coefficients "b" */ -} ALEQFilter; - -typedef struct ALequalizerState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; - - /* Effect parameters */ - ALEQFilter bandfilter[4]; -} ALequalizerState; - -static ALvoid ALequalizerState_Destruct(ALequalizerState *state) -{ - (void)state; -} - -static ALboolean ALequalizerState_DeviceUpdate(ALequalizerState *state, ALCdevice *device) -{ - return AL_TRUE; - (void)state; - (void)device; -} - -static ALvoid ALequalizerState_Update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot) -{ - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain; - ALuint it; - - for(it = 0;it < MaxChannels;it++) - state->Gain[it] = 0.0f; - for(it = 0; it < device->NumChan; it++) - { - enum Channel chan = device->Speaker2Chan[it]; - state->Gain[chan] = gain; - } - - /* Calculate coefficients for the each type of filter */ - for(it = 0; it < 4; it++) - { - ALfloat gain; - ALfloat filter_frequency; - ALfloat bandwidth = 0.0f; - ALfloat w0; - ALfloat alpha = 0.0f; - - /* convert linear gains to filter gains */ - switch (it) - { - case 0: /* Low Shelf */ - gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.LowGain)) / 40.0f); - filter_frequency = slot->effect.Equalizer.LowCutoff; - break; - case 1: /* Peaking */ - gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.Mid1Gain)) / 40.0f); - filter_frequency = slot->effect.Equalizer.Mid1Center; - bandwidth = slot->effect.Equalizer.Mid1Width; - break; - case 2: /* Peaking */ - gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.Mid2Gain)) / 40.0f); - filter_frequency = slot->effect.Equalizer.Mid2Center; - bandwidth = slot->effect.Equalizer.Mid2Width; - break; - case 3: /* High Shelf */ - gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.HighGain)) / 40.0f); - filter_frequency = slot->effect.Equalizer.HighCutoff; - break; - } - - w0 = 2.0f*F_PI * filter_frequency / frequency; - - /* Calculate filter coefficients depending on filter type */ - switch(state->bandfilter[it].type) - { - case LOW_SHELF: - alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * - (1.0f / 0.75f - 1.0f) + 2.0f); - state->bandfilter[it].b[0] = gain * ((gain + 1.0f) - - (gain - 1.0f) * cosf(w0) + - 2.0f * sqrtf(gain) * alpha); - state->bandfilter[it].b[1] = 2.0f * gain * ((gain - 1.0f) - - (gain + 1.0f) * cosf(w0)); - state->bandfilter[it].b[2] = gain * ((gain + 1.0f) - - (gain - 1.0f) * cosf(w0) - - 2.0f * sqrtf(gain) * alpha); - state->bandfilter[it].a[0] = (gain + 1.0f) + - (gain - 1.0f) * cosf(w0) + - 2.0f * sqrtf(gain) * alpha; - state->bandfilter[it].a[1] = -2.0f * ((gain - 1.0f) + - (gain + 1.0f) * cosf(w0)); - state->bandfilter[it].a[2] = (gain + 1.0f) + - (gain - 1.0f) * cosf(w0) - - 2.0f * sqrtf(gain) * alpha; - break; - case HIGH_SHELF: - alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * - (1.0f / 0.75f - 1.0f) + 2.0f); - state->bandfilter[it].b[0] = gain * ((gain + 1.0f) + - (gain - 1.0f) * cosf(w0) + - 2.0f * sqrtf(gain) * alpha); - state->bandfilter[it].b[1] = -2.0f * gain * ((gain - 1.0f) + - (gain + 1.0f) * - cosf(w0)); - state->bandfilter[it].b[2] = gain * ((gain + 1.0f) + - (gain - 1.0f) * cosf(w0) - - 2.0f * sqrtf(gain) * alpha); - state->bandfilter[it].a[0] = (gain + 1.0f) - - (gain - 1.0f) * cosf(w0) + - 2.0f * sqrtf(gain) * alpha; - state->bandfilter[it].a[1] = 2.0f * ((gain - 1.0f) - - (gain + 1.0f) * cosf(w0)); - state->bandfilter[it].a[2] = (gain + 1.0f) - - (gain - 1.0f) * cosf(w0) - - 2.0f * sqrtf(gain) * alpha; - break; - case PEAKING: - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); - state->bandfilter[it].b[0] = 1.0f + alpha * gain; - state->bandfilter[it].b[1] = -2.0f * cosf(w0); - state->bandfilter[it].b[2] = 1.0f - alpha * gain; - state->bandfilter[it].a[0] = 1.0f + alpha / gain; - state->bandfilter[it].a[1] = -2.0f * cosf(w0); - state->bandfilter[it].a[2] = 1.0f - alpha / gain; - break; - } - } -} - -static ALvoid ALequalizerState_Process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - ALuint base; - ALuint it; - ALuint kt; - ALuint ft; - - for(base = 0;base < SamplesToDo;) - { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); - - for(it = 0;it < td;it++) - { - ALfloat smp = SamplesIn[base+it]; - ALfloat tempsmp; - - for(ft = 0;ft < 4;ft++) - { - ALEQFilter *filter = &state->bandfilter[ft]; - - tempsmp = filter->b[0] / filter->a[0] * smp + - filter->b[1] / filter->a[0] * filter->x[0] + - filter->b[2] / filter->a[0] * filter->x[1] - - filter->a[1] / filter->a[0] * filter->y[0] - - filter->a[2] / filter->a[0] * filter->y[1]; - - filter->x[1] = filter->x[0]; - filter->x[0] = smp; - filter->y[1] = filter->y[0]; - filter->y[0] = tempsmp; - smp = tempsmp; - } - - temps[it] = 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 ALeffectStateFactory *ALequalizerState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); - - -ALeffectState *ALequalizerStateFactory_create(void) -{ - ALequalizerState *state; - int it; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALequalizerState, ALeffectState, state); - - state->bandfilter[0].type = LOW_SHELF; - state->bandfilter[1].type = PEAKING; - state->bandfilter[2].type = PEAKING; - state->bandfilter[3].type = HIGH_SHELF; - - /* Initialize sample history only on filter creation to avoid */ - /* sound clicks if filter settings were changed in runtime. */ - for(it = 0; it < 4; it++) - { - state->bandfilter[it].x[0] = 0.0f; - state->bandfilter[it].x[1] = 0.0f; - state->bandfilter[it].y[0] = 0.0f; - state->bandfilter[it].y[1] = 0.0f; - } - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALequalizerStateFactory_destroy(ALeffectState *effect) -{ - ALequalizerState *state = STATIC_UPCAST(ALequalizerState, ALeffectState, effect); - ALequalizerState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory); - - -static void init_equalizer_factory(void) -{ - SET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory, &EqualizerFactory); -} - -ALeffectStateFactory *ALequalizerStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_equalizer_factory); - return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory); -} - - -void equalizer_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - effect=effect; - val=val; - - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void equalizer_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - equalizer_SetParami(effect, context, param, vals[0]); -} -void equalizer_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - if(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN) - effect->Equalizer.LowGain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_LOW_CUTOFF: - if(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF) - effect->Equalizer.LowCutoff = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID1_GAIN: - if(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN) - effect->Equalizer.Mid1Gain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID1_CENTER: - if(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER) - effect->Equalizer.Mid1Center = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID1_WIDTH: - if(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH) - effect->Equalizer.Mid1Width = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID2_GAIN: - if(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN) - effect->Equalizer.Mid2Gain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID2_CENTER: - if(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER) - effect->Equalizer.Mid2Center = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_MID2_WIDTH: - if(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH) - effect->Equalizer.Mid2Width = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_HIGH_GAIN: - if(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN) - effect->Equalizer.HighGain = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - if(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF) - effect->Equalizer.HighCutoff = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void equalizer_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - equalizer_SetParamf(effect, context, param, vals[0]); -} - -void equalizer_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - effect=effect; - val=val; - - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void equalizer_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - equalizer_GetParami(effect, context, param, vals); -} -void equalizer_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - *val = effect->Equalizer.LowGain; - break; - - case AL_EQUALIZER_LOW_CUTOFF: - *val = effect->Equalizer.LowCutoff; - break; - - case AL_EQUALIZER_MID1_GAIN: - *val = effect->Equalizer.Mid1Gain; - break; - - case AL_EQUALIZER_MID1_CENTER: - *val = effect->Equalizer.Mid1Center; - break; - - case AL_EQUALIZER_MID1_WIDTH: - *val = effect->Equalizer.Mid1Width; - break; - - case AL_EQUALIZER_MID2_GAIN: - *val = effect->Equalizer.Mid2Gain; - break; - - case AL_EQUALIZER_MID2_CENTER: - *val = effect->Equalizer.Mid2Center; - break; - - case AL_EQUALIZER_MID2_WIDTH: - *val = effect->Equalizer.Mid2Width; - break; - - case AL_EQUALIZER_HIGH_GAIN: - *val = effect->Equalizer.HighGain; - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - *val = effect->Equalizer.HighCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void equalizer_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - equalizer_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcFlanger.c b/Alc/alcFlanger.c deleted file mode 100644 index a0f94a46..00000000 --- a/Alc/alcFlanger.c +++ /dev/null @@ -1,411 +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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALflangerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALflangerStateFactory; - -static ALflangerStateFactory FlangerFactory; - - -typedef struct ALflangerState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBufferLeft; - ALfloat *SampleBufferRight; - ALuint BufferLength; - ALint offset; - ALfloat lfo_coeff; - ALint lfo_disp; - - /* Gains for left and right sides */ - ALfloat Gain[2][MaxChannels]; - - /* effect parameters */ - ALint waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; -} ALflangerState; - -static ALvoid ALflangerState_Destruct(ALflangerState *state) -{ - free(state->SampleBufferLeft); - state->SampleBufferLeft = NULL; - - free(state->SampleBufferRight); - state->SampleBufferRight = NULL; -} - -static ALboolean ALflangerState_DeviceUpdate(ALflangerState *state, ALCdevice *Device) -{ - ALuint maxlen; - ALuint it; - - maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); - - if(maxlen != state->BufferLength) - { - void *temp; - - temp = realloc(state->SampleBufferLeft, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - state->SampleBufferLeft = temp; - - temp = realloc(state->SampleBufferRight, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - state->SampleBufferRight = temp; - - state->BufferLength = maxlen; - } - - for(it = 0;it < state->BufferLength;it++) - { - state->SampleBufferLeft[it] = 0.0f; - state->SampleBufferRight[it] = 0.0f; - } - - return AL_TRUE; -} - -static ALvoid ALflangerState_Update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALfloat frequency = (ALfloat)Device->Frequency; - ALfloat rate; - ALint phase; - ALuint it; - - for(it = 0;it < MaxChannels;it++) - { - state->Gain[0][it] = 0.0f; - state->Gain[1][it] = 0.0f; - } - - state->waveform = Slot->effect.Flanger.Waveform; - state->depth = Slot->effect.Flanger.Depth; - state->feedback = Slot->effect.Flanger.Feedback; - state->delay = fastf2i(Slot->effect.Flanger.Delay * frequency); - - /* Gains for left and right sides */ - ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); - ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); - - phase = Slot->effect.Flanger.Phase; - rate = Slot->effect.Flanger.Rate; - - /* Calculate LFO coefficient */ - switch(state->waveform) - { - case AL_FLANGER_WAVEFORM_TRIANGLE: - if(rate == 0.0f) - state->lfo_coeff = 0.0f; - else - state->lfo_coeff = 1.0f / (frequency / rate); - break; - case AL_FLANGER_WAVEFORM_SINUSOID: - if(rate == 0.0f) - state->lfo_coeff = 0.0f; - else - state->lfo_coeff = F_PI * 2.0f / (frequency / rate); - break; - } - - /* Calculate lfo phase displacement */ - if(phase == 0 || rate == 0.0f) - state->lfo_disp = 0; - else - state->lfo_disp = fastf2i(frequency / rate / (360.0f/phase)); -} - -static __inline void Triangle(ALint *delay_left, ALint *delay_right, ALint offset, const ALflangerState *state) -{ - ALfloat lfo_value; - - lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * offset * 4.0f, 4.0f)); - lfo_value *= state->depth * state->delay; - *delay_left = fastf2i(lfo_value) + state->delay; - - lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * - (offset+state->lfo_disp) * 4.0f, - 4.0f)); - lfo_value *= state->depth * state->delay; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -static __inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALint offset, const ALflangerState *state) -{ - ALfloat lfo_value; - - lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff * offset, 2.0f*F_PI)); - lfo_value *= state->depth * state->delay; - *delay_left = fastf2i(lfo_value) + state->delay; - - lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff * (offset+state->lfo_disp), - 2.0f*F_PI)); - lfo_value *= state->depth * state->delay; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -#define DECL_TEMPLATE(func) \ -static void Process##func(ALflangerState *state, ALuint SamplesToDo, \ - const ALfloat *restrict SamplesIn, \ - ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ -{ \ - const ALint mask = state->BufferLength-1; \ - ALint offset = state->offset; \ - ALuint it, kt; \ - ALuint base; \ - \ - for(base = 0;base < SamplesToDo;) \ - { \ - ALfloat temps[64][2]; \ - ALuint td = minu(SamplesToDo-base, 64); \ - \ - for(it = 0;it < td;it++,offset++) \ - { \ - ALint delay_left, delay_right; \ - (func)(&delay_left, &delay_right, offset, state); \ - \ - temps[it][0] = state->SampleBufferLeft[(offset-delay_left)&mask]; \ - state->SampleBufferLeft[offset&mask] = (temps[it][0] + \ - SamplesIn[it+base]) * \ - state->feedback; \ - \ - temps[it][1] = state->SampleBufferRight[(offset-delay_right)&mask];\ - state->SampleBufferRight[offset&mask] = (temps[it][1] + \ - SamplesIn[it+base]) * \ - state->feedback; \ - } \ - \ - for(kt = 0;kt < MaxChannels;kt++) \ - { \ - ALfloat gain = state->Gain[0][kt]; \ - if(gain > 0.00001f) \ - { \ - for(it = 0;it < td;it++) \ - SamplesOut[kt][it+base] += temps[it][0] * gain; \ - } \ - \ - gain = state->Gain[1][kt]; \ - if(gain > 0.00001f) \ - { \ - for(it = 0;it < td;it++) \ - SamplesOut[kt][it+base] += temps[it][1] * gain; \ - } \ - } \ - \ - base += td; \ - } \ - \ - state->offset = offset; \ -} - -DECL_TEMPLATE(Triangle) -DECL_TEMPLATE(Sinusoid) - -#undef DECL_TEMPLATE - -static ALvoid ALflangerState_Process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - if(state->waveform == AL_FLANGER_WAVEFORM_TRIANGLE) - ProcessTriangle(state, SamplesToDo, SamplesIn, SamplesOut); - else if(state->waveform == AL_FLANGER_WAVEFORM_SINUSOID) - ProcessSinusoid(state, SamplesToDo, SamplesIn, SamplesOut); -} - -static ALeffectStateFactory *ALflangerState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); - - -ALeffectState *ALflangerStateFactory_create(void) -{ - ALflangerState *state; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALflangerState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBufferLeft = NULL; - state->SampleBufferRight = NULL; - state->offset = 0; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALflangerStateFactory_destroy(ALeffectState *effect) -{ - ALflangerState *state = STATIC_UPCAST(ALflangerState, ALeffectState, effect); - ALflangerState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory); - - -static void init_flanger_factory(void) -{ - SET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory, &FlangerFactory); -} - -ALeffectStateFactory *ALflangerStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_flanger_factory); - return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); -} - - -void flanger_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_FLANGER_WAVEFORM: - if(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM) - effect->Flanger.Waveform = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_FLANGER_PHASE: - if(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE) - effect->Flanger.Phase = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void flanger_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - flanger_SetParami(effect, context, param, vals[0]); -} -void flanger_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_FLANGER_RATE: - if(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE) - effect->Flanger.Rate = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_FLANGER_DEPTH: - if(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH) - effect->Flanger.Depth = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_FLANGER_FEEDBACK: - if(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK) - effect->Flanger.Feedback = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_FLANGER_DELAY: - if(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY) - effect->Flanger.Delay = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void flanger_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - flanger_SetParamf(effect, context, param, vals[0]); -} - -void flanger_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_FLANGER_WAVEFORM: - *val = effect->Flanger.Waveform; - break; - - case AL_FLANGER_PHASE: - *val = effect->Flanger.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void flanger_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - flanger_GetParami(effect, context, param, vals); -} -void flanger_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_FLANGER_RATE: - *val = effect->Flanger.Rate; - break; - - case AL_FLANGER_DEPTH: - *val = effect->Flanger.Depth; - break; - - case AL_FLANGER_FEEDBACK: - *val = effect->Flanger.Feedback; - break; - - case AL_FLANGER_DELAY: - *val = effect->Flanger.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void flanger_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - flanger_GetParamf(effect, context, param, vals); -} diff --git a/Alc/alcModulator.c b/Alc/alcModulator.c deleted file mode 100644 index ec99bd53..00000000 --- a/Alc/alcModulator.c +++ /dev/null @@ -1,343 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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 "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -typedef struct ALmodulatorStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALmodulatorStateFactory; - -static ALmodulatorStateFactory ModulatorFactory; - - -typedef struct ALmodulatorState { - DERIVE_FROM_TYPE(ALeffectState); - - enum { - SINUSOID, - SAWTOOTH, - SQUARE - } Waveform; - - ALuint index; - ALuint step; - - ALfloat Gain[MaxChannels]; - - FILTER iirFilter; -} ALmodulatorState; - -#define WAVEFORM_FRACBITS 24 -#define WAVEFORM_FRACONE (1<> (WAVEFORM_FRACBITS - 1)) & 1); -} - - -static __inline ALfloat hpFilter1P(FILTER *iir, ALfloat input) -{ - ALfloat *history = iir->history; - ALfloat a = iir->coeff; - ALfloat output = input; - - output = output + (history[0]-output)*a; - history[0] = output; - - return input - output; -} - - -#define DECL_TEMPLATE(func) \ -static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ - const ALfloat *restrict SamplesIn, \ - ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ -{ \ - const ALuint step = state->step; \ - ALuint index = state->index; \ - ALuint base; \ - \ - for(base = 0;base < SamplesToDo;) \ - { \ - ALfloat temps[64]; \ - ALuint td = minu(SamplesToDo-base, 64); \ - ALuint i, k; \ - \ - for(i = 0;i < td;i++) \ - { \ - ALfloat samp; \ - samp = SamplesIn[base+i]; \ - samp = hpFilter1P(&state->iirFilter, samp); \ - \ - index += step; \ - index &= WAVEFORM_FRACMASK; \ - temps[i] = samp * func(index); \ - } \ - \ - for(k = 0;k < MaxChannels;k++) \ - { \ - ALfloat gain = state->Gain[k]; \ - if(!(gain > 0.00001f)) \ - continue; \ - \ - for(i = 0;i < td;i++) \ - SamplesOut[k][base+i] += gain * temps[i]; \ - } \ - \ - base += td; \ - } \ - state->index = index; \ -} - -DECL_TEMPLATE(Sin) -DECL_TEMPLATE(Saw) -DECL_TEMPLATE(Square) - -#undef DECL_TEMPLATE - - -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) -{ - (void)state; -} - -static ALboolean ALmodulatorState_DeviceUpdate(ALmodulatorState *state, ALCdevice *Device) -{ - return AL_TRUE; - (void)state; - (void)Device; -} - -static ALvoid ALmodulatorState_Update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALfloat gain, cw, a = 0.0f; - ALuint index; - - if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->Waveform = SINUSOID; - else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - state->Waveform = SAWTOOTH; - else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) - state->Waveform = SQUARE; - - state->step = fastf2u(Slot->effect.Modulator.Frequency*WAVEFORM_FRACONE / - Device->Frequency); - if(state->step == 0) state->step = 1; - - cw = cosf(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff / - Device->Frequency); - a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); - state->iirFilter.coeff = a; - - gain = sqrtf(1.0f/Device->NumChan); - gain *= Slot->Gain; - for(index = 0;index < MaxChannels;index++) - state->Gain[index] = 0.0f; - for(index = 0;index < Device->NumChan;index++) - { - enum Channel chan = Device->Speaker2Chan[index]; - state->Gain[chan] = gain; - } -} - -static ALvoid ALmodulatorState_Process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - switch(state->Waveform) - { - case SINUSOID: - ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut); - break; - - case SAWTOOTH: - ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut); - break; - - case SQUARE: - ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut); - break; - } -} - -static ALeffectStateFactory *ALmodulatorState_getCreator(void) -{ - return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory); -} - -DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); - - -static ALeffectState *ALmodulatorStateFactory_create(void) -{ - ALmodulatorState *state; - - state = malloc(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALmodulatorState, ALeffectState, state); - - state->index = 0; - state->step = 1; - - state->iirFilter.coeff = 0.0f; - state->iirFilter.history[0] = 0.0f; - - return STATIC_CAST(ALeffectState, state); -} - -static ALvoid ALmodulatorStateFactory_destroy(ALeffectState *effect) -{ - ALmodulatorState *state = STATIC_UPCAST(ALmodulatorState, ALeffectState, effect); - ALmodulatorState_Destruct(state); - free(state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory); - - -static void init_modulator_factory(void) -{ - SET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory, &ModulatorFactory); -} - -ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void) -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, init_modulator_factory); - return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory); -} - - -void mod_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - if(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY) - effect->Modulator.Frequency = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - if(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF) - effect->Modulator.HighPassCutoff = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void mod_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - mod_SetParamf(effect, context, param, vals[0]); -} -void mod_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - mod_SetParamf(effect, context, param, (ALfloat)val); - break; - - case AL_RING_MODULATOR_WAVEFORM: - if(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM) - effect->Modulator.Waveform = val; - else - alSetError(context, AL_INVALID_VALUE); - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void mod_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - mod_SetParami(effect, context, param, vals[0]); -} - -void mod_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = (ALint)effect->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = (ALint)effect->Modulator.HighPassCutoff; - break; - case AL_RING_MODULATOR_WAVEFORM: - *val = effect->Modulator.Waveform; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void mod_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - mod_GetParami(effect, context, param, vals); -} -void mod_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = effect->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = effect->Modulator.HighPassCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM); - break; - } -} -void mod_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - mod_GetParamf(effect, context, param, vals); -} diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c new file mode 100644 index 00000000..e5a20b5d --- /dev/null +++ b/Alc/effects/chorus.c @@ -0,0 +1,411 @@ +/** + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALchorusStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALchorusStateFactory; + +static ALchorusStateFactory ChorusFactory; + + +typedef struct ALchorusState { + DERIVE_FROM_TYPE(ALeffectState); + + ALfloat *SampleBufferLeft; + ALfloat *SampleBufferRight; + ALuint BufferLength; + ALint offset; + ALfloat lfo_coeff; + ALint lfo_disp; + + /* Gains for left and right sides */ + ALfloat Gain[2][MaxChannels]; + + /* effect parameters */ + ALint waveform; + ALint delay; + ALfloat depth; + ALfloat feedback; +} ALchorusState; + +static ALvoid ALchorusState_Destruct(ALchorusState *state) +{ + free(state->SampleBufferLeft); + state->SampleBufferLeft = NULL; + + free(state->SampleBufferRight); + state->SampleBufferRight = NULL; +} + +static ALboolean ALchorusState_DeviceUpdate(ALchorusState *state, ALCdevice *Device) +{ + ALuint maxlen; + ALuint it; + + maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1; + maxlen = NextPowerOf2(maxlen); + + if(maxlen != state->BufferLength) + { + void *temp; + + temp = realloc(state->SampleBufferLeft, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + state->SampleBufferLeft = temp; + + temp = realloc(state->SampleBufferRight, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + state->SampleBufferRight = temp; + + state->BufferLength = maxlen; + } + + for(it = 0;it < state->BufferLength;it++) + { + state->SampleBufferLeft[it] = 0.0f; + state->SampleBufferRight[it] = 0.0f; + } + + return AL_TRUE; +} + +static ALvoid ALchorusState_Update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALfloat frequency = (ALfloat)Device->Frequency; + ALfloat rate; + ALint phase; + ALuint it; + + for (it = 0; it < MaxChannels; it++) + { + state->Gain[0][it] = 0.0f; + state->Gain[1][it] = 0.0f; + } + + state->waveform = Slot->effect.Chorus.Waveform; + state->depth = Slot->effect.Chorus.Depth; + state->feedback = Slot->effect.Chorus.Feedback; + state->delay = fastf2i(Slot->effect.Chorus.Delay * frequency); + + /* Gains for left and right sides */ + ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); + ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); + + phase = Slot->effect.Chorus.Phase; + rate = Slot->effect.Chorus.Rate; + + /* Calculate LFO coefficient */ + switch (state->waveform) + { + case AL_CHORUS_WAVEFORM_TRIANGLE: + if(rate == 0.0f) + state->lfo_coeff = 0.0f; + else + state->lfo_coeff = 1.0f / (frequency / rate); + break; + case AL_CHORUS_WAVEFORM_SINUSOID: + if(rate == 0.0f) + state->lfo_coeff = 0.0f; + else + state->lfo_coeff = F_PI*2.0f / (frequency / rate); + break; + } + + /* Calculate lfo phase displacement */ + if(phase == 0 || rate == 0.0f) + state->lfo_disp = 0; + else + state->lfo_disp = fastf2i(frequency / rate / (360.0f/phase)); +} + +static __inline void Triangle(ALint *delay_left, ALint *delay_right, ALint offset, const ALchorusState *state) +{ + ALfloat lfo_value; + + lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff*offset*4.0f, 4.0f)); + lfo_value *= state->depth * state->delay; + *delay_left = fastf2i(lfo_value) + state->delay; + + lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + (offset+state->lfo_disp)*4.0f, + 4.0f)); + lfo_value *= state->depth * state->delay; + *delay_right = fastf2i(lfo_value) + state->delay; +} + +static __inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALint offset, const ALchorusState *state) +{ + ALfloat lfo_value; + + lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff*offset, 2.0f*F_PI)); + lfo_value *= state->depth * state->delay; + *delay_left = fastf2i(lfo_value) + state->delay; + + lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff*(offset+state->lfo_disp), + 2.0f*F_PI)); + lfo_value *= state->depth * state->delay; + *delay_right = fastf2i(lfo_value) + state->delay; +} + +#define DECL_TEMPLATE(func) \ +static void Process##func(ALchorusState *state, ALuint SamplesToDo, \ + const ALfloat *restrict SamplesIn, \ + ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ +{ \ + const ALint mask = state->BufferLength-1; \ + ALint offset = state->offset; \ + ALuint it, kt; \ + ALuint base; \ + \ + for(base = 0;base < SamplesToDo;) \ + { \ + ALfloat temps[64][2]; \ + ALuint td = minu(SamplesToDo-base, 64); \ + \ + for(it = 0;it < td;it++,offset++) \ + { \ + ALint delay_left, delay_right; \ + (func)(&delay_left, &delay_right, offset, state); \ + \ + temps[it][0] = state->SampleBufferLeft[(offset-delay_left)&mask]; \ + state->SampleBufferLeft[offset&mask] = (temps[it][0] + \ + SamplesIn[it+base]) * \ + state->feedback; \ + \ + temps[it][1] = state->SampleBufferRight[(offset-delay_right)&mask];\ + state->SampleBufferRight[offset&mask] = (temps[it][1] + \ + SamplesIn[it+base]) * \ + state->feedback; \ + } \ + \ + for(kt = 0;kt < MaxChannels;kt++) \ + { \ + ALfloat gain = state->Gain[0][kt]; \ + if(gain > 0.00001f) \ + { \ + for(it = 0;it < td;it++) \ + SamplesOut[kt][it+base] += temps[it][0] * gain; \ + } \ + \ + gain = state->Gain[1][kt]; \ + if(gain > 0.00001f) \ + { \ + for(it = 0;it < td;it++) \ + SamplesOut[kt][it+base] += temps[it][1] * gain; \ + } \ + } \ + \ + base += td; \ + } \ + \ + state->offset = offset; \ +} + +DECL_TEMPLATE(Triangle) +DECL_TEMPLATE(Sinusoid) + +#undef DECL_TEMPLATE + +static ALvoid ALchorusState_Process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + if(state->waveform == AL_CHORUS_WAVEFORM_TRIANGLE) + ProcessTriangle(state, SamplesToDo, SamplesIn, SamplesOut); + else if(state->waveform == AL_CHORUS_WAVEFORM_SINUSOID) + ProcessSinusoid(state, SamplesToDo, SamplesIn, SamplesOut); +} + +static ALeffectStateFactory *ALchorusState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &ChorusFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); + + +static ALeffectState *ALchorusStateFactory_create(void) +{ + ALchorusState *state; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALchorusState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBufferLeft = NULL; + state->SampleBufferRight = NULL; + state->offset = 0; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALchorusStateFactory_destroy(ALeffectState *effect) +{ + ALchorusState *state = STATIC_UPCAST(ALchorusState, ALeffectState, effect); + ALchorusState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory); + + +static void init_chorus_factory(void) +{ + SET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory, &ChorusFactory); +} + +ALeffectStateFactory *ALchorusStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_chorus_factory); + return STATIC_CAST(ALeffectStateFactory, &ChorusFactory); +} + + +void chorus_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_CHORUS_WAVEFORM: + if(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM) + effect->Chorus.Waveform = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_CHORUS_PHASE: + if(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE) + effect->Chorus.Phase = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void chorus_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + chorus_SetParami(effect, context, param, vals[0]); +} +void chorus_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_CHORUS_RATE: + if(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE) + effect->Chorus.Rate = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_CHORUS_DEPTH: + if(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH) + effect->Chorus.Depth = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_CHORUS_FEEDBACK: + if(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK) + effect->Chorus.Feedback = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_CHORUS_DELAY: + if(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY) + effect->Chorus.Delay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void chorus_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + chorus_SetParamf(effect, context, param, vals[0]); +} + +void chorus_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_CHORUS_WAVEFORM: + *val = effect->Chorus.Waveform; + break; + + case AL_CHORUS_PHASE: + *val = effect->Chorus.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void chorus_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + chorus_GetParami(effect, context, param, vals); +} +void chorus_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_CHORUS_RATE: + *val = effect->Chorus.Rate; + break; + + case AL_CHORUS_DEPTH: + *val = effect->Chorus.Depth; + break; + + case AL_CHORUS_FEEDBACK: + *val = effect->Chorus.Feedback; + break; + + case AL_CHORUS_DELAY: + *val = effect->Chorus.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void chorus_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + chorus_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c new file mode 100644 index 00000000..bd266b0e --- /dev/null +++ b/Alc/effects/dedicated.c @@ -0,0 +1,183 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson. + * 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 "config.h" + +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALdedicatedStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALdedicatedStateFactory; + +static ALdedicatedStateFactory DedicatedFactory; + + +typedef struct ALdedicatedState { + DERIVE_FROM_TYPE(ALeffectState); + + ALfloat gains[MaxChannels]; +} ALdedicatedState; + + +static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) +{ + (void)state; +} + +static ALboolean ALdedicatedState_DeviceUpdate(ALdedicatedState *state, ALCdevice *Device) +{ + return AL_TRUE; + (void)state; + (void)Device; +} + +static ALvoid ALdedicatedState_Update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot) +{ + ALfloat Gain; + ALsizei s; + + Gain = Slot->Gain * Slot->effect.Dedicated.Gain; + for(s = 0;s < MaxChannels;s++) + state->gains[s] = 0.0f; + + if(Slot->effect.type == AL_EFFECT_DEDICATED_DIALOGUE) + ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains); + else if(Slot->effect.type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + state->gains[LFE] = Gain; +} + +static ALvoid ALdedicatedState_Process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + const ALfloat *gains = state->gains; + ALuint i, c; + + for(c = 0;c < MaxChannels;c++) + { + if(!(gains[c] > 0.00001f)) + continue; + + for(i = 0;i < SamplesToDo;i++) + SamplesOut[c][i] = SamplesIn[i] * gains[c]; + } +} + +static ALeffectStateFactory *ALdedicatedState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); + + +ALeffectState *ALdedicatedStateFactory_create(void) +{ + ALdedicatedState *state; + ALsizei s; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALdedicatedState, ALeffectState, state); + + for(s = 0;s < MaxChannels;s++) + state->gains[s] = 0.0f; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALdedicatedStateFactory_destroy(ALeffectState *effect) +{ + ALdedicatedState *state = STATIC_UPCAST(ALdedicatedState, ALeffectState, effect); + ALdedicatedState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory); + + +static void init_dedicated_factory(void) +{ + SET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory, &DedicatedFactory); +} + +ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_dedicated_factory); + return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory); +} + + +void ded_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +void ded_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ded_SetParami(effect, context, param, vals[0]); +} +void ded_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + if(val >= 0.0f && isfinite(val)) + effect->Dedicated.Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void ded_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ded_SetParamf(effect, context, param, vals[0]); +} + +void ded_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +void ded_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ded_GetParami(effect, context, param, vals); +} +void ded_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + *val = effect->Dedicated.Gain; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void ded_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ded_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c new file mode 100644 index 00000000..7828377c --- /dev/null +++ b/Alc/effects/distortion.c @@ -0,0 +1,402 @@ +/** + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALdistortionStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALdistortionStateFactory; + +static ALdistortionStateFactory DistortionFactory; + + +/* Filters implementation is based on the "Cookbook formulae for audio * + * EQ biquad filter coefficients" by Robert Bristow-Johnson * + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ + +typedef enum ALEQFilterType { + LOWPASS, + BANDPASS, +} ALEQFilterType; + +typedef struct ALEQFilter { + ALEQFilterType type; + ALfloat x[2]; /* History of two last input samples */ + ALfloat y[2]; /* History of two last output samples */ + ALfloat a[3]; /* Transfer function coefficients "a" */ + ALfloat b[3]; /* Transfer function coefficients "b" */ +} ALEQFilter; + +typedef struct ALdistortionState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MaxChannels]; + + /* Effect parameters */ + ALEQFilter bandpass; + ALEQFilter lowpass; + ALfloat attenuation; + ALfloat edge_coeff; +} ALdistortionState; + +static ALvoid ALdistortionState_Destruct(ALdistortionState *state) +{ + (void)state; +} + +static ALboolean ALdistortionState_DeviceUpdate(ALdistortionState *state, ALCdevice *device) +{ + return AL_TRUE; + (void)state; + (void)device; +} + +static ALvoid ALdistortionState_Update(ALdistortionState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALfloat gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; + ALfloat frequency = (ALfloat)Device->Frequency; + ALuint it; + ALfloat w0; + ALfloat alpha; + ALfloat bandwidth; + ALfloat cutoff; + ALfloat edge; + + for(it = 0;it < MaxChannels;it++) + state->Gain[it] = 0.0f; + for(it = 0;it < Device->NumChan;it++) + { + enum Channel chan = Device->Speaker2Chan[it]; + state->Gain[chan] = gain; + } + + /* Store distorted signal attenuation settings */ + state->attenuation = Slot->effect.Distortion.Gain; + + /* Store waveshaper edge settings */ + edge = sinf(Slot->effect.Distortion.Edge * (F_PI/2.0f)); + state->edge_coeff = 2.0f * edge / (1.0f-edge); + + /* Lowpass filter */ + cutoff = Slot->effect.Distortion.LowpassCutoff; + /* Bandwidth value is constant in octaves */ + bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); + w0 = 2.0f*F_PI * cutoff / (frequency*4.0f); + alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); + state->lowpass.b[0] = (1.0f - cosf(w0)) / 2.0f; + state->lowpass.b[1] = 1.0f - cosf(w0); + state->lowpass.b[2] = (1.0f - cosf(w0)) / 2.0f; + state->lowpass.a[0] = 1.0f + alpha; + state->lowpass.a[1] = -2.0f * cosf(w0); + state->lowpass.a[2] = 1.0f - alpha; + + /* Bandpass filter */ + cutoff = Slot->effect.Distortion.EQCenter; + /* Convert bandwidth in Hz to octaves */ + bandwidth = Slot->effect.Distortion.EQBandwidth / (cutoff * 0.67f); + w0 = 2.0f*F_PI * cutoff / (frequency*4.0f); + alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); + state->bandpass.b[0] = alpha; + state->bandpass.b[1] = 0; + state->bandpass.b[2] = -alpha; + state->bandpass.a[0] = 1.0f + alpha; + state->bandpass.a[1] = -2.0f * cosf(w0); + state->bandpass.a[2] = 1.0f - alpha; +} + +static ALvoid ALdistortionState_Process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + const ALfloat fc = state->edge_coeff; + float oversample_buffer[64][4]; + ALfloat tempsmp; + ALuint base; + ALuint it; + ALuint ot; + ALuint kt; + + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); + + /* Perform 4x oversampling to avoid aliasing. */ + /* Oversampling greatly improves distortion */ + /* quality and allows to implement lowpass and */ + /* bandpass filters using high frequencies, at */ + /* which classic IIR filters became unstable. */ + + /* Fill oversample buffer using zero stuffing */ + for(it = 0;it < td;it++) + { + oversample_buffer[it][0] = SamplesIn[it+base]; + oversample_buffer[it][1] = 0.0f; + oversample_buffer[it][2] = 0.0f; + oversample_buffer[it][3] = 0.0f; + } + + /* First step, do lowpass filtering of original signal, */ + /* additionally perform buffer interpolation and lowpass */ + /* cutoff for oversampling (which is fortunately first */ + /* step of distortion). So combine three operations into */ + /* the one. */ + for(it = 0;it < td;it++) + { + for(ot = 0;ot < 4;ot++) + { + tempsmp = state->lowpass.b[0] / state->lowpass.a[0] * oversample_buffer[it][ot] + + state->lowpass.b[1] / state->lowpass.a[0] * state->lowpass.x[0] + + state->lowpass.b[2] / state->lowpass.a[0] * state->lowpass.x[1] - + state->lowpass.a[1] / state->lowpass.a[0] * state->lowpass.y[0] - + state->lowpass.a[2] / state->lowpass.a[0] * state->lowpass.y[1]; + + state->lowpass.x[1] = state->lowpass.x[0]; + state->lowpass.x[0] = oversample_buffer[it][ot]; + state->lowpass.y[1] = state->lowpass.y[0]; + state->lowpass.y[0] = tempsmp; + /* Restore signal power by multiplying sample by amount of oversampling */ + oversample_buffer[it][ot] = tempsmp * 4.0f; + } + } + + for(it = 0;it < td;it++) + { + /* Second step, do distortion using waveshaper function */ + /* to emulate signal processing during tube overdriving. */ + /* Three steps of waveshaping are intended to modify */ + /* waveform without boost/clipping/attenuation process. */ + for(ot = 0;ot < 4;ot++) + { + ALfloat smp = oversample_buffer[it][ot]; + + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + + /* Third step, do bandpass filtering of distorted signal */ + tempsmp = state->bandpass.b[0] / state->bandpass.a[0] * smp + + state->bandpass.b[1] / state->bandpass.a[0] * state->bandpass.x[0] + + state->bandpass.b[2] / state->bandpass.a[0] * state->bandpass.x[1] - + state->bandpass.a[1] / state->bandpass.a[0] * state->bandpass.y[0] - + state->bandpass.a[2] / state->bandpass.a[0] * state->bandpass.y[1]; + + state->bandpass.x[1] = state->bandpass.x[0]; + state->bandpass.x[0] = smp; + state->bandpass.y[1] = state->bandpass.y[0]; + state->bandpass.y[0] = tempsmp; + + oversample_buffer[it][ot] = tempsmp; + } + + /* Fourth step, final, do attenuation and perform decimation, */ + /* store only one sample out of 4. */ + temps[it] = oversample_buffer[it][0] * state->attenuation; + } + + 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 ALeffectStateFactory *ALdistortionState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &DistortionFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); + + +static ALeffectState *ALdistortionStateFactory_create(void) +{ + ALdistortionState *state; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALdistortionState, ALeffectState, state); + + state->bandpass.type = BANDPASS; + state->lowpass.type = LOWPASS; + + /* Initialize sample history only on filter creation to avoid */ + /* sound clicks if filter settings were changed in runtime. */ + state->bandpass.x[0] = 0.0f; + state->bandpass.x[1] = 0.0f; + state->lowpass.y[0] = 0.0f; + state->lowpass.y[1] = 0.0f; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALdistortionStateFactory_destroy(ALeffectState *effect) +{ + ALdistortionState *state = STATIC_UPCAST(ALdistortionState, ALeffectState, effect); + ALdistortionState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory); + + +static void init_distortion_factory(void) +{ + SET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory, &DistortionFactory); +} + +ALeffectStateFactory *ALdistortionStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_distortion_factory); + return STATIC_CAST(ALeffectStateFactory, &DistortionFactory); +} + + +void distortion_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + effect=effect; + val=val; + + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void distortion_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + distortion_SetParami(effect, context, param, vals[0]); +} +void distortion_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_DISTORTION_EDGE: + if(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE) + effect->Distortion.Edge = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_DISTORTION_GAIN: + if(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN) + effect->Distortion.Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + if(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF) + effect->Distortion.LowpassCutoff = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_DISTORTION_EQCENTER: + if(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER) + effect->Distortion.EQCenter = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_DISTORTION_EQBANDWIDTH: + if(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH) + effect->Distortion.EQBandwidth = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void distortion_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + distortion_SetParamf(effect, context, param, vals[0]); +} + +void distortion_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + effect=effect; + val=val; + + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void distortion_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + distortion_GetParami(effect, context, param, vals); +} +void distortion_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_DISTORTION_EDGE: + *val = effect->Distortion.Edge; + break; + + case AL_DISTORTION_GAIN: + *val = effect->Distortion.Gain; + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + *val = effect->Distortion.LowpassCutoff; + break; + + case AL_DISTORTION_EQCENTER: + *val = effect->Distortion.EQCenter; + break; + + case AL_DISTORTION_EQBANDWIDTH: + *val = effect->Distortion.EQBandwidth; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void distortion_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + distortion_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c new file mode 100644 index 00000000..d5915295 --- /dev/null +++ b/Alc/effects/echo.c @@ -0,0 +1,324 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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 "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALechoStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALechoStateFactory; + +static ALechoStateFactory EchoFactory; + + +typedef struct ALechoState { + DERIVE_FROM_TYPE(ALeffectState); + + ALfloat *SampleBuffer; + ALuint BufferLength; + + // The echo is two tap. The delay is the number of samples from before the + // current offset + struct { + ALuint delay; + } Tap[2]; + ALuint Offset; + /* The panning gains for the two taps */ + ALfloat Gain[2][MaxChannels]; + + ALfloat FeedGain; + + FILTER iirFilter; +} ALechoState; + +static ALvoid ALechoState_Destruct(ALechoState *state) +{ + free(state->SampleBuffer); + state->SampleBuffer = NULL; +} + +static ALboolean ALechoState_DeviceUpdate(ALechoState *state, ALCdevice *Device) +{ + ALuint maxlen, i; + + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; + maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; + maxlen = NextPowerOf2(maxlen); + + if(maxlen != state->BufferLength) + { + void *temp; + + temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); + if(!temp) + return AL_FALSE; + state->SampleBuffer = temp; + state->BufferLength = maxlen; + } + for(i = 0;i < state->BufferLength;i++) + state->SampleBuffer[i] = 0.0f; + + return AL_TRUE; +} + +static ALvoid ALechoState_Update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALuint frequency = Device->Frequency; + ALfloat lrpan, cw, g, gain; + ALfloat dirGain; + ALuint i; + + state->Tap[0].delay = fastf2u(Slot->effect.Echo.Delay * frequency) + 1; + state->Tap[1].delay = fastf2u(Slot->effect.Echo.LRDelay * frequency); + state->Tap[1].delay += state->Tap[0].delay; + + lrpan = Slot->effect.Echo.Spread; + + state->FeedGain = Slot->effect.Echo.Feedback; + + cw = cosf(F_PI*2.0f * LOWPASSFREQREF / frequency); + g = 1.0f - Slot->effect.Echo.Damping; + state->iirFilter.coeff = lpCoeffCalc(g, cw); + + gain = Slot->Gain; + for(i = 0;i < MaxChannels;i++) + { + state->Gain[0][i] = 0.0f; + state->Gain[1][i] = 0.0f; + } + + dirGain = fabsf(lrpan); + + /* First tap panning */ + ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]); + + /* Second tap panning */ + ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]); +} + +static ALvoid ALechoState_Process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + const ALuint mask = state->BufferLength-1; + const ALuint tap1 = state->Tap[0].delay; + const ALuint tap2 = state->Tap[1].delay; + ALuint offset = state->Offset; + ALfloat smp; + ALuint base; + ALuint i, k; + + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[64][2]; + ALuint td = minu(SamplesToDo-base, 64); + + for(i = 0;i < td;i++) + { + /* First tap */ + temps[i][0] = state->SampleBuffer[(offset-tap1) & mask]; + /* Second tap */ + temps[i][1] = state->SampleBuffer[(offset-tap2) & mask]; + + // Apply damping and feedback gain to the second tap, and mix in the + // new sample + smp = lpFilter2P(&state->iirFilter, temps[i][1]+SamplesIn[i]); + state->SampleBuffer[offset&mask] = smp * state->FeedGain; + } + + for(k = 0;k < MaxChannels;k++) + { + ALfloat gain = state->Gain[0][k]; + if(gain > 0.00001f) + { + for(i = 0;i < td;i++) + SamplesOut[k][i+base] += temps[i][0] * gain; + } + + gain = state->Gain[1][k]; + if(gain > 0.00001f) + { + for(i = 0;i < td;i++) + SamplesOut[k][i+base] += temps[i][1] * gain; + } + } + + base += td; + } + + state->Offset = offset; +} + +static ALeffectStateFactory *ALechoState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &EchoFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); + + +ALeffectState *ALechoStateFactory_create(void) +{ + ALechoState *state; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALechoState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBuffer = NULL; + + state->Tap[0].delay = 0; + state->Tap[1].delay = 0; + state->Offset = 0; + + state->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + state->iirFilter.history[1] = 0.0f; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALechoStateFactory_destroy(ALeffectState *effect) +{ + ALechoState *state = STATIC_UPCAST(ALechoState, ALeffectState, effect); + ALechoState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory); + + +static void init_echo_factory(void) +{ + SET_VTABLE2(ALechoStateFactory, ALeffectStateFactory, &EchoFactory); +} + +ALeffectStateFactory *ALechoStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_echo_factory); + return STATIC_CAST(ALeffectStateFactory, &EchoFactory); +} + + +void echo_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +void echo_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + echo_SetParami(effect, context, param, vals[0]); +} +void echo_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_ECHO_DELAY: + if(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY) + effect->Echo.Delay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_LRDELAY: + if(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY) + effect->Echo.LRDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_DAMPING: + if(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING) + effect->Echo.Damping = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_FEEDBACK: + if(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK) + effect->Echo.Feedback = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_SPREAD: + if(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD) + effect->Echo.Spread = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void echo_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + echo_SetParamf(effect, context, param, vals[0]); +} + +void echo_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +void echo_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + echo_GetParami(effect, context, param, vals); +} +void echo_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_ECHO_DELAY: + *val = effect->Echo.Delay; + break; + + case AL_ECHO_LRDELAY: + *val = effect->Echo.LRDelay; + break; + + case AL_ECHO_DAMPING: + *val = effect->Echo.Damping; + break; + + case AL_ECHO_FEEDBACK: + *val = effect->Echo.Feedback; + break; + + case AL_ECHO_SPREAD: + *val = effect->Echo.Spread; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void echo_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + echo_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c new file mode 100644 index 00000000..d397a9ba --- /dev/null +++ b/Alc/effects/equalizer.c @@ -0,0 +1,499 @@ +/** + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALequalizerStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALequalizerStateFactory; + +static ALequalizerStateFactory EqualizerFactory; + + +/* The document "Effects Extension Guide.pdf" says that low and high * + * frequencies are cutoff frequencies. This is not fully correct, they * + * are corner frequencies for low and high shelf filters. If they were * + * just cutoff frequencies, there would be no need in cutoff frequency * + * gains, which are present. Documentation for "Creative Proteus X2" * + * software describes 4-band equalizer functionality in a much better * + * way. This equalizer seems to be a predecessor of OpenAL 4-band * + * equalizer. With low and high shelf filters we are able to cutoff * + * frequencies below and/or above corner frequencies using attenuation * + * gains (below 1.0) and amplify all low and/or high frequencies using * + * gains above 1.0. * + * * + * Low-shelf Low Mid Band High Mid Band High-shelf * + * corner center center corner * + * frequency frequency frequency frequency * + * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * + * * + * | | | | * + * | | | | * + * B -----+ /--+--\ /--+--\ +----- * + * O |\ | | | | | | /| * + * O | \ - | - - | - / | * + * S + | \ | | | | | | / | * + * T | | | | | | | | | | * + * ---------+---------------+------------------+---------------+-------- * + * C | | | | | | | | | | * + * U - | / | | | | | | \ | * + * T | / - | - - | - \ | * + * O |/ | | | | | | \| * + * F -----+ \--+--/ \--+--/ +----- * + * F | | | | * + * | | | | * + * * + * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * + * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * + * octaves for two mid bands. * + * * + * Implementation is based on the "Cookbook formulae for audio EQ biquad * + * filter coefficients" by Robert Bristow-Johnson * + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ + +typedef enum ALEQFilterType { + LOW_SHELF, + HIGH_SHELF, + PEAKING +} ALEQFilterType; + +typedef struct ALEQFilter { + ALEQFilterType type; + ALfloat x[2]; /* History of two last input samples */ + ALfloat y[2]; /* History of two last output samples */ + ALfloat a[3]; /* Transfer function coefficients "a" */ + ALfloat b[3]; /* Transfer function coefficients "b" */ +} ALEQFilter; + +typedef struct ALequalizerState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MaxChannels]; + + /* Effect parameters */ + ALEQFilter bandfilter[4]; +} ALequalizerState; + +static ALvoid ALequalizerState_Destruct(ALequalizerState *state) +{ + (void)state; +} + +static ALboolean ALequalizerState_DeviceUpdate(ALequalizerState *state, ALCdevice *device) +{ + return AL_TRUE; + (void)state; + (void)device; +} + +static ALvoid ALequalizerState_Update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot) +{ + ALfloat frequency = (ALfloat)device->Frequency; + ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain; + ALuint it; + + for(it = 0;it < MaxChannels;it++) + state->Gain[it] = 0.0f; + for(it = 0; it < device->NumChan; it++) + { + enum Channel chan = device->Speaker2Chan[it]; + state->Gain[chan] = gain; + } + + /* Calculate coefficients for the each type of filter */ + for(it = 0; it < 4; it++) + { + ALfloat gain; + ALfloat filter_frequency; + ALfloat bandwidth = 0.0f; + ALfloat w0; + ALfloat alpha = 0.0f; + + /* convert linear gains to filter gains */ + switch (it) + { + case 0: /* Low Shelf */ + gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.LowGain)) / 40.0f); + filter_frequency = slot->effect.Equalizer.LowCutoff; + break; + case 1: /* Peaking */ + gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.Mid1Gain)) / 40.0f); + filter_frequency = slot->effect.Equalizer.Mid1Center; + bandwidth = slot->effect.Equalizer.Mid1Width; + break; + case 2: /* Peaking */ + gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.Mid2Gain)) / 40.0f); + filter_frequency = slot->effect.Equalizer.Mid2Center; + bandwidth = slot->effect.Equalizer.Mid2Width; + break; + case 3: /* High Shelf */ + gain = powf(10.0f, (20.0f * log10f(slot->effect.Equalizer.HighGain)) / 40.0f); + filter_frequency = slot->effect.Equalizer.HighCutoff; + break; + } + + w0 = 2.0f*F_PI * filter_frequency / frequency; + + /* Calculate filter coefficients depending on filter type */ + switch(state->bandfilter[it].type) + { + case LOW_SHELF: + alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * + (1.0f / 0.75f - 1.0f) + 2.0f); + state->bandfilter[it].b[0] = gain * ((gain + 1.0f) - + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha); + state->bandfilter[it].b[1] = 2.0f * gain * ((gain - 1.0f) - + (gain + 1.0f) * cosf(w0)); + state->bandfilter[it].b[2] = gain * ((gain + 1.0f) - + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha); + state->bandfilter[it].a[0] = (gain + 1.0f) + + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha; + state->bandfilter[it].a[1] = -2.0f * ((gain - 1.0f) + + (gain + 1.0f) * cosf(w0)); + state->bandfilter[it].a[2] = (gain + 1.0f) + + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha; + break; + case HIGH_SHELF: + alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * + (1.0f / 0.75f - 1.0f) + 2.0f); + state->bandfilter[it].b[0] = gain * ((gain + 1.0f) + + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha); + state->bandfilter[it].b[1] = -2.0f * gain * ((gain - 1.0f) + + (gain + 1.0f) * + cosf(w0)); + state->bandfilter[it].b[2] = gain * ((gain + 1.0f) + + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha); + state->bandfilter[it].a[0] = (gain + 1.0f) - + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha; + state->bandfilter[it].a[1] = 2.0f * ((gain - 1.0f) - + (gain + 1.0f) * cosf(w0)); + state->bandfilter[it].a[2] = (gain + 1.0f) - + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha; + break; + case PEAKING: + alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); + state->bandfilter[it].b[0] = 1.0f + alpha * gain; + state->bandfilter[it].b[1] = -2.0f * cosf(w0); + state->bandfilter[it].b[2] = 1.0f - alpha * gain; + state->bandfilter[it].a[0] = 1.0f + alpha / gain; + state->bandfilter[it].a[1] = -2.0f * cosf(w0); + state->bandfilter[it].a[2] = 1.0f - alpha / gain; + break; + } + } +} + +static ALvoid ALequalizerState_Process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + ALuint base; + ALuint it; + ALuint kt; + ALuint ft; + + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); + + for(it = 0;it < td;it++) + { + ALfloat smp = SamplesIn[base+it]; + ALfloat tempsmp; + + for(ft = 0;ft < 4;ft++) + { + ALEQFilter *filter = &state->bandfilter[ft]; + + tempsmp = filter->b[0] / filter->a[0] * smp + + filter->b[1] / filter->a[0] * filter->x[0] + + filter->b[2] / filter->a[0] * filter->x[1] - + filter->a[1] / filter->a[0] * filter->y[0] - + filter->a[2] / filter->a[0] * filter->y[1]; + + filter->x[1] = filter->x[0]; + filter->x[0] = smp; + filter->y[1] = filter->y[0]; + filter->y[0] = tempsmp; + smp = tempsmp; + } + + temps[it] = 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 ALeffectStateFactory *ALequalizerState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); + + +ALeffectState *ALequalizerStateFactory_create(void) +{ + ALequalizerState *state; + int it; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALequalizerState, ALeffectState, state); + + state->bandfilter[0].type = LOW_SHELF; + state->bandfilter[1].type = PEAKING; + state->bandfilter[2].type = PEAKING; + state->bandfilter[3].type = HIGH_SHELF; + + /* Initialize sample history only on filter creation to avoid */ + /* sound clicks if filter settings were changed in runtime. */ + for(it = 0; it < 4; it++) + { + state->bandfilter[it].x[0] = 0.0f; + state->bandfilter[it].x[1] = 0.0f; + state->bandfilter[it].y[0] = 0.0f; + state->bandfilter[it].y[1] = 0.0f; + } + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALequalizerStateFactory_destroy(ALeffectState *effect) +{ + ALequalizerState *state = STATIC_UPCAST(ALequalizerState, ALeffectState, effect); + ALequalizerState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory); + + +static void init_equalizer_factory(void) +{ + SET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory, &EqualizerFactory); +} + +ALeffectStateFactory *ALequalizerStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_equalizer_factory); + return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory); +} + + +void equalizer_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + effect=effect; + val=val; + + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void equalizer_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + equalizer_SetParami(effect, context, param, vals[0]); +} +void equalizer_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + if(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN) + effect->Equalizer.LowGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_LOW_CUTOFF: + if(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF) + effect->Equalizer.LowCutoff = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID1_GAIN: + if(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN) + effect->Equalizer.Mid1Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID1_CENTER: + if(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER) + effect->Equalizer.Mid1Center = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID1_WIDTH: + if(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH) + effect->Equalizer.Mid1Width = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID2_GAIN: + if(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN) + effect->Equalizer.Mid2Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID2_CENTER: + if(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER) + effect->Equalizer.Mid2Center = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_MID2_WIDTH: + if(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH) + effect->Equalizer.Mid2Width = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_HIGH_GAIN: + if(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN) + effect->Equalizer.HighGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + if(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF) + effect->Equalizer.HighCutoff = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void equalizer_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + equalizer_SetParamf(effect, context, param, vals[0]); +} + +void equalizer_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + effect=effect; + val=val; + + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void equalizer_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + equalizer_GetParami(effect, context, param, vals); +} +void equalizer_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + *val = effect->Equalizer.LowGain; + break; + + case AL_EQUALIZER_LOW_CUTOFF: + *val = effect->Equalizer.LowCutoff; + break; + + case AL_EQUALIZER_MID1_GAIN: + *val = effect->Equalizer.Mid1Gain; + break; + + case AL_EQUALIZER_MID1_CENTER: + *val = effect->Equalizer.Mid1Center; + break; + + case AL_EQUALIZER_MID1_WIDTH: + *val = effect->Equalizer.Mid1Width; + break; + + case AL_EQUALIZER_MID2_GAIN: + *val = effect->Equalizer.Mid2Gain; + break; + + case AL_EQUALIZER_MID2_CENTER: + *val = effect->Equalizer.Mid2Center; + break; + + case AL_EQUALIZER_MID2_WIDTH: + *val = effect->Equalizer.Mid2Width; + break; + + case AL_EQUALIZER_HIGH_GAIN: + *val = effect->Equalizer.HighGain; + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + *val = effect->Equalizer.HighCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void equalizer_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + equalizer_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c new file mode 100644 index 00000000..a0f94a46 --- /dev/null +++ b/Alc/effects/flanger.c @@ -0,0 +1,411 @@ +/** + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALflangerStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALflangerStateFactory; + +static ALflangerStateFactory FlangerFactory; + + +typedef struct ALflangerState { + DERIVE_FROM_TYPE(ALeffectState); + + ALfloat *SampleBufferLeft; + ALfloat *SampleBufferRight; + ALuint BufferLength; + ALint offset; + ALfloat lfo_coeff; + ALint lfo_disp; + + /* Gains for left and right sides */ + ALfloat Gain[2][MaxChannels]; + + /* effect parameters */ + ALint waveform; + ALint delay; + ALfloat depth; + ALfloat feedback; +} ALflangerState; + +static ALvoid ALflangerState_Destruct(ALflangerState *state) +{ + free(state->SampleBufferLeft); + state->SampleBufferLeft = NULL; + + free(state->SampleBufferRight); + state->SampleBufferRight = NULL; +} + +static ALboolean ALflangerState_DeviceUpdate(ALflangerState *state, ALCdevice *Device) +{ + ALuint maxlen; + ALuint it; + + maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1; + maxlen = NextPowerOf2(maxlen); + + if(maxlen != state->BufferLength) + { + void *temp; + + temp = realloc(state->SampleBufferLeft, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + state->SampleBufferLeft = temp; + + temp = realloc(state->SampleBufferRight, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + state->SampleBufferRight = temp; + + state->BufferLength = maxlen; + } + + for(it = 0;it < state->BufferLength;it++) + { + state->SampleBufferLeft[it] = 0.0f; + state->SampleBufferRight[it] = 0.0f; + } + + return AL_TRUE; +} + +static ALvoid ALflangerState_Update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALfloat frequency = (ALfloat)Device->Frequency; + ALfloat rate; + ALint phase; + ALuint it; + + for(it = 0;it < MaxChannels;it++) + { + state->Gain[0][it] = 0.0f; + state->Gain[1][it] = 0.0f; + } + + state->waveform = Slot->effect.Flanger.Waveform; + state->depth = Slot->effect.Flanger.Depth; + state->feedback = Slot->effect.Flanger.Feedback; + state->delay = fastf2i(Slot->effect.Flanger.Delay * frequency); + + /* Gains for left and right sides */ + ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); + ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); + + phase = Slot->effect.Flanger.Phase; + rate = Slot->effect.Flanger.Rate; + + /* Calculate LFO coefficient */ + switch(state->waveform) + { + case AL_FLANGER_WAVEFORM_TRIANGLE: + if(rate == 0.0f) + state->lfo_coeff = 0.0f; + else + state->lfo_coeff = 1.0f / (frequency / rate); + break; + case AL_FLANGER_WAVEFORM_SINUSOID: + if(rate == 0.0f) + state->lfo_coeff = 0.0f; + else + state->lfo_coeff = F_PI * 2.0f / (frequency / rate); + break; + } + + /* Calculate lfo phase displacement */ + if(phase == 0 || rate == 0.0f) + state->lfo_disp = 0; + else + state->lfo_disp = fastf2i(frequency / rate / (360.0f/phase)); +} + +static __inline void Triangle(ALint *delay_left, ALint *delay_right, ALint offset, const ALflangerState *state) +{ + ALfloat lfo_value; + + lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * offset * 4.0f, 4.0f)); + lfo_value *= state->depth * state->delay; + *delay_left = fastf2i(lfo_value) + state->delay; + + lfo_value = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + (offset+state->lfo_disp) * 4.0f, + 4.0f)); + lfo_value *= state->depth * state->delay; + *delay_right = fastf2i(lfo_value) + state->delay; +} + +static __inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALint offset, const ALflangerState *state) +{ + ALfloat lfo_value; + + lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff * offset, 2.0f*F_PI)); + lfo_value *= state->depth * state->delay; + *delay_left = fastf2i(lfo_value) + state->delay; + + lfo_value = 1.0f + sinf(fmodf(state->lfo_coeff * (offset+state->lfo_disp), + 2.0f*F_PI)); + lfo_value *= state->depth * state->delay; + *delay_right = fastf2i(lfo_value) + state->delay; +} + +#define DECL_TEMPLATE(func) \ +static void Process##func(ALflangerState *state, ALuint SamplesToDo, \ + const ALfloat *restrict SamplesIn, \ + ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ +{ \ + const ALint mask = state->BufferLength-1; \ + ALint offset = state->offset; \ + ALuint it, kt; \ + ALuint base; \ + \ + for(base = 0;base < SamplesToDo;) \ + { \ + ALfloat temps[64][2]; \ + ALuint td = minu(SamplesToDo-base, 64); \ + \ + for(it = 0;it < td;it++,offset++) \ + { \ + ALint delay_left, delay_right; \ + (func)(&delay_left, &delay_right, offset, state); \ + \ + temps[it][0] = state->SampleBufferLeft[(offset-delay_left)&mask]; \ + state->SampleBufferLeft[offset&mask] = (temps[it][0] + \ + SamplesIn[it+base]) * \ + state->feedback; \ + \ + temps[it][1] = state->SampleBufferRight[(offset-delay_right)&mask];\ + state->SampleBufferRight[offset&mask] = (temps[it][1] + \ + SamplesIn[it+base]) * \ + state->feedback; \ + } \ + \ + for(kt = 0;kt < MaxChannels;kt++) \ + { \ + ALfloat gain = state->Gain[0][kt]; \ + if(gain > 0.00001f) \ + { \ + for(it = 0;it < td;it++) \ + SamplesOut[kt][it+base] += temps[it][0] * gain; \ + } \ + \ + gain = state->Gain[1][kt]; \ + if(gain > 0.00001f) \ + { \ + for(it = 0;it < td;it++) \ + SamplesOut[kt][it+base] += temps[it][1] * gain; \ + } \ + } \ + \ + base += td; \ + } \ + \ + state->offset = offset; \ +} + +DECL_TEMPLATE(Triangle) +DECL_TEMPLATE(Sinusoid) + +#undef DECL_TEMPLATE + +static ALvoid ALflangerState_Process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + if(state->waveform == AL_FLANGER_WAVEFORM_TRIANGLE) + ProcessTriangle(state, SamplesToDo, SamplesIn, SamplesOut); + else if(state->waveform == AL_FLANGER_WAVEFORM_SINUSOID) + ProcessSinusoid(state, SamplesToDo, SamplesIn, SamplesOut); +} + +static ALeffectStateFactory *ALflangerState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); + + +ALeffectState *ALflangerStateFactory_create(void) +{ + ALflangerState *state; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALflangerState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBufferLeft = NULL; + state->SampleBufferRight = NULL; + state->offset = 0; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALflangerStateFactory_destroy(ALeffectState *effect) +{ + ALflangerState *state = STATIC_UPCAST(ALflangerState, ALeffectState, effect); + ALflangerState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory); + + +static void init_flanger_factory(void) +{ + SET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory, &FlangerFactory); +} + +ALeffectStateFactory *ALflangerStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_flanger_factory); + return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); +} + + +void flanger_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_FLANGER_WAVEFORM: + if(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM) + effect->Flanger.Waveform = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_FLANGER_PHASE: + if(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE) + effect->Flanger.Phase = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void flanger_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + flanger_SetParami(effect, context, param, vals[0]); +} +void flanger_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_FLANGER_RATE: + if(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE) + effect->Flanger.Rate = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_FLANGER_DEPTH: + if(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH) + effect->Flanger.Depth = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_FLANGER_FEEDBACK: + if(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK) + effect->Flanger.Feedback = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_FLANGER_DELAY: + if(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY) + effect->Flanger.Delay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void flanger_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + flanger_SetParamf(effect, context, param, vals[0]); +} + +void flanger_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_FLANGER_WAVEFORM: + *val = effect->Flanger.Waveform; + break; + + case AL_FLANGER_PHASE: + *val = effect->Flanger.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void flanger_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + flanger_GetParami(effect, context, param, vals); +} +void flanger_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_FLANGER_RATE: + *val = effect->Flanger.Rate; + break; + + case AL_FLANGER_DEPTH: + *val = effect->Flanger.Depth; + break; + + case AL_FLANGER_FEEDBACK: + *val = effect->Flanger.Feedback; + break; + + case AL_FLANGER_DELAY: + *val = effect->Flanger.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void flanger_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + flanger_GetParamf(effect, context, param, vals); +} diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c new file mode 100644 index 00000000..ec99bd53 --- /dev/null +++ b/Alc/effects/modulator.c @@ -0,0 +1,343 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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 "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALmodulatorStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALmodulatorStateFactory; + +static ALmodulatorStateFactory ModulatorFactory; + + +typedef struct ALmodulatorState { + DERIVE_FROM_TYPE(ALeffectState); + + enum { + SINUSOID, + SAWTOOTH, + SQUARE + } Waveform; + + ALuint index; + ALuint step; + + ALfloat Gain[MaxChannels]; + + FILTER iirFilter; +} ALmodulatorState; + +#define WAVEFORM_FRACBITS 24 +#define WAVEFORM_FRACONE (1<> (WAVEFORM_FRACBITS - 1)) & 1); +} + + +static __inline ALfloat hpFilter1P(FILTER *iir, ALfloat input) +{ + ALfloat *history = iir->history; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + + return input - output; +} + + +#define DECL_TEMPLATE(func) \ +static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ + const ALfloat *restrict SamplesIn, \ + ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ +{ \ + const ALuint step = state->step; \ + ALuint index = state->index; \ + ALuint base; \ + \ + for(base = 0;base < SamplesToDo;) \ + { \ + ALfloat temps[64]; \ + ALuint td = minu(SamplesToDo-base, 64); \ + ALuint i, k; \ + \ + for(i = 0;i < td;i++) \ + { \ + ALfloat samp; \ + samp = SamplesIn[base+i]; \ + samp = hpFilter1P(&state->iirFilter, samp); \ + \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + temps[i] = samp * func(index); \ + } \ + \ + for(k = 0;k < MaxChannels;k++) \ + { \ + ALfloat gain = state->Gain[k]; \ + if(!(gain > 0.00001f)) \ + continue; \ + \ + for(i = 0;i < td;i++) \ + SamplesOut[k][base+i] += gain * temps[i]; \ + } \ + \ + base += td; \ + } \ + state->index = index; \ +} + +DECL_TEMPLATE(Sin) +DECL_TEMPLATE(Saw) +DECL_TEMPLATE(Square) + +#undef DECL_TEMPLATE + + +static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) +{ + (void)state; +} + +static ALboolean ALmodulatorState_DeviceUpdate(ALmodulatorState *state, ALCdevice *Device) +{ + return AL_TRUE; + (void)state; + (void)Device; +} + +static ALvoid ALmodulatorState_Update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALfloat gain, cw, a = 0.0f; + ALuint index; + + if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + state->Waveform = SINUSOID; + else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + state->Waveform = SAWTOOTH; + else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) + state->Waveform = SQUARE; + + state->step = fastf2u(Slot->effect.Modulator.Frequency*WAVEFORM_FRACONE / + Device->Frequency); + if(state->step == 0) state->step = 1; + + cw = cosf(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff / + Device->Frequency); + a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); + state->iirFilter.coeff = a; + + gain = sqrtf(1.0f/Device->NumChan); + gain *= Slot->Gain; + for(index = 0;index < MaxChannels;index++) + state->Gain[index] = 0.0f; + for(index = 0;index < Device->NumChan;index++) + { + enum Channel chan = Device->Speaker2Chan[index]; + state->Gain[chan] = gain; + } +} + +static ALvoid ALmodulatorState_Process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +{ + switch(state->Waveform) + { + case SINUSOID: + ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut); + break; + + case SAWTOOTH: + ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut); + break; + + case SQUARE: + ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut); + break; + } +} + +static ALeffectStateFactory *ALmodulatorState_getCreator(void) +{ + return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); + + +static ALeffectState *ALmodulatorStateFactory_create(void) +{ + ALmodulatorState *state; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALmodulatorState, ALeffectState, state); + + state->index = 0; + state->step = 1; + + state->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + + return STATIC_CAST(ALeffectState, state); +} + +static ALvoid ALmodulatorStateFactory_destroy(ALeffectState *effect) +{ + ALmodulatorState *state = STATIC_UPCAST(ALmodulatorState, ALeffectState, effect); + ALmodulatorState_Destruct(state); + free(state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory); + + +static void init_modulator_factory(void) +{ + SET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory, &ModulatorFactory); +} + +ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, init_modulator_factory); + return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory); +} + + +void mod_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + if(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY) + effect->Modulator.Frequency = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + if(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF) + effect->Modulator.HighPassCutoff = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void mod_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + mod_SetParamf(effect, context, param, vals[0]); +} +void mod_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + mod_SetParamf(effect, context, param, (ALfloat)val); + break; + + case AL_RING_MODULATOR_WAVEFORM: + if(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM) + effect->Modulator.Waveform = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void mod_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + mod_SetParami(effect, context, param, vals[0]); +} + +void mod_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = (ALint)effect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = (ALint)effect->Modulator.HighPassCutoff; + break; + case AL_RING_MODULATOR_WAVEFORM: + *val = effect->Modulator.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void mod_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + mod_GetParami(effect, context, param, vals); +} +void mod_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = effect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = effect->Modulator.HighPassCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +void mod_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + mod_GetParamf(effect, context, param, vals); +} -- cgit v1.2.3