Check for unsigned underflow
[openal-soft.git] / al / effects / chorus.cpp
blob7d8569bcd61a0517ffae28303249a07600c16c13
2 #include "config.h"
4 #include <optional>
5 #include <stdexcept>
7 #include "AL/al.h"
8 #include "AL/efx.h"
10 #include "effects.h"
12 #if ALSOFT_EAX
13 #include <cassert>
14 #include "al/eax/effect.h"
15 #include "al/eax/exception.h"
16 #include "al/eax/utils.h"
17 #endif // ALSOFT_EAX
20 namespace {
22 static_assert(ChorusMaxDelay >= AL_CHORUS_MAX_DELAY, "Chorus max delay too small");
23 static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too small");
25 static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
26 static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
28 constexpr std::optional<ChorusWaveform> WaveformFromEnum(ALenum type) noexcept
30 switch(type)
32 case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid;
33 case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle;
35 return std::nullopt;
37 constexpr ALenum EnumFromWaveform(ChorusWaveform type)
39 switch(type)
41 case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
42 case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
44 throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
47 constexpr EffectProps genDefaultChorusProps() noexcept
49 ChorusProps props{};
50 props.Waveform = WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM).value();
51 props.Phase = AL_CHORUS_DEFAULT_PHASE;
52 props.Rate = AL_CHORUS_DEFAULT_RATE;
53 props.Depth = AL_CHORUS_DEFAULT_DEPTH;
54 props.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
55 props.Delay = AL_CHORUS_DEFAULT_DELAY;
56 return props;
59 constexpr EffectProps genDefaultFlangerProps() noexcept
61 ChorusProps props{};
62 props.Waveform = WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM).value();
63 props.Phase = AL_FLANGER_DEFAULT_PHASE;
64 props.Rate = AL_FLANGER_DEFAULT_RATE;
65 props.Depth = AL_FLANGER_DEFAULT_DEPTH;
66 props.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
67 props.Delay = AL_FLANGER_DEFAULT_DELAY;
68 return props;
71 } // namespace
73 const EffectProps ChorusEffectProps{genDefaultChorusProps()};
75 void ChorusEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
77 switch(param)
79 case AL_CHORUS_WAVEFORM:
80 if(auto formopt = WaveformFromEnum(val))
81 props.Waveform = *formopt;
82 else
83 throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
84 break;
86 case AL_CHORUS_PHASE:
87 if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
88 throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
89 props.Phase = val;
90 break;
92 default:
93 throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
96 void ChorusEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
97 { SetParami(props, param, *vals); }
98 void ChorusEffectHandler::SetParamf(ChorusProps &props, ALenum param, float val)
100 switch(param)
102 case AL_CHORUS_RATE:
103 if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
104 throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
105 props.Rate = val;
106 break;
108 case AL_CHORUS_DEPTH:
109 if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
110 throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
111 props.Depth = val;
112 break;
114 case AL_CHORUS_FEEDBACK:
115 if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
116 throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
117 props.Feedback = val;
118 break;
120 case AL_CHORUS_DELAY:
121 if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
122 throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
123 props.Delay = val;
124 break;
126 default:
127 throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
130 void ChorusEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
131 { SetParamf(props, param, *vals); }
133 void ChorusEffectHandler::GetParami(const ChorusProps &props, ALenum param, int *val)
135 switch(param)
137 case AL_CHORUS_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
138 case AL_CHORUS_PHASE: *val = props.Phase; break;
140 default:
141 throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
144 void ChorusEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
145 { GetParami(props, param, vals); }
146 void ChorusEffectHandler::GetParamf(const ChorusProps &props, ALenum param, float *val)
148 switch(param)
150 case AL_CHORUS_RATE: *val = props.Rate; break;
151 case AL_CHORUS_DEPTH: *val = props.Depth; break;
152 case AL_CHORUS_FEEDBACK: *val = props.Feedback; break;
153 case AL_CHORUS_DELAY: *val = props.Delay; break;
155 default:
156 throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
159 void ChorusEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
160 { GetParamf(props, param, vals); }
163 const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
165 void FlangerEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
167 switch(param)
169 case AL_FLANGER_WAVEFORM:
170 if(auto formopt = WaveformFromEnum(val))
171 props.Waveform = *formopt;
172 else
173 throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
174 break;
176 case AL_FLANGER_PHASE:
177 if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
178 throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
179 props.Phase = val;
180 break;
182 default:
183 throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
186 void FlangerEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
187 { SetParami(props, param, *vals); }
188 void FlangerEffectHandler::SetParamf(ChorusProps &props, ALenum param, float val)
190 switch(param)
192 case AL_FLANGER_RATE:
193 if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
194 throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
195 props.Rate = val;
196 break;
198 case AL_FLANGER_DEPTH:
199 if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
200 throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
201 props.Depth = val;
202 break;
204 case AL_FLANGER_FEEDBACK:
205 if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
206 throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
207 props.Feedback = val;
208 break;
210 case AL_FLANGER_DELAY:
211 if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
212 throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
213 props.Delay = val;
214 break;
216 default:
217 throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
220 void FlangerEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
221 { SetParamf(props, param, *vals); }
223 void FlangerEffectHandler::GetParami(const ChorusProps &props, ALenum param, int *val)
225 switch(param)
227 case AL_FLANGER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
228 case AL_FLANGER_PHASE: *val = props.Phase; break;
230 default:
231 throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
234 void FlangerEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
235 { GetParami(props, param, vals); }
236 void FlangerEffectHandler::GetParamf(const ChorusProps &props, ALenum param, float *val)
238 switch(param)
240 case AL_FLANGER_RATE: *val = props.Rate; break;
241 case AL_FLANGER_DEPTH: *val = props.Depth; break;
242 case AL_FLANGER_FEEDBACK: *val = props.Feedback; break;
243 case AL_FLANGER_DELAY: *val = props.Delay; break;
245 default:
246 throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
249 void FlangerEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
250 { GetParamf(props, param, vals); }
253 #if ALSOFT_EAX
254 namespace {
256 struct EaxChorusTraits {
257 using EaxProps = EAXCHORUSPROPERTIES;
258 using Committer = EaxChorusCommitter;
260 static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; }
262 static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; }
263 static constexpr auto eax_allparameters_param_id() { return EAXCHORUS_ALLPARAMETERS; }
264 static constexpr auto eax_waveform_param_id() { return EAXCHORUS_WAVEFORM; }
265 static constexpr auto eax_phase_param_id() { return EAXCHORUS_PHASE; }
266 static constexpr auto eax_rate_param_id() { return EAXCHORUS_RATE; }
267 static constexpr auto eax_depth_param_id() { return EAXCHORUS_DEPTH; }
268 static constexpr auto eax_feedback_param_id() { return EAXCHORUS_FEEDBACK; }
269 static constexpr auto eax_delay_param_id() { return EAXCHORUS_DELAY; }
271 static constexpr auto eax_min_waveform() { return EAXCHORUS_MINWAVEFORM; }
272 static constexpr auto eax_min_phase() { return EAXCHORUS_MINPHASE; }
273 static constexpr auto eax_min_rate() { return EAXCHORUS_MINRATE; }
274 static constexpr auto eax_min_depth() { return EAXCHORUS_MINDEPTH; }
275 static constexpr auto eax_min_feedback() { return EAXCHORUS_MINFEEDBACK; }
276 static constexpr auto eax_min_delay() { return EAXCHORUS_MINDELAY; }
278 static constexpr auto eax_max_waveform() { return EAXCHORUS_MAXWAVEFORM; }
279 static constexpr auto eax_max_phase() { return EAXCHORUS_MAXPHASE; }
280 static constexpr auto eax_max_rate() { return EAXCHORUS_MAXRATE; }
281 static constexpr auto eax_max_depth() { return EAXCHORUS_MAXDEPTH; }
282 static constexpr auto eax_max_feedback() { return EAXCHORUS_MAXFEEDBACK; }
283 static constexpr auto eax_max_delay() { return EAXCHORUS_MAXDELAY; }
285 static constexpr auto eax_default_waveform() { return EAXCHORUS_DEFAULTWAVEFORM; }
286 static constexpr auto eax_default_phase() { return EAXCHORUS_DEFAULTPHASE; }
287 static constexpr auto eax_default_rate() { return EAXCHORUS_DEFAULTRATE; }
288 static constexpr auto eax_default_depth() { return EAXCHORUS_DEFAULTDEPTH; }
289 static constexpr auto eax_default_feedback() { return EAXCHORUS_DEFAULTFEEDBACK; }
290 static constexpr auto eax_default_delay() { return EAXCHORUS_DEFAULTDELAY; }
292 static constexpr auto efx_min_waveform() { return AL_CHORUS_MIN_WAVEFORM; }
293 static constexpr auto efx_min_phase() { return AL_CHORUS_MIN_PHASE; }
294 static constexpr auto efx_min_rate() { return AL_CHORUS_MIN_RATE; }
295 static constexpr auto efx_min_depth() { return AL_CHORUS_MIN_DEPTH; }
296 static constexpr auto efx_min_feedback() { return AL_CHORUS_MIN_FEEDBACK; }
297 static constexpr auto efx_min_delay() { return AL_CHORUS_MIN_DELAY; }
299 static constexpr auto efx_max_waveform() { return AL_CHORUS_MAX_WAVEFORM; }
300 static constexpr auto efx_max_phase() { return AL_CHORUS_MAX_PHASE; }
301 static constexpr auto efx_max_rate() { return AL_CHORUS_MAX_RATE; }
302 static constexpr auto efx_max_depth() { return AL_CHORUS_MAX_DEPTH; }
303 static constexpr auto efx_max_feedback() { return AL_CHORUS_MAX_FEEDBACK; }
304 static constexpr auto efx_max_delay() { return AL_CHORUS_MAX_DELAY; }
306 static constexpr auto efx_default_waveform() { return AL_CHORUS_DEFAULT_WAVEFORM; }
307 static constexpr auto efx_default_phase() { return AL_CHORUS_DEFAULT_PHASE; }
308 static constexpr auto efx_default_rate() { return AL_CHORUS_DEFAULT_RATE; }
309 static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; }
310 static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; }
311 static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; }
313 static ChorusWaveform eax_waveform(unsigned long type)
315 if(type == EAX_CHORUS_SINUSOID) return ChorusWaveform::Sinusoid;
316 if(type == EAX_CHORUS_TRIANGLE) return ChorusWaveform::Triangle;
317 return ChorusWaveform::Sinusoid;
319 }; // EaxChorusTraits
321 struct EaxFlangerTraits {
322 using EaxProps = EAXFLANGERPROPERTIES;
323 using Committer = EaxFlangerCommitter;
325 static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; }
327 static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; }
328 static constexpr auto eax_allparameters_param_id() { return EAXFLANGER_ALLPARAMETERS; }
329 static constexpr auto eax_waveform_param_id() { return EAXFLANGER_WAVEFORM; }
330 static constexpr auto eax_phase_param_id() { return EAXFLANGER_PHASE; }
331 static constexpr auto eax_rate_param_id() { return EAXFLANGER_RATE; }
332 static constexpr auto eax_depth_param_id() { return EAXFLANGER_DEPTH; }
333 static constexpr auto eax_feedback_param_id() { return EAXFLANGER_FEEDBACK; }
334 static constexpr auto eax_delay_param_id() { return EAXFLANGER_DELAY; }
336 static constexpr auto eax_min_waveform() { return EAXFLANGER_MINWAVEFORM; }
337 static constexpr auto eax_min_phase() { return EAXFLANGER_MINPHASE; }
338 static constexpr auto eax_min_rate() { return EAXFLANGER_MINRATE; }
339 static constexpr auto eax_min_depth() { return EAXFLANGER_MINDEPTH; }
340 static constexpr auto eax_min_feedback() { return EAXFLANGER_MINFEEDBACK; }
341 static constexpr auto eax_min_delay() { return EAXFLANGER_MINDELAY; }
343 static constexpr auto eax_max_waveform() { return EAXFLANGER_MAXWAVEFORM; }
344 static constexpr auto eax_max_phase() { return EAXFLANGER_MAXPHASE; }
345 static constexpr auto eax_max_rate() { return EAXFLANGER_MAXRATE; }
346 static constexpr auto eax_max_depth() { return EAXFLANGER_MAXDEPTH; }
347 static constexpr auto eax_max_feedback() { return EAXFLANGER_MAXFEEDBACK; }
348 static constexpr auto eax_max_delay() { return EAXFLANGER_MAXDELAY; }
350 static constexpr auto eax_default_waveform() { return EAXFLANGER_DEFAULTWAVEFORM; }
351 static constexpr auto eax_default_phase() { return EAXFLANGER_DEFAULTPHASE; }
352 static constexpr auto eax_default_rate() { return EAXFLANGER_DEFAULTRATE; }
353 static constexpr auto eax_default_depth() { return EAXFLANGER_DEFAULTDEPTH; }
354 static constexpr auto eax_default_feedback() { return EAXFLANGER_DEFAULTFEEDBACK; }
355 static constexpr auto eax_default_delay() { return EAXFLANGER_DEFAULTDELAY; }
357 static constexpr auto efx_min_waveform() { return AL_FLANGER_MIN_WAVEFORM; }
358 static constexpr auto efx_min_phase() { return AL_FLANGER_MIN_PHASE; }
359 static constexpr auto efx_min_rate() { return AL_FLANGER_MIN_RATE; }
360 static constexpr auto efx_min_depth() { return AL_FLANGER_MIN_DEPTH; }
361 static constexpr auto efx_min_feedback() { return AL_FLANGER_MIN_FEEDBACK; }
362 static constexpr auto efx_min_delay() { return AL_FLANGER_MIN_DELAY; }
364 static constexpr auto efx_max_waveform() { return AL_FLANGER_MAX_WAVEFORM; }
365 static constexpr auto efx_max_phase() { return AL_FLANGER_MAX_PHASE; }
366 static constexpr auto efx_max_rate() { return AL_FLANGER_MAX_RATE; }
367 static constexpr auto efx_max_depth() { return AL_FLANGER_MAX_DEPTH; }
368 static constexpr auto efx_max_feedback() { return AL_FLANGER_MAX_FEEDBACK; }
369 static constexpr auto efx_max_delay() { return AL_FLANGER_MAX_DELAY; }
371 static constexpr auto efx_default_waveform() { return AL_FLANGER_DEFAULT_WAVEFORM; }
372 static constexpr auto efx_default_phase() { return AL_FLANGER_DEFAULT_PHASE; }
373 static constexpr auto efx_default_rate() { return AL_FLANGER_DEFAULT_RATE; }
374 static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; }
375 static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; }
376 static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; }
378 static ChorusWaveform eax_waveform(unsigned long type)
380 if(type == EAX_FLANGER_SINUSOID) return ChorusWaveform::Sinusoid;
381 if(type == EAX_FLANGER_TRIANGLE) return ChorusWaveform::Triangle;
382 return ChorusWaveform::Sinusoid;
384 }; // EaxFlangerTraits
386 template<typename TTraits>
387 struct ChorusFlangerEffect {
388 using Traits = TTraits;
389 using EaxProps = typename Traits::EaxProps;
390 using Committer = typename Traits::Committer;
391 using Exception = typename Committer::Exception;
393 struct WaveformValidator {
394 void operator()(unsigned long ulWaveform) const
396 eax_validate_range<Exception>(
397 "Waveform",
398 ulWaveform,
399 Traits::eax_min_waveform(),
400 Traits::eax_max_waveform());
402 }; // WaveformValidator
404 struct PhaseValidator {
405 void operator()(long lPhase) const
407 eax_validate_range<Exception>(
408 "Phase",
409 lPhase,
410 Traits::eax_min_phase(),
411 Traits::eax_max_phase());
413 }; // PhaseValidator
415 struct RateValidator {
416 void operator()(float flRate) const
418 eax_validate_range<Exception>(
419 "Rate",
420 flRate,
421 Traits::eax_min_rate(),
422 Traits::eax_max_rate());
424 }; // RateValidator
426 struct DepthValidator {
427 void operator()(float flDepth) const
429 eax_validate_range<Exception>(
430 "Depth",
431 flDepth,
432 Traits::eax_min_depth(),
433 Traits::eax_max_depth());
435 }; // DepthValidator
437 struct FeedbackValidator {
438 void operator()(float flFeedback) const
440 eax_validate_range<Exception>(
441 "Feedback",
442 flFeedback,
443 Traits::eax_min_feedback(),
444 Traits::eax_max_feedback());
446 }; // FeedbackValidator
448 struct DelayValidator {
449 void operator()(float flDelay) const
451 eax_validate_range<Exception>(
452 "Delay",
453 flDelay,
454 Traits::eax_min_delay(),
455 Traits::eax_max_delay());
457 }; // DelayValidator
459 struct AllValidator {
460 void operator()(const EaxProps& all) const
462 WaveformValidator{}(all.ulWaveform);
463 PhaseValidator{}(all.lPhase);
464 RateValidator{}(all.flRate);
465 DepthValidator{}(all.flDepth);
466 FeedbackValidator{}(all.flFeedback);
467 DelayValidator{}(all.flDelay);
469 }; // AllValidator
471 public:
472 static void SetDefaults(EaxEffectProps &props)
474 auto&& all = props.emplace<EaxProps>();
475 all.ulWaveform = Traits::eax_default_waveform();
476 all.lPhase = Traits::eax_default_phase();
477 all.flRate = Traits::eax_default_rate();
478 all.flDepth = Traits::eax_default_depth();
479 all.flFeedback = Traits::eax_default_feedback();
480 all.flDelay = Traits::eax_default_delay();
484 static void Get(const EaxCall &call, const EaxProps &all)
486 switch(call.get_property_id())
488 case Traits::eax_none_param_id():
489 break;
490 case Traits::eax_allparameters_param_id():
491 call.template set_value<Exception>(all);
492 break;
493 case Traits::eax_waveform_param_id():
494 call.template set_value<Exception>(all.ulWaveform);
495 break;
496 case Traits::eax_phase_param_id():
497 call.template set_value<Exception>(all.lPhase);
498 break;
499 case Traits::eax_rate_param_id():
500 call.template set_value<Exception>(all.flRate);
501 break;
502 case Traits::eax_depth_param_id():
503 call.template set_value<Exception>(all.flDepth);
504 break;
505 case Traits::eax_feedback_param_id():
506 call.template set_value<Exception>(all.flFeedback);
507 break;
508 case Traits::eax_delay_param_id():
509 call.template set_value<Exception>(all.flDelay);
510 break;
511 default:
512 Committer::fail_unknown_property_id();
516 static void Set(const EaxCall &call, EaxProps &all)
518 switch(call.get_property_id())
520 case Traits::eax_none_param_id():
521 break;
522 case Traits::eax_allparameters_param_id():
523 Committer::template defer<AllValidator>(call, all);
524 break;
525 case Traits::eax_waveform_param_id():
526 Committer::template defer<WaveformValidator>(call, all.ulWaveform);
527 break;
528 case Traits::eax_phase_param_id():
529 Committer::template defer<PhaseValidator>(call, all.lPhase);
530 break;
531 case Traits::eax_rate_param_id():
532 Committer::template defer<RateValidator>(call, all.flRate);
533 break;
534 case Traits::eax_depth_param_id():
535 Committer::template defer<DepthValidator>(call, all.flDepth);
536 break;
537 case Traits::eax_feedback_param_id():
538 Committer::template defer<FeedbackValidator>(call, all.flFeedback);
539 break;
540 case Traits::eax_delay_param_id():
541 Committer::template defer<DelayValidator>(call, all.flDelay);
542 break;
543 default:
544 Committer::fail_unknown_property_id();
548 static bool Commit(const EaxProps &props, EaxEffectProps &props_, ChorusProps &al_props_)
550 if(auto *cur = std::get_if<EaxProps>(&props_); cur && *cur == props)
551 return false;
553 props_ = props;
555 al_props_.Waveform = Traits::eax_waveform(props.ulWaveform);
556 al_props_.Phase = static_cast<int>(props.lPhase);
557 al_props_.Rate = props.flRate;
558 al_props_.Depth = props.flDepth;
559 al_props_.Feedback = props.flFeedback;
560 al_props_.Delay = props.flDelay;
562 return true;
564 }; // EaxChorusFlangerEffect
567 using ChorusCommitter = EaxCommitter<EaxChorusCommitter>;
568 using FlangerCommitter = EaxCommitter<EaxFlangerCommitter>;
570 } // namespace
572 template<>
573 struct ChorusCommitter::Exception : public EaxException
575 explicit Exception(const char *message) : EaxException{"EAX_CHORUS_EFFECT", message}
579 template<>
580 [[noreturn]] void ChorusCommitter::fail(const char *message)
582 throw Exception{message};
585 bool EaxChorusCommitter::commit(const EAXCHORUSPROPERTIES &props)
587 using Committer = ChorusFlangerEffect<EaxChorusTraits>;
588 return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
591 void EaxChorusCommitter::SetDefaults(EaxEffectProps &props)
593 using Committer = ChorusFlangerEffect<EaxChorusTraits>;
594 Committer::SetDefaults(props);
597 void EaxChorusCommitter::Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props)
599 using Committer = ChorusFlangerEffect<EaxChorusTraits>;
600 Committer::Get(call, props);
603 void EaxChorusCommitter::Set(const EaxCall &call, EAXCHORUSPROPERTIES &props)
605 using Committer = ChorusFlangerEffect<EaxChorusTraits>;
606 Committer::Set(call, props);
609 template<>
610 struct FlangerCommitter::Exception : public EaxException
612 explicit Exception(const char *message) : EaxException{"EAX_FLANGER_EFFECT", message}
616 template<>
617 [[noreturn]] void FlangerCommitter::fail(const char *message)
619 throw Exception{message};
622 bool EaxFlangerCommitter::commit(const EAXFLANGERPROPERTIES &props)
624 using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
625 return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
628 void EaxFlangerCommitter::SetDefaults(EaxEffectProps &props)
630 using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
631 Committer::SetDefaults(props);
634 void EaxFlangerCommitter::Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props)
636 using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
637 Committer::Get(call, props);
640 void EaxFlangerCommitter::Set(const EaxCall &call, EAXFLANGERPROPERTIES &props)
642 using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
643 Committer::Set(call, props);
646 #endif // ALSOFT_EAX