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 typedef struct ALmodulatorState
{
36 DERIVE_FROM_TYPE(ALeffectState
);
38 void (*GetSamples
)(ALfloat
*, ALsizei
, const ALsizei
, ALsizei
);
43 alignas(16) ALfloat ModSamples
[MAX_UPDATE_SAMPLES
];
48 ALfloat CurrentGains
[MAX_OUTPUT_CHANNELS
];
49 ALfloat TargetGains
[MAX_OUTPUT_CHANNELS
];
50 } Chans
[MAX_EFFECT_CHANNELS
];
53 static ALvoid
ALmodulatorState_Destruct(ALmodulatorState
*state
);
54 static ALboolean
ALmodulatorState_deviceUpdate(ALmodulatorState
*state
, ALCdevice
*device
);
55 static ALvoid
ALmodulatorState_update(ALmodulatorState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
);
56 static ALvoid
ALmodulatorState_process(ALmodulatorState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
);
57 DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState
)
59 DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState
);
62 #define WAVEFORM_FRACBITS 24
63 #define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
64 #define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
66 static inline ALfloat
Sin(ALsizei index
)
68 return sinf(index
*(F_TAU
/WAVEFORM_FRACONE
) - F_PI
)*0.5f
+ 0.5f
;
71 static inline ALfloat
Saw(ALsizei index
)
73 return (ALfloat
)index
/ WAVEFORM_FRACONE
;
76 static inline ALfloat
Square(ALsizei index
)
78 return (ALfloat
)((index
>> (WAVEFORM_FRACBITS
- 1)) & 1);
81 #define DECL_TEMPLATE(func) \
82 static void Modulate##func(ALfloat *restrict dst, ALsizei index, \
83 const ALsizei step, ALsizei todo) \
86 for(i = 0;i < todo;i++) \
89 index &= WAVEFORM_FRACMASK; \
90 dst[i] = func(index); \
101 static void ALmodulatorState_Construct(ALmodulatorState
*state
)
103 ALeffectState_Construct(STATIC_CAST(ALeffectState
, state
));
104 SET_VTABLE2(ALmodulatorState
, ALeffectState
, state
);
110 static ALvoid
ALmodulatorState_Destruct(ALmodulatorState
*state
)
112 ALeffectState_Destruct(STATIC_CAST(ALeffectState
,state
));
115 static ALboolean
ALmodulatorState_deviceUpdate(ALmodulatorState
*state
, ALCdevice
*UNUSED(device
))
118 for(i
= 0;i
< MAX_EFFECT_CHANNELS
;i
++)
120 ALfilterState_clear(&state
->Chans
[i
].Filter
);
121 for(j
= 0;j
< MAX_OUTPUT_CHANNELS
;j
++)
122 state
->Chans
[i
].CurrentGains
[j
] = 0.0f
;
127 static ALvoid
ALmodulatorState_update(ALmodulatorState
*state
, const ALCcontext
*context
, const ALeffectslot
*slot
, const ALeffectProps
*props
)
129 const ALCdevice
*device
= context
->Device
;
133 if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SINUSOID
)
134 state
->GetSamples
= ModulateSin
;
135 else if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SAWTOOTH
)
136 state
->GetSamples
= ModulateSaw
;
137 else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
138 state
->GetSamples
= ModulateSquare
;
140 state
->step
= fastf2i(props
->Modulator
.Frequency
*WAVEFORM_FRACONE
/
142 state
->step
= clampi(state
->step
, 1, WAVEFORM_FRACONE
-1);
144 /* Custom filter coeffs, which match the old version instead of a low-shelf. */
145 cw
= cosf(F_TAU
* props
->Modulator
.HighPassCutoff
/ device
->Frequency
);
146 a
= (2.0f
-cw
) - sqrtf(powf(2.0f
-cw
, 2.0f
) - 1.0f
);
148 state
->Chans
[0].Filter
.b0
= a
;
149 state
->Chans
[0].Filter
.b1
= -a
;
150 state
->Chans
[0].Filter
.b2
= 0.0f
;
151 state
->Chans
[0].Filter
.a1
= -a
;
152 state
->Chans
[0].Filter
.a2
= 0.0f
;
153 for(i
= 1;i
< MAX_EFFECT_CHANNELS
;i
++)
154 ALfilterState_copyParams(&state
->Chans
[i
].Filter
, &state
->Chans
[0].Filter
);
156 STATIC_CAST(ALeffectState
,state
)->OutBuffer
= device
->FOAOut
.Buffer
;
157 STATIC_CAST(ALeffectState
,state
)->OutChannels
= device
->FOAOut
.NumChannels
;
158 for(i
= 0;i
< MAX_EFFECT_CHANNELS
;i
++)
159 ComputeFirstOrderGains(&device
->FOAOut
, IdentityMatrixf
.m
[i
],
160 slot
->Params
.Gain
, state
->Chans
[i
].TargetGains
);
163 static ALvoid
ALmodulatorState_process(ALmodulatorState
*state
, ALsizei SamplesToDo
, const ALfloat (*restrict SamplesIn
)[BUFFERSIZE
], ALfloat (*restrict SamplesOut
)[BUFFERSIZE
], ALsizei NumChannels
)
165 ALfloat
*restrict modsamples
= ASSUME_ALIGNED(state
->ModSamples
, 16);
166 const ALsizei step
= state
->step
;
169 for(base
= 0;base
< SamplesToDo
;)
171 alignas(16) ALfloat temps
[2][MAX_UPDATE_SAMPLES
];
172 ALsizei td
= mini(MAX_UPDATE_SAMPLES
, SamplesToDo
-base
);
175 state
->GetSamples(modsamples
, state
->index
, step
, td
);
176 state
->index
+= (step
*td
) & WAVEFORM_FRACMASK
;
177 state
->index
&= WAVEFORM_FRACMASK
;
179 for(c
= 0;c
< MAX_EFFECT_CHANNELS
;c
++)
181 ALfilterState_process(&state
->Chans
[c
].Filter
, temps
[0], &SamplesIn
[c
][base
], td
);
182 for(i
= 0;i
< td
;i
++)
183 temps
[1][i
] = temps
[0][i
] * modsamples
[i
];
185 MixSamples(temps
[1], NumChannels
, SamplesOut
, state
->Chans
[c
].CurrentGains
,
186 state
->Chans
[c
].TargetGains
, SamplesToDo
-base
, base
, td
);
194 typedef struct ModulatorStateFactory
{
195 DERIVE_FROM_TYPE(EffectStateFactory
);
196 } ModulatorStateFactory
;
198 static ALeffectState
*ModulatorStateFactory_create(ModulatorStateFactory
*UNUSED(factory
))
200 ALmodulatorState
*state
;
202 NEW_OBJ0(state
, ALmodulatorState
)();
203 if(!state
) return NULL
;
205 return STATIC_CAST(ALeffectState
, state
);
208 DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory
);
210 EffectStateFactory
*ModulatorStateFactory_getFactory(void)
212 static ModulatorStateFactory ModulatorFactory
= { { GET_VTABLE2(ModulatorStateFactory
, EffectStateFactory
) } };
214 return STATIC_CAST(EffectStateFactory
, &ModulatorFactory
);
218 void ALmodulator_setParamf(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat val
)
220 ALeffectProps
*props
= &effect
->Props
;
223 case AL_RING_MODULATOR_FREQUENCY
:
224 if(!(val
>= AL_RING_MODULATOR_MIN_FREQUENCY
&& val
<= AL_RING_MODULATOR_MAX_FREQUENCY
))
225 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator frequency out of range");
226 props
->Modulator
.Frequency
= val
;
229 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
230 if(!(val
>= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
&& val
<= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
))
231 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator high-pass cutoff out of range");
232 props
->Modulator
.HighPassCutoff
= val
;
236 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
239 void ALmodulator_setParamfv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
240 { ALmodulator_setParamf(effect
, context
, param
, vals
[0]); }
241 void ALmodulator_setParami(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint val
)
243 ALeffectProps
*props
= &effect
->Props
;
246 case AL_RING_MODULATOR_FREQUENCY
:
247 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
248 ALmodulator_setParamf(effect
, context
, param
, (ALfloat
)val
);
251 case AL_RING_MODULATOR_WAVEFORM
:
252 if(!(val
>= AL_RING_MODULATOR_MIN_WAVEFORM
&& val
<= AL_RING_MODULATOR_MAX_WAVEFORM
))
253 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid modulator waveform");
254 props
->Modulator
.Waveform
= val
;
258 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
261 void ALmodulator_setParamiv(ALeffect
*effect
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
262 { ALmodulator_setParami(effect
, context
, param
, vals
[0]); }
264 void ALmodulator_getParami(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*val
)
266 const ALeffectProps
*props
= &effect
->Props
;
269 case AL_RING_MODULATOR_FREQUENCY
:
270 *val
= (ALint
)props
->Modulator
.Frequency
;
272 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
273 *val
= (ALint
)props
->Modulator
.HighPassCutoff
;
275 case AL_RING_MODULATOR_WAVEFORM
:
276 *val
= props
->Modulator
.Waveform
;
280 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
283 void ALmodulator_getParamiv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
284 { ALmodulator_getParami(effect
, context
, param
, vals
); }
285 void ALmodulator_getParamf(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
287 const ALeffectProps
*props
= &effect
->Props
;
290 case AL_RING_MODULATOR_FREQUENCY
:
291 *val
= props
->Modulator
.Frequency
;
293 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
294 *val
= props
->Modulator
.HighPassCutoff
;
298 alSetError(context
, AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
301 void ALmodulator_getParamfv(const ALeffect
*effect
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
302 { ALmodulator_getParamf(effect
, context
, param
, vals
); }
304 DEFINE_ALEFFECT_VTABLE(ALmodulator
);