Clean up some messy rounding code
[openal-soft.git] / Alc / effects / flanger.c
blobb25b95cc7aafb85c4deb521c24b82c8c855eaad5
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 ALsizei BufferLength;
43 ALsizei offset;
44 ALsizei 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);
59 static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device);
60 static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
61 static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
62 DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
64 DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
67 static void ALflangerState_Construct(ALflangerState *state)
69 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
70 SET_VTABLE2(ALflangerState, ALeffectState, state);
72 state->BufferLength = 0;
73 state->SampleBuffer[0] = NULL;
74 state->SampleBuffer[1] = NULL;
75 state->offset = 0;
76 state->lfo_range = 1;
77 state->waveform = FWF_Triangle;
80 static ALvoid ALflangerState_Destruct(ALflangerState *state)
82 al_free(state->SampleBuffer[0]);
83 state->SampleBuffer[0] = NULL;
84 state->SampleBuffer[1] = NULL;
86 ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
89 static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
91 ALsizei maxlen;
92 ALsizei it;
94 maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 2.0f * Device->Frequency) + 1;
95 maxlen = NextPowerOf2(maxlen);
97 if(maxlen != state->BufferLength)
99 void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
100 if(!temp) return AL_FALSE;
102 al_free(state->SampleBuffer[0]);
103 state->SampleBuffer[0] = temp;
104 state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
106 state->BufferLength = maxlen;
109 for(it = 0;it < state->BufferLength;it++)
111 state->SampleBuffer[0][it] = 0.0f;
112 state->SampleBuffer[1][it] = 0.0f;
115 return AL_TRUE;
118 static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
120 ALfloat frequency = (ALfloat)Device->Frequency;
121 ALfloat coeffs[MAX_AMBI_COEFFS];
122 ALfloat rate;
123 ALint phase;
125 switch(props->Flanger.Waveform)
127 case AL_FLANGER_WAVEFORM_TRIANGLE:
128 state->waveform = FWF_Triangle;
129 break;
130 case AL_FLANGER_WAVEFORM_SINUSOID:
131 state->waveform = FWF_Sinusoid;
132 break;
134 state->feedback = props->Flanger.Feedback;
135 state->delay = fastf2i(props->Flanger.Delay * frequency);
136 /* The LFO depth is scaled to be relative to the sample delay. */
137 state->depth = props->Flanger.Depth * state->delay;
139 /* Gains for left and right sides */
140 CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
141 ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
142 CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
143 ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
145 phase = props->Flanger.Phase;
146 rate = props->Flanger.Rate;
147 if(!(rate > 0.0f))
149 state->lfo_scale = 0.0f;
150 state->lfo_range = 1;
151 state->lfo_disp = 0;
153 else
155 /* Calculate LFO coefficient */
156 state->lfo_range = fastf2i(frequency/rate + 0.5f);
157 switch(state->waveform)
159 case FWF_Triangle:
160 state->lfo_scale = 4.0f / state->lfo_range;
161 break;
162 case FWF_Sinusoid:
163 state->lfo_scale = F_TAU / state->lfo_range;
164 break;
167 /* Calculate lfo phase displacement */
168 if(phase >= 0)
169 state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
170 else
171 state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f));
175 static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
176 const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
177 const ALsizei todo)
179 ALsizei i;
180 for(i = 0;i < todo;i++)
182 delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
183 offset = (offset+1)%lfo_range;
187 static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
188 const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
189 const ALsizei todo)
191 ALsizei i;
192 for(i = 0;i < todo;i++)
194 delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
195 offset = (offset+1)%lfo_range;
199 static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
201 ALfloat *restrict leftbuf = state->SampleBuffer[0];
202 ALfloat *restrict rightbuf = state->SampleBuffer[1];
203 const ALsizei bufmask = state->BufferLength-1;
204 const ALfloat feedback = state->feedback;
205 ALsizei offset = state->offset;
206 ALsizei i, c;
207 ALsizei base;
209 for(base = 0;base < SamplesToDo;)
211 const ALsizei todo = mini(128, SamplesToDo-base);
212 ALfloat temps[128][2];
213 ALint moddelays[2][128];
215 switch(state->waveform)
217 case FWF_Triangle:
218 GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
219 state->lfo_scale, state->depth, state->delay, todo);
220 GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
221 state->lfo_range, state->lfo_scale, state->depth, state->delay,
222 todo);
223 break;
224 case FWF_Sinusoid:
225 GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
226 state->lfo_scale, state->depth, state->delay, todo);
227 GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
228 state->lfo_range, state->lfo_scale, state->depth, state->delay,
229 todo);
230 break;
233 for(i = 0;i < todo;i++)
235 leftbuf[offset&bufmask] = SamplesIn[0][base+i];
236 temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
237 leftbuf[offset&bufmask] += temps[i][0];
239 rightbuf[offset&bufmask] = SamplesIn[0][base+i];
240 temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
241 rightbuf[offset&bufmask] += temps[i][1];
243 offset++;
246 for(c = 0;c < NumChannels;c++)
248 ALfloat gain = state->Gain[0][c];
249 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
251 for(i = 0;i < todo;i++)
252 SamplesOut[c][i+base] += temps[i][0] * gain;
255 gain = state->Gain[1][c];
256 if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
258 for(i = 0;i < todo;i++)
259 SamplesOut[c][i+base] += temps[i][1] * gain;
263 base += todo;
266 state->offset = offset;
270 typedef struct ALflangerStateFactory {
271 DERIVE_FROM_TYPE(ALeffectStateFactory);
272 } ALflangerStateFactory;
274 ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
276 ALflangerState *state;
278 NEW_OBJ0(state, ALflangerState)();
279 if(!state) return NULL;
281 return STATIC_CAST(ALeffectState, state);
284 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
286 ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
288 static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
290 return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
294 void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
296 ALeffectProps *props = &effect->Props;
297 switch(param)
299 case AL_FLANGER_WAVEFORM:
300 if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
301 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
302 props->Flanger.Waveform = val;
303 break;
305 case AL_FLANGER_PHASE:
306 if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
307 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
308 props->Flanger.Phase = val;
309 break;
311 default:
312 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
315 void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
317 ALflanger_setParami(effect, context, param, vals[0]);
319 void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
321 ALeffectProps *props = &effect->Props;
322 switch(param)
324 case AL_FLANGER_RATE:
325 if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
326 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
327 props->Flanger.Rate = val;
328 break;
330 case AL_FLANGER_DEPTH:
331 if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
332 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
333 props->Flanger.Depth = val;
334 break;
336 case AL_FLANGER_FEEDBACK:
337 if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
338 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
339 props->Flanger.Feedback = val;
340 break;
342 case AL_FLANGER_DELAY:
343 if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
344 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
345 props->Flanger.Delay = val;
346 break;
348 default:
349 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
352 void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
354 ALflanger_setParamf(effect, context, param, vals[0]);
357 void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
359 const ALeffectProps *props = &effect->Props;
360 switch(param)
362 case AL_FLANGER_WAVEFORM:
363 *val = props->Flanger.Waveform;
364 break;
366 case AL_FLANGER_PHASE:
367 *val = props->Flanger.Phase;
368 break;
370 default:
371 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
374 void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
376 ALflanger_getParami(effect, context, param, vals);
378 void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
380 const ALeffectProps *props = &effect->Props;
381 switch(param)
383 case AL_FLANGER_RATE:
384 *val = props->Flanger.Rate;
385 break;
387 case AL_FLANGER_DEPTH:
388 *val = props->Flanger.Depth;
389 break;
391 case AL_FLANGER_FEEDBACK:
392 *val = props->Flanger.Feedback;
393 break;
395 case AL_FLANGER_DELAY:
396 *val = props->Flanger.Delay;
397 break;
399 default:
400 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
403 void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
405 ALflanger_getParamf(effect, context, param, vals);
408 DEFINE_ALEFFECT_VTABLE(ALflanger);