Define the CoreAudio default name only when needed
[openal-soft.git] / al / effects / modulator.cpp
blobec7520e27328ee41bdf18fd6ddcb08a44b6c2b80
2 #include "config.h"
4 #include <stdexcept>
6 #include "AL/al.h"
7 #include "AL/efx.h"
9 #include "alc/effects/base.h"
10 #include "aloptional.h"
11 #include "effects.h"
13 #ifdef ALSOFT_EAX
14 #include <cassert>
16 #include "alnumeric.h"
18 #include "al/eax_exception.h"
19 #include "al/eax_utils.h"
20 #endif // ALSOFT_EAX
23 namespace {
25 al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
27 switch(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);
33 return al::nullopt;
35 ALenum EnumFromWaveform(ModulatorWaveform type)
37 switch(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)
49 switch(param)
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;
55 break;
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;
61 break;
63 default:
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)
71 switch(param)
73 case AL_RING_MODULATOR_FREQUENCY:
74 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
75 Modulator_setParamf(props, param, static_cast<float>(val));
76 break;
78 case AL_RING_MODULATOR_WAVEFORM:
79 if(auto formopt = WaveformFromEmum(val))
80 props->Modulator.Waveform = *formopt;
81 else
82 throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
83 break;
85 default:
86 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
87 param};
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)
95 switch(param)
97 case AL_RING_MODULATOR_FREQUENCY:
98 *val = static_cast<int>(props->Modulator.Frequency);
99 break;
100 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
101 *val = static_cast<int>(props->Modulator.HighPassCutoff);
102 break;
103 case AL_RING_MODULATOR_WAVEFORM:
104 *val = EnumFromWaveform(props->Modulator.Waveform);
105 break;
107 default:
108 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
109 param};
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)
116 switch(param)
118 case AL_RING_MODULATOR_FREQUENCY:
119 *val = props->Modulator.Frequency;
120 break;
121 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
122 *val = props->Modulator.HighPassCutoff;
123 break;
125 default:
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
134 EffectProps props{};
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);
138 return props;
141 } // namespace
143 DEFINE_ALEFFECT_VTABLE(Modulator);
145 const EffectProps ModulatorEffectProps{genDefaultProps()};
147 #ifdef ALSOFT_EAX
148 namespace {
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 :
163 public EaxEffect
165 public:
166 EaxRingModulatorEffect();
169 // [[nodiscard]]
170 bool dispatch(
171 const EaxEaxCall& eax_call) override;
174 private:
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();
192 // [[nodiscard]]
193 bool get(
194 const EaxEaxCall& eax_call);
197 void validate_frequency(
198 float flFrequency);
200 void validate_high_pass_cutoff(
201 float flHighPassCutOff);
203 void validate_waveform(
204 unsigned long ulWaveform);
206 void validate_all(
207 const EAXRINGMODULATORPROPERTIES& all);
210 void defer_frequency(
211 float flFrequency);
213 void defer_high_pass_cutoff(
214 float flHighPassCutOff);
216 void defer_waveform(
217 unsigned long ulWaveform);
219 void defer_all(
220 const EAXRINGMODULATORPROPERTIES& all);
223 void defer_frequency(
224 const EaxEaxCall& eax_call);
226 void defer_high_pass_cutoff(
227 const EaxEaxCall& eax_call);
229 void defer_waveform(
230 const EaxEaxCall& eax_call);
232 void defer_all(
233 const EaxEaxCall& eax_call);
236 // [[nodiscard]]
237 bool apply_deferred();
239 // [[nodiscard]]
240 bool set(
241 const EaxEaxCall& eax_call);
242 }; // EaxRingModulatorEffect
245 class EaxRingModulatorEffectException :
246 public EaxException
248 public:
249 explicit EaxRingModulatorEffectException(
250 const char* message)
252 EaxException{"EAX_RING_MODULATOR_EFFECT", message}
255 }; // EaxRingModulatorEffectException
258 EaxRingModulatorEffect::EaxRingModulatorEffect()
259 : EaxEffect{AL_EFFECT_RING_MODULATOR}
261 set_eax_defaults();
262 set_efx_defaults();
265 // [[nodiscard]]
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;
278 eax_d_ = eax_;
281 void EaxRingModulatorEffect::set_efx_frequency()
283 const auto frequency = clamp(
284 eax_.flFrequency,
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()
315 set_efx_frequency();
316 set_efx_high_pass_cutoff();
317 set_efx_waveform();
320 // [[nodiscard]]
321 bool EaxRingModulatorEffect::get(
322 const EaxEaxCall& eax_call)
324 switch (eax_call.get_property_id())
326 case EAXRINGMODULATOR_NONE:
327 break;
329 case EAXRINGMODULATOR_ALLPARAMETERS:
330 eax_call.set_value<EaxRingModulatorEffectException>(eax_);
331 break;
333 case EAXRINGMODULATOR_FREQUENCY:
334 eax_call.set_value<EaxRingModulatorEffectException>(eax_.flFrequency);
335 break;
337 case EAXRINGMODULATOR_HIGHPASSCUTOFF:
338 eax_call.set_value<EaxRingModulatorEffectException>(eax_.flHighPassCutOff);
339 break;
341 case EAXRINGMODULATOR_WAVEFORM:
342 eax_call.set_value<EaxRingModulatorEffectException>(eax_.ulWaveform);
343 break;
345 default:
346 throw EaxRingModulatorEffectException{"Unsupported property id."};
349 return false;
352 void EaxRingModulatorEffect::validate_frequency(
353 float flFrequency)
355 eax_validate_range<EaxRingModulatorEffectException>(
356 "Frequency",
357 flFrequency,
358 EAXRINGMODULATOR_MINFREQUENCY,
359 EAXRINGMODULATOR_MAXFREQUENCY);
362 void EaxRingModulatorEffect::validate_high_pass_cutoff(
363 float flHighPassCutOff)
365 eax_validate_range<EaxRingModulatorEffectException>(
366 "High-Pass Cutoff",
367 flHighPassCutOff,
368 EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
369 EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
372 void EaxRingModulatorEffect::validate_waveform(
373 unsigned long ulWaveform)
375 eax_validate_range<EaxRingModulatorEffectException>(
376 "Waveform",
377 ulWaveform,
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(
391 float flFrequency)
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 =
423 eax_call.get_value<
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 =
434 eax_call.get_value<
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 =
445 eax_call.get_value<
446 EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform)>();
448 validate_waveform(waveform);
449 defer_waveform(waveform);
452 void EaxRingModulatorEffect::defer_all(
453 const EaxEaxCall& eax_call)
455 const auto& all =
456 eax_call.get_value<EaxRingModulatorEffectException, const EAXRINGMODULATORPROPERTIES>();
458 validate_all(all);
459 defer_all(all);
462 // [[nodiscard]]
463 bool EaxRingModulatorEffect::apply_deferred()
465 if (eax_dirty_flags_ == EaxRingModulatorEffectDirtyFlags{})
467 return false;
470 eax_ = eax_d_;
472 if (eax_dirty_flags_.flFrequency)
474 set_efx_frequency();
477 if (eax_dirty_flags_.flHighPassCutOff)
479 set_efx_high_pass_cutoff();
482 if (eax_dirty_flags_.ulWaveform)
484 set_efx_waveform();
487 eax_dirty_flags_ = EaxRingModulatorEffectDirtyFlags{};
489 return true;
492 // [[nodiscard]]
493 bool EaxRingModulatorEffect::set(
494 const EaxEaxCall& eax_call)
496 switch (eax_call.get_property_id())
498 case EAXRINGMODULATOR_NONE:
499 break;
501 case EAXRINGMODULATOR_ALLPARAMETERS:
502 defer_all(eax_call);
503 break;
505 case EAXRINGMODULATOR_FREQUENCY:
506 defer_frequency(eax_call);
507 break;
509 case EAXRINGMODULATOR_HIGHPASSCUTOFF:
510 defer_high_pass_cutoff(eax_call);
511 break;
513 case EAXRINGMODULATOR_WAVEFORM:
514 defer_waveform(eax_call);
515 break;
517 default:
518 throw EaxRingModulatorEffectException{"Unsupported property id."};
521 if (!eax_call.is_deferred())
523 return apply_deferred();
526 return false;
529 } // namespace
531 EaxEffectUPtr eax_create_eax_ring_modulator_effect()
533 return std::make_unique<EaxRingModulatorEffect>();
536 #endif // ALSOFT_EAX