9 #include "alc/effects/base.h"
10 #include "aloptional.h"
16 #include "alnumeric.h"
18 #include "al/eax_exception.h"
19 #include "al/eax_utils.h"
25 al::optional
<ModulatorWaveform
> WaveformFromEmum(ALenum value
)
29 case AL_RING_MODULATOR_SINUSOID
: return al::make_optional(ModulatorWaveform::Sinusoid
);
30 case AL_RING_MODULATOR_SAWTOOTH
: return al::make_optional(ModulatorWaveform::Sawtooth
);
31 case AL_RING_MODULATOR_SQUARE
: return al::make_optional(ModulatorWaveform::Square
);
35 ALenum
EnumFromWaveform(ModulatorWaveform type
)
39 case ModulatorWaveform::Sinusoid
: return AL_RING_MODULATOR_SINUSOID
;
40 case ModulatorWaveform::Sawtooth
: return AL_RING_MODULATOR_SAWTOOTH
;
41 case ModulatorWaveform::Square
: return AL_RING_MODULATOR_SQUARE
;
43 throw std::runtime_error
{"Invalid modulator waveform: " +
44 std::to_string(static_cast<int>(type
))};
47 void Modulator_setParamf(EffectProps
*props
, ALenum param
, float val
)
51 case AL_RING_MODULATOR_FREQUENCY
:
52 if(!(val
>= AL_RING_MODULATOR_MIN_FREQUENCY
&& val
<= AL_RING_MODULATOR_MAX_FREQUENCY
))
53 throw effect_exception
{AL_INVALID_VALUE
, "Modulator frequency out of range: %f", val
};
54 props
->Modulator
.Frequency
= val
;
57 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
58 if(!(val
>= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
&& val
<= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
))
59 throw effect_exception
{AL_INVALID_VALUE
, "Modulator high-pass cutoff out of range: %f", val
};
60 props
->Modulator
.HighPassCutoff
= val
;
64 throw effect_exception
{AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
};
67 void Modulator_setParamfv(EffectProps
*props
, ALenum param
, const float *vals
)
68 { Modulator_setParamf(props
, param
, vals
[0]); }
69 void Modulator_setParami(EffectProps
*props
, ALenum param
, int val
)
73 case AL_RING_MODULATOR_FREQUENCY
:
74 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
75 Modulator_setParamf(props
, param
, static_cast<float>(val
));
78 case AL_RING_MODULATOR_WAVEFORM
:
79 if(auto formopt
= WaveformFromEmum(val
))
80 props
->Modulator
.Waveform
= *formopt
;
82 throw effect_exception
{AL_INVALID_VALUE
, "Invalid modulator waveform: 0x%04x", val
};
86 throw effect_exception
{AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x",
90 void Modulator_setParamiv(EffectProps
*props
, ALenum param
, const int *vals
)
91 { Modulator_setParami(props
, param
, vals
[0]); }
93 void Modulator_getParami(const EffectProps
*props
, ALenum param
, int *val
)
97 case AL_RING_MODULATOR_FREQUENCY
:
98 *val
= static_cast<int>(props
->Modulator
.Frequency
);
100 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
101 *val
= static_cast<int>(props
->Modulator
.HighPassCutoff
);
103 case AL_RING_MODULATOR_WAVEFORM
:
104 *val
= EnumFromWaveform(props
->Modulator
.Waveform
);
108 throw effect_exception
{AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x",
112 void Modulator_getParamiv(const EffectProps
*props
, ALenum param
, int *vals
)
113 { Modulator_getParami(props
, param
, vals
); }
114 void Modulator_getParamf(const EffectProps
*props
, ALenum param
, float *val
)
118 case AL_RING_MODULATOR_FREQUENCY
:
119 *val
= props
->Modulator
.Frequency
;
121 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
122 *val
= props
->Modulator
.HighPassCutoff
;
126 throw effect_exception
{AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
};
129 void Modulator_getParamfv(const EffectProps
*props
, ALenum param
, float *vals
)
130 { Modulator_getParamf(props
, param
, vals
); }
132 EffectProps
genDefaultProps() noexcept
135 props
.Modulator
.Frequency
= AL_RING_MODULATOR_DEFAULT_FREQUENCY
;
136 props
.Modulator
.HighPassCutoff
= AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF
;
137 props
.Modulator
.Waveform
= *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM
);
143 DEFINE_ALEFFECT_VTABLE(Modulator
);
145 const EffectProps ModulatorEffectProps
{genDefaultProps()};
150 using EaxRingModulatorEffectDirtyFlagsValue
= std::uint_least8_t;
152 struct EaxRingModulatorEffectDirtyFlags
154 using EaxIsBitFieldStruct
= bool;
156 EaxRingModulatorEffectDirtyFlagsValue flFrequency
: 1;
157 EaxRingModulatorEffectDirtyFlagsValue flHighPassCutOff
: 1;
158 EaxRingModulatorEffectDirtyFlagsValue ulWaveform
: 1;
159 }; // EaxPitchShifterEffectDirtyFlags
162 class EaxRingModulatorEffect final
:
166 EaxRingModulatorEffect();
168 void dispatch(const EaxEaxCall
& eax_call
) override
;
171 bool apply_deferred() override
;
174 EAXRINGMODULATORPROPERTIES eax_
{};
175 EAXRINGMODULATORPROPERTIES eax_d_
{};
176 EaxRingModulatorEffectDirtyFlags eax_dirty_flags_
{};
178 void set_eax_defaults();
180 void set_efx_frequency();
181 void set_efx_high_pass_cutoff();
182 void set_efx_waveform();
183 void set_efx_defaults();
185 void get(const EaxEaxCall
& eax_call
);
187 void validate_frequency(float flFrequency
);
188 void validate_high_pass_cutoff(float flHighPassCutOff
);
189 void validate_waveform(unsigned long ulWaveform
);
190 void validate_all(const EAXRINGMODULATORPROPERTIES
& all
);
192 void defer_frequency(float flFrequency
);
193 void defer_high_pass_cutoff(float flHighPassCutOff
);
194 void defer_waveform(unsigned long ulWaveform
);
195 void defer_all(const EAXRINGMODULATORPROPERTIES
& all
);
197 void defer_frequency(const EaxEaxCall
& eax_call
);
198 void defer_high_pass_cutoff(const EaxEaxCall
& eax_call
);
199 void defer_waveform(const EaxEaxCall
& eax_call
);
200 void defer_all(const EaxEaxCall
& eax_call
);
202 void set(const EaxEaxCall
& eax_call
);
203 }; // EaxRingModulatorEffect
206 class EaxRingModulatorEffectException
:
210 explicit EaxRingModulatorEffectException(
213 EaxException
{"EAX_RING_MODULATOR_EFFECT", message
}
216 }; // EaxRingModulatorEffectException
219 EaxRingModulatorEffect::EaxRingModulatorEffect()
220 : EaxEffect
{AL_EFFECT_RING_MODULATOR
}
226 void EaxRingModulatorEffect::dispatch(const EaxEaxCall
& eax_call
)
228 eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
231 void EaxRingModulatorEffect::set_eax_defaults()
233 eax_
.flFrequency
= EAXRINGMODULATOR_DEFAULTFREQUENCY
;
234 eax_
.flHighPassCutOff
= EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF
;
235 eax_
.ulWaveform
= EAXRINGMODULATOR_DEFAULTWAVEFORM
;
240 void EaxRingModulatorEffect::set_efx_frequency()
242 const auto frequency
= clamp(
244 AL_RING_MODULATOR_MIN_FREQUENCY
,
245 AL_RING_MODULATOR_MAX_FREQUENCY
);
247 al_effect_props_
.Modulator
.Frequency
= frequency
;
250 void EaxRingModulatorEffect::set_efx_high_pass_cutoff()
252 const auto high_pass_cutoff
= clamp(
253 eax_
.flHighPassCutOff
,
254 AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
,
255 AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
);
257 al_effect_props_
.Modulator
.HighPassCutoff
= high_pass_cutoff
;
260 void EaxRingModulatorEffect::set_efx_waveform()
262 const auto waveform
= clamp(
263 static_cast<ALint
>(eax_
.ulWaveform
),
264 AL_RING_MODULATOR_MIN_WAVEFORM
,
265 AL_RING_MODULATOR_MAX_WAVEFORM
);
267 const auto efx_waveform
= WaveformFromEmum(waveform
);
268 assert(efx_waveform
.has_value());
269 al_effect_props_
.Modulator
.Waveform
= *efx_waveform
;
272 void EaxRingModulatorEffect::set_efx_defaults()
275 set_efx_high_pass_cutoff();
279 void EaxRingModulatorEffect::get(const EaxEaxCall
& eax_call
)
281 switch(eax_call
.get_property_id())
283 case EAXRINGMODULATOR_NONE
:
286 case EAXRINGMODULATOR_ALLPARAMETERS
:
287 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
);
290 case EAXRINGMODULATOR_FREQUENCY
:
291 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.flFrequency
);
294 case EAXRINGMODULATOR_HIGHPASSCUTOFF
:
295 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.flHighPassCutOff
);
298 case EAXRINGMODULATOR_WAVEFORM
:
299 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.ulWaveform
);
303 throw EaxRingModulatorEffectException
{"Unsupported property id."};
307 void EaxRingModulatorEffect::validate_frequency(
310 eax_validate_range
<EaxRingModulatorEffectException
>(
313 EAXRINGMODULATOR_MINFREQUENCY
,
314 EAXRINGMODULATOR_MAXFREQUENCY
);
317 void EaxRingModulatorEffect::validate_high_pass_cutoff(
318 float flHighPassCutOff
)
320 eax_validate_range
<EaxRingModulatorEffectException
>(
323 EAXRINGMODULATOR_MINHIGHPASSCUTOFF
,
324 EAXRINGMODULATOR_MAXHIGHPASSCUTOFF
);
327 void EaxRingModulatorEffect::validate_waveform(
328 unsigned long ulWaveform
)
330 eax_validate_range
<EaxRingModulatorEffectException
>(
333 EAXRINGMODULATOR_MINWAVEFORM
,
334 EAXRINGMODULATOR_MAXWAVEFORM
);
337 void EaxRingModulatorEffect::validate_all(
338 const EAXRINGMODULATORPROPERTIES
& all
)
340 validate_frequency(all
.flFrequency
);
341 validate_high_pass_cutoff(all
.flHighPassCutOff
);
342 validate_waveform(all
.ulWaveform
);
345 void EaxRingModulatorEffect::defer_frequency(
348 eax_d_
.flFrequency
= flFrequency
;
349 eax_dirty_flags_
.flFrequency
= (eax_
.flFrequency
!= eax_d_
.flFrequency
);
352 void EaxRingModulatorEffect::defer_high_pass_cutoff(
353 float flHighPassCutOff
)
355 eax_d_
.flHighPassCutOff
= flHighPassCutOff
;
356 eax_dirty_flags_
.flHighPassCutOff
= (eax_
.flHighPassCutOff
!= eax_d_
.flHighPassCutOff
);
359 void EaxRingModulatorEffect::defer_waveform(
360 unsigned long ulWaveform
)
362 eax_d_
.ulWaveform
= ulWaveform
;
363 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
366 void EaxRingModulatorEffect::defer_all(
367 const EAXRINGMODULATORPROPERTIES
& all
)
369 defer_frequency(all
.flFrequency
);
370 defer_high_pass_cutoff(all
.flHighPassCutOff
);
371 defer_waveform(all
.ulWaveform
);
374 void EaxRingModulatorEffect::defer_frequency(
375 const EaxEaxCall
& eax_call
)
377 const auto& frequency
=
379 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::flFrequency
)>();
381 validate_frequency(frequency
);
382 defer_frequency(frequency
);
385 void EaxRingModulatorEffect::defer_high_pass_cutoff(
386 const EaxEaxCall
& eax_call
)
388 const auto& high_pass_cutoff
=
390 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::flHighPassCutOff
)>();
392 validate_high_pass_cutoff(high_pass_cutoff
);
393 defer_high_pass_cutoff(high_pass_cutoff
);
396 void EaxRingModulatorEffect::defer_waveform(
397 const EaxEaxCall
& eax_call
)
399 const auto& waveform
=
401 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform
)>();
403 validate_waveform(waveform
);
404 defer_waveform(waveform
);
407 void EaxRingModulatorEffect::defer_all(
408 const EaxEaxCall
& eax_call
)
411 eax_call
.get_value
<EaxRingModulatorEffectException
, const EAXRINGMODULATORPROPERTIES
>();
418 bool EaxRingModulatorEffect::apply_deferred()
420 if (eax_dirty_flags_
== EaxRingModulatorEffectDirtyFlags
{})
427 if (eax_dirty_flags_
.flFrequency
)
432 if (eax_dirty_flags_
.flHighPassCutOff
)
434 set_efx_high_pass_cutoff();
437 if (eax_dirty_flags_
.ulWaveform
)
442 eax_dirty_flags_
= EaxRingModulatorEffectDirtyFlags
{};
447 void EaxRingModulatorEffect::set(const EaxEaxCall
& eax_call
)
449 switch (eax_call
.get_property_id())
451 case EAXRINGMODULATOR_NONE
:
454 case EAXRINGMODULATOR_ALLPARAMETERS
:
458 case EAXRINGMODULATOR_FREQUENCY
:
459 defer_frequency(eax_call
);
462 case EAXRINGMODULATOR_HIGHPASSCUTOFF
:
463 defer_high_pass_cutoff(eax_call
);
466 case EAXRINGMODULATOR_WAVEFORM
:
467 defer_waveform(eax_call
);
471 throw EaxRingModulatorEffectException
{"Unsupported property id."};
477 EaxEffectUPtr
eax_create_eax_ring_modulator_effect()
479 return std::make_unique
<EaxRingModulatorEffect
>();