2 * OpenAL cross platform audio library
3 * Copyright (C) 2009 by Chris Robinson.
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 typedef struct ALechoState
{
34 DERIVE_FROM_TYPE(ALeffectState
);
36 ALfloat
*SampleBuffer
;
39 // The echo is two tap. The delay is the number of samples from before the
45 /* The panning gains for the two taps */
46 ALfloat Gain
[2][MAX_OUTPUT_CHANNELS
];
53 static ALvoid
ALechoState_Destruct(ALechoState
*state
)
55 free(state
->SampleBuffer
);
56 state
->SampleBuffer
= NULL
;
59 static ALboolean
ALechoState_deviceUpdate(ALechoState
*state
, ALCdevice
*Device
)
63 // Use the next power of 2 for the buffer length, so the tap offsets can be
64 // wrapped using a mask instead of a modulo
65 maxlen
= fastf2u(AL_ECHO_MAX_DELAY
* Device
->Frequency
) + 1;
66 maxlen
+= fastf2u(AL_ECHO_MAX_LRDELAY
* Device
->Frequency
) + 1;
67 maxlen
= NextPowerOf2(maxlen
);
69 if(maxlen
!= state
->BufferLength
)
73 temp
= realloc(state
->SampleBuffer
, maxlen
* sizeof(ALfloat
));
74 if(!temp
) return AL_FALSE
;
75 state
->SampleBuffer
= temp
;
76 state
->BufferLength
= maxlen
;
78 for(i
= 0;i
< state
->BufferLength
;i
++)
79 state
->SampleBuffer
[i
] = 0.0f
;
84 static ALvoid
ALechoState_update(ALechoState
*state
, ALCdevice
*Device
, const ALeffectslot
*Slot
)
86 ALfloat pandir
[3] = { 0.0f
, 0.0f
, 0.0f
};
87 ALuint frequency
= Device
->Frequency
;
88 ALfloat gain
= Slot
->Gain
;
91 state
->Tap
[0].delay
= fastf2u(Slot
->EffectProps
.Echo
.Delay
* frequency
) + 1;
92 state
->Tap
[1].delay
= fastf2u(Slot
->EffectProps
.Echo
.LRDelay
* frequency
);
93 state
->Tap
[1].delay
+= state
->Tap
[0].delay
;
95 lrpan
= Slot
->EffectProps
.Echo
.Spread
;
97 state
->FeedGain
= Slot
->EffectProps
.Echo
.Feedback
;
99 ALfilterState_setParams(&state
->Filter
, ALfilterType_HighShelf
,
100 1.0f
- Slot
->EffectProps
.Echo
.Damping
,
101 LOWPASSFREQREF
/frequency
, 0.0f
);
103 /* First tap panning */
105 ComputeDirectionalGains(Device
, pandir
, gain
, state
->Gain
[0]);
107 /* Second tap panning */
109 ComputeDirectionalGains(Device
, pandir
, gain
, state
->Gain
[1]);
112 static ALvoid
ALechoState_process(ALechoState
*state
, ALuint SamplesToDo
, const ALfloat
*restrict SamplesIn
, ALfloat (*restrict SamplesOut
)[BUFFERSIZE
])
114 const ALuint mask
= state
->BufferLength
-1;
115 const ALuint tap1
= state
->Tap
[0].delay
;
116 const ALuint tap2
= state
->Tap
[1].delay
;
117 ALuint offset
= state
->Offset
;
122 for(base
= 0;base
< SamplesToDo
;)
124 ALfloat temps
[64][2];
125 ALuint td
= minu(SamplesToDo
-base
, 64);
127 for(i
= 0;i
< td
;i
++)
130 temps
[i
][0] = state
->SampleBuffer
[(offset
-tap1
) & mask
];
132 temps
[i
][1] = state
->SampleBuffer
[(offset
-tap2
) & mask
];
134 // Apply damping and feedback gain to the second tap, and mix in the
136 smp
= ALfilterState_processSingle(&state
->Filter
, temps
[i
][1]+SamplesIn
[i
+base
]);
137 state
->SampleBuffer
[offset
&mask
] = smp
* state
->FeedGain
;
141 for(k
= 0;k
< MAX_OUTPUT_CHANNELS
;k
++)
143 ALfloat gain
= state
->Gain
[0][k
];
144 if(gain
> GAIN_SILENCE_THRESHOLD
)
146 for(i
= 0;i
< td
;i
++)
147 SamplesOut
[k
][i
+base
] += temps
[i
][0] * gain
;
150 gain
= state
->Gain
[1][k
];
151 if(gain
> GAIN_SILENCE_THRESHOLD
)
153 for(i
= 0;i
< td
;i
++)
154 SamplesOut
[k
][i
+base
] += temps
[i
][1] * gain
;
161 state
->Offset
= offset
;
164 DECLARE_DEFAULT_ALLOCATORS(ALechoState
)
166 DEFINE_ALEFFECTSTATE_VTABLE(ALechoState
);
169 typedef struct ALechoStateFactory
{
170 DERIVE_FROM_TYPE(ALeffectStateFactory
);
171 } ALechoStateFactory
;
173 ALeffectState
*ALechoStateFactory_create(ALechoStateFactory
*UNUSED(factory
))
177 state
= ALechoState_New(sizeof(*state
));
178 if(!state
) return NULL
;
179 SET_VTABLE2(ALechoState
, ALeffectState
, state
);
181 state
->BufferLength
= 0;
182 state
->SampleBuffer
= NULL
;
184 state
->Tap
[0].delay
= 0;
185 state
->Tap
[1].delay
= 0;
188 ALfilterState_clear(&state
->Filter
);
190 return STATIC_CAST(ALeffectState
, state
);
193 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory
);
195 ALeffectStateFactory
*ALechoStateFactory_getFactory(void)
197 static ALechoStateFactory EchoFactory
= { { GET_VTABLE2(ALechoStateFactory
, ALeffectStateFactory
) } };
199 return STATIC_CAST(ALeffectStateFactory
, &EchoFactory
);
203 void ALecho_setParami(ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum
UNUSED(param
), ALint
UNUSED(val
))
204 { SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
); }
205 void ALecho_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
207 ALecho_setParami(effect
, context
, param
, vals
[0]);
209 void ALecho_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
211 ALeffectProps
*props
= &effect
->Props
;
215 if(!(val
>= AL_ECHO_MIN_DELAY
&& val
<= AL_ECHO_MAX_DELAY
))
216 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
217 props
->Echo
.Delay
= val
;
220 case AL_ECHO_LRDELAY
:
221 if(!(val
>= AL_ECHO_MIN_LRDELAY
&& val
<= AL_ECHO_MAX_LRDELAY
))
222 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
223 props
->Echo
.LRDelay
= val
;
226 case AL_ECHO_DAMPING
:
227 if(!(val
>= AL_ECHO_MIN_DAMPING
&& val
<= AL_ECHO_MAX_DAMPING
))
228 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
229 props
->Echo
.Damping
= val
;
232 case AL_ECHO_FEEDBACK
:
233 if(!(val
>= AL_ECHO_MIN_FEEDBACK
&& val
<= AL_ECHO_MAX_FEEDBACK
))
234 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
235 props
->Echo
.Feedback
= val
;
239 if(!(val
>= AL_ECHO_MIN_SPREAD
&& val
<= AL_ECHO_MAX_SPREAD
))
240 SET_ERROR_AND_RETURN(context
, AL_INVALID_VALUE
);
241 props
->Echo
.Spread
= val
;
245 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
248 void ALecho_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
250 ALecho_setParamf(effect
, context
, param
, vals
[0]);
253 void ALecho_getParami(const ALeffect
*UNUSED(effect
), ALCcontext
*context
, ALenum
UNUSED(param
), ALint
*UNUSED(val
))
254 { SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
); }
255 void ALecho_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
257 ALecho_getParami(effect
, context
, param
, vals
);
259 void ALecho_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
261 const ALeffectProps
*props
= &effect
->Props
;
265 *val
= props
->Echo
.Delay
;
268 case AL_ECHO_LRDELAY
:
269 *val
= props
->Echo
.LRDelay
;
272 case AL_ECHO_DAMPING
:
273 *val
= props
->Echo
.Damping
;
276 case AL_ECHO_FEEDBACK
:
277 *val
= props
->Echo
.Feedback
;
281 *val
= props
->Echo
.Spread
;
285 SET_ERROR_AND_RETURN(context
, AL_INVALID_ENUM
);
288 void ALecho_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
290 ALecho_getParamf(effect
, context
, param
, vals
);
293 DEFINE_ALEFFECT_VTABLE(ALecho
);