9 #include "alc/effects/base.h"
10 #include "aloptional.h"
11 #include "core/logging.h"
17 #include "alnumeric.h"
19 #include "al/eax/exception.h"
20 #include "al/eax/utils.h"
26 static_assert(ChorusMaxDelay
>= AL_CHORUS_MAX_DELAY
, "Chorus max delay too small");
27 static_assert(FlangerMaxDelay
>= AL_FLANGER_MAX_DELAY
, "Flanger max delay too small");
29 static_assert(AL_CHORUS_WAVEFORM_SINUSOID
== AL_FLANGER_WAVEFORM_SINUSOID
, "Chorus/Flanger waveform value mismatch");
30 static_assert(AL_CHORUS_WAVEFORM_TRIANGLE
== AL_FLANGER_WAVEFORM_TRIANGLE
, "Chorus/Flanger waveform value mismatch");
32 inline al::optional
<ChorusWaveform
> WaveformFromEnum(ALenum type
)
36 case AL_CHORUS_WAVEFORM_SINUSOID
: return al::make_optional(ChorusWaveform::Sinusoid
);
37 case AL_CHORUS_WAVEFORM_TRIANGLE
: return al::make_optional(ChorusWaveform::Triangle
);
41 inline ALenum
EnumFromWaveform(ChorusWaveform type
)
45 case ChorusWaveform::Sinusoid
: return AL_CHORUS_WAVEFORM_SINUSOID
;
46 case ChorusWaveform::Triangle
: return AL_CHORUS_WAVEFORM_TRIANGLE
;
48 throw std::runtime_error
{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type
))};
51 void Chorus_setParami(EffectProps
*props
, ALenum param
, int val
)
55 case AL_CHORUS_WAVEFORM
:
56 if(auto formopt
= WaveformFromEnum(val
))
57 props
->Chorus
.Waveform
= *formopt
;
59 throw effect_exception
{AL_INVALID_VALUE
, "Invalid chorus waveform: 0x%04x", val
};
63 if(!(val
>= AL_CHORUS_MIN_PHASE
&& val
<= AL_CHORUS_MAX_PHASE
))
64 throw effect_exception
{AL_INVALID_VALUE
, "Chorus phase out of range: %d", val
};
65 props
->Chorus
.Phase
= val
;
69 throw effect_exception
{AL_INVALID_ENUM
, "Invalid chorus integer property 0x%04x", param
};
72 void Chorus_setParamiv(EffectProps
*props
, ALenum param
, const int *vals
)
73 { Chorus_setParami(props
, param
, vals
[0]); }
74 void Chorus_setParamf(EffectProps
*props
, ALenum param
, float val
)
79 if(!(val
>= AL_CHORUS_MIN_RATE
&& val
<= AL_CHORUS_MAX_RATE
))
80 throw effect_exception
{AL_INVALID_VALUE
, "Chorus rate out of range: %f", val
};
81 props
->Chorus
.Rate
= val
;
85 if(!(val
>= AL_CHORUS_MIN_DEPTH
&& val
<= AL_CHORUS_MAX_DEPTH
))
86 throw effect_exception
{AL_INVALID_VALUE
, "Chorus depth out of range: %f", val
};
87 props
->Chorus
.Depth
= val
;
90 case AL_CHORUS_FEEDBACK
:
91 if(!(val
>= AL_CHORUS_MIN_FEEDBACK
&& val
<= AL_CHORUS_MAX_FEEDBACK
))
92 throw effect_exception
{AL_INVALID_VALUE
, "Chorus feedback out of range: %f", val
};
93 props
->Chorus
.Feedback
= val
;
97 if(!(val
>= AL_CHORUS_MIN_DELAY
&& val
<= AL_CHORUS_MAX_DELAY
))
98 throw effect_exception
{AL_INVALID_VALUE
, "Chorus delay out of range: %f", val
};
99 props
->Chorus
.Delay
= val
;
103 throw effect_exception
{AL_INVALID_ENUM
, "Invalid chorus float property 0x%04x", param
};
106 void Chorus_setParamfv(EffectProps
*props
, ALenum param
, const float *vals
)
107 { Chorus_setParamf(props
, param
, vals
[0]); }
109 void Chorus_getParami(const EffectProps
*props
, ALenum param
, int *val
)
113 case AL_CHORUS_WAVEFORM
:
114 *val
= EnumFromWaveform(props
->Chorus
.Waveform
);
117 case AL_CHORUS_PHASE
:
118 *val
= props
->Chorus
.Phase
;
122 throw effect_exception
{AL_INVALID_ENUM
, "Invalid chorus integer property 0x%04x", param
};
125 void Chorus_getParamiv(const EffectProps
*props
, ALenum param
, int *vals
)
126 { Chorus_getParami(props
, param
, vals
); }
127 void Chorus_getParamf(const EffectProps
*props
, ALenum param
, float *val
)
132 *val
= props
->Chorus
.Rate
;
135 case AL_CHORUS_DEPTH
:
136 *val
= props
->Chorus
.Depth
;
139 case AL_CHORUS_FEEDBACK
:
140 *val
= props
->Chorus
.Feedback
;
143 case AL_CHORUS_DELAY
:
144 *val
= props
->Chorus
.Delay
;
148 throw effect_exception
{AL_INVALID_ENUM
, "Invalid chorus float property 0x%04x", param
};
151 void Chorus_getParamfv(const EffectProps
*props
, ALenum param
, float *vals
)
152 { Chorus_getParamf(props
, param
, vals
); }
154 const EffectProps
genDefaultChorusProps() noexcept
157 props
.Chorus
.Waveform
= *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM
);
158 props
.Chorus
.Phase
= AL_CHORUS_DEFAULT_PHASE
;
159 props
.Chorus
.Rate
= AL_CHORUS_DEFAULT_RATE
;
160 props
.Chorus
.Depth
= AL_CHORUS_DEFAULT_DEPTH
;
161 props
.Chorus
.Feedback
= AL_CHORUS_DEFAULT_FEEDBACK
;
162 props
.Chorus
.Delay
= AL_CHORUS_DEFAULT_DELAY
;
167 void Flanger_setParami(EffectProps
*props
, ALenum param
, int val
)
171 case AL_FLANGER_WAVEFORM
:
172 if(auto formopt
= WaveformFromEnum(val
))
173 props
->Chorus
.Waveform
= *formopt
;
175 throw effect_exception
{AL_INVALID_VALUE
, "Invalid flanger waveform: 0x%04x", val
};
178 case AL_FLANGER_PHASE
:
179 if(!(val
>= AL_FLANGER_MIN_PHASE
&& val
<= AL_FLANGER_MAX_PHASE
))
180 throw effect_exception
{AL_INVALID_VALUE
, "Flanger phase out of range: %d", val
};
181 props
->Chorus
.Phase
= val
;
185 throw effect_exception
{AL_INVALID_ENUM
, "Invalid flanger integer property 0x%04x", param
};
188 void Flanger_setParamiv(EffectProps
*props
, ALenum param
, const int *vals
)
189 { Flanger_setParami(props
, param
, vals
[0]); }
190 void Flanger_setParamf(EffectProps
*props
, ALenum param
, float val
)
194 case AL_FLANGER_RATE
:
195 if(!(val
>= AL_FLANGER_MIN_RATE
&& val
<= AL_FLANGER_MAX_RATE
))
196 throw effect_exception
{AL_INVALID_VALUE
, "Flanger rate out of range: %f", val
};
197 props
->Chorus
.Rate
= val
;
200 case AL_FLANGER_DEPTH
:
201 if(!(val
>= AL_FLANGER_MIN_DEPTH
&& val
<= AL_FLANGER_MAX_DEPTH
))
202 throw effect_exception
{AL_INVALID_VALUE
, "Flanger depth out of range: %f", val
};
203 props
->Chorus
.Depth
= val
;
206 case AL_FLANGER_FEEDBACK
:
207 if(!(val
>= AL_FLANGER_MIN_FEEDBACK
&& val
<= AL_FLANGER_MAX_FEEDBACK
))
208 throw effect_exception
{AL_INVALID_VALUE
, "Flanger feedback out of range: %f", val
};
209 props
->Chorus
.Feedback
= val
;
212 case AL_FLANGER_DELAY
:
213 if(!(val
>= AL_FLANGER_MIN_DELAY
&& val
<= AL_FLANGER_MAX_DELAY
))
214 throw effect_exception
{AL_INVALID_VALUE
, "Flanger delay out of range: %f", val
};
215 props
->Chorus
.Delay
= val
;
219 throw effect_exception
{AL_INVALID_ENUM
, "Invalid flanger float property 0x%04x", param
};
222 void Flanger_setParamfv(EffectProps
*props
, ALenum param
, const float *vals
)
223 { Flanger_setParamf(props
, param
, vals
[0]); }
225 void Flanger_getParami(const EffectProps
*props
, ALenum param
, int *val
)
229 case AL_FLANGER_WAVEFORM
:
230 *val
= EnumFromWaveform(props
->Chorus
.Waveform
);
233 case AL_FLANGER_PHASE
:
234 *val
= props
->Chorus
.Phase
;
238 throw effect_exception
{AL_INVALID_ENUM
, "Invalid flanger integer property 0x%04x", param
};
241 void Flanger_getParamiv(const EffectProps
*props
, ALenum param
, int *vals
)
242 { Flanger_getParami(props
, param
, vals
); }
243 void Flanger_getParamf(const EffectProps
*props
, ALenum param
, float *val
)
247 case AL_FLANGER_RATE
:
248 *val
= props
->Chorus
.Rate
;
251 case AL_FLANGER_DEPTH
:
252 *val
= props
->Chorus
.Depth
;
255 case AL_FLANGER_FEEDBACK
:
256 *val
= props
->Chorus
.Feedback
;
259 case AL_FLANGER_DELAY
:
260 *val
= props
->Chorus
.Delay
;
264 throw effect_exception
{AL_INVALID_ENUM
, "Invalid flanger float property 0x%04x", param
};
267 void Flanger_getParamfv(const EffectProps
*props
, ALenum param
, float *vals
)
268 { Flanger_getParamf(props
, param
, vals
); }
270 EffectProps
genDefaultFlangerProps() noexcept
273 props
.Chorus
.Waveform
= *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM
);
274 props
.Chorus
.Phase
= AL_FLANGER_DEFAULT_PHASE
;
275 props
.Chorus
.Rate
= AL_FLANGER_DEFAULT_RATE
;
276 props
.Chorus
.Depth
= AL_FLANGER_DEFAULT_DEPTH
;
277 props
.Chorus
.Feedback
= AL_FLANGER_DEFAULT_FEEDBACK
;
278 props
.Chorus
.Delay
= AL_FLANGER_DEFAULT_DELAY
;
284 DEFINE_ALEFFECT_VTABLE(Chorus
);
286 const EffectProps ChorusEffectProps
{genDefaultChorusProps()};
288 DEFINE_ALEFFECT_VTABLE(Flanger
);
290 const EffectProps FlangerEffectProps
{genDefaultFlangerProps()};
296 void eax_set_efx_waveform(
298 EffectProps
& al_effect_props
)
300 const auto efx_waveform
= WaveformFromEnum(waveform
);
301 assert(efx_waveform
.has_value());
302 al_effect_props
.Chorus
.Waveform
= *efx_waveform
;
305 void eax_set_efx_phase(
307 EffectProps
& al_effect_props
)
309 al_effect_props
.Chorus
.Phase
= phase
;
312 void eax_set_efx_rate(
314 EffectProps
& al_effect_props
)
316 al_effect_props
.Chorus
.Rate
= rate
;
319 void eax_set_efx_depth(
321 EffectProps
& al_effect_props
)
323 al_effect_props
.Chorus
.Depth
= depth
;
326 void eax_set_efx_feedback(
328 EffectProps
& al_effect_props
)
330 al_effect_props
.Chorus
.Feedback
= feedback
;
333 void eax_set_efx_delay(
335 EffectProps
& al_effect_props
)
337 al_effect_props
.Chorus
.Delay
= delay
;
341 using EaxChorusEffectDirtyFlagsValue
= std::uint_least8_t;
343 struct EaxChorusEffectDirtyFlags
345 using EaxIsBitFieldStruct
= bool;
347 EaxChorusEffectDirtyFlagsValue ulWaveform
: 1;
348 EaxChorusEffectDirtyFlagsValue lPhase
: 1;
349 EaxChorusEffectDirtyFlagsValue flRate
: 1;
350 EaxChorusEffectDirtyFlagsValue flDepth
: 1;
351 EaxChorusEffectDirtyFlagsValue flFeedback
: 1;
352 EaxChorusEffectDirtyFlagsValue flDelay
: 1;
353 }; // EaxChorusEffectDirtyFlags
356 class EaxChorusEffect final
:
362 void dispatch(const EaxEaxCall
& eax_call
) override
;
365 bool apply_deferred() override
;
368 EAXCHORUSPROPERTIES eax_
{};
369 EAXCHORUSPROPERTIES eax_d_
{};
370 EaxChorusEffectDirtyFlags eax_dirty_flags_
{};
372 void set_eax_defaults() noexcept
;
374 void set_efx_waveform();
375 void set_efx_phase();
377 void set_efx_depth();
378 void set_efx_feedback();
379 void set_efx_delay();
380 void set_efx_defaults();
382 void get(const EaxEaxCall
& eax_call
);
384 void validate_waveform(unsigned long ulWaveform
);
385 void validate_phase(long lPhase
);
386 void validate_rate(float flRate
);
387 void validate_depth(float flDepth
);
388 void validate_feedback(float flFeedback
);
389 void validate_delay(float flDelay
);
390 void validate_all(const EAXCHORUSPROPERTIES
& eax_all
);
392 void defer_waveform(unsigned long ulWaveform
);
393 void defer_phase(long lPhase
);
394 void defer_rate(float flRate
);
395 void defer_depth(float flDepth
);
396 void defer_feedback(float flFeedback
);
397 void defer_delay(float flDelay
);
398 void defer_all(const EAXCHORUSPROPERTIES
& eax_all
);
400 void defer_waveform(const EaxEaxCall
& eax_call
);
401 void defer_phase(const EaxEaxCall
& eax_call
);
402 void defer_rate(const EaxEaxCall
& eax_call
);
403 void defer_depth(const EaxEaxCall
& eax_call
);
404 void defer_feedback(const EaxEaxCall
& eax_call
);
405 void defer_delay(const EaxEaxCall
& eax_call
);
406 void defer_all(const EaxEaxCall
& eax_call
);
408 void set(const EaxEaxCall
& eax_call
);
409 }; // EaxChorusEffect
412 class EaxChorusEffectException
:
416 explicit EaxChorusEffectException(
419 EaxException
{"EAX_CHORUS_EFFECT", message
}
422 }; // EaxChorusEffectException
425 EaxChorusEffect::EaxChorusEffect()
426 : EaxEffect
{AL_EFFECT_CHORUS
}
432 void EaxChorusEffect::dispatch(const EaxEaxCall
& eax_call
)
434 eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
437 void EaxChorusEffect::set_eax_defaults() noexcept
439 eax_
.ulWaveform
= EAXCHORUS_DEFAULTWAVEFORM
;
440 eax_
.lPhase
= EAXCHORUS_DEFAULTPHASE
;
441 eax_
.flRate
= EAXCHORUS_DEFAULTRATE
;
442 eax_
.flDepth
= EAXCHORUS_DEFAULTDEPTH
;
443 eax_
.flFeedback
= EAXCHORUS_DEFAULTFEEDBACK
;
444 eax_
.flDelay
= EAXCHORUS_DEFAULTDELAY
;
449 void EaxChorusEffect::set_efx_waveform()
451 const auto waveform
= clamp(
452 static_cast<ALint
>(eax_
.ulWaveform
),
453 AL_CHORUS_MIN_WAVEFORM
,
454 AL_CHORUS_MAX_WAVEFORM
);
456 eax_set_efx_waveform(waveform
, al_effect_props_
);
459 void EaxChorusEffect::set_efx_phase()
461 const auto phase
= clamp(
462 static_cast<ALint
>(eax_
.lPhase
),
464 AL_CHORUS_MAX_PHASE
);
466 eax_set_efx_phase(phase
, al_effect_props_
);
469 void EaxChorusEffect::set_efx_rate()
471 const auto rate
= clamp(
476 eax_set_efx_rate(rate
, al_effect_props_
);
479 void EaxChorusEffect::set_efx_depth()
481 const auto depth
= clamp(
484 AL_CHORUS_MAX_DEPTH
);
486 eax_set_efx_depth(depth
, al_effect_props_
);
489 void EaxChorusEffect::set_efx_feedback()
491 const auto feedback
= clamp(
493 AL_CHORUS_MIN_FEEDBACK
,
494 AL_CHORUS_MAX_FEEDBACK
);
496 eax_set_efx_feedback(feedback
, al_effect_props_
);
499 void EaxChorusEffect::set_efx_delay()
501 const auto delay
= clamp(
504 AL_CHORUS_MAX_DELAY
);
506 eax_set_efx_delay(delay
, al_effect_props_
);
509 void EaxChorusEffect::set_efx_defaults()
519 void EaxChorusEffect::get(const EaxEaxCall
& eax_call
)
521 switch(eax_call
.get_property_id())
526 case EAXCHORUS_ALLPARAMETERS
:
527 eax_call
.set_value
<EaxChorusEffectException
>(eax_
);
530 case EAXCHORUS_WAVEFORM
:
531 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.ulWaveform
);
534 case EAXCHORUS_PHASE
:
535 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.lPhase
);
539 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flRate
);
542 case EAXCHORUS_DEPTH
:
543 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flDepth
);
546 case EAXCHORUS_FEEDBACK
:
547 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flFeedback
);
550 case EAXCHORUS_DELAY
:
551 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flDelay
);
555 throw EaxChorusEffectException
{"Unsupported property id."};
559 void EaxChorusEffect::validate_waveform(
560 unsigned long ulWaveform
)
562 eax_validate_range
<EaxChorusEffectException
>(
565 EAXCHORUS_MINWAVEFORM
,
566 EAXCHORUS_MAXWAVEFORM
);
569 void EaxChorusEffect::validate_phase(
572 eax_validate_range
<EaxChorusEffectException
>(
579 void EaxChorusEffect::validate_rate(
582 eax_validate_range
<EaxChorusEffectException
>(
589 void EaxChorusEffect::validate_depth(
592 eax_validate_range
<EaxChorusEffectException
>(
599 void EaxChorusEffect::validate_feedback(
602 eax_validate_range
<EaxChorusEffectException
>(
605 EAXCHORUS_MINFEEDBACK
,
606 EAXCHORUS_MAXFEEDBACK
);
609 void EaxChorusEffect::validate_delay(
612 eax_validate_range
<EaxChorusEffectException
>(
619 void EaxChorusEffect::validate_all(
620 const EAXCHORUSPROPERTIES
& eax_all
)
622 validate_waveform(eax_all
.ulWaveform
);
623 validate_phase(eax_all
.lPhase
);
624 validate_rate(eax_all
.flRate
);
625 validate_depth(eax_all
.flDepth
);
626 validate_feedback(eax_all
.flFeedback
);
627 validate_delay(eax_all
.flDelay
);
630 void EaxChorusEffect::defer_waveform(
631 unsigned long ulWaveform
)
633 eax_d_
.ulWaveform
= ulWaveform
;
634 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
637 void EaxChorusEffect::defer_phase(
640 eax_d_
.lPhase
= lPhase
;
641 eax_dirty_flags_
.lPhase
= (eax_
.lPhase
!= eax_d_
.lPhase
);
644 void EaxChorusEffect::defer_rate(
647 eax_d_
.flRate
= flRate
;
648 eax_dirty_flags_
.flRate
= (eax_
.flRate
!= eax_d_
.flRate
);
651 void EaxChorusEffect::defer_depth(
654 eax_d_
.flDepth
= flDepth
;
655 eax_dirty_flags_
.flDepth
= (eax_
.flDepth
!= eax_d_
.flDepth
);
658 void EaxChorusEffect::defer_feedback(
661 eax_d_
.flFeedback
= flFeedback
;
662 eax_dirty_flags_
.flFeedback
= (eax_
.flFeedback
!= eax_d_
.flFeedback
);
665 void EaxChorusEffect::defer_delay(
668 eax_d_
.flDelay
= flDelay
;
669 eax_dirty_flags_
.flDelay
= (eax_
.flDelay
!= eax_d_
.flDelay
);
672 void EaxChorusEffect::defer_all(
673 const EAXCHORUSPROPERTIES
& eax_all
)
675 defer_waveform(eax_all
.ulWaveform
);
676 defer_phase(eax_all
.lPhase
);
677 defer_rate(eax_all
.flRate
);
678 defer_depth(eax_all
.flDepth
);
679 defer_feedback(eax_all
.flFeedback
);
680 defer_delay(eax_all
.flDelay
);
683 void EaxChorusEffect::defer_waveform(
684 const EaxEaxCall
& eax_call
)
686 const auto& waveform
=
687 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::ulWaveform
)>();
689 validate_waveform(waveform
);
690 defer_waveform(waveform
);
693 void EaxChorusEffect::defer_phase(
694 const EaxEaxCall
& eax_call
)
697 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::lPhase
)>();
699 validate_phase(phase
);
703 void EaxChorusEffect::defer_rate(
704 const EaxEaxCall
& eax_call
)
707 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flRate
)>();
713 void EaxChorusEffect::defer_depth(
714 const EaxEaxCall
& eax_call
)
717 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flDepth
)>();
719 validate_depth(depth
);
723 void EaxChorusEffect::defer_feedback(
724 const EaxEaxCall
& eax_call
)
726 const auto& feedback
=
727 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flFeedback
)>();
729 validate_feedback(feedback
);
730 defer_feedback(feedback
);
733 void EaxChorusEffect::defer_delay(
734 const EaxEaxCall
& eax_call
)
737 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flDelay
)>();
739 validate_delay(delay
);
743 void EaxChorusEffect::defer_all(
744 const EaxEaxCall
& eax_call
)
747 eax_call
.get_value
<EaxChorusEffectException
, const EAXCHORUSPROPERTIES
>();
754 bool EaxChorusEffect::apply_deferred()
756 if (eax_dirty_flags_
== EaxChorusEffectDirtyFlags
{})
763 if (eax_dirty_flags_
.ulWaveform
)
768 if (eax_dirty_flags_
.lPhase
)
773 if (eax_dirty_flags_
.flRate
)
778 if (eax_dirty_flags_
.flDepth
)
783 if (eax_dirty_flags_
.flFeedback
)
788 if (eax_dirty_flags_
.flDelay
)
793 eax_dirty_flags_
= EaxChorusEffectDirtyFlags
{};
798 void EaxChorusEffect::set(const EaxEaxCall
& eax_call
)
800 switch(eax_call
.get_property_id())
805 case EAXCHORUS_ALLPARAMETERS
:
809 case EAXCHORUS_WAVEFORM
:
810 defer_waveform(eax_call
);
813 case EAXCHORUS_PHASE
:
814 defer_phase(eax_call
);
818 defer_rate(eax_call
);
821 case EAXCHORUS_DEPTH
:
822 defer_depth(eax_call
);
825 case EAXCHORUS_FEEDBACK
:
826 defer_feedback(eax_call
);
829 case EAXCHORUS_DELAY
:
830 defer_delay(eax_call
);
834 throw EaxChorusEffectException
{"Unsupported property id."};
842 EaxEffectUPtr
eax_create_eax_chorus_effect()
844 return std::make_unique
<::EaxChorusEffect
>();
852 using EaxFlangerEffectDirtyFlagsValue
= std::uint_least8_t;
854 struct EaxFlangerEffectDirtyFlags
856 using EaxIsBitFieldStruct
= bool;
858 EaxFlangerEffectDirtyFlagsValue ulWaveform
: 1;
859 EaxFlangerEffectDirtyFlagsValue lPhase
: 1;
860 EaxFlangerEffectDirtyFlagsValue flRate
: 1;
861 EaxFlangerEffectDirtyFlagsValue flDepth
: 1;
862 EaxFlangerEffectDirtyFlagsValue flFeedback
: 1;
863 EaxFlangerEffectDirtyFlagsValue flDelay
: 1;
864 }; // EaxFlangerEffectDirtyFlags
867 class EaxFlangerEffect final
:
874 void dispatch(const EaxEaxCall
& eax_call
) override
;
877 bool apply_deferred() override
;
880 EAXFLANGERPROPERTIES eax_
{};
881 EAXFLANGERPROPERTIES eax_d_
{};
882 EaxFlangerEffectDirtyFlags eax_dirty_flags_
{};
884 void set_eax_defaults();
886 void set_efx_waveform();
887 void set_efx_phase();
889 void set_efx_depth();
890 void set_efx_feedback();
891 void set_efx_delay();
892 void set_efx_defaults();
894 void get(const EaxEaxCall
& eax_call
);
896 void validate_waveform(unsigned long ulWaveform
);
897 void validate_phase(long lPhase
);
898 void validate_rate(float flRate
);
899 void validate_depth(float flDepth
);
900 void validate_feedback(float flFeedback
);
901 void validate_delay(float flDelay
);
902 void validate_all(const EAXFLANGERPROPERTIES
& all
);
904 void defer_waveform(unsigned long ulWaveform
);
905 void defer_phase(long lPhase
);
906 void defer_rate(float flRate
);
907 void defer_depth(float flDepth
);
908 void defer_feedback(float flFeedback
);
909 void defer_delay(float flDelay
);
910 void defer_all(const EAXFLANGERPROPERTIES
& all
);
912 void defer_waveform(const EaxEaxCall
& eax_call
);
913 void defer_phase(const EaxEaxCall
& eax_call
);
914 void defer_rate(const EaxEaxCall
& eax_call
);
915 void defer_depth(const EaxEaxCall
& eax_call
);
916 void defer_feedback(const EaxEaxCall
& eax_call
);
917 void defer_delay(const EaxEaxCall
& eax_call
);
918 void defer_all(const EaxEaxCall
& eax_call
);
920 void set(const EaxEaxCall
& eax_call
);
921 }; // EaxFlangerEffect
924 class EaxFlangerEffectException
:
928 explicit EaxFlangerEffectException(
931 EaxException
{"EAX_FLANGER_EFFECT", message
}
934 }; // EaxFlangerEffectException
937 EaxFlangerEffect::EaxFlangerEffect()
938 : EaxEffect
{AL_EFFECT_FLANGER
}
944 void EaxFlangerEffect::dispatch(const EaxEaxCall
& eax_call
)
946 eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
949 void EaxFlangerEffect::set_eax_defaults()
951 eax_
.ulWaveform
= EAXFLANGER_DEFAULTWAVEFORM
;
952 eax_
.lPhase
= EAXFLANGER_DEFAULTPHASE
;
953 eax_
.flRate
= EAXFLANGER_DEFAULTRATE
;
954 eax_
.flDepth
= EAXFLANGER_DEFAULTDEPTH
;
955 eax_
.flFeedback
= EAXFLANGER_DEFAULTFEEDBACK
;
956 eax_
.flDelay
= EAXFLANGER_DEFAULTDELAY
;
961 void EaxFlangerEffect::set_efx_waveform()
963 const auto waveform
= clamp(
964 static_cast<ALint
>(eax_
.ulWaveform
),
965 AL_FLANGER_MIN_WAVEFORM
,
966 AL_FLANGER_MAX_WAVEFORM
);
968 eax_set_efx_waveform(waveform
, al_effect_props_
);
971 void EaxFlangerEffect::set_efx_phase()
973 const auto phase
= clamp(
974 static_cast<ALint
>(eax_
.lPhase
),
975 AL_FLANGER_MIN_PHASE
,
976 AL_FLANGER_MAX_PHASE
);
978 eax_set_efx_phase(phase
, al_effect_props_
);
981 void EaxFlangerEffect::set_efx_rate()
983 const auto rate
= clamp(
986 AL_FLANGER_MAX_RATE
);
988 eax_set_efx_rate(rate
, al_effect_props_
);
991 void EaxFlangerEffect::set_efx_depth()
993 const auto depth
= clamp(
995 AL_FLANGER_MIN_DEPTH
,
996 AL_FLANGER_MAX_DEPTH
);
998 eax_set_efx_depth(depth
, al_effect_props_
);
1001 void EaxFlangerEffect::set_efx_feedback()
1003 const auto feedback
= clamp(
1005 AL_FLANGER_MIN_FEEDBACK
,
1006 AL_FLANGER_MAX_FEEDBACK
);
1008 eax_set_efx_feedback(feedback
, al_effect_props_
);
1011 void EaxFlangerEffect::set_efx_delay()
1013 const auto delay
= clamp(
1015 AL_FLANGER_MIN_DELAY
,
1016 AL_FLANGER_MAX_DELAY
);
1018 eax_set_efx_delay(delay
, al_effect_props_
);
1021 void EaxFlangerEffect::set_efx_defaults()
1031 void EaxFlangerEffect::get(const EaxEaxCall
& eax_call
)
1033 switch(eax_call
.get_property_id())
1035 case EAXFLANGER_NONE
:
1038 case EAXFLANGER_ALLPARAMETERS
:
1039 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
);
1042 case EAXFLANGER_WAVEFORM
:
1043 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.ulWaveform
);
1046 case EAXFLANGER_PHASE
:
1047 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.lPhase
);
1050 case EAXFLANGER_RATE
:
1051 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flRate
);
1054 case EAXFLANGER_DEPTH
:
1055 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flDepth
);
1058 case EAXFLANGER_FEEDBACK
:
1059 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flFeedback
);
1062 case EAXFLANGER_DELAY
:
1063 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flDelay
);
1067 throw EaxFlangerEffectException
{"Unsupported property id."};
1071 void EaxFlangerEffect::validate_waveform(
1072 unsigned long ulWaveform
)
1074 eax_validate_range
<EaxFlangerEffectException
>(
1077 EAXFLANGER_MINWAVEFORM
,
1078 EAXFLANGER_MAXWAVEFORM
);
1081 void EaxFlangerEffect::validate_phase(
1084 eax_validate_range
<EaxFlangerEffectException
>(
1087 EAXFLANGER_MINPHASE
,
1088 EAXFLANGER_MAXPHASE
);
1091 void EaxFlangerEffect::validate_rate(
1094 eax_validate_range
<EaxFlangerEffectException
>(
1098 EAXFLANGER_MAXRATE
);
1101 void EaxFlangerEffect::validate_depth(
1104 eax_validate_range
<EaxFlangerEffectException
>(
1107 EAXFLANGER_MINDEPTH
,
1108 EAXFLANGER_MAXDEPTH
);
1111 void EaxFlangerEffect::validate_feedback(
1114 eax_validate_range
<EaxFlangerEffectException
>(
1117 EAXFLANGER_MINFEEDBACK
,
1118 EAXFLANGER_MAXFEEDBACK
);
1121 void EaxFlangerEffect::validate_delay(
1124 eax_validate_range
<EaxFlangerEffectException
>(
1127 EAXFLANGER_MINDELAY
,
1128 EAXFLANGER_MAXDELAY
);
1131 void EaxFlangerEffect::validate_all(
1132 const EAXFLANGERPROPERTIES
& all
)
1134 validate_waveform(all
.ulWaveform
);
1135 validate_phase(all
.lPhase
);
1136 validate_rate(all
.flRate
);
1137 validate_depth(all
.flDepth
);
1138 validate_feedback(all
.flDelay
);
1139 validate_delay(all
.flDelay
);
1142 void EaxFlangerEffect::defer_waveform(
1143 unsigned long ulWaveform
)
1145 eax_d_
.ulWaveform
= ulWaveform
;
1146 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
1149 void EaxFlangerEffect::defer_phase(
1152 eax_d_
.lPhase
= lPhase
;
1153 eax_dirty_flags_
.lPhase
= (eax_
.lPhase
!= eax_d_
.lPhase
);
1156 void EaxFlangerEffect::defer_rate(
1159 eax_d_
.flRate
= flRate
;
1160 eax_dirty_flags_
.flRate
= (eax_
.flRate
!= eax_d_
.flRate
);
1163 void EaxFlangerEffect::defer_depth(
1166 eax_d_
.flDepth
= flDepth
;
1167 eax_dirty_flags_
.flDepth
= (eax_
.flDepth
!= eax_d_
.flDepth
);
1170 void EaxFlangerEffect::defer_feedback(
1173 eax_d_
.flFeedback
= flFeedback
;
1174 eax_dirty_flags_
.flFeedback
= (eax_
.flFeedback
!= eax_d_
.flFeedback
);
1177 void EaxFlangerEffect::defer_delay(
1180 eax_d_
.flDelay
= flDelay
;
1181 eax_dirty_flags_
.flDelay
= (eax_
.flDelay
!= eax_d_
.flDelay
);
1184 void EaxFlangerEffect::defer_all(
1185 const EAXFLANGERPROPERTIES
& all
)
1187 defer_waveform(all
.ulWaveform
);
1188 defer_phase(all
.lPhase
);
1189 defer_rate(all
.flRate
);
1190 defer_depth(all
.flDepth
);
1191 defer_feedback(all
.flDelay
);
1192 defer_delay(all
.flDelay
);
1195 void EaxFlangerEffect::defer_waveform(
1196 const EaxEaxCall
& eax_call
)
1198 const auto& waveform
=
1199 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::ulWaveform
)>();
1201 validate_waveform(waveform
);
1202 defer_waveform(waveform
);
1205 void EaxFlangerEffect::defer_phase(
1206 const EaxEaxCall
& eax_call
)
1209 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::lPhase
)>();
1211 validate_phase(phase
);
1215 void EaxFlangerEffect::defer_rate(
1216 const EaxEaxCall
& eax_call
)
1219 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flRate
)>();
1221 validate_rate(rate
);
1225 void EaxFlangerEffect::defer_depth(
1226 const EaxEaxCall
& eax_call
)
1229 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flDepth
)>();
1231 validate_depth(depth
);
1235 void EaxFlangerEffect::defer_feedback(
1236 const EaxEaxCall
& eax_call
)
1238 const auto& feedback
=
1239 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flFeedback
)>();
1241 validate_feedback(feedback
);
1242 defer_feedback(feedback
);
1245 void EaxFlangerEffect::defer_delay(
1246 const EaxEaxCall
& eax_call
)
1249 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flDelay
)>();
1251 validate_delay(delay
);
1255 void EaxFlangerEffect::defer_all(
1256 const EaxEaxCall
& eax_call
)
1259 eax_call
.get_value
<EaxFlangerEffectException
, const EAXFLANGERPROPERTIES
>();
1266 bool EaxFlangerEffect::apply_deferred()
1268 if (eax_dirty_flags_
== EaxFlangerEffectDirtyFlags
{})
1275 if (eax_dirty_flags_
.ulWaveform
)
1280 if (eax_dirty_flags_
.lPhase
)
1285 if (eax_dirty_flags_
.flRate
)
1290 if (eax_dirty_flags_
.flDepth
)
1295 if (eax_dirty_flags_
.flFeedback
)
1300 if (eax_dirty_flags_
.flDelay
)
1305 eax_dirty_flags_
= EaxFlangerEffectDirtyFlags
{};
1310 void EaxFlangerEffect::set(const EaxEaxCall
& eax_call
)
1312 switch(eax_call
.get_property_id())
1314 case EAXFLANGER_NONE
:
1317 case EAXFLANGER_ALLPARAMETERS
:
1318 defer_all(eax_call
);
1321 case EAXFLANGER_WAVEFORM
:
1322 defer_waveform(eax_call
);
1325 case EAXFLANGER_PHASE
:
1326 defer_phase(eax_call
);
1329 case EAXFLANGER_RATE
:
1330 defer_rate(eax_call
);
1333 case EAXFLANGER_DEPTH
:
1334 defer_depth(eax_call
);
1337 case EAXFLANGER_FEEDBACK
:
1338 defer_feedback(eax_call
);
1341 case EAXFLANGER_DELAY
:
1342 defer_delay(eax_call
);
1346 throw EaxFlangerEffectException
{"Unsupported property id."};
1352 EaxEffectUPtr
eax_create_eax_flanger_effect()
1354 return std::make_unique
<EaxFlangerEffect
>();
1357 #endif // ALSOFT_EAX