diff options
author | Chris Robinson <[email protected]> | 2013-10-03 07:55:12 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2013-10-03 07:55:12 -0700 |
commit | 41175ec84c81a9b04e0f6501024935ae137ca0f3 (patch) | |
tree | 3d698c0b72890814353976dd8ce25faaefc626e7 | |
parent | b9fd3f9eb4f1aac20ff47938539b7fbf76044152 (diff) |
Implement the Compressor effect
-rw-r--r-- | Alc/ALc.c | 36 | ||||
-rw-r--r-- | Alc/effects/compressor.c | 216 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | OpenAL32/Include/alAuxEffectSlot.h | 1 | ||||
-rw-r--r-- | OpenAL32/Include/alEffect.h | 66 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 1 | ||||
-rw-r--r-- | OpenAL32/alEffect.c | 4 | ||||
-rw-r--r-- | OpenAL32/alExtension.c | 1 | ||||
-rw-r--r-- | alsoftrc.sample | 2 |
9 files changed, 279 insertions, 49 deletions
@@ -526,9 +526,7 @@ static const ALCenums enumeration[] = { #endif DECL(AL_EFFECT_RING_MODULATOR), DECL(AL_EFFECT_AUTOWAH), -#if 0 DECL(AL_EFFECT_COMPRESSOR), -#endif DECL(AL_EFFECT_EQUALIZER), DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), DECL(AL_EFFECT_DEDICATED_DIALOGUE), @@ -571,12 +569,6 @@ static const ALCenums enumeration[] = { DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), DECL(AL_REVERB_DECAY_HFLIMIT), - DECL(AL_ECHO_DELAY), - DECL(AL_ECHO_LRDELAY), - DECL(AL_ECHO_DAMPING), - DECL(AL_ECHO_FEEDBACK), - DECL(AL_ECHO_SPREAD), - DECL(AL_CHORUS_WAVEFORM), DECL(AL_CHORUS_PHASE), DECL(AL_CHORUS_RATE), @@ -584,6 +576,18 @@ static const ALCenums enumeration[] = { DECL(AL_CHORUS_FEEDBACK), DECL(AL_CHORUS_DELAY), + DECL(AL_DISTORTION_EDGE), + DECL(AL_DISTORTION_GAIN), + DECL(AL_DISTORTION_LOWPASS_CUTOFF), + DECL(AL_DISTORTION_EQCENTER), + DECL(AL_DISTORTION_EQBANDWIDTH), + + DECL(AL_ECHO_DELAY), + DECL(AL_ECHO_LRDELAY), + DECL(AL_ECHO_DAMPING), + DECL(AL_ECHO_FEEDBACK), + DECL(AL_ECHO_SPREAD), + DECL(AL_FLANGER_WAVEFORM), DECL(AL_FLANGER_PHASE), DECL(AL_FLANGER_RATE), @@ -591,6 +595,12 @@ static const ALCenums enumeration[] = { DECL(AL_FLANGER_FEEDBACK), DECL(AL_FLANGER_DELAY), + DECL(AL_RING_MODULATOR_FREQUENCY), + DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), + DECL(AL_RING_MODULATOR_WAVEFORM), + + DECL(AL_COMPRESSOR_ONOFF), + DECL(AL_EQUALIZER_LOW_GAIN), DECL(AL_EQUALIZER_LOW_CUTOFF), DECL(AL_EQUALIZER_MID1_GAIN), @@ -602,16 +612,6 @@ static const ALCenums enumeration[] = { DECL(AL_EQUALIZER_HIGH_GAIN), DECL(AL_EQUALIZER_HIGH_CUTOFF), - DECL(AL_DISTORTION_EDGE), - DECL(AL_DISTORTION_GAIN), - DECL(AL_DISTORTION_LOWPASS_CUTOFF), - DECL(AL_DISTORTION_EQCENTER), - DECL(AL_DISTORTION_EQBANDWIDTH), - - DECL(AL_RING_MODULATOR_FREQUENCY), - DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), - DECL(AL_RING_MODULATOR_WAVEFORM), - DECL(AL_DEDICATED_GAIN), { NULL, (ALCenum)0 } diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c new file mode 100644 index 00000000..6c3ab425 --- /dev/null +++ b/Alc/effects/compressor.c @@ -0,0 +1,216 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Anis A. Hireche + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include <stdlib.h> + +#include "config.h" +#include "alError.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alu.h" + +typedef struct ALcompressorStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALcompressorStateFactory; + +static ALcompressorStateFactory CompressorFactory; + + +typedef struct ALcompressorState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MaxChannels]; + + /* Effect parameters */ + ALboolean Enabled; + ALfloat Envelope; + ALfloat EnvGain; + ALfloat Attack; + ALfloat Release; +} ALcompressorState; + +static ALvoid ALcompressorState_Destruct(ALcompressorState *state) +{ + (void)state; +} + +static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device) +{ + state->Attack = expf(-1.0f / (device->Frequency * 0.0001f)); + state->Release = expf(-1.0f / (device->Frequency * 0.3f)); + state->Envelope = 0.0f; + state->EnvGain = 1.0f; + + return AL_TRUE; +} + +static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALfloat gain; + + state->Enabled = Slot->EffectProps.Compressor.OnOff; + /* FIXME: Could maybe use the compressor's attack/release to move the gain to 1? */ + if(!state->Enabled) + state->EnvGain = 1.0f; + + gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; + SetGains(Device, gain, state->Gain); +} + +static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE]) +{ + ALfloat env = state->Envelope; + ALfloat envgain = state->EnvGain; + ALfloat tattack = state->Attack; + ALfloat trelease = state->Release; + ALuint it, kt; + ALuint base; + ALfloat theta; + ALfloat rms; + + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); + ALfloat summ = 0.0f; + + for(it = 0;it < td;it++) + { + ALfloat smp = SamplesIn[it+base] * 0.5f; + summ += smp * smp; + temps[it] = smp; + } + + if(state->Enabled) + { + const ALfloat threshold = 0.5f; + const ALfloat slope = 0.5f; + + /* computing rms and envelope */ + rms = sqrtf(summ / td); + theta = ((rms > env) ? tattack : trelease); + env = (1.0f - theta)*rms + theta*env; + + /* applying a hard-knee rms based compressor */ + if(env > threshold) + envgain = envgain - (env - threshold) * slope; + } + + for(kt = 0;kt < MaxChannels;kt++) + { + ALfloat gain = state->Gain[kt] * envgain * 2.0f; + if(!(gain > 0.00001f)) + continue; + + for(it = 0;it < td;it++) + SamplesOut[kt][base+it] += gain * temps[it]; + } + + base += td; + } + + state->Envelope = env; + state->EnvGain = envgain; +} + +static void ALcompressorState_Delete(ALcompressorState *state) +{ + free(state); +} + +DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); + + +static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *factory) +{ + ALcompressorState *state; + (void)factory; + + state = malloc(sizeof(*state)); + if(!state) return NULL; + SET_VTABLE2(ALcompressorState, ALeffectState, state); + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory); + +ALeffectStateFactory *ALcompressorStateFactory_getFactory(void) +{ + SET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory, &CompressorFactory); + return STATIC_CAST(ALeffectStateFactory, &CompressorFactory); +} + + +void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_COMPRESSOR_ONOFF: + if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) + SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + props->Compressor.OnOff = val; + break; + + default: + SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + } +} + +void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALcompressor_setParami(effect, context, param, vals[0]); +} + +void ALcompressor_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val;} + +void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALcompressor_setParamf(effect, context, param, vals[0]); +} + +void ALcompressor_getParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_COMPRESSOR_ONOFF: + *val = props->Compressor.OnOff; + break; + default: + SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + } +} +void ALcompressor_getParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALcompressor_getParami(effect, context, param, vals); +} +void ALcompressor_getParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); (void)effect;(void)param;(void)val;} + +void ALcompressor_getParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALcompressor_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALcompressor); diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b9d3ba4..44903eb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -474,6 +474,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/bs2b.c Alc/effects/autowah.c Alc/effects/chorus.c + Alc/effects/compressor.c Alc/effects/dedicated.c Alc/effects/distortion.c Alc/effects/echo.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 00de7a3b..945860a0 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -98,6 +98,7 @@ ALeffectStateFactory *ALnullStateFactory_getFactory(void); ALeffectStateFactory *ALreverbStateFactory_getFactory(void); ALeffectStateFactory *ALautowahStateFactory_getFactory(void); ALeffectStateFactory *ALchorusStateFactory_getFactory(void); +ALeffectStateFactory *ALcompressorStateFactory_getFactory(void); ALeffectStateFactory *ALdistortionStateFactory_getFactory(void); ALeffectStateFactory *ALechoStateFactory_getFactory(void); ALeffectStateFactory *ALequalizerStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 7269c13e..89fa5381 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -14,6 +14,7 @@ enum { REVERB, AUTOWAH, CHORUS, + COMPRESSOR, DISTORTION, ECHO, EQUALIZER, @@ -52,6 +53,7 @@ extern const struct ALeffectVtable ALeaxreverb_vtable; extern const struct ALeffectVtable ALreverb_vtable; extern const struct ALeffectVtable ALautowah_vtable; extern const struct ALeffectVtable ALchorus_vtable; +extern const struct ALeffectVtable ALcompressor_vtable; extern const struct ALeffectVtable ALdistortion_vtable; extern const struct ALeffectVtable ALecho_vtable; extern const struct ALeffectVtable ALequalizer_vtable; @@ -99,42 +101,35 @@ typedef union ALeffectProps { } Autowah; struct { - ALfloat Delay; - ALfloat LRDelay; - - ALfloat Damping; + ALint Waveform; + ALint Phase; + ALfloat Rate; + ALfloat Depth; ALfloat Feedback; - - ALfloat Spread; - } Echo; + ALfloat Delay; + } Chorus; struct { - ALfloat Frequency; - ALfloat HighPassCutoff; - ALint Waveform; - } Modulator; + ALboolean OnOff; + } Compressor; struct { + ALfloat Edge; ALfloat Gain; - } Dedicated; + ALfloat LowpassCutoff; + ALfloat EQCenter; + ALfloat EQBandwidth; + } Distortion; struct { - ALint Waveform; - ALint Phase; - ALfloat Rate; - ALfloat Depth; - ALfloat Feedback; ALfloat Delay; - } Chorus; + ALfloat LRDelay; - struct { - ALint Waveform; - ALint Phase; - ALfloat Rate; - ALfloat Depth; + ALfloat Damping; ALfloat Feedback; - ALfloat Delay; - } Flanger; + + ALfloat Spread; + } Echo; struct { ALfloat Delay; @@ -151,12 +146,23 @@ typedef union ALeffectProps { } Equalizer; struct { - ALfloat Edge; + ALint Waveform; + ALint Phase; + ALfloat Rate; + ALfloat Depth; + ALfloat Feedback; + ALfloat Delay; + } Flanger; + + struct { + ALfloat Frequency; + ALfloat HighPassCutoff; + ALint Waveform; + } Modulator; + + struct { ALfloat Gain; - ALfloat LowpassCutoff; - ALfloat EQCenter; - ALfloat EQBandwidth; - } Distortion; + } Dedicated; } ALeffectProps; typedef struct ALeffect { diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 827820eb..5fde2d3d 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -459,6 +459,7 @@ void InitEffectFactoryMap(void) InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory); + InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index ed6a1d5a..ca908a40 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -429,6 +429,10 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; effect->vtbl = &ALchorus_vtable; break; + case AL_EFFECT_COMPRESSOR: + effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; + effect->vtbl = &ALcompressor_vtable; + break; case AL_EFFECT_DISTORTION: effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 236e56d0..785f172e 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -40,6 +40,7 @@ const struct EffectList EffectList[] = { { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, { "autowah", AUTOWAH, "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH }, { "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, + { "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, { "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, { "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, { "equalizer", EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, diff --git a/alsoftrc.sample b/alsoftrc.sample index 656f1bf0..bb5bb088 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -127,7 +127,7 @@ # Sets which effects to exclude, preventing apps from using them. This can # help for apps that try to use effects which are too CPU intensive for the # system to handle. Available effects are: eaxreverb,reverb,autowah,chorus, -# distortion,echo,equalizer,flanger,modulator,dedicated +# compressor,distortion,echo,equalizer,flanger,modulator,dedicated #excludefx = ## slots: |