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();
171 const EaxEaxCall
& eax_call
) override
;
175 EAXRINGMODULATORPROPERTIES eax_
{};
176 EAXRINGMODULATORPROPERTIES eax_d_
{};
177 EaxRingModulatorEffectDirtyFlags eax_dirty_flags_
{};
180 void set_eax_defaults();
183 void set_efx_frequency();
185 void set_efx_high_pass_cutoff();
187 void set_efx_waveform();
189 void set_efx_defaults();
194 const EaxEaxCall
& eax_call
);
197 void validate_frequency(
200 void validate_high_pass_cutoff(
201 float flHighPassCutOff
);
203 void validate_waveform(
204 unsigned long ulWaveform
);
207 const EAXRINGMODULATORPROPERTIES
& all
);
210 void defer_frequency(
213 void defer_high_pass_cutoff(
214 float flHighPassCutOff
);
217 unsigned long ulWaveform
);
220 const EAXRINGMODULATORPROPERTIES
& all
);
223 void defer_frequency(
224 const EaxEaxCall
& eax_call
);
226 void defer_high_pass_cutoff(
227 const EaxEaxCall
& eax_call
);
230 const EaxEaxCall
& eax_call
);
233 const EaxEaxCall
& eax_call
);
237 bool apply_deferred();
241 const EaxEaxCall
& eax_call
);
242 }; // EaxRingModulatorEffect
245 class EaxRingModulatorEffectException
:
249 explicit EaxRingModulatorEffectException(
252 EaxException
{"EAX_RING_MODULATOR_EFFECT", message
}
255 }; // EaxRingModulatorEffectException
258 EaxRingModulatorEffect::EaxRingModulatorEffect()
259 : EaxEffect
{AL_EFFECT_RING_MODULATOR
}
266 bool EaxRingModulatorEffect::dispatch(
267 const EaxEaxCall
& eax_call
)
269 return eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
272 void EaxRingModulatorEffect::set_eax_defaults()
274 eax_
.flFrequency
= EAXRINGMODULATOR_DEFAULTFREQUENCY
;
275 eax_
.flHighPassCutOff
= EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF
;
276 eax_
.ulWaveform
= EAXRINGMODULATOR_DEFAULTWAVEFORM
;
281 void EaxRingModulatorEffect::set_efx_frequency()
283 const auto frequency
= clamp(
285 AL_RING_MODULATOR_MIN_FREQUENCY
,
286 AL_RING_MODULATOR_MAX_FREQUENCY
);
288 al_effect_props_
.Modulator
.Frequency
= frequency
;
291 void EaxRingModulatorEffect::set_efx_high_pass_cutoff()
293 const auto high_pass_cutoff
= clamp(
294 eax_
.flHighPassCutOff
,
295 AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
,
296 AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
);
298 al_effect_props_
.Modulator
.HighPassCutoff
= high_pass_cutoff
;
301 void EaxRingModulatorEffect::set_efx_waveform()
303 const auto waveform
= clamp(
304 static_cast<ALint
>(eax_
.ulWaveform
),
305 AL_RING_MODULATOR_MIN_WAVEFORM
,
306 AL_RING_MODULATOR_MAX_WAVEFORM
);
308 const auto efx_waveform
= WaveformFromEmum(waveform
);
309 assert(efx_waveform
.has_value());
310 al_effect_props_
.Modulator
.Waveform
= *efx_waveform
;
313 void EaxRingModulatorEffect::set_efx_defaults()
316 set_efx_high_pass_cutoff();
321 bool EaxRingModulatorEffect::get(
322 const EaxEaxCall
& eax_call
)
324 switch (eax_call
.get_property_id())
326 case EAXRINGMODULATOR_NONE
:
329 case EAXRINGMODULATOR_ALLPARAMETERS
:
330 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
);
333 case EAXRINGMODULATOR_FREQUENCY
:
334 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.flFrequency
);
337 case EAXRINGMODULATOR_HIGHPASSCUTOFF
:
338 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.flHighPassCutOff
);
341 case EAXRINGMODULATOR_WAVEFORM
:
342 eax_call
.set_value
<EaxRingModulatorEffectException
>(eax_
.ulWaveform
);
346 throw EaxRingModulatorEffectException
{"Unsupported property id."};
352 void EaxRingModulatorEffect::validate_frequency(
355 eax_validate_range
<EaxRingModulatorEffectException
>(
358 EAXRINGMODULATOR_MINFREQUENCY
,
359 EAXRINGMODULATOR_MAXFREQUENCY
);
362 void EaxRingModulatorEffect::validate_high_pass_cutoff(
363 float flHighPassCutOff
)
365 eax_validate_range
<EaxRingModulatorEffectException
>(
368 EAXRINGMODULATOR_MINHIGHPASSCUTOFF
,
369 EAXRINGMODULATOR_MAXHIGHPASSCUTOFF
);
372 void EaxRingModulatorEffect::validate_waveform(
373 unsigned long ulWaveform
)
375 eax_validate_range
<EaxRingModulatorEffectException
>(
378 EAXRINGMODULATOR_MINWAVEFORM
,
379 EAXRINGMODULATOR_MAXWAVEFORM
);
382 void EaxRingModulatorEffect::validate_all(
383 const EAXRINGMODULATORPROPERTIES
& all
)
385 validate_frequency(all
.flFrequency
);
386 validate_high_pass_cutoff(all
.flHighPassCutOff
);
387 validate_waveform(all
.ulWaveform
);
390 void EaxRingModulatorEffect::defer_frequency(
393 eax_d_
.flFrequency
= flFrequency
;
394 eax_dirty_flags_
.flFrequency
= (eax_
.flFrequency
!= eax_d_
.flFrequency
);
397 void EaxRingModulatorEffect::defer_high_pass_cutoff(
398 float flHighPassCutOff
)
400 eax_d_
.flHighPassCutOff
= flHighPassCutOff
;
401 eax_dirty_flags_
.flHighPassCutOff
= (eax_
.flHighPassCutOff
!= eax_d_
.flHighPassCutOff
);
404 void EaxRingModulatorEffect::defer_waveform(
405 unsigned long ulWaveform
)
407 eax_d_
.ulWaveform
= ulWaveform
;
408 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
411 void EaxRingModulatorEffect::defer_all(
412 const EAXRINGMODULATORPROPERTIES
& all
)
414 defer_frequency(all
.flFrequency
);
415 defer_high_pass_cutoff(all
.flHighPassCutOff
);
416 defer_waveform(all
.ulWaveform
);
419 void EaxRingModulatorEffect::defer_frequency(
420 const EaxEaxCall
& eax_call
)
422 const auto& frequency
=
424 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::flFrequency
)>();
426 validate_frequency(frequency
);
427 defer_frequency(frequency
);
430 void EaxRingModulatorEffect::defer_high_pass_cutoff(
431 const EaxEaxCall
& eax_call
)
433 const auto& high_pass_cutoff
=
435 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::flHighPassCutOff
)>();
437 validate_high_pass_cutoff(high_pass_cutoff
);
438 defer_high_pass_cutoff(high_pass_cutoff
);
441 void EaxRingModulatorEffect::defer_waveform(
442 const EaxEaxCall
& eax_call
)
444 const auto& waveform
=
446 EaxRingModulatorEffectException
, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform
)>();
448 validate_waveform(waveform
);
449 defer_waveform(waveform
);
452 void EaxRingModulatorEffect::defer_all(
453 const EaxEaxCall
& eax_call
)
456 eax_call
.get_value
<EaxRingModulatorEffectException
, const EAXRINGMODULATORPROPERTIES
>();
463 bool EaxRingModulatorEffect::apply_deferred()
465 if (eax_dirty_flags_
== EaxRingModulatorEffectDirtyFlags
{})
472 if (eax_dirty_flags_
.flFrequency
)
477 if (eax_dirty_flags_
.flHighPassCutOff
)
479 set_efx_high_pass_cutoff();
482 if (eax_dirty_flags_
.ulWaveform
)
487 eax_dirty_flags_
= EaxRingModulatorEffectDirtyFlags
{};
493 bool EaxRingModulatorEffect::set(
494 const EaxEaxCall
& eax_call
)
496 switch (eax_call
.get_property_id())
498 case EAXRINGMODULATOR_NONE
:
501 case EAXRINGMODULATOR_ALLPARAMETERS
:
505 case EAXRINGMODULATOR_FREQUENCY
:
506 defer_frequency(eax_call
);
509 case EAXRINGMODULATOR_HIGHPASSCUTOFF
:
510 defer_high_pass_cutoff(eax_call
);
513 case EAXRINGMODULATOR_WAVEFORM
:
514 defer_waveform(eax_call
);
518 throw EaxRingModulatorEffectException
{"Unsupported property id."};
521 if (!eax_call
.is_deferred())
523 return apply_deferred();
531 EaxEffectUPtr
eax_create_eax_ring_modulator_effect()
533 return std::make_unique
<EaxRingModulatorEffect
>();