Print whether direct channels are off or on to stdout in alffplay
[openal-soft.git] / Alc / effects / compressor.c
blob1426ea705652d2bcff720acefb93dee7f9b88a67
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[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
36 /* Effect parameters */
37 ALboolean Enabled;
38 ALfloat AttackRate;
39 ALfloat ReleaseRate;
40 ALfloat GainCtrl;
41 } ALcompressorState;
43 static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
44 static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
45 static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
46 static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
47 DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
49 DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
52 static void ALcompressorState_Construct(ALcompressorState *state)
54 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
55 SET_VTABLE2(ALcompressorState, ALeffectState, state);
57 state->Enabled = AL_TRUE;
58 state->AttackRate = 0.0f;
59 state->ReleaseRate = 0.0f;
60 state->GainCtrl = 1.0f;
63 static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
65 ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
68 static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
70 const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
71 const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
73 state->AttackRate = 1.0f / attackTime;
74 state->ReleaseRate = 1.0f / releaseTime;
76 return AL_TRUE;
79 static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
81 aluMatrixf matrix;
82 ALuint i;
84 state->Enabled = props->Compressor.OnOff;
86 aluMatrixfSet(&matrix,
87 1.0f, 0.0f, 0.0f, 0.0f,
88 0.0f, 1.0f, 0.0f, 0.0f,
89 0.0f, 0.0f, 1.0f, 0.0f,
90 0.0f, 0.0f, 0.0f, 1.0f
93 STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
94 STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
95 for(i = 0;i < 4;i++)
96 ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain,
97 state->Gain[i]);
100 static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
102 ALuint i, j, k;
103 ALuint base;
105 for(base = 0;base < SamplesToDo;)
107 ALfloat temps[64][4];
108 ALuint td = minu(64, SamplesToDo-base);
110 /* Load samples into the temp buffer first. */
111 for(j = 0;j < 4;j++)
113 for(i = 0;i < td;i++)
114 temps[i][j] = SamplesIn[j][i+base];
117 if(state->Enabled)
119 ALfloat gain = state->GainCtrl;
120 ALfloat output, amplitude;
122 for(i = 0;i < td;i++)
124 /* Roughly calculate the maximum amplitude from the 4-channel
125 * signal, and attack or release the gain control to reach it.
127 amplitude = fabsf(temps[i][0]);
128 amplitude = maxf(amplitude + fabsf(temps[i][1]),
129 maxf(amplitude + fabsf(temps[i][2]),
130 amplitude + fabsf(temps[i][3])));
131 if(amplitude > gain)
132 gain = minf(gain+state->AttackRate, amplitude);
133 else if(amplitude < gain)
134 gain = maxf(gain-state->ReleaseRate, amplitude);
136 /* Apply the inverse of the gain control to normalize/compress
137 * the volume. */
138 output = 1.0f / clampf(gain, 0.5f, 2.0f);
139 for(j = 0;j < 4;j++)
140 temps[i][j] *= output;
143 state->GainCtrl = gain;
145 else
147 ALfloat gain = state->GainCtrl;
148 ALfloat output, amplitude;
150 for(i = 0;i < td;i++)
152 /* Same as above, except the amplitude is forced to 1. This
153 * helps ensure smooth gain changes when the compressor is
154 * turned on and off.
156 amplitude = 1.0f;
157 if(amplitude > gain)
158 gain = minf(gain+state->AttackRate, amplitude);
159 else if(amplitude < gain)
160 gain = maxf(gain-state->ReleaseRate, amplitude);
162 output = 1.0f / clampf(gain, 0.5f, 2.0f);
163 for(j = 0;j < 4;j++)
164 temps[i][j] *= output;
167 state->GainCtrl = gain;
170 /* Now mix to the output. */
171 for(j = 0;j < 4;j++)
173 for(k = 0;k < NumChannels;k++)
175 ALfloat gain = state->Gain[j][k];
176 if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
177 continue;
179 for(i = 0;i < td;i++)
180 SamplesOut[k][base+i] += gain * temps[i][j];
184 base += td;
189 typedef struct ALcompressorStateFactory {
190 DERIVE_FROM_TYPE(ALeffectStateFactory);
191 } ALcompressorStateFactory;
193 static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
195 ALcompressorState *state;
197 NEW_OBJ0(state, ALcompressorState)();
198 if(!state) return NULL;
200 return STATIC_CAST(ALeffectState, state);
203 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
205 ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
207 static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
209 return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
213 void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
215 ALeffectProps *props = &effect->Props;
216 switch(param)
218 case AL_COMPRESSOR_ONOFF:
219 if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
220 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
221 props->Compressor.OnOff = val;
222 break;
224 default:
225 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
228 void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
230 ALcompressor_setParami(effect, context, param, vals[0]);
232 void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
233 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
234 void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
236 ALcompressor_setParamf(effect, context, param, vals[0]);
239 void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
241 const ALeffectProps *props = &effect->Props;
242 switch(param)
244 case AL_COMPRESSOR_ONOFF:
245 *val = props->Compressor.OnOff;
246 break;
247 default:
248 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
251 void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
253 ALcompressor_getParami(effect, context, param, vals);
255 void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
256 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
257 void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
259 ALcompressor_getParamf(effect, context, param, vals);
262 DEFINE_ALEFFECT_VTABLE(ALcompressor);