Improve radius behavior with scaling of ambisonic coefficients
[openal-soft.git] / Alc / effects / flanger.c
bloba71eb9c2229c6853ca85290ef8f6c6915f791e73
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 enum FlangerWaveForm {
34 FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
35 FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
38 typedef struct ALflangerState {
39 DERIVE_FROM_TYPE(ALeffectState);
41 ALfloat *SampleBuffer[2];
42 ALuint BufferLength;
43 ALuint offset;
44 ALuint lfo_range;
45 ALfloat lfo_scale;
46 ALint lfo_disp;
48 /* Gains for left and right sides */
49 ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
51 /* effect parameters */
52 enum FlangerWaveForm waveform;
53 ALint delay;
54 ALfloat depth;
55 ALfloat feedback;
56 } ALflangerState;
58 static ALvoid ALflangerState_Destruct(ALflangerState *state)
60 free(state->SampleBuffer[0]);
61 state->SampleBuffer[0] = NULL;
62 state->SampleBuffer[1] = NULL;
65 static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
67 ALuint maxlen;
68 ALuint it;
70 maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1;
71 maxlen = NextPowerOf2(maxlen);
73 if(maxlen != state->BufferLength)
75 void *temp;
77 temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2);
78 if(!temp) return AL_FALSE;
79 state->SampleBuffer[0] = temp;
80 state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
82 state->BufferLength = maxlen;
85 for(it = 0;it < state->BufferLength;it++)
87 state->SampleBuffer[0][it] = 0.0f;
88 state->SampleBuffer[1][it] = 0.0f;
91 return AL_TRUE;
94 static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot)
96 ALfloat frequency = (ALfloat)Device->Frequency;
97 ALfloat coeffs[MAX_AMBI_COEFFS];
98 ALfloat rate;
99 ALint phase;
101 switch(Slot->EffectProps.Flanger.Waveform)
103 case AL_FLANGER_WAVEFORM_TRIANGLE:
104 state->waveform = FWF_Triangle;
105 break;
106 case AL_FLANGER_WAVEFORM_SINUSOID:
107 state->waveform = FWF_Sinusoid;
108 break;
110 state->depth = Slot->EffectProps.Flanger.Depth;
111 state->feedback = Slot->EffectProps.Flanger.Feedback;
112 state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
114 /* Gains for left and right sides */
115 CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
116 ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]);
117 CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
118 ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]);
120 phase = Slot->EffectProps.Flanger.Phase;
121 rate = Slot->EffectProps.Flanger.Rate;
122 if(!(rate > 0.0f))
124 state->lfo_scale = 0.0f;
125 state->lfo_range = 1;
126 state->lfo_disp = 0;
128 else
130 /* Calculate LFO coefficient */
131 state->lfo_range = fastf2u(frequency/rate + 0.5f);
132 switch(state->waveform)
134 case FWF_Triangle:
135 state->lfo_scale = 4.0f / state->lfo_range;
136 break;
137 case FWF_Sinusoid:
138 state->lfo_scale = F_TAU / state->lfo_range;
139 break;
142 /* Calculate lfo phase displacement */
143 state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
147 static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
149 ALfloat lfo_value;
151 lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
152 lfo_value *= state->depth * state->delay;
153 *delay_left = fastf2i(lfo_value) + state->delay;
155 offset += state->lfo_disp;
156 lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
157 lfo_value *= state->depth * state->delay;
158 *delay_right = fastf2i(lfo_value) + state->delay;
161 static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
163 ALfloat lfo_value;
165 lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
166 lfo_value *= state->depth * state->delay;
167 *delay_left = fastf2i(lfo_value) + state->delay;
169 offset += state->lfo_disp;
170 lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
171 lfo_value *= state->depth * state->delay;
172 *delay_right = fastf2i(lfo_value) + state->delay;
175 #define DECL_TEMPLATE(Func) \
176 static void Process##Func(ALflangerState *state, const ALuint SamplesToDo, \
177 const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
179 const ALuint bufmask = state->BufferLength-1; \
180 ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
181 ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
182 ALuint offset = state->offset; \
183 const ALfloat feedback = state->feedback; \
184 ALuint it; \
186 for(it = 0;it < SamplesToDo;it++) \
188 ALint delay_left, delay_right; \
189 Func(&delay_left, &delay_right, offset, state); \
191 out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
192 leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
194 out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
195 rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
197 offset++; \
199 state->offset = offset; \
202 DECL_TEMPLATE(Triangle)
203 DECL_TEMPLATE(Sinusoid)
205 #undef DECL_TEMPLATE
207 static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
209 ALuint it, kt;
210 ALuint base;
212 for(base = 0;base < SamplesToDo;)
214 ALfloat temps[128][2];
215 ALuint td = minu(128, SamplesToDo-base);
217 switch(state->waveform)
219 case FWF_Triangle:
220 ProcessTriangle(state, td, SamplesIn[0]+base, temps);
221 break;
222 case FWF_Sinusoid:
223 ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
224 break;
227 for(kt = 0;kt < NumChannels;kt++)
229 ALfloat gain = state->Gain[0][kt];
230 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
232 for(it = 0;it < td;it++)
233 SamplesOut[kt][it+base] += temps[it][0] * gain;
236 gain = state->Gain[1][kt];
237 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
239 for(it = 0;it < td;it++)
240 SamplesOut[kt][it+base] += temps[it][1] * gain;
244 base += td;
248 DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
250 DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
253 typedef struct ALflangerStateFactory {
254 DERIVE_FROM_TYPE(ALeffectStateFactory);
255 } ALflangerStateFactory;
257 ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
259 ALflangerState *state;
261 state = ALflangerState_New(sizeof(*state));
262 if(!state) return NULL;
263 SET_VTABLE2(ALflangerState, ALeffectState, state);
265 state->BufferLength = 0;
266 state->SampleBuffer[0] = NULL;
267 state->SampleBuffer[1] = NULL;
268 state->offset = 0;
269 state->lfo_range = 1;
270 state->waveform = FWF_Triangle;
272 return STATIC_CAST(ALeffectState, state);
275 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
277 ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
279 static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
281 return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
285 void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
287 ALeffectProps *props = &effect->Props;
288 switch(param)
290 case AL_FLANGER_WAVEFORM:
291 if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
292 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
293 props->Flanger.Waveform = val;
294 break;
296 case AL_FLANGER_PHASE:
297 if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
298 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
299 props->Flanger.Phase = val;
300 break;
302 default:
303 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
306 void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
308 ALflanger_setParami(effect, context, param, vals[0]);
310 void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
312 ALeffectProps *props = &effect->Props;
313 switch(param)
315 case AL_FLANGER_RATE:
316 if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
317 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
318 props->Flanger.Rate = val;
319 break;
321 case AL_FLANGER_DEPTH:
322 if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
323 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
324 props->Flanger.Depth = val;
325 break;
327 case AL_FLANGER_FEEDBACK:
328 if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
329 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
330 props->Flanger.Feedback = val;
331 break;
333 case AL_FLANGER_DELAY:
334 if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
335 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
336 props->Flanger.Delay = val;
337 break;
339 default:
340 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
343 void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
345 ALflanger_setParamf(effect, context, param, vals[0]);
348 void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
350 const ALeffectProps *props = &effect->Props;
351 switch(param)
353 case AL_FLANGER_WAVEFORM:
354 *val = props->Flanger.Waveform;
355 break;
357 case AL_FLANGER_PHASE:
358 *val = props->Flanger.Phase;
359 break;
361 default:
362 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
365 void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
367 ALflanger_getParami(effect, context, param, vals);
369 void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
371 const ALeffectProps *props = &effect->Props;
372 switch(param)
374 case AL_FLANGER_RATE:
375 *val = props->Flanger.Rate;
376 break;
378 case AL_FLANGER_DEPTH:
379 *val = props->Flanger.Depth;
380 break;
382 case AL_FLANGER_FEEDBACK:
383 *val = props->Flanger.Feedback;
384 break;
386 case AL_FLANGER_DELAY:
387 *val = props->Flanger.Delay;
388 break;
390 default:
391 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
394 void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
396 ALflanger_getParamf(effect, context, param, vals);
399 DEFINE_ALEFFECT_VTABLE(ALflanger);