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
27 #include "alAuxEffectSlot.h"
30 #include "filters/defs.h"
33 #define MAX_UPDATE_SAMPLES 128
35 struct ALmodulatorState final
: public ALeffectState
{
36 void (*GetSamples
)(ALfloat
*RESTRICT
, ALsizei
, const ALsizei
, ALsizei
);
44 ALfloat CurrentGains
[MAX_OUTPUT_CHANNELS
];
45 ALfloat TargetGains
[MAX_OUTPUT_CHANNELS
];
46 } Chans
[MAX_EFFECT_CHANNELS
];
49 static ALvoid
ALmodulatorState_Destruct(ALmodulatorState
*state
);
50 static ALboolean
ALmodulatorState_deviceUpdate(ALmodulatorState
*state
, ALCdevice
*device
);
51 static ALvoid
ALmodulatorState_update(ALmodulatorState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
);
52 static ALvoid
ALmodulatorState_process(ALmodulatorState
*state
, ALsizei SamplesToDo
, const ALfloat (*RESTRICT SamplesIn
)[BUFFERSIZE
], ALfloat (*RESTRICT SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
);
53 DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState
)
55 DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState
);
58 #define WAVEFORM_FRACBITS 24
59 #define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
60 #define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
62 static inline ALfloat
Sin(ALsizei index
)
64 return sinf((ALfloat
)index
* (F_TAU
/ WAVEFORM_FRACONE
));
67 static inline ALfloat
Saw(ALsizei index
)
69 return (ALfloat
)index
*(2.0f
/WAVEFORM_FRACONE
) - 1.0f
;
72 static inline ALfloat
Square(ALsizei index
)
74 return (ALfloat
)(((index
>>(WAVEFORM_FRACBITS
-2))&2) - 1);
77 static inline ALfloat
One(ALsizei
UNUSED(index
))
82 #define DECL_TEMPLATE(func) \
83 static void Modulate##func(ALfloat *RESTRICT dst, ALsizei index, \
84 const ALsizei step, ALsizei todo) \
87 for(i = 0;i < todo;i++) \
90 index &= WAVEFORM_FRACMASK; \
91 dst[i] = func(index); \
103 static void ALmodulatorState_Construct(ALmodulatorState
*state
)
105 new (state
) ALmodulatorState
{};
106 ALeffectState_Construct(STATIC_CAST(ALeffectState
, state
));
107 SET_VTABLE2(ALmodulatorState
, ALeffectState
, state
);
113 static ALvoid
ALmodulatorState_Destruct(ALmodulatorState
*state
)
115 ALeffectState_Destruct(STATIC_CAST(ALeffectState
,state
));
116 state
->~ALmodulatorState();
119 static ALboolean
ALmodulatorState_deviceUpdate(ALmodulatorState
*state
, ALCdevice
*UNUSED(device
))
122 for(i
= 0;i
< MAX_EFFECT_CHANNELS
;i
++)
124 BiquadFilter_clear(&state
->Chans
[i
].Filter
);
125 for(j
= 0;j
< MAX_OUTPUT_CHANNELS
;j
++)
126 state
->Chans
[i
].CurrentGains
[j
] = 0.0f
;
131 static ALvoid
ALmodulatorState_update(ALmodulatorState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
)
133 const ALCdevice
*device
= context
->Device
;
137 state
->step
= fastf2i(props
->Modulator
.Frequency
/ (ALfloat
)device
->Frequency
*
139 state
->step
= clampi(state
->step
, 0, WAVEFORM_FRACONE
-1);
142 state
->GetSamples
= ModulateOne
;
143 else if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SINUSOID
)
144 state
->GetSamples
= ModulateSin
;
145 else if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SAWTOOTH
)
146 state
->GetSamples
= ModulateSaw
;
147 else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
148 state
->GetSamples
= ModulateSquare
;
150 f0norm
= props
->Modulator
.HighPassCutoff
/ (ALfloat
)device
->Frequency
;
151 f0norm
= clampf(f0norm
, 1.0f
/512.0f
, 0.49f
);
152 /* Bandwidth value is constant in octaves. */
153 BiquadFilter_setParams(&state
->Chans
[0].Filter
, BiquadType_HighPass
, 1.0f
,
154 f0norm
, calc_rcpQ_from_bandwidth(f0norm
, 0.75f
));
155 for(i
= 1;i
< MAX_EFFECT_CHANNELS
;i
++)
156 BiquadFilter_copyParams(&state
->Chans
[i
].Filter
, &state
->Chans
[0].Filter
);
158 STATIC_CAST(ALeffectState
,state
)->OutBuffer
= device
->FOAOut
.Buffer
;
159 STATIC_CAST(ALeffectState
,state
)->OutChannels
= device
->FOAOut
.NumChannels
;
160 for(i
= 0;i
< MAX_EFFECT_CHANNELS
;i
++)
161 ComputePanGains(&device
->FOAOut
, IdentityMatrixf
.m
[i
], slot
->Params
.Gain
,
162 state
->Chans
[i
].TargetGains
);
165 static ALvoid
ALmodulatorState_process(ALmodulatorState
*state
, ALsizei SamplesToDo
, const ALfloat (*RESTRICT SamplesIn
)[BUFFERSIZE
], ALfloat (*RESTRICT SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
)
167 const ALsizei step
= state
->step
;
170 for(base
= 0;base
< SamplesToDo
;)
172 alignas(16) ALfloat modsamples
[MAX_UPDATE_SAMPLES
];
173 ALsizei td
= mini(MAX_UPDATE_SAMPLES
, SamplesToDo
-base
);
176 state
->GetSamples(modsamples
, state
->index
, step
, td
);
177 state
->index
+= (step
*td
) & WAVEFORM_FRACMASK
;
178 state
->index
&= WAVEFORM_FRACMASK
;
180 for(c
= 0;c
< MAX_EFFECT_CHANNELS
;c
++)
182 alignas(16) ALfloat temps
[MAX_UPDATE_SAMPLES
];
184 BiquadFilter_process(&state
->Chans
[c
].Filter
, temps
, &SamplesIn
[c
][base
], td
);
185 for(i
= 0;i
< td
;i
++)
186 temps
[i
] *= modsamples
[i
];
188 MixSamples(temps
, NumChannels
, SamplesOut
, state
->Chans
[c
].CurrentGains
,
189 state
->Chans
[c
].TargetGains
, SamplesToDo
-base
, base
, td
);
197 struct ModulatorStateFactory final
: public EffectStateFactory
{
198 ModulatorStateFactory() noexcept
;
201 static ALeffectState
*ModulatorStateFactory_create(ModulatorStateFactory
*UNUSED(factory
))
203 ALmodulatorState
*state
;
205 NEW_OBJ0(state
, ALmodulatorState
)();
206 if(!state
) return NULL
;
208 return STATIC_CAST(ALeffectState
, state
);
211 DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory
);
213 ModulatorStateFactory::ModulatorStateFactory() noexcept
214 : EffectStateFactory
{GET_VTABLE2(ModulatorStateFactory
, EffectStateFactory
)}
217 EffectStateFactory
*ModulatorStateFactory_getFactory(void)
219 static ModulatorStateFactory ModulatorFactory
{};
220 return STATIC_CAST(EffectStateFactory
, &ModulatorFactory
);
224 void ALmodulator_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
226 ALeffectProps
*props
= &effect
->Props
;
229 case AL_RING_MODULATOR_FREQUENCY
:
230 if(!(val
>= AL_RING_MODULATOR_MIN_FREQUENCY
&& val
<= AL_RING_MODULATOR_MAX_FREQUENCY
))
231 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator frequency out of range");
232 props
->Modulator
.Frequency
= val
;
235 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
236 if(!(val
>= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
&& val
<= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
))
237 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator high-pass cutoff out of range");
238 props
->Modulator
.HighPassCutoff
= val
;
242 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
245 void ALmodulator_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
246 { ALmodulator_setParamf(effect
, context
, param
, vals
[0]); }
247 void ALmodulator_setParami(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint val
)
249 ALeffectProps
*props
= &effect
->Props
;
252 case AL_RING_MODULATOR_FREQUENCY
:
253 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
254 ALmodulator_setParamf(effect
, context
, param
, (ALfloat
)val
);
257 case AL_RING_MODULATOR_WAVEFORM
:
258 if(!(val
>= AL_RING_MODULATOR_MIN_WAVEFORM
&& val
<= AL_RING_MODULATOR_MAX_WAVEFORM
))
259 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid modulator waveform");
260 props
->Modulator
.Waveform
= val
;
264 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
267 void ALmodulator_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
268 { ALmodulator_setParami(effect
, context
, param
, vals
[0]); }
270 void ALmodulator_getParami(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*val
)
272 const ALeffectProps
*props
= &effect
->Props
;
275 case AL_RING_MODULATOR_FREQUENCY
:
276 *val
= (ALint
)props
->Modulator
.Frequency
;
278 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
279 *val
= (ALint
)props
->Modulator
.HighPassCutoff
;
281 case AL_RING_MODULATOR_WAVEFORM
:
282 *val
= props
->Modulator
.Waveform
;
286 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
289 void ALmodulator_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
290 { ALmodulator_getParami(effect
, context
, param
, vals
); }
291 void ALmodulator_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
293 const ALeffectProps
*props
= &effect
->Props
;
296 case AL_RING_MODULATOR_FREQUENCY
:
297 *val
= props
->Modulator
.Frequency
;
299 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
300 *val
= props
->Modulator
.HighPassCutoff
;
304 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
307 void ALmodulator_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
308 { ALmodulator_getParamf(effect
, context
, param
, vals
); }
310 DEFINE_ALEFFECT_VTABLE(ALmodulator
);