EFX: Align some arrays used in intrinsics (#180)
[openal-soft.git] / Alc / effects / chorus.c
blob3710d936c6151845b45812806470632aa01fb974
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 "alAuxEffectSlot.h"
28 #include "alError.h"
29 #include "alu.h"
30 #include "filters/defs.h"
33 static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
34 static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
36 enum WaveForm {
37 WF_Sinusoid,
38 WF_Triangle
41 typedef struct ALchorusState {
42 DERIVE_FROM_TYPE(ALeffectState);
44 ALfloat *SampleBuffer;
45 ALsizei BufferLength;
46 ALsizei offset;
48 ALsizei lfo_offset;
49 ALsizei lfo_range;
50 ALfloat lfo_scale;
51 ALint lfo_disp;
53 /* Gains for left and right sides */
54 struct {
55 ALfloat Current[MAX_OUTPUT_CHANNELS];
56 ALfloat Target[MAX_OUTPUT_CHANNELS];
57 } Gains[2];
59 /* effect parameters */
60 enum WaveForm waveform;
61 ALint delay;
62 ALfloat depth;
63 ALfloat feedback;
64 } ALchorusState;
66 static ALvoid ALchorusState_Destruct(ALchorusState *state);
67 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
68 static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
69 static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
70 DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
72 DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
75 static void ALchorusState_Construct(ALchorusState *state)
77 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
78 SET_VTABLE2(ALchorusState, ALeffectState, state);
80 state->BufferLength = 0;
81 state->SampleBuffer = NULL;
82 state->offset = 0;
83 state->lfo_offset = 0;
84 state->lfo_range = 1;
85 state->waveform = WF_Triangle;
88 static ALvoid ALchorusState_Destruct(ALchorusState *state)
90 al_free(state->SampleBuffer);
91 state->SampleBuffer = NULL;
93 ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
96 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
98 const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY);
99 ALsizei maxlen;
101 maxlen = NextPowerOf2(fastf2i(max_delay*2.0f*Device->Frequency) + 1);
102 if(maxlen <= 0) return AL_FALSE;
104 if(maxlen != state->BufferLength)
106 void *temp = al_calloc(16, maxlen * sizeof(ALfloat));
107 if(!temp) return AL_FALSE;
109 al_free(state->SampleBuffer);
110 state->SampleBuffer = temp;
112 state->BufferLength = maxlen;
115 memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat));
116 memset(state->Gains, 0, sizeof(state->Gains));
118 return AL_TRUE;
121 static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
123 const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS;
124 const ALCdevice *device = Context->Device;
125 ALfloat frequency = (ALfloat)device->Frequency;
126 ALfloat coeffs[MAX_AMBI_COEFFS];
127 ALfloat rate;
128 ALint phase;
130 switch(props->Chorus.Waveform)
132 case AL_CHORUS_WAVEFORM_TRIANGLE:
133 state->waveform = WF_Triangle;
134 break;
135 case AL_CHORUS_WAVEFORM_SINUSOID:
136 state->waveform = WF_Sinusoid;
137 break;
140 /* The LFO depth is scaled to be relative to the sample delay. Clamp the
141 * delay and depth to allow enough padding for resampling.
143 state->delay = maxi(fastf2i(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f),
144 mindelay);
145 state->depth = minf(props->Chorus.Depth * state->delay,
146 (ALfloat)(state->delay - mindelay));
148 state->feedback = props->Chorus.Feedback;
150 /* Gains for left and right sides */
151 CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
152 ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target);
153 CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
154 ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target);
156 phase = props->Chorus.Phase;
157 rate = props->Chorus.Rate;
158 if(!(rate > 0.0f))
160 state->lfo_offset = 0;
161 state->lfo_range = 1;
162 state->lfo_scale = 0.0f;
163 state->lfo_disp = 0;
165 else
167 /* Calculate LFO coefficient (number of samples per cycle). Limit the
168 * max range to avoid overflow when calculating the displacement.
170 ALsizei lfo_range = mini(fastf2i(frequency/rate + 0.5f), INT_MAX/360 - 180);
172 state->lfo_offset = fastf2i((ALfloat)state->lfo_offset/state->lfo_range*
173 lfo_range + 0.5f) % lfo_range;
174 state->lfo_range = lfo_range;
175 switch(state->waveform)
177 case WF_Triangle:
178 state->lfo_scale = 4.0f / state->lfo_range;
179 break;
180 case WF_Sinusoid:
181 state->lfo_scale = F_TAU / state->lfo_range;
182 break;
185 /* Calculate lfo phase displacement */
186 if(phase < 0) phase = 360 + phase;
187 state->lfo_disp = (state->lfo_range*phase + 180) / 360;
191 static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
192 const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
193 const ALsizei todo)
195 ALsizei i;
196 for(i = 0;i < todo;i++)
198 delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
199 offset = (offset+1)%lfo_range;
203 static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
204 const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
205 const ALsizei todo)
207 ALsizei i;
208 for(i = 0;i < todo;i++)
210 delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
211 offset = (offset+1)%lfo_range;
216 static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
218 const ALsizei bufmask = state->BufferLength-1;
219 const ALfloat feedback = state->feedback;
220 const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS;
221 ALfloat *restrict delaybuf = state->SampleBuffer;
222 ALsizei offset = state->offset;
223 ALsizei i, c;
224 ALsizei base;
226 for(base = 0;base < SamplesToDo;)
228 const ALsizei todo = mini(256, SamplesToDo-base);
229 ALint moddelays[2][256];
230 alignas(16) ALfloat temps[2][256];
232 if(state->waveform == WF_Sinusoid)
234 GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale,
235 state->depth, state->delay, todo);
236 GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range,
237 state->lfo_range, state->lfo_scale, state->depth, state->delay,
238 todo);
240 else /*if(state->waveform == WF_Triangle)*/
242 GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale,
243 state->depth, state->delay, todo);
244 GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range,
245 state->lfo_range, state->lfo_scale, state->depth, state->delay,
246 todo);
248 state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range;
250 for(i = 0;i < todo;i++)
252 ALint delay;
253 ALfloat mu;
255 // Feed the buffer's input first (necessary for delays < 1).
256 delaybuf[offset&bufmask] = SamplesIn[0][base+i];
258 // Tap for the left output.
259 delay = offset - (moddelays[0][i]>>FRACTIONBITS);
260 mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE);
261 temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask],
262 delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask],
263 mu);
265 // Tap for the right output.
266 delay = offset - (moddelays[1][i]>>FRACTIONBITS);
267 mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE);
268 temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask],
269 delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask],
270 mu);
272 // Accumulate feedback from the average delay of the taps.
273 delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback;
274 offset++;
277 for(c = 0;c < 2;c++)
278 MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current,
279 state->Gains[c].Target, SamplesToDo-base, base, todo);
281 base += todo;
284 state->offset = offset;
288 typedef struct ChorusStateFactory {
289 DERIVE_FROM_TYPE(EffectStateFactory);
290 } ChorusStateFactory;
292 static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory))
294 ALchorusState *state;
296 NEW_OBJ0(state, ALchorusState)();
297 if(!state) return NULL;
299 return STATIC_CAST(ALeffectState, state);
302 DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory);
305 EffectStateFactory *ChorusStateFactory_getFactory(void)
307 static ChorusStateFactory ChorusFactory = { { GET_VTABLE2(ChorusStateFactory, EffectStateFactory) } };
309 return STATIC_CAST(EffectStateFactory, &ChorusFactory);
313 void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
315 ALeffectProps *props = &effect->Props;
316 switch(param)
318 case AL_CHORUS_WAVEFORM:
319 if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
320 SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform");
321 props->Chorus.Waveform = val;
322 break;
324 case AL_CHORUS_PHASE:
325 if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
326 SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range");
327 props->Chorus.Phase = val;
328 break;
330 default:
331 alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
334 void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
335 { ALchorus_setParami(effect, context, param, vals[0]); }
336 void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
338 ALeffectProps *props = &effect->Props;
339 switch(param)
341 case AL_CHORUS_RATE:
342 if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
343 SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range");
344 props->Chorus.Rate = val;
345 break;
347 case AL_CHORUS_DEPTH:
348 if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
349 SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range");
350 props->Chorus.Depth = val;
351 break;
353 case AL_CHORUS_FEEDBACK:
354 if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
355 SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range");
356 props->Chorus.Feedback = val;
357 break;
359 case AL_CHORUS_DELAY:
360 if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
361 SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range");
362 props->Chorus.Delay = val;
363 break;
365 default:
366 alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
369 void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
370 { ALchorus_setParamf(effect, context, param, vals[0]); }
372 void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
374 const ALeffectProps *props = &effect->Props;
375 switch(param)
377 case AL_CHORUS_WAVEFORM:
378 *val = props->Chorus.Waveform;
379 break;
381 case AL_CHORUS_PHASE:
382 *val = props->Chorus.Phase;
383 break;
385 default:
386 alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
389 void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
390 { ALchorus_getParami(effect, context, param, vals); }
391 void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
393 const ALeffectProps *props = &effect->Props;
394 switch(param)
396 case AL_CHORUS_RATE:
397 *val = props->Chorus.Rate;
398 break;
400 case AL_CHORUS_DEPTH:
401 *val = props->Chorus.Depth;
402 break;
404 case AL_CHORUS_FEEDBACK:
405 *val = props->Chorus.Feedback;
406 break;
408 case AL_CHORUS_DELAY:
409 *val = props->Chorus.Delay;
410 break;
412 default:
413 alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
416 void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
417 { ALchorus_getParamf(effect, context, param, vals); }
419 DEFINE_ALEFFECT_VTABLE(ALchorus);
422 /* Flanger is basically a chorus with a really short delay. They can both use
423 * the same processing functions, so piggyback flanger on the chorus functions.
425 typedef struct FlangerStateFactory {
426 DERIVE_FROM_TYPE(EffectStateFactory);
427 } FlangerStateFactory;
429 ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory))
431 ALchorusState *state;
433 NEW_OBJ0(state, ALchorusState)();
434 if(!state) return NULL;
436 return STATIC_CAST(ALeffectState, state);
439 DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory);
441 EffectStateFactory *FlangerStateFactory_getFactory(void)
443 static FlangerStateFactory FlangerFactory = { { GET_VTABLE2(FlangerStateFactory, EffectStateFactory) } };
445 return STATIC_CAST(EffectStateFactory, &FlangerFactory);
449 void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
451 ALeffectProps *props = &effect->Props;
452 switch(param)
454 case AL_FLANGER_WAVEFORM:
455 if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
456 SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform");
457 props->Chorus.Waveform = val;
458 break;
460 case AL_FLANGER_PHASE:
461 if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
462 SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range");
463 props->Chorus.Phase = val;
464 break;
466 default:
467 alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param);
470 void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
471 { ALflanger_setParami(effect, context, param, vals[0]); }
472 void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
474 ALeffectProps *props = &effect->Props;
475 switch(param)
477 case AL_FLANGER_RATE:
478 if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
479 SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range");
480 props->Chorus.Rate = val;
481 break;
483 case AL_FLANGER_DEPTH:
484 if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
485 SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range");
486 props->Chorus.Depth = val;
487 break;
489 case AL_FLANGER_FEEDBACK:
490 if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
491 SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range");
492 props->Chorus.Feedback = val;
493 break;
495 case AL_FLANGER_DELAY:
496 if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
497 SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range");
498 props->Chorus.Delay = val;
499 break;
501 default:
502 alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
505 void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
506 { ALflanger_setParamf(effect, context, param, vals[0]); }
508 void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
510 const ALeffectProps *props = &effect->Props;
511 switch(param)
513 case AL_FLANGER_WAVEFORM:
514 *val = props->Chorus.Waveform;
515 break;
517 case AL_FLANGER_PHASE:
518 *val = props->Chorus.Phase;
519 break;
521 default:
522 alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param);
525 void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
526 { ALflanger_getParami(effect, context, param, vals); }
527 void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
529 const ALeffectProps *props = &effect->Props;
530 switch(param)
532 case AL_FLANGER_RATE:
533 *val = props->Chorus.Rate;
534 break;
536 case AL_FLANGER_DEPTH:
537 *val = props->Chorus.Depth;
538 break;
540 case AL_FLANGER_FEEDBACK:
541 *val = props->Chorus.Feedback;
542 break;
544 case AL_FLANGER_DELAY:
545 *val = props->Chorus.Delay;
546 break;
548 default:
549 alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
552 void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
553 { ALflanger_getParamf(effect, context, param, vals); }
555 DEFINE_ALEFFECT_VTABLE(ALflanger);