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
)
60 free(state
->SampleBuffer
[0]);
61 state
->SampleBuffer
[0] = NULL
;
62 state
->SampleBuffer
[1] = NULL
;
65 static ALboolean
ALflangerState_deviceUpdate(ALflangerState
*state
, ALCdevice
*Device
)
70 maxlen
= fastf2u(AL_FLANGER_MAX_DELAY
* 3.0f
* Device
->Frequency
) + 1;
71 maxlen
= NextPowerOf2(maxlen
);
73 if(maxlen
!= state
->BufferLength
)
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
;
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
];
101 switch(Slot
->EffectProps
.Flanger
.Waveform
)
103 case AL_FLANGER_WAVEFORM_TRIANGLE
:
104 state
->waveform
= FWF_Triangle
;
106 case AL_FLANGER_WAVEFORM_SINUSOID
:
107 state
->waveform
= FWF_Sinusoid
;
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
;
124 state
->lfo_scale
= 0.0f
;
125 state
->lfo_range
= 1;
130 /* Calculate LFO coefficient */
131 state
->lfo_range
= fastf2u(frequency
/rate
+ 0.5f
);
132 switch(state
->waveform
)
135 state
->lfo_scale
= 4.0f
/ state
->lfo_range
;
138 state
->lfo_scale
= F_TAU
/ state
->lfo_range
;
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
)
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
)
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; \
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; \
199 state->offset = offset; \
202 DECL_TEMPLATE(Triangle
)
203 DECL_TEMPLATE(Sinusoid
)
207 static ALvoid
ALflangerState_process(ALflangerState
*state
, ALuint SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALuint NumChannels
)
212 for(base
= 0;base
< SamplesToDo
;)
214 ALfloat temps
[128][2];
215 ALuint td
= minu(128, SamplesToDo
-base
);
217 switch(state
->waveform
)
220 ProcessTriangle(state
, td
, SamplesIn
[0]+base
, temps
);
223 ProcessSinusoid(state
, td
, SamplesIn
[0]+base
, temps
);
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
353 case AL_FLANGER_WAVEFORM
:
354 *val
= props
->Flanger
.Waveform
;
357 case AL_FLANGER_PHASE
:
358 *val
= props
->Flanger
.Phase
;
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
;
374 case AL_FLANGER_RATE
:
375 *val
= props
->Flanger
.Rate
;
378 case AL_FLANGER_DEPTH
:
379 *val
= props
->Flanger
.Depth
;
382 case AL_FLANGER_FEEDBACK
:
383 *val
= props
->Flanger
.Feedback
;
386 case AL_FLANGER_DELAY
:
387 *val
= props
->Flanger
.Delay
;
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
);