diff options
-rw-r--r-- | Alc/ALc.c | 18 | ||||
-rw-r--r-- | Alc/alcChorus.c | 395 | ||||
-rw-r--r-- | Alc/alcFlanger.c | 395 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alAuxEffectSlot.h | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alEffect.h | 38 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 10 | ||||
-rw-r--r-- | OpenAL32/alEffect.c | 34 | ||||
-rw-r--r-- | OpenAL32/alExtension.c | 2 | ||||
-rw-r--r-- | alsoftrc.sample | 4 |
10 files changed, 896 insertions, 4 deletions
@@ -512,13 +512,13 @@ static const ALCenums enumeration[] = { DECL(AL_EFFECT_NULL), DECL(AL_EFFECT_REVERB), DECL(AL_EFFECT_EAXREVERB), -#if 0 DECL(AL_EFFECT_CHORUS), +#if 0 DECL(AL_EFFECT_DISTORTION), #endif DECL(AL_EFFECT_ECHO), -#if 0 DECL(AL_EFFECT_FLANGER), +#if 0 DECL(AL_EFFECT_FREQUENCY_SHIFTER), DECL(AL_EFFECT_VOCAL_MORPHER), DECL(AL_EFFECT_PITCH_SHIFTER), @@ -576,6 +576,20 @@ static const ALCenums enumeration[] = { DECL(AL_ECHO_FEEDBACK), DECL(AL_ECHO_SPREAD), + DECL(AL_CHORUS_WAVEFORM), + DECL(AL_CHORUS_PHASE), + DECL(AL_CHORUS_RATE), + DECL(AL_CHORUS_DEPTH), + DECL(AL_CHORUS_FEEDBACK), + DECL(AL_CHORUS_DELAY), + + DECL(AL_FLANGER_WAVEFORM), + DECL(AL_FLANGER_PHASE), + DECL(AL_FLANGER_RATE), + DECL(AL_FLANGER_DEPTH), + DECL(AL_FLANGER_FEEDBACK), + DECL(AL_FLANGER_DELAY), + DECL(AL_RING_MODULATOR_FREQUENCY), DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), diff --git a/Alc/alcChorus.c b/Alc/alcChorus.c new file mode 100644 index 00000000..5a97ff17 --- /dev/null +++ b/Alc/alcChorus.c @@ -0,0 +1,395 @@ +/** + * 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 <math.h> +#include <stdlib.h> + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALchorusState { + // Must be first in all effects! + ALeffectState state; + + 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 phase; + ALfloat rate; + ALfloat depth; + ALfloat feedback; + ALfloat delay; + ALfloat frequency; +} ALchorusState; + +static ALvoid ChorusDestroy(ALeffectState *effect) +{ + ALchorusState *state = (ALchorusState*)effect; + + if (state) + { + if (state->SampleBufferLeft != NULL) + { + free(state->SampleBufferLeft); + state->SampleBufferLeft = NULL; + } + if (state->SampleBufferRight != NULL) + { + free(state->SampleBufferRight); + state->SampleBufferRight = NULL; + } + free(state); + } +} + +static ALboolean ChorusDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALchorusState *state = (ALchorusState*)effect; + 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; + } + + state->frequency=(ALfloat)Device->Frequency; + + return AL_TRUE; +} + +static ALvoid ChorusUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALchorusState *state = (ALchorusState*)effect; + 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->phase = Slot->effect.Chorus.Phase; + state->rate = Slot->effect.Chorus.Rate; + state->depth = Slot->effect.Chorus.Depth; + state->feedback = Slot->effect.Chorus.Feedback; + state->delay = Slot->effect.Chorus.Delay; + state->frequency=(ALfloat)Device->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]); + + /* Calculate LFO coefficient */ + switch (state->waveform) + { + case AL_CHORUS_WAVEFORM_TRIANGLE: + if (state->rate == 0.0f) + { + state->lfo_coeff = 0.0f; + } + else + { + state->lfo_coeff = 1.0f / ((ALfloat)Device->Frequency / state->rate); + } + break; + case AL_CHORUS_WAVEFORM_SINUSOID: + if (state->rate == 0.0f) + { + state->lfo_coeff = 0.0f; + } + else + { + state->lfo_coeff = F_PI * 2.0f / ((ALfloat)Device->Frequency / state->rate); + } + break; + } + + /* Calculate lfo phase displacement */ + if ((state->phase == 0) || (state->rate == 0.0f)) + { + state->lfo_disp = 0; + } + else + { + state->lfo_disp = (ALint) ((ALfloat)Device->Frequency / + state->rate / (360.0f / (ALfloat)state->phase)); + } +} + +static ALvoid ChorusProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALchorusState *state = (ALchorusState*)effect; + const ALuint mask = state->BufferLength-1; + ALuint it; + ALuint kt; + ALint offset; + ALfloat lfo_value_left = 0.0f; + ALfloat lfo_value_right = 0.0f; + ALint delay_left = 0; + ALint delay_right = 0; + ALfloat smp; + + offset=state->offset; + + switch (state->waveform) + { + case AL_CHORUS_WAVEFORM_TRIANGLE: + for (it = 0; it < SamplesToDo; it++, offset++) + { + lfo_value_left = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + offset * 4.0f, 4.0f)); + lfo_value_left *= state->depth * state->delay; + lfo_value_left += state->delay; + delay_left = (ALint)(lfo_value_left * state->frequency); + lfo_value_right = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + (offset + state->lfo_disp) * 4.0f, 4.0f)); + lfo_value_right *= state->depth * state->delay; + lfo_value_right += state->delay; + delay_right = (ALint)(lfo_value_right * state->frequency); + + smp = state->SampleBufferLeft[(offset-delay_left) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[0][kt]; + } + state->SampleBufferLeft[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + smp = state->SampleBufferRight[(offset-delay_right) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[1][kt]; + } + state->SampleBufferRight[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + } + break; + case AL_CHORUS_WAVEFORM_SINUSOID: + for (it = 0; it < SamplesToDo; it++, offset++) + { + lfo_value_left = 1.0f + sinf(fmodf(state->lfo_coeff * + offset, 2 * F_PI)); + lfo_value_left *= state->depth * state->delay; + lfo_value_left += state->delay; + delay_left = (ALint)(lfo_value_left * state->frequency); + lfo_value_right = 1.0f + sinf(fmodf(state->lfo_coeff * + (offset + state->lfo_disp), 2 * F_PI)); + lfo_value_right *= state->depth * state->delay; + lfo_value_right += state->delay; + delay_right = (ALint)(lfo_value_right * state->frequency); + + smp = state->SampleBufferLeft[(offset-delay_left) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[0][kt]; + } + state->SampleBufferLeft[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + smp = state->SampleBufferRight[(offset-delay_right) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[1][kt]; + } + state->SampleBufferRight[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + } + break; + } + + state->offset=offset; +} + +ALeffectState *ChorusCreate(void) +{ + ALchorusState *state; + + state = malloc(sizeof(*state)); + if(!state) + return NULL; + + state->state.Destroy = ChorusDestroy; + state->state.DeviceUpdate = ChorusDeviceUpdate; + state->state.Update = ChorusUpdate; + state->state.Process = ChorusProcess; + + state->BufferLength = 0; + state->SampleBufferLeft = NULL; + state->SampleBufferRight = NULL; + state->offset = 0; + + return &state->state; +} + +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/alcFlanger.c b/Alc/alcFlanger.c new file mode 100644 index 00000000..a1047c01 --- /dev/null +++ b/Alc/alcFlanger.c @@ -0,0 +1,395 @@ +/** + * 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 <math.h> +#include <stdlib.h> + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALflangerState { + // Must be first in all effects! + ALeffectState state; + + 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 phase; + ALfloat rate; + ALfloat depth; + ALfloat feedback; + ALfloat delay; + ALfloat frequency; +} ALflangerState; + +static ALvoid FlangerDestroy(ALeffectState *effect) +{ + ALflangerState *state = (ALflangerState*)effect; + + if (state) + { + if (state->SampleBufferLeft != NULL) + { + free(state->SampleBufferLeft); + state->SampleBufferLeft = NULL; + } + if (state->SampleBufferRight != NULL) + { + free(state->SampleBufferRight); + state->SampleBufferRight = NULL; + } + free(state); + } +} + +static ALboolean FlangerDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALflangerState *state = (ALflangerState*)effect; + 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; + } + + state->frequency=(ALfloat)Device->Frequency; + + return AL_TRUE; +} + +static ALvoid FlangerUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALflangerState *state = (ALflangerState*)effect; + 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->phase = Slot->effect.Flanger.Phase; + state->rate = Slot->effect.Flanger.Rate; + state->depth = Slot->effect.Flanger.Depth; + state->feedback = Slot->effect.Flanger.Feedback; + state->delay = Slot->effect.Flanger.Delay; + state->frequency=(ALfloat)Device->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]); + + /* Calculate LFO coefficient */ + switch (state->waveform) + { + case AL_FLANGER_WAVEFORM_TRIANGLE: + if (state->rate == 0.0f) + { + state->lfo_coeff = 0.0f; + } + else + { + state->lfo_coeff = 1.0f / ((ALfloat)Device->Frequency / state->rate); + } + break; + case AL_FLANGER_WAVEFORM_SINUSOID: + if (state->rate == 0.0f) + { + state->lfo_coeff = 0.0f; + } + else + { + state->lfo_coeff = F_PI * 2.0f / ((ALfloat)Device->Frequency / state->rate); + } + break; + } + + /* Calculate lfo phase displacement */ + if ((state->phase == 0) || (state->rate == 0.0f)) + { + state->lfo_disp = 0; + } + else + { + state->lfo_disp = (ALint) ((ALfloat)Device->Frequency / + state->rate / (360.0f / (ALfloat)state->phase)); + } +} + +static ALvoid FlangerProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALflangerState *state = (ALflangerState*)effect; + const ALuint mask = state->BufferLength-1; + ALuint it; + ALuint kt; + ALint offset; + ALfloat lfo_value_left = 0.0f; + ALfloat lfo_value_right = 0.0f; + ALint delay_left = 0; + ALint delay_right = 0; + ALfloat smp; + + offset=state->offset; + + switch (state->waveform) + { + case AL_FLANGER_WAVEFORM_TRIANGLE: + for (it = 0; it < SamplesToDo; it++, offset++) + { + lfo_value_left = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + offset * 4.0f, 4.0f)); + lfo_value_left *= state->depth * state->delay; + lfo_value_left += state->delay; + delay_left = (ALint)(lfo_value_left * state->frequency); + lfo_value_right = 2.0f - fabsf(2.0f - fmodf(state->lfo_coeff * + (offset + state->lfo_disp) * 4.0f, 4.0f)); + lfo_value_right *= state->depth * state->delay; + lfo_value_right += state->delay; + delay_right = (ALint)(lfo_value_right * state->frequency); + + smp = state->SampleBufferLeft[(offset-delay_left) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[0][kt]; + } + state->SampleBufferLeft[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + smp = state->SampleBufferRight[(offset-delay_right) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[1][kt]; + } + state->SampleBufferRight[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + } + break; + case AL_FLANGER_WAVEFORM_SINUSOID: + for (it = 0; it < SamplesToDo; it++, offset++) + { + lfo_value_left = 1.0f + sinf(fmodf(state->lfo_coeff * + offset, 2 * F_PI)); + lfo_value_left *= state->depth * state->delay; + lfo_value_left += state->delay; + delay_left = (ALint)(lfo_value_left * state->frequency); + lfo_value_right = 1.0f + sinf(fmodf(state->lfo_coeff * + (offset + state->lfo_disp), 2 * F_PI)); + lfo_value_right *= state->depth * state->delay; + lfo_value_right += state->delay; + delay_right = (ALint)(lfo_value_right * state->frequency); + + smp = state->SampleBufferLeft[(offset-delay_left) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[0][kt]; + } + state->SampleBufferLeft[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + smp = state->SampleBufferRight[(offset-delay_right) & mask]; + for (kt = 0; kt < MaxChannels; kt++) + { + SamplesOut[kt][it] += smp * state->Gain[1][kt]; + } + state->SampleBufferRight[offset & mask] = (smp + SamplesIn[it]) * state->feedback; + } + break; + } + + state->offset=offset; +} + +ALeffectState *FlangerCreate(void) +{ + ALflangerState *state; + + state = malloc(sizeof(*state)); + if(!state) + return NULL; + + state->state.Destroy = FlangerDestroy; + state->state.DeviceUpdate = FlangerDeviceUpdate; + state->state.Update = FlangerUpdate; + state->state.Process = FlangerProcess; + + state->BufferLength = 0; + state->SampleBufferLeft = NULL; + state->SampleBufferRight = NULL; + state->offset = 0; + + return &state->state; +} + +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/CMakeLists.txt b/CMakeLists.txt index 35ba5651..4d7c5c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -445,9 +445,11 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c ) SET(ALC_OBJS Alc/ALc.c Alc/ALu.c + Alc/alcChorus.c Alc/alcConfig.c Alc/alcDedicated.c Alc/alcEcho.c + Alc/alcFlanger.c Alc/alcModulator.c Alc/alcReverb.c Alc/alcRing.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 4c14b1f7..e39a3d91 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -46,6 +46,8 @@ ALeffectState *ReverbCreate(void); ALeffectState *EchoCreate(void); ALeffectState *ModulatorCreate(void); ALeffectState *DedicatedCreate(void); +ALeffectState *ChorusCreate(void); +ALeffectState *FlangerCreate(void); #define ALeffectState_Destroy(a) ((a)->Destroy((a))) #define ALeffectState_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b))) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 77ff97a8..87dc717d 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -13,6 +13,8 @@ enum { ECHO, MODULATOR, DEDICATED, + CHORUS, + FLANGER, MAX_EFFECTS }; @@ -75,6 +77,24 @@ typedef struct ALeffect ALfloat Gain; } Dedicated; + struct { + ALint Waveform; + ALint Phase; + ALfloat Rate; + ALfloat Depth; + ALfloat Feedback; + ALfloat Delay; + } Chorus; + + struct { + ALint Waveform; + ALint Phase; + ALfloat Rate; + ALfloat Depth; + ALfloat Feedback; + ALfloat Delay; + } Flanger; + void (*SetParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val); void (*SetParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); void (*SetParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); @@ -120,6 +140,15 @@ void reverb_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALin void reverb_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); void reverb_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); +void chorus_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); +void chorus_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); +void chorus_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); +void chorus_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); +void chorus_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val); +void chorus_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals); +void chorus_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); +void chorus_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); + void echo_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); void echo_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); void echo_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); @@ -129,6 +158,15 @@ void echo_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint void echo_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); void echo_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); +void flanger_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); +void flanger_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); +void flanger_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); +void flanger_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); +void flanger_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val); +void flanger_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals); +void flanger_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); +void flanger_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); + void mod_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); void mod_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); void mod_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 23cfa4ac..99e8daf1 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -537,6 +537,16 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e if(!State) err = AL_OUT_OF_MEMORY; } } + else if(newtype == AL_EFFECT_CHORUS && EffectSlot->effect.type != AL_EFFECT_CHORUS) + { + State = ChorusCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + else if(newtype == AL_EFFECT_FLANGER && EffectSlot->effect.type != AL_EFFECT_FLANGER) + { + State = FlangerCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } if(err != AL_NO_ERROR) { diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 2c684626..07bbaa8e 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -470,6 +470,40 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->GetParamf = ded_GetParamf; effect->GetParamfv = ded_GetParamfv; break; + case AL_EFFECT_CHORUS: + effect->Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; + effect->Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; + effect->Chorus.Rate = AL_CHORUS_MAX_RATE; + effect->Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; + effect->Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; + effect->Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; + + effect->SetParami = chorus_SetParami; + effect->SetParamiv = chorus_SetParamiv; + effect->SetParamf = chorus_SetParamf; + effect->SetParamfv = chorus_SetParamfv; + effect->GetParami = chorus_GetParami; + effect->GetParamiv = chorus_GetParamiv; + effect->GetParamf = chorus_GetParamf; + effect->GetParamfv = chorus_GetParamfv; + break; + case AL_EFFECT_FLANGER: + effect->Flanger.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; + effect->Flanger.Phase = AL_FLANGER_DEFAULT_PHASE; + effect->Flanger.Rate = AL_FLANGER_MAX_RATE; + effect->Flanger.Depth = AL_FLANGER_DEFAULT_DEPTH; + effect->Flanger.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; + effect->Flanger.Delay = AL_FLANGER_DEFAULT_DELAY; + + effect->SetParami = flanger_SetParami; + effect->SetParamiv = flanger_SetParamiv; + effect->SetParamf = flanger_SetParamf; + effect->SetParamfv = flanger_SetParamfv; + effect->GetParami = flanger_GetParami; + effect->GetParamiv = flanger_GetParamiv; + effect->GetParamf = flanger_GetParamf; + effect->GetParamfv = flanger_GetParamfv; + break; default: effect->SetParami = null_SetParami; effect->SetParamiv = null_SetParamiv; diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index c73200d0..f22c89e5 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -42,6 +42,8 @@ const struct EffectList EffectList[] = { { "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, + { "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, + { "flanger", FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, { NULL, 0, NULL, (ALenum)0 } }; diff --git a/alsoftrc.sample b/alsoftrc.sample index dd5ae4db..27aee718 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -126,8 +126,8 @@ ## excludefx: # Sets which effects to exclude, preventing apps from using them. This can # help for apps that try to use effects which are too CPU intensive for the -# system to handle. Available effects are: eaxreverb,reverb,echo,modulator, -# dedicated +# system to handle. Available effects are: eaxreverb,reverb,chorus,echo, +# flanger,modulator,dedicated #excludefx = ## slots: |