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
28 #include "alAuxEffectSlot.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];
48 /* Gains for left and right sides */
49 ALfloat Gain
[2][MAX_OUTPUT_CHANNELS
];
51 /* effect parameters */
52 enum FlangerWaveForm waveform
;
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
;
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
)
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
;
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
];
125 switch(props
->Flanger
.Waveform
)
127 case AL_FLANGER_WAVEFORM_TRIANGLE
:
128 state
->waveform
= FWF_Triangle
;
130 case AL_FLANGER_WAVEFORM_SINUSOID
:
131 state
->waveform
= FWF_Sinusoid
;
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
;
149 state
->lfo_scale
= 0.0f
;
150 state
->lfo_range
= 1;
155 /* Calculate LFO coefficient */
156 state
->lfo_range
= fastf2i(frequency
/rate
+ 0.5f
);
157 switch(state
->waveform
)
160 state
->lfo_scale
= 4.0f
/ state
->lfo_range
;
163 state
->lfo_scale
= F_TAU
/ state
->lfo_range
;
167 /* Calculate lfo phase displacement */
169 state
->lfo_disp
= fastf2i(state
->lfo_range
* (phase
/360.0f
));
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
,
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
,
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
;
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
)
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
,
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
,
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];
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
362 case AL_FLANGER_WAVEFORM
:
363 *val
= props
->Flanger
.Waveform
;
366 case AL_FLANGER_PHASE
:
367 *val
= props
->Flanger
.Phase
;
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
;
383 case AL_FLANGER_RATE
:
384 *val
= props
->Flanger
.Rate
;
387 case AL_FLANGER_DEPTH
:
388 *val
= props
->Flanger
.Depth
;
391 case AL_FLANGER_FEEDBACK
:
392 *val
= props
->Flanger
.Feedback
;
395 case AL_FLANGER_DELAY
:
396 *val
= props
->Flanger
.Delay
;
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
);