Don't trace for every GetDriverIndexForName call
[openal-soft.git] / Alc / effects / distortion.c
blob4619894dd91233ff2f2dcc2ad461c1d1bd5c055e
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2013 by Mike Gorchak
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 "config.h"
23 #include <math.h>
24 #include <stdlib.h>
26 #include "alMain.h"
27 #include "alFilter.h"
28 #include "alAuxEffectSlot.h"
29 #include "alError.h"
30 #include "alu.h"
33 typedef struct ALdistortionState {
34 DERIVE_FROM_TYPE(ALeffectState);
36 /* Effect gains for each channel */
37 ALfloat Gain[MAX_OUTPUT_CHANNELS];
39 /* Effect parameters */
40 ALfilterState lowpass;
41 ALfilterState bandpass;
42 ALfloat attenuation;
43 ALfloat edge_coeff;
44 } ALdistortionState;
46 static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
47 static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
48 static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
49 static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
50 DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
52 DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
55 static void ALdistortionState_Construct(ALdistortionState *state)
57 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
58 SET_VTABLE2(ALdistortionState, ALeffectState, state);
60 ALfilterState_clear(&state->lowpass);
61 ALfilterState_clear(&state->bandpass);
64 static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
66 ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
69 static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
71 return AL_TRUE;
74 static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
76 ALfloat frequency = (ALfloat)Device->Frequency;
77 ALfloat bandwidth;
78 ALfloat cutoff;
79 ALfloat edge;
81 /* Store distorted signal attenuation settings. */
82 state->attenuation = props->Distortion.Gain;
84 /* Store waveshaper edge settings. */
85 edge = sinf(props->Distortion.Edge * (F_PI_2));
86 edge = minf(edge, 0.99f);
87 state->edge_coeff = 2.0f * edge / (1.0f-edge);
89 cutoff = props->Distortion.LowpassCutoff;
90 /* Bandwidth value is constant in octaves. */
91 bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
92 /* Multiply sampling frequency by the amount of oversampling done during
93 * processing.
95 ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
96 cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
99 cutoff = props->Distortion.EQCenter;
100 /* Convert bandwidth in Hz to octaves. */
101 bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
102 ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
103 cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
106 ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain);
109 static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
111 const ALfloat fc = state->edge_coeff;
112 ALsizei it, kt;
113 ALsizei base;
115 for(base = 0;base < SamplesToDo;)
117 float buffer[2][64 * 4];
118 ALsizei td = mini(64, SamplesToDo-base);
120 /* Perform 4x oversampling to avoid aliasing. Oversampling greatly
121 * improves distortion quality and allows to implement lowpass and
122 * bandpass filters using high frequencies, at which classic IIR
123 * filters became unstable.
126 /* Fill oversample buffer using zero stuffing. */
127 for(it = 0;it < td;it++)
129 /* Multiply the sample by the amount of oversampling to maintain
130 * the signal's power.
132 buffer[0][it*4 + 0] = SamplesIn[0][it+base] * 4.0f;
133 buffer[0][it*4 + 1] = 0.0f;
134 buffer[0][it*4 + 2] = 0.0f;
135 buffer[0][it*4 + 3] = 0.0f;
138 /* First step, do lowpass filtering of original signal. Additionally
139 * perform buffer interpolation and lowpass cutoff for oversampling
140 * (which is fortunately first step of distortion). So combine three
141 * operations into the one.
143 ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4);
145 /* Second step, do distortion using waveshaper function to emulate
146 * signal processing during tube overdriving. Three steps of
147 * waveshaping are intended to modify waveform without boost/clipping/
148 * attenuation process.
150 for(it = 0;it < td*4;it++)
152 ALfloat smp = buffer[1][it];
154 smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
155 smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
156 smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
158 buffer[0][it] = smp;
161 /* Third step, do bandpass filtering of distorted signal. */
162 ALfilterState_process(&state->bandpass, buffer[1], buffer[0], td*4);
164 for(kt = 0;kt < NumChannels;kt++)
166 /* Fourth step, final, do attenuation and perform decimation,
167 * store only one sample out of 4.
169 ALfloat gain = state->Gain[kt] * state->attenuation;
170 if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
171 continue;
173 for(it = 0;it < td;it++)
174 SamplesOut[kt][base+it] += gain * buffer[1][it*4];
177 base += td;
182 typedef struct ALdistortionStateFactory {
183 DERIVE_FROM_TYPE(ALeffectStateFactory);
184 } ALdistortionStateFactory;
186 static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
188 ALdistortionState *state;
190 NEW_OBJ0(state, ALdistortionState)();
191 if(!state) return NULL;
193 return STATIC_CAST(ALeffectState, state);
196 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
199 ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
201 static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
203 return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
207 void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
208 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
209 void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
211 ALdistortion_setParami(effect, context, param, vals[0]);
213 void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
215 ALeffectProps *props = &effect->Props;
216 switch(param)
218 case AL_DISTORTION_EDGE:
219 if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
220 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
221 props->Distortion.Edge = val;
222 break;
224 case AL_DISTORTION_GAIN:
225 if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
226 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
227 props->Distortion.Gain = val;
228 break;
230 case AL_DISTORTION_LOWPASS_CUTOFF:
231 if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
232 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
233 props->Distortion.LowpassCutoff = val;
234 break;
236 case AL_DISTORTION_EQCENTER:
237 if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
238 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
239 props->Distortion.EQCenter = val;
240 break;
242 case AL_DISTORTION_EQBANDWIDTH:
243 if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
244 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
245 props->Distortion.EQBandwidth = val;
246 break;
248 default:
249 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
252 void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
254 ALdistortion_setParamf(effect, context, param, vals[0]);
257 void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
258 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
259 void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
261 ALdistortion_getParami(effect, context, param, vals);
263 void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
265 const ALeffectProps *props = &effect->Props;
266 switch(param)
268 case AL_DISTORTION_EDGE:
269 *val = props->Distortion.Edge;
270 break;
272 case AL_DISTORTION_GAIN:
273 *val = props->Distortion.Gain;
274 break;
276 case AL_DISTORTION_LOWPASS_CUTOFF:
277 *val = props->Distortion.LowpassCutoff;
278 break;
280 case AL_DISTORTION_EQCENTER:
281 *val = props->Distortion.EQCenter;
282 break;
284 case AL_DISTORTION_EQBANDWIDTH:
285 *val = props->Distortion.EQBandwidth;
286 break;
288 default:
289 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
292 void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
294 ALdistortion_getParamf(effect, context, param, vals);
297 DEFINE_ALEFFECT_VTABLE(ALdistortion);