Avoid taking the square-root of the ambient gain
[openal-soft.git] / Alc / effects / compressor.c
blob9554a0f2620dc0c256f456ed4932e15792f7a9c1
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2013 by Anis A. Hireche
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include <stdlib.h>
23 #include "config.h"
24 #include "alError.h"
25 #include "alMain.h"
26 #include "alAuxEffectSlot.h"
27 #include "alu.h"
30 typedef struct ALcompressorState {
31 DERIVE_FROM_TYPE(ALeffectState);
33 /* Effect gains for each channel */
34 ALfloat Gain[MaxChannels];
36 /* Effect parameters */
37 ALboolean Enabled;
38 ALfloat AttackRate;
39 ALfloat ReleaseRate;
40 ALfloat GainCtrl;
41 } ALcompressorState;
43 static ALvoid ALcompressorState_Destruct(ALcompressorState *UNUSED(state))
47 static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
49 const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
50 const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
52 state->AttackRate = 1.0f / attackTime;
53 state->ReleaseRate = 1.0f / releaseTime;
55 return AL_TRUE;
58 static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot)
60 ALfloat gain;
62 state->Enabled = Slot->EffectProps.Compressor.OnOff;
64 gain = 1.0f/Device->NumSpeakers * Slot->Gain;
65 SetGains(Device, gain, state->Gain);
68 static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
70 ALuint it, kt;
71 ALuint base;
73 for(base = 0;base < SamplesToDo;)
75 ALfloat temps[64];
76 ALuint td = minu(SamplesToDo-base, 64);
78 if(state->Enabled)
80 ALfloat output, smp, amplitude;
81 ALfloat gain = state->GainCtrl;
83 for(it = 0;it < td;it++)
85 smp = SamplesIn[it+base];
87 amplitude = fabsf(smp);
88 if(amplitude > gain)
89 gain = minf(gain+state->AttackRate, amplitude);
90 else if(amplitude < gain)
91 gain = maxf(gain-state->ReleaseRate, amplitude);
92 output = 1.0f / clampf(gain, 0.5f, 2.0f);
94 temps[it] = smp * output;
97 state->GainCtrl = gain;
99 else
101 ALfloat output, smp, amplitude;
102 ALfloat gain = state->GainCtrl;
104 for(it = 0;it < td;it++)
106 smp = SamplesIn[it+base];
108 amplitude = 1.0f;
109 if(amplitude > gain)
110 gain = minf(gain+state->AttackRate, amplitude);
111 else if(amplitude < gain)
112 gain = maxf(gain-state->ReleaseRate, amplitude);
113 output = 1.0f / clampf(gain, 0.5f, 2.0f);
115 temps[it] = smp * output;
118 state->GainCtrl = gain;
122 for(kt = 0;kt < MaxChannels;kt++)
124 ALfloat gain = state->Gain[kt];
125 if(!(gain > GAIN_SILENCE_THRESHOLD))
126 continue;
128 for(it = 0;it < td;it++)
129 SamplesOut[kt][base+it] += gain * temps[it];
132 base += td;
136 DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
138 DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
141 typedef struct ALcompressorStateFactory {
142 DERIVE_FROM_TYPE(ALeffectStateFactory);
143 } ALcompressorStateFactory;
145 static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
147 ALcompressorState *state;
149 state = ALcompressorState_New(sizeof(*state));
150 if(!state) return NULL;
151 SET_VTABLE2(ALcompressorState, ALeffectState, state);
153 state->Enabled = AL_TRUE;
154 state->AttackRate = 0.0f;
155 state->ReleaseRate = 0.0f;
156 state->GainCtrl = 1.0f;
158 return STATIC_CAST(ALeffectState, state);
161 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
163 ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
165 static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
167 return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
171 void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
173 ALeffectProps *props = &effect->Props;
174 switch(param)
176 case AL_COMPRESSOR_ONOFF:
177 if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
178 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
179 props->Compressor.OnOff = val;
180 break;
182 default:
183 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
186 void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
188 ALcompressor_setParami(effect, context, param, vals[0]);
190 void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
191 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
192 void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
194 ALcompressor_setParamf(effect, context, param, vals[0]);
197 void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
199 const ALeffectProps *props = &effect->Props;
200 switch(param)
202 case AL_COMPRESSOR_ONOFF:
203 *val = props->Compressor.OnOff;
204 break;
205 default:
206 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
209 void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
211 ALcompressor_getParami(effect, context, param, vals);
213 void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
214 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
215 void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
217 ALcompressor_getParamf(effect, context, param, vals);
220 DEFINE_ALEFFECT_VTABLE(ALcompressor);