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"
34 CWF_Triangle
= AL_CHORUS_WAVEFORM_TRIANGLE
,
35 CWF_Sinusoid
= AL_CHORUS_WAVEFORM_SINUSOID
38 typedef struct ALchorusState
{
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 ChorusWaveForm waveform
;
58 static ALvoid
ALchorusState_Destruct(ALchorusState
*state
)
60 al_free(state
->SampleBuffer
[0]);
61 state
->SampleBuffer
[0] = NULL
;
62 state
->SampleBuffer
[1] = NULL
;
63 ALeffectState_Destruct(STATIC_CAST(ALeffectState
,state
));
66 static ALboolean
ALchorusState_deviceUpdate(ALchorusState
*state
, ALCdevice
*Device
)
71 maxlen
= fastf2u(AL_CHORUS_MAX_DELAY
* 3.0f
* Device
->Frequency
) + 1;
72 maxlen
= NextPowerOf2(maxlen
);
74 if(maxlen
!= state
->BufferLength
)
76 void *temp
= al_calloc(16, maxlen
* sizeof(ALfloat
) * 2);
77 if(!temp
) return AL_FALSE
;
79 al_free(state
->SampleBuffer
[0]);
80 state
->SampleBuffer
[0] = temp
;
81 state
->SampleBuffer
[1] = state
->SampleBuffer
[0] + maxlen
;
83 state
->BufferLength
= maxlen
;
86 for(it
= 0;it
< state
->BufferLength
;it
++)
88 state
->SampleBuffer
[0][it
] = 0.0f
;
89 state
->SampleBuffer
[1][it
] = 0.0f
;
95 static ALvoid
ALchorusState_update(ALchorusState
*state
, const ALCdevice
*Device
, const ALeffectslot
*Slot
, const ALeffectProps
*props
)
97 ALfloat frequency
= (ALfloat
)Device
->Frequency
;
98 ALfloat coeffs
[MAX_AMBI_COEFFS
];
102 switch(props
->Chorus
.Waveform
)
104 case AL_CHORUS_WAVEFORM_TRIANGLE
:
105 state
->waveform
= CWF_Triangle
;
107 case AL_CHORUS_WAVEFORM_SINUSOID
:
108 state
->waveform
= CWF_Sinusoid
;
111 state
->depth
= props
->Chorus
.Depth
;
112 state
->feedback
= props
->Chorus
.Feedback
;
113 state
->delay
= fastf2i(props
->Chorus
.Delay
* frequency
);
115 /* Gains for left and right sides */
116 CalcXYZCoeffs(-1.0f
, 0.0f
, 0.0f
, 0.0f
, coeffs
);
117 ComputePanningGains(Device
->Dry
, coeffs
, Slot
->Params
.Gain
, state
->Gain
[0]);
118 CalcXYZCoeffs( 1.0f
, 0.0f
, 0.0f
, 0.0f
, coeffs
);
119 ComputePanningGains(Device
->Dry
, coeffs
, Slot
->Params
.Gain
, state
->Gain
[1]);
121 phase
= props
->Chorus
.Phase
;
122 rate
= props
->Chorus
.Rate
;
125 state
->lfo_scale
= 0.0f
;
126 state
->lfo_range
= 1;
131 /* Calculate LFO coefficient */
132 state
->lfo_range
= fastf2u(frequency
/rate
+ 0.5f
);
133 switch(state
->waveform
)
136 state
->lfo_scale
= 4.0f
/ state
->lfo_range
;
139 state
->lfo_scale
= F_TAU
/ state
->lfo_range
;
143 /* Calculate lfo phase displacement */
144 state
->lfo_disp
= fastf2i(state
->lfo_range
* (phase
/360.0f
));
148 static inline void Triangle(ALint
*delay_left
, ALint
*delay_right
, ALuint offset
, const ALchorusState
*state
)
152 lfo_value
= 2.0f
- fabsf(2.0f
- state
->lfo_scale
*(offset
%state
->lfo_range
));
153 lfo_value
*= state
->depth
* state
->delay
;
154 *delay_left
= fastf2i(lfo_value
) + state
->delay
;
156 offset
+= state
->lfo_disp
;
157 lfo_value
= 2.0f
- fabsf(2.0f
- state
->lfo_scale
*(offset
%state
->lfo_range
));
158 lfo_value
*= state
->depth
* state
->delay
;
159 *delay_right
= fastf2i(lfo_value
) + state
->delay
;
162 static inline void Sinusoid(ALint
*delay_left
, ALint
*delay_right
, ALuint offset
, const ALchorusState
*state
)
166 lfo_value
= 1.0f
+ sinf(state
->lfo_scale
*(offset
%state
->lfo_range
));
167 lfo_value
*= state
->depth
* state
->delay
;
168 *delay_left
= fastf2i(lfo_value
) + state
->delay
;
170 offset
+= state
->lfo_disp
;
171 lfo_value
= 1.0f
+ sinf(state
->lfo_scale
*(offset
%state
->lfo_range
));
172 lfo_value
*= state
->depth
* state
->delay
;
173 *delay_right
= fastf2i(lfo_value
) + state
->delay
;
176 #define DECL_TEMPLATE(Func) \
177 static void Process##Func(ALchorusState *state, const ALuint SamplesToDo, \
178 const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
180 const ALuint bufmask = state->BufferLength-1; \
181 ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
182 ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
183 ALuint offset = state->offset; \
184 const ALfloat feedback = state->feedback; \
187 for(it = 0;it < SamplesToDo;it++) \
189 ALint delay_left, delay_right; \
190 Func(&delay_left, &delay_right, offset, state); \
192 out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
193 leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
195 out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
196 rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
200 state->offset = offset; \
203 DECL_TEMPLATE(Triangle
)
204 DECL_TEMPLATE(Sinusoid
)
208 static ALvoid
ALchorusState_process(ALchorusState
*state
, ALuint SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALuint NumChannels
)
213 for(base
= 0;base
< SamplesToDo
;)
215 ALfloat temps
[128][2];
216 ALuint td
= minu(128, SamplesToDo
-base
);
218 switch(state
->waveform
)
221 ProcessTriangle(state
, td
, SamplesIn
[0]+base
, temps
);
224 ProcessSinusoid(state
, td
, SamplesIn
[0]+base
, temps
);
228 for(kt
= 0;kt
< NumChannels
;kt
++)
230 ALfloat gain
= state
->Gain
[0][kt
];
231 if(fabsf(gain
) > GAIN_SILENCE_THRESHOLD
)
233 for(it
= 0;it
< td
;it
++)
234 SamplesOut
[kt
][it
+base
] += temps
[it
][0] * gain
;
237 gain
= state
->Gain
[1][kt
];
238 if(fabsf(gain
) > GAIN_SILENCE_THRESHOLD
)
240 for(it
= 0;it
< td
;it
++)
241 SamplesOut
[kt
][it
+base
] += temps
[it
][1] * gain
;
249 DECLARE_DEFAULT_ALLOCATORS(ALchorusState
)
251 DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState
);
254 typedef struct ALchorusStateFactory
{
255 DERIVE_FROM_TYPE(ALeffectStateFactory
);
256 } ALchorusStateFactory
;
258 static ALeffectState
*ALchorusStateFactory_create(ALchorusStateFactory
*UNUSED(factory
))
260 ALchorusState
*state
;
262 state
= ALchorusState_New(sizeof(*state
));
263 if(!state
) return NULL
;
264 SET_VTABLE2(ALchorusState
, ALeffectState
, state
);
266 state
->BufferLength
= 0;
267 state
->SampleBuffer
[0] = NULL
;
268 state
->SampleBuffer
[1] = NULL
;
270 state
->lfo_range
= 1;
271 state
->waveform
= CWF_Triangle
;
273 return STATIC_CAST(ALeffectState
, state
);
276 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory
);
279 ALeffectStateFactory
*ALchorusStateFactory_getFactory(void)
281 static ALchorusStateFactory ChorusFactory
= { { GET_VTABLE2(ALchorusStateFactory
, ALeffectStateFactory
) } };
283 return STATIC_CAST(ALeffectStateFactory
, &ChorusFactory
);
287 void ALchorus_setParami(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint val
)
289 ALeffectProps
*props
= &effect
->Props
;
292 case AL_CHORUS_WAVEFORM
:
293 if(!(val
>= AL_CHORUS_MIN_WAVEFORM
&& val
<= AL_CHORUS_MAX_WAVEFORM
))
294 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
295 props
->Chorus
.Waveform
= val
;
298 case AL_CHORUS_PHASE
:
299 if(!(val
>= AL_CHORUS_MIN_PHASE
&& val
<= AL_CHORUS_MAX_PHASE
))
300 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
301 props
->Chorus
.Phase
= val
;
305 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
308 void ALchorus_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
310 ALchorus_setParami(effect
, context
, param
, vals
[0]);
312 void ALchorus_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
314 ALeffectProps
*props
= &effect
->Props
;
318 if(!(val
>= AL_CHORUS_MIN_RATE
&& val
<= AL_CHORUS_MAX_RATE
))
319 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
320 props
->Chorus
.Rate
= val
;
323 case AL_CHORUS_DEPTH
:
324 if(!(val
>= AL_CHORUS_MIN_DEPTH
&& val
<= AL_CHORUS_MAX_DEPTH
))
325 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
326 props
->Chorus
.Depth
= val
;
329 case AL_CHORUS_FEEDBACK
:
330 if(!(val
>= AL_CHORUS_MIN_FEEDBACK
&& val
<= AL_CHORUS_MAX_FEEDBACK
))
331 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
332 props
->Chorus
.Feedback
= val
;
335 case AL_CHORUS_DELAY
:
336 if(!(val
>= AL_CHORUS_MIN_DELAY
&& val
<= AL_CHORUS_MAX_DELAY
))
337 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
338 props
->Chorus
.Delay
= val
;
342 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
345 void ALchorus_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
347 ALchorus_setParamf(effect
, context
, param
, vals
[0]);
350 void ALchorus_getParami(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*val
)
352 const ALeffectProps
*props
= &effect
->Props
;
355 case AL_CHORUS_WAVEFORM
:
356 *val
= props
->Chorus
.Waveform
;
359 case AL_CHORUS_PHASE
:
360 *val
= props
->Chorus
.Phase
;
364 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
367 void ALchorus_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
369 ALchorus_getParami(effect
, context
, param
, vals
);
371 void ALchorus_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
373 const ALeffectProps
*props
= &effect
->Props
;
377 *val
= props
->Chorus
.Rate
;
380 case AL_CHORUS_DEPTH
:
381 *val
= props
->Chorus
.Depth
;
384 case AL_CHORUS_FEEDBACK
:
385 *val
= props
->Chorus
.Feedback
;
388 case AL_CHORUS_DELAY
:
389 *val
= props
->Chorus
.Delay
;
393 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
396 void ALchorus_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
398 ALchorus_getParamf(effect
, context
, param
, vals
);
401 DEFINE_ALEFFECT_VTABLE(ALchorus
);