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
:
365 const EaxEaxCall
& eax_call
) override
;
369 EAXCHORUSPROPERTIES eax_
{};
370 EAXCHORUSPROPERTIES eax_d_
{};
371 EaxChorusEffectDirtyFlags eax_dirty_flags_
{};
374 void set_eax_defaults() noexcept
;
377 void set_efx_waveform();
379 void set_efx_phase();
383 void set_efx_depth();
385 void set_efx_feedback();
387 void set_efx_delay();
389 void set_efx_defaults();
394 const EaxEaxCall
& eax_call
);
397 void validate_waveform(
398 unsigned long ulWaveform
);
409 void validate_feedback(
416 const EAXCHORUSPROPERTIES
& eax_all
);
420 unsigned long ulWaveform
);
438 const EAXCHORUSPROPERTIES
& eax_all
);
442 const EaxEaxCall
& eax_call
);
445 const EaxEaxCall
& eax_call
);
448 const EaxEaxCall
& eax_call
);
451 const EaxEaxCall
& eax_call
);
454 const EaxEaxCall
& eax_call
);
457 const EaxEaxCall
& eax_call
);
460 const EaxEaxCall
& eax_call
);
464 bool apply_deferred();
468 const EaxEaxCall
& eax_call
);
469 }; // EaxChorusEffect
472 class EaxChorusEffectException
:
476 explicit EaxChorusEffectException(
479 EaxException
{"EAX_CHORUS_EFFECT", message
}
482 }; // EaxChorusEffectException
485 EaxChorusEffect::EaxChorusEffect()
486 : EaxEffect
{AL_EFFECT_CHORUS
}
493 bool EaxChorusEffect::dispatch(
494 const EaxEaxCall
& eax_call
)
496 return eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
499 void EaxChorusEffect::set_eax_defaults() noexcept
501 eax_
.ulWaveform
= EAXCHORUS_DEFAULTWAVEFORM
;
502 eax_
.lPhase
= EAXCHORUS_DEFAULTPHASE
;
503 eax_
.flRate
= EAXCHORUS_DEFAULTRATE
;
504 eax_
.flDepth
= EAXCHORUS_DEFAULTDEPTH
;
505 eax_
.flFeedback
= EAXCHORUS_DEFAULTFEEDBACK
;
506 eax_
.flDelay
= EAXCHORUS_DEFAULTDELAY
;
511 void EaxChorusEffect::set_efx_waveform()
513 const auto waveform
= clamp(
514 static_cast<ALint
>(eax_
.ulWaveform
),
515 AL_CHORUS_MIN_WAVEFORM
,
516 AL_CHORUS_MAX_WAVEFORM
);
518 eax_set_efx_waveform(waveform
, al_effect_props_
);
521 void EaxChorusEffect::set_efx_phase()
523 const auto phase
= clamp(
524 static_cast<ALint
>(eax_
.lPhase
),
526 AL_CHORUS_MAX_PHASE
);
528 eax_set_efx_phase(phase
, al_effect_props_
);
531 void EaxChorusEffect::set_efx_rate()
533 const auto rate
= clamp(
538 eax_set_efx_rate(rate
, al_effect_props_
);
541 void EaxChorusEffect::set_efx_depth()
543 const auto depth
= clamp(
546 AL_CHORUS_MAX_DEPTH
);
548 eax_set_efx_depth(depth
, al_effect_props_
);
551 void EaxChorusEffect::set_efx_feedback()
553 const auto feedback
= clamp(
555 AL_CHORUS_MIN_FEEDBACK
,
556 AL_CHORUS_MAX_FEEDBACK
);
558 eax_set_efx_feedback(feedback
, al_effect_props_
);
561 void EaxChorusEffect::set_efx_delay()
563 const auto delay
= clamp(
566 AL_CHORUS_MAX_DELAY
);
568 eax_set_efx_delay(delay
, al_effect_props_
);
571 void EaxChorusEffect::set_efx_defaults()
581 bool EaxChorusEffect::get(
582 const EaxEaxCall
& eax_call
)
584 switch (eax_call
.get_property_id())
589 case EAXCHORUS_ALLPARAMETERS
:
590 eax_call
.set_value
<EaxChorusEffectException
>(eax_
);
593 case EAXCHORUS_WAVEFORM
:
594 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.ulWaveform
);
597 case EAXCHORUS_PHASE
:
598 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.lPhase
);
602 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flRate
);
605 case EAXCHORUS_DEPTH
:
606 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flDepth
);
609 case EAXCHORUS_FEEDBACK
:
610 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flFeedback
);
613 case EAXCHORUS_DELAY
:
614 eax_call
.set_value
<EaxChorusEffectException
>(eax_
.flDelay
);
618 throw EaxChorusEffectException
{"Unsupported property id."};
624 void EaxChorusEffect::validate_waveform(
625 unsigned long ulWaveform
)
627 eax_validate_range
<EaxChorusEffectException
>(
630 EAXCHORUS_MINWAVEFORM
,
631 EAXCHORUS_MAXWAVEFORM
);
634 void EaxChorusEffect::validate_phase(
637 eax_validate_range
<EaxChorusEffectException
>(
644 void EaxChorusEffect::validate_rate(
647 eax_validate_range
<EaxChorusEffectException
>(
654 void EaxChorusEffect::validate_depth(
657 eax_validate_range
<EaxChorusEffectException
>(
664 void EaxChorusEffect::validate_feedback(
667 eax_validate_range
<EaxChorusEffectException
>(
670 EAXCHORUS_MINFEEDBACK
,
671 EAXCHORUS_MAXFEEDBACK
);
674 void EaxChorusEffect::validate_delay(
677 eax_validate_range
<EaxChorusEffectException
>(
684 void EaxChorusEffect::validate_all(
685 const EAXCHORUSPROPERTIES
& eax_all
)
687 validate_waveform(eax_all
.ulWaveform
);
688 validate_phase(eax_all
.lPhase
);
689 validate_rate(eax_all
.flRate
);
690 validate_depth(eax_all
.flDepth
);
691 validate_feedback(eax_all
.flFeedback
);
692 validate_delay(eax_all
.flDelay
);
695 void EaxChorusEffect::defer_waveform(
696 unsigned long ulWaveform
)
698 eax_d_
.ulWaveform
= ulWaveform
;
699 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
702 void EaxChorusEffect::defer_phase(
705 eax_d_
.lPhase
= lPhase
;
706 eax_dirty_flags_
.lPhase
= (eax_
.lPhase
!= eax_d_
.lPhase
);
709 void EaxChorusEffect::defer_rate(
712 eax_d_
.flRate
= flRate
;
713 eax_dirty_flags_
.flRate
= (eax_
.flRate
!= eax_d_
.flRate
);
716 void EaxChorusEffect::defer_depth(
719 eax_d_
.flDepth
= flDepth
;
720 eax_dirty_flags_
.flDepth
= (eax_
.flDepth
!= eax_d_
.flDepth
);
723 void EaxChorusEffect::defer_feedback(
726 eax_d_
.flFeedback
= flFeedback
;
727 eax_dirty_flags_
.flFeedback
= (eax_
.flFeedback
!= eax_d_
.flFeedback
);
730 void EaxChorusEffect::defer_delay(
733 eax_d_
.flDelay
= flDelay
;
734 eax_dirty_flags_
.flDelay
= (eax_
.flDelay
!= eax_d_
.flDelay
);
737 void EaxChorusEffect::defer_all(
738 const EAXCHORUSPROPERTIES
& eax_all
)
740 defer_waveform(eax_all
.ulWaveform
);
741 defer_phase(eax_all
.lPhase
);
742 defer_rate(eax_all
.flRate
);
743 defer_depth(eax_all
.flDepth
);
744 defer_feedback(eax_all
.flFeedback
);
745 defer_delay(eax_all
.flDelay
);
748 void EaxChorusEffect::defer_waveform(
749 const EaxEaxCall
& eax_call
)
751 const auto& waveform
=
752 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::ulWaveform
)>();
754 validate_waveform(waveform
);
755 defer_waveform(waveform
);
758 void EaxChorusEffect::defer_phase(
759 const EaxEaxCall
& eax_call
)
762 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::lPhase
)>();
764 validate_phase(phase
);
768 void EaxChorusEffect::defer_rate(
769 const EaxEaxCall
& eax_call
)
772 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flRate
)>();
778 void EaxChorusEffect::defer_depth(
779 const EaxEaxCall
& eax_call
)
782 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flDepth
)>();
784 validate_depth(depth
);
788 void EaxChorusEffect::defer_feedback(
789 const EaxEaxCall
& eax_call
)
791 const auto& feedback
=
792 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flFeedback
)>();
794 validate_feedback(feedback
);
795 defer_feedback(feedback
);
798 void EaxChorusEffect::defer_delay(
799 const EaxEaxCall
& eax_call
)
802 eax_call
.get_value
<EaxChorusEffectException
, const decltype(EAXCHORUSPROPERTIES::flDelay
)>();
804 validate_delay(delay
);
808 void EaxChorusEffect::defer_all(
809 const EaxEaxCall
& eax_call
)
812 eax_call
.get_value
<EaxChorusEffectException
, const EAXCHORUSPROPERTIES
>();
819 bool EaxChorusEffect::apply_deferred()
821 if (eax_dirty_flags_
== EaxChorusEffectDirtyFlags
{})
828 if (eax_dirty_flags_
.ulWaveform
)
833 if (eax_dirty_flags_
.lPhase
)
838 if (eax_dirty_flags_
.flRate
)
843 if (eax_dirty_flags_
.flDepth
)
848 if (eax_dirty_flags_
.flFeedback
)
853 if (eax_dirty_flags_
.flDelay
)
858 eax_dirty_flags_
= EaxChorusEffectDirtyFlags
{};
864 bool EaxChorusEffect::set(
865 const EaxEaxCall
& eax_call
)
867 switch (eax_call
.get_property_id())
872 case EAXCHORUS_ALLPARAMETERS
:
876 case EAXCHORUS_WAVEFORM
:
877 defer_waveform(eax_call
);
880 case EAXCHORUS_PHASE
:
881 defer_phase(eax_call
);
885 defer_rate(eax_call
);
888 case EAXCHORUS_DEPTH
:
889 defer_depth(eax_call
);
892 case EAXCHORUS_FEEDBACK
:
893 defer_feedback(eax_call
);
896 case EAXCHORUS_DELAY
:
897 defer_delay(eax_call
);
901 throw EaxChorusEffectException
{"Unsupported property id."};
904 if (!eax_call
.is_deferred())
906 return apply_deferred();
916 EaxEffectUPtr
eax_create_eax_chorus_effect()
918 return std::make_unique
<::EaxChorusEffect
>();
926 using EaxFlangerEffectDirtyFlagsValue
= std::uint_least8_t;
928 struct EaxFlangerEffectDirtyFlags
930 using EaxIsBitFieldStruct
= bool;
932 EaxFlangerEffectDirtyFlagsValue ulWaveform
: 1;
933 EaxFlangerEffectDirtyFlagsValue lPhase
: 1;
934 EaxFlangerEffectDirtyFlagsValue flRate
: 1;
935 EaxFlangerEffectDirtyFlagsValue flDepth
: 1;
936 EaxFlangerEffectDirtyFlagsValue flFeedback
: 1;
937 EaxFlangerEffectDirtyFlagsValue flDelay
: 1;
938 }; // EaxFlangerEffectDirtyFlags
941 class EaxFlangerEffect final
:
950 const EaxEaxCall
& eax_call
) override
;
954 EAXFLANGERPROPERTIES eax_
{};
955 EAXFLANGERPROPERTIES eax_d_
{};
956 EaxFlangerEffectDirtyFlags eax_dirty_flags_
{};
959 void set_eax_defaults();
962 void set_efx_waveform();
964 void set_efx_phase();
968 void set_efx_depth();
970 void set_efx_feedback();
972 void set_efx_delay();
974 void set_efx_defaults();
979 const EaxEaxCall
& eax_call
);
982 void validate_waveform(
983 unsigned long ulWaveform
);
994 void validate_feedback(
1001 const EAXFLANGERPROPERTIES
& all
);
1004 void defer_waveform(
1005 unsigned long ulWaveform
);
1016 void defer_feedback(
1023 const EAXFLANGERPROPERTIES
& all
);
1026 void defer_waveform(
1027 const EaxEaxCall
& eax_call
);
1030 const EaxEaxCall
& eax_call
);
1033 const EaxEaxCall
& eax_call
);
1036 const EaxEaxCall
& eax_call
);
1038 void defer_feedback(
1039 const EaxEaxCall
& eax_call
);
1042 const EaxEaxCall
& eax_call
);
1045 const EaxEaxCall
& eax_call
);
1049 bool apply_deferred();
1053 const EaxEaxCall
& eax_call
);
1054 }; // EaxFlangerEffect
1057 class EaxFlangerEffectException
:
1061 explicit EaxFlangerEffectException(
1062 const char* message
)
1064 EaxException
{"EAX_FLANGER_EFFECT", message
}
1067 }; // EaxFlangerEffectException
1070 EaxFlangerEffect::EaxFlangerEffect()
1071 : EaxEffect
{AL_EFFECT_FLANGER
}
1078 bool EaxFlangerEffect::dispatch(
1079 const EaxEaxCall
& eax_call
)
1081 return eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
1084 void EaxFlangerEffect::set_eax_defaults()
1086 eax_
.ulWaveform
= EAXFLANGER_DEFAULTWAVEFORM
;
1087 eax_
.lPhase
= EAXFLANGER_DEFAULTPHASE
;
1088 eax_
.flRate
= EAXFLANGER_DEFAULTRATE
;
1089 eax_
.flDepth
= EAXFLANGER_DEFAULTDEPTH
;
1090 eax_
.flFeedback
= EAXFLANGER_DEFAULTFEEDBACK
;
1091 eax_
.flDelay
= EAXFLANGER_DEFAULTDELAY
;
1096 void EaxFlangerEffect::set_efx_waveform()
1098 const auto waveform
= clamp(
1099 static_cast<ALint
>(eax_
.ulWaveform
),
1100 AL_FLANGER_MIN_WAVEFORM
,
1101 AL_FLANGER_MAX_WAVEFORM
);
1103 eax_set_efx_waveform(waveform
, al_effect_props_
);
1106 void EaxFlangerEffect::set_efx_phase()
1108 const auto phase
= clamp(
1109 static_cast<ALint
>(eax_
.lPhase
),
1110 AL_FLANGER_MIN_PHASE
,
1111 AL_FLANGER_MAX_PHASE
);
1113 eax_set_efx_phase(phase
, al_effect_props_
);
1116 void EaxFlangerEffect::set_efx_rate()
1118 const auto rate
= clamp(
1120 AL_FLANGER_MIN_RATE
,
1121 AL_FLANGER_MAX_RATE
);
1123 eax_set_efx_rate(rate
, al_effect_props_
);
1126 void EaxFlangerEffect::set_efx_depth()
1128 const auto depth
= clamp(
1130 AL_FLANGER_MIN_DEPTH
,
1131 AL_FLANGER_MAX_DEPTH
);
1133 eax_set_efx_depth(depth
, al_effect_props_
);
1136 void EaxFlangerEffect::set_efx_feedback()
1138 const auto feedback
= clamp(
1140 AL_FLANGER_MIN_FEEDBACK
,
1141 AL_FLANGER_MAX_FEEDBACK
);
1143 eax_set_efx_feedback(feedback
, al_effect_props_
);
1146 void EaxFlangerEffect::set_efx_delay()
1148 const auto delay
= clamp(
1150 AL_FLANGER_MIN_DELAY
,
1151 AL_FLANGER_MAX_DELAY
);
1153 eax_set_efx_delay(delay
, al_effect_props_
);
1156 void EaxFlangerEffect::set_efx_defaults()
1167 bool EaxFlangerEffect::get(
1168 const EaxEaxCall
& eax_call
)
1170 switch (eax_call
.get_property_id())
1172 case EAXFLANGER_NONE
:
1175 case EAXFLANGER_ALLPARAMETERS
:
1176 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
);
1179 case EAXFLANGER_WAVEFORM
:
1180 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.ulWaveform
);
1183 case EAXFLANGER_PHASE
:
1184 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.lPhase
);
1187 case EAXFLANGER_RATE
:
1188 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flRate
);
1191 case EAXFLANGER_DEPTH
:
1192 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flDepth
);
1195 case EAXFLANGER_FEEDBACK
:
1196 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flFeedback
);
1199 case EAXFLANGER_DELAY
:
1200 eax_call
.set_value
<EaxFlangerEffectException
>(eax_
.flDelay
);
1204 throw EaxFlangerEffectException
{"Unsupported property id."};
1210 void EaxFlangerEffect::validate_waveform(
1211 unsigned long ulWaveform
)
1213 eax_validate_range
<EaxFlangerEffectException
>(
1216 EAXFLANGER_MINWAVEFORM
,
1217 EAXFLANGER_MAXWAVEFORM
);
1220 void EaxFlangerEffect::validate_phase(
1223 eax_validate_range
<EaxFlangerEffectException
>(
1226 EAXFLANGER_MINPHASE
,
1227 EAXFLANGER_MAXPHASE
);
1230 void EaxFlangerEffect::validate_rate(
1233 eax_validate_range
<EaxFlangerEffectException
>(
1237 EAXFLANGER_MAXRATE
);
1240 void EaxFlangerEffect::validate_depth(
1243 eax_validate_range
<EaxFlangerEffectException
>(
1246 EAXFLANGER_MINDEPTH
,
1247 EAXFLANGER_MAXDEPTH
);
1250 void EaxFlangerEffect::validate_feedback(
1253 eax_validate_range
<EaxFlangerEffectException
>(
1256 EAXFLANGER_MINFEEDBACK
,
1257 EAXFLANGER_MAXFEEDBACK
);
1260 void EaxFlangerEffect::validate_delay(
1263 eax_validate_range
<EaxFlangerEffectException
>(
1266 EAXFLANGER_MINDELAY
,
1267 EAXFLANGER_MAXDELAY
);
1270 void EaxFlangerEffect::validate_all(
1271 const EAXFLANGERPROPERTIES
& all
)
1273 validate_waveform(all
.ulWaveform
);
1274 validate_phase(all
.lPhase
);
1275 validate_rate(all
.flRate
);
1276 validate_depth(all
.flDepth
);
1277 validate_feedback(all
.flDelay
);
1278 validate_delay(all
.flDelay
);
1281 void EaxFlangerEffect::defer_waveform(
1282 unsigned long ulWaveform
)
1284 eax_d_
.ulWaveform
= ulWaveform
;
1285 eax_dirty_flags_
.ulWaveform
= (eax_
.ulWaveform
!= eax_d_
.ulWaveform
);
1288 void EaxFlangerEffect::defer_phase(
1291 eax_d_
.lPhase
= lPhase
;
1292 eax_dirty_flags_
.lPhase
= (eax_
.lPhase
!= eax_d_
.lPhase
);
1295 void EaxFlangerEffect::defer_rate(
1298 eax_d_
.flRate
= flRate
;
1299 eax_dirty_flags_
.flRate
= (eax_
.flRate
!= eax_d_
.flRate
);
1302 void EaxFlangerEffect::defer_depth(
1305 eax_d_
.flDepth
= flDepth
;
1306 eax_dirty_flags_
.flDepth
= (eax_
.flDepth
!= eax_d_
.flDepth
);
1309 void EaxFlangerEffect::defer_feedback(
1312 eax_d_
.flFeedback
= flFeedback
;
1313 eax_dirty_flags_
.flFeedback
= (eax_
.flFeedback
!= eax_d_
.flFeedback
);
1316 void EaxFlangerEffect::defer_delay(
1319 eax_d_
.flDelay
= flDelay
;
1320 eax_dirty_flags_
.flDelay
= (eax_
.flDelay
!= eax_d_
.flDelay
);
1323 void EaxFlangerEffect::defer_all(
1324 const EAXFLANGERPROPERTIES
& all
)
1326 defer_waveform(all
.ulWaveform
);
1327 defer_phase(all
.lPhase
);
1328 defer_rate(all
.flRate
);
1329 defer_depth(all
.flDepth
);
1330 defer_feedback(all
.flDelay
);
1331 defer_delay(all
.flDelay
);
1334 void EaxFlangerEffect::defer_waveform(
1335 const EaxEaxCall
& eax_call
)
1337 const auto& waveform
=
1338 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::ulWaveform
)>();
1340 validate_waveform(waveform
);
1341 defer_waveform(waveform
);
1344 void EaxFlangerEffect::defer_phase(
1345 const EaxEaxCall
& eax_call
)
1348 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::lPhase
)>();
1350 validate_phase(phase
);
1354 void EaxFlangerEffect::defer_rate(
1355 const EaxEaxCall
& eax_call
)
1358 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flRate
)>();
1360 validate_rate(rate
);
1364 void EaxFlangerEffect::defer_depth(
1365 const EaxEaxCall
& eax_call
)
1368 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flDepth
)>();
1370 validate_depth(depth
);
1374 void EaxFlangerEffect::defer_feedback(
1375 const EaxEaxCall
& eax_call
)
1377 const auto& feedback
=
1378 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flFeedback
)>();
1380 validate_feedback(feedback
);
1381 defer_feedback(feedback
);
1384 void EaxFlangerEffect::defer_delay(
1385 const EaxEaxCall
& eax_call
)
1388 eax_call
.get_value
<EaxFlangerEffectException
, const decltype(EAXFLANGERPROPERTIES::flDelay
)>();
1390 validate_delay(delay
);
1394 void EaxFlangerEffect::defer_all(
1395 const EaxEaxCall
& eax_call
)
1398 eax_call
.get_value
<EaxFlangerEffectException
, const EAXFLANGERPROPERTIES
>();
1405 bool EaxFlangerEffect::apply_deferred()
1407 if (eax_dirty_flags_
== EaxFlangerEffectDirtyFlags
{})
1414 if (eax_dirty_flags_
.ulWaveform
)
1419 if (eax_dirty_flags_
.lPhase
)
1424 if (eax_dirty_flags_
.flRate
)
1429 if (eax_dirty_flags_
.flDepth
)
1434 if (eax_dirty_flags_
.flFeedback
)
1439 if (eax_dirty_flags_
.flDelay
)
1444 eax_dirty_flags_
= EaxFlangerEffectDirtyFlags
{};
1450 bool EaxFlangerEffect::set(
1451 const EaxEaxCall
& eax_call
)
1453 switch (eax_call
.get_property_id())
1455 case EAXFLANGER_NONE
:
1458 case EAXFLANGER_ALLPARAMETERS
:
1459 defer_all(eax_call
);
1462 case EAXFLANGER_WAVEFORM
:
1463 defer_waveform(eax_call
);
1466 case EAXFLANGER_PHASE
:
1467 defer_phase(eax_call
);
1470 case EAXFLANGER_RATE
:
1471 defer_rate(eax_call
);
1474 case EAXFLANGER_DEPTH
:
1475 defer_depth(eax_call
);
1478 case EAXFLANGER_FEEDBACK
:
1479 defer_feedback(eax_call
);
1482 case EAXFLANGER_DELAY
:
1483 defer_delay(eax_call
);
1487 throw EaxFlangerEffectException
{"Unsupported property id."};
1490 if (!eax_call
.is_deferred())
1492 return apply_deferred();
1500 EaxEffectUPtr
eax_create_eax_flanger_effect()
1502 return std::make_unique
<EaxFlangerEffect
>();
1505 #endif // ALSOFT_EAX