Pas the output device channel count to ALeffectState::process
[openal-soft.git] / Alc / effects / flanger.c
blob460bb866297d1138181a6154387aa1a966bb51d8
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, ALCdevice *Device, const ALeffectslot *Slot)
96 static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
97 static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
98 ALfloat frequency = (ALfloat)Device->Frequency;
99 ALfloat rate;
100 ALint phase;
102 switch(Slot->EffectProps.Flanger.Waveform)
104 case AL_FLANGER_WAVEFORM_TRIANGLE:
105 state->waveform = FWF_Triangle;
106 break;
107 case AL_FLANGER_WAVEFORM_SINUSOID:
108 state->waveform = FWF_Sinusoid;
109 break;
111 state->depth = Slot->EffectProps.Flanger.Depth;
112 state->feedback = Slot->EffectProps.Flanger.Feedback;
113 state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
115 /* Gains for left and right sides */
116 ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
117 ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
119 phase = Slot->EffectProps.Flanger.Phase;
120 rate = Slot->EffectProps.Flanger.Rate;
121 if(!(rate > 0.0f))
123 state->lfo_scale = 0.0f;
124 state->lfo_range = 1;
125 state->lfo_disp = 0;
127 else
129 /* Calculate LFO coefficient */
130 state->lfo_range = fastf2u(frequency/rate + 0.5f);
131 switch(state->waveform)
133 case FWF_Triangle:
134 state->lfo_scale = 4.0f / state->lfo_range;
135 break;
136 case FWF_Sinusoid:
137 state->lfo_scale = F_2PI / state->lfo_range;
138 break;
141 /* Calculate lfo phase displacement */
142 state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
146 static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
148 ALfloat lfo_value;
150 lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
151 lfo_value *= state->depth * state->delay;
152 *delay_left = fastf2i(lfo_value) + state->delay;
154 offset += state->lfo_disp;
155 lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
156 lfo_value *= state->depth * state->delay;
157 *delay_right = fastf2i(lfo_value) + state->delay;
160 static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
162 ALfloat lfo_value;
164 lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
165 lfo_value *= state->depth * state->delay;
166 *delay_left = fastf2i(lfo_value) + state->delay;
168 offset += state->lfo_disp;
169 lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
170 lfo_value *= state->depth * state->delay;
171 *delay_right = fastf2i(lfo_value) + state->delay;
174 #define DECL_TEMPLATE(Func) \
175 static void Process##Func(ALflangerState *state, const ALuint SamplesToDo, \
176 const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
178 const ALuint bufmask = state->BufferLength-1; \
179 ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
180 ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
181 ALuint offset = state->offset; \
182 const ALfloat feedback = state->feedback; \
183 ALuint it; \
185 for(it = 0;it < SamplesToDo;it++) \
187 ALint delay_left, delay_right; \
188 Func(&delay_left, &delay_right, offset, state); \
190 out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
191 leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
193 out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
194 rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
196 offset++; \
198 state->offset = offset; \
201 DECL_TEMPLATE(Triangle)
202 DECL_TEMPLATE(Sinusoid)
204 #undef DECL_TEMPLATE
206 static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
208 ALuint it, kt;
209 ALuint base;
211 for(base = 0;base < SamplesToDo;)
213 ALfloat temps[64][2];
214 ALuint td = minu(SamplesToDo-base, 64);
216 switch(state->waveform)
218 case FWF_Triangle:
219 ProcessTriangle(state, td, SamplesIn+base, temps);
220 break;
221 case FWF_Sinusoid:
222 ProcessSinusoid(state, td, SamplesIn+base, temps);
223 break;
226 for(kt = 0;kt < NumChannels;kt++)
228 ALfloat gain = state->Gain[0][kt];
229 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
231 for(it = 0;it < td;it++)
232 SamplesOut[kt][it+base] += temps[it][0] * gain;
235 gain = state->Gain[1][kt];
236 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
238 for(it = 0;it < td;it++)
239 SamplesOut[kt][it+base] += temps[it][1] * gain;
243 base += td;
247 DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
249 DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
252 typedef struct ALflangerStateFactory {
253 DERIVE_FROM_TYPE(ALeffectStateFactory);
254 } ALflangerStateFactory;
256 ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
258 ALflangerState *state;
260 state = ALflangerState_New(sizeof(*state));
261 if(!state) return NULL;
262 SET_VTABLE2(ALflangerState, ALeffectState, state);
264 state->BufferLength = 0;
265 state->SampleBuffer[0] = NULL;
266 state->SampleBuffer[1] = NULL;
267 state->offset = 0;
268 state->lfo_range = 1;
269 state->waveform = FWF_Triangle;
271 return STATIC_CAST(ALeffectState, state);
274 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
276 ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
278 static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
280 return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
284 void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
286 ALeffectProps *props = &effect->Props;
287 switch(param)
289 case AL_FLANGER_WAVEFORM:
290 if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
291 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
292 props->Flanger.Waveform = val;
293 break;
295 case AL_FLANGER_PHASE:
296 if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
297 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
298 props->Flanger.Phase = val;
299 break;
301 default:
302 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
305 void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
307 ALflanger_setParami(effect, context, param, vals[0]);
309 void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
311 ALeffectProps *props = &effect->Props;
312 switch(param)
314 case AL_FLANGER_RATE:
315 if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
316 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
317 props->Flanger.Rate = val;
318 break;
320 case AL_FLANGER_DEPTH:
321 if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
322 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
323 props->Flanger.Depth = val;
324 break;
326 case AL_FLANGER_FEEDBACK:
327 if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
328 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
329 props->Flanger.Feedback = val;
330 break;
332 case AL_FLANGER_DELAY:
333 if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
334 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
335 props->Flanger.Delay = val;
336 break;
338 default:
339 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
342 void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
344 ALflanger_setParamf(effect, context, param, vals[0]);
347 void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
349 const ALeffectProps *props = &effect->Props;
350 switch(param)
352 case AL_FLANGER_WAVEFORM:
353 *val = props->Flanger.Waveform;
354 break;
356 case AL_FLANGER_PHASE:
357 *val = props->Flanger.Phase;
358 break;
360 default:
361 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
364 void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
366 ALflanger_getParami(effect, context, param, vals);
368 void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
370 const ALeffectProps *props = &effect->Props;
371 switch(param)
373 case AL_FLANGER_RATE:
374 *val = props->Flanger.Rate;
375 break;
377 case AL_FLANGER_DEPTH:
378 *val = props->Flanger.Depth;
379 break;
381 case AL_FLANGER_FEEDBACK:
382 *val = props->Flanger.Feedback;
383 break;
385 case AL_FLANGER_DELAY:
386 *val = props->Flanger.Delay;
387 break;
389 default:
390 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
393 void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
395 ALflanger_getParamf(effect, context, param, vals);
398 DEFINE_ALEFFECT_VTABLE(ALflanger);