2 * OpenAL cross platform audio library
3 * Copyright (C) 2013 by Anis A. Hireche, Nasca Octavian Paul
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
28 #include "alAuxEffectSlot.h"
31 /* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up
32 * or down depending on the input signal, and a resonant peak at the cutoff.
34 * Currently, we assume a cutoff frequency range of 500hz (no amplitude) to
35 * 3khz (peak gain). Peak gain is assumed to be in normalized scale.
38 typedef struct ALautowahState
{
39 DERIVE_FROM_TYPE(ALeffectState
);
41 /* Effect gains for each channel */
42 ALfloat Gain
[MaxChannels
];
44 /* Effect parameters */
52 /* Samples processing */
53 ALfilterState LowPass
;
56 static ALvoid
ALautowahState_Destruct(ALautowahState
*UNUSED(state
))
60 static ALboolean
ALautowahState_deviceUpdate(ALautowahState
*state
, ALCdevice
*device
)
62 state
->Frequency
= (ALfloat
)device
->Frequency
;
66 static ALvoid
ALautowahState_update(ALautowahState
*state
, ALCdevice
*device
, const ALeffectslot
*slot
)
68 ALfloat attackTime
, releaseTime
;
71 attackTime
= slot
->EffectProps
.Autowah
.AttackTime
* state
->Frequency
;
72 releaseTime
= slot
->EffectProps
.Autowah
.ReleaseTime
* state
->Frequency
;
74 state
->AttackRate
= powf(1.0f
/GAIN_SILENCE_THRESHOLD
, 1.0f
/attackTime
);
75 state
->ReleaseRate
= powf(GAIN_SILENCE_THRESHOLD
/1.0f
, 1.0f
/releaseTime
);
76 state
->PeakGain
= slot
->EffectProps
.Autowah
.PeakGain
;
77 state
->Resonance
= slot
->EffectProps
.Autowah
.Resonance
;
79 gain
= sqrtf(1.0f
/ device
->NumChan
) * slot
->Gain
;
80 SetGains(device
, gain
, state
->Gain
);
83 static ALvoid
ALautowahState_process(ALautowahState
*state
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[BUFFERSIZE
])
88 for(base
= 0;base
< SamplesToDo
;)
91 ALuint td
= minu(SamplesToDo
-base
, 64);
92 ALfloat gain
= state
->GainCtrl
;
94 for(it
= 0;it
< td
;it
++)
96 ALfloat smp
= SamplesIn
[it
+base
];
101 /* Similar to compressor, we get the current amplitude of the
102 * incoming signal, and attack or release to reach it. */
103 amplitude
= fabsf(smp
);
105 gain
= minf(gain
*state
->AttackRate
, amplitude
);
106 else if(amplitude
< gain
)
107 gain
= maxf(gain
*state
->ReleaseRate
, amplitude
);
108 gain
= maxf(gain
, GAIN_SILENCE_THRESHOLD
);
110 /* FIXME: What range does the filter cover? */
111 cutoff
= lerp(20.0f
, 20000.0f
, minf(gain
/state
->PeakGain
, 1.0f
));
113 /* The code below is like calling ALfilterState_setParams with
114 * ALfilterType_LowPass. However, instead of passing a bandwidth,
115 * we use the resonance property for Q. This also inlines the call.
117 w0
= F_2PI
* cutoff
/ state
->Frequency
;
119 /* FIXME: Resonance controls the resonant peak, or Q. How? Not sure
120 * that Q = resonance*0.1. */
121 alpha
= sinf(w0
) / (2.0f
* state
->Resonance
*0.1f
);
122 state
->LowPass
.b
[0] = (1.0f
- cosf(w0
)) / 2.0f
;
123 state
->LowPass
.b
[1] = 1.0f
- cosf(w0
);
124 state
->LowPass
.b
[2] = (1.0f
- cosf(w0
)) / 2.0f
;
125 state
->LowPass
.a
[0] = 1.0f
+ alpha
;
126 state
->LowPass
.a
[1] = -2.0f
* cosf(w0
);
127 state
->LowPass
.a
[2] = 1.0f
- alpha
;
129 state
->LowPass
.b
[2] /= state
->LowPass
.a
[0];
130 state
->LowPass
.b
[1] /= state
->LowPass
.a
[0];
131 state
->LowPass
.b
[0] /= state
->LowPass
.a
[0];
132 state
->LowPass
.a
[2] /= state
->LowPass
.a
[0];
133 state
->LowPass
.a
[1] /= state
->LowPass
.a
[0];
134 state
->LowPass
.a
[0] /= state
->LowPass
.a
[0];
136 temps
[it
] = ALfilterState_processSingle(&state
->LowPass
, smp
);
138 state
->GainCtrl
= gain
;
140 for(kt
= 0;kt
< MaxChannels
;kt
++)
142 ALfloat gain
= state
->Gain
[kt
];
143 if(!(gain
> GAIN_SILENCE_THRESHOLD
))
146 for(it
= 0;it
< td
;it
++)
147 SamplesOut
[kt
][base
+it
] += gain
* temps
[it
];
154 DECLARE_DEFAULT_ALLOCATORS(ALautowahState
)
156 DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState
);
159 typedef struct ALautowahStateFactory
{
160 DERIVE_FROM_TYPE(ALeffectStateFactory
);
161 } ALautowahStateFactory
;
163 static ALeffectState
*ALautowahStateFactory_create(ALautowahStateFactory
*UNUSED(factory
))
165 ALautowahState
*state
;
167 state
= ALautowahState_New(sizeof(*state
));
168 if(!state
) return NULL
;
169 SET_VTABLE2(ALautowahState
, ALeffectState
, state
);
171 state
->AttackRate
= 1.0f
;
172 state
->ReleaseRate
= 1.0f
;
173 state
->Resonance
= 2.0f
;
174 state
->PeakGain
= 1.0f
;
175 state
->GainCtrl
= 1.0f
;
177 ALfilterState_clear(&state
->LowPass
);
179 return STATIC_CAST(ALeffectState
, state
);
182 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALautowahStateFactory
);
184 ALeffectStateFactory
*ALautowahStateFactory_getFactory(void)
186 static ALautowahStateFactory AutowahFactory
= { { GET_VTABLE2(ALautowahStateFactory
, ALeffectStateFactory
) } };
188 return STATIC_CAST(ALeffectStateFactory
, &AutowahFactory
);
192 void ALautowah_setParami(ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum
UNUSED(param
), ALint
UNUSED(val
))
193 { SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
); }
194 void ALautowah_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
196 ALautowah_setParami(effect
, context
, param
, vals
[0]);
198 void ALautowah_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
200 ALeffectProps
*props
= &effect
->Props
;
203 case AL_AUTOWAH_ATTACK_TIME
:
204 if(!(val
>= AL_AUTOWAH_MIN_ATTACK_TIME
&& val
<= AL_AUTOWAH_MAX_ATTACK_TIME
))
205 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
206 props
->Autowah
.AttackTime
= val
;
209 case AL_AUTOWAH_RELEASE_TIME
:
210 if(!(val
>= AL_AUTOWAH_MIN_RELEASE_TIME
&& val
<= AL_AUTOWAH_MAX_RELEASE_TIME
))
211 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
212 props
->Autowah
.ReleaseTime
= val
;
215 case AL_AUTOWAH_RESONANCE
:
216 if(!(val
>= AL_AUTOWAH_MIN_RESONANCE
&& val
<= AL_AUTOWAH_MAX_RESONANCE
))
217 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
218 props
->Autowah
.Resonance
= val
;
221 case AL_AUTOWAH_PEAK_GAIN
:
222 if(!(val
>= AL_AUTOWAH_MIN_PEAK_GAIN
&& val
<= AL_AUTOWAH_MAX_PEAK_GAIN
))
223 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
224 props
->Autowah
.PeakGain
= val
;
228 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
231 void ALautowah_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
233 ALautowah_setParamf(effect
, context
, param
, vals
[0]);
236 void ALautowah_getParami(const ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum
UNUSED(param
), ALint
*UNUSED(val
))
237 { SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
); }
238 void ALautowah_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
240 ALautowah_getParami(effect
, context
, param
, vals
);
242 void ALautowah_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
244 const ALeffectProps
*props
= &effect
->Props
;
247 case AL_AUTOWAH_ATTACK_TIME
:
248 *val
= props
->Autowah
.AttackTime
;
251 case AL_AUTOWAH_RELEASE_TIME
:
252 *val
= props
->Autowah
.ReleaseTime
;
255 case AL_AUTOWAH_RESONANCE
:
256 *val
= props
->Autowah
.Resonance
;
259 case AL_AUTOWAH_PEAK_GAIN
:
260 *val
= props
->Autowah
.PeakGain
;
264 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
267 void ALautowah_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
269 ALautowah_getParamf(effect
, context
, param
, vals
);
272 DEFINE_ALEFFECT_VTABLE(ALautowah
);