Define the CoreAudio default name only when needed
[openal-soft.git] / al / effects / fshifter.cpp
blob0100a864ccce4cba8bccb0f715d4b3dde24a3a8f
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<FShifterDirection> DirectionFromEmum(ALenum value)
27 switch(value)
29 case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: return al::make_optional(FShifterDirection::Down);
30 case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return al::make_optional(FShifterDirection::Up);
31 case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return al::make_optional(FShifterDirection::Off);
33 return al::nullopt;
35 ALenum EnumFromDirection(FShifterDirection dir)
37 switch(dir)
39 case FShifterDirection::Down: return AL_FREQUENCY_SHIFTER_DIRECTION_DOWN;
40 case FShifterDirection::Up: return AL_FREQUENCY_SHIFTER_DIRECTION_UP;
41 case FShifterDirection::Off: return AL_FREQUENCY_SHIFTER_DIRECTION_OFF;
43 throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
46 void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
48 switch(param)
50 case AL_FREQUENCY_SHIFTER_FREQUENCY:
51 if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
52 throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
53 props->Fshifter.Frequency = val;
54 break;
56 default:
57 throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
58 param};
61 void Fshifter_setParamfv(EffectProps *props, ALenum param, const float *vals)
62 { Fshifter_setParamf(props, param, vals[0]); }
64 void Fshifter_setParami(EffectProps *props, ALenum param, int val)
66 switch(param)
68 case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
69 if(auto diropt = DirectionFromEmum(val))
70 props->Fshifter.LeftDirection = *diropt;
71 else
72 throw effect_exception{AL_INVALID_VALUE,
73 "Unsupported frequency shifter left direction: 0x%04x", val};
74 break;
76 case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
77 if(auto diropt = DirectionFromEmum(val))
78 props->Fshifter.RightDirection = *diropt;
79 else
80 throw effect_exception{AL_INVALID_VALUE,
81 "Unsupported frequency shifter right direction: 0x%04x", val};
82 break;
84 default:
85 throw effect_exception{AL_INVALID_ENUM,
86 "Invalid frequency shifter integer property 0x%04x", param};
89 void Fshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
90 { Fshifter_setParami(props, param, vals[0]); }
92 void Fshifter_getParami(const EffectProps *props, ALenum param, int *val)
94 switch(param)
96 case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
97 *val = EnumFromDirection(props->Fshifter.LeftDirection);
98 break;
99 case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
100 *val = EnumFromDirection(props->Fshifter.RightDirection);
101 break;
102 default:
103 throw effect_exception{AL_INVALID_ENUM,
104 "Invalid frequency shifter integer property 0x%04x", param};
107 void Fshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
108 { Fshifter_getParami(props, param, vals); }
110 void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
112 switch(param)
114 case AL_FREQUENCY_SHIFTER_FREQUENCY:
115 *val = props->Fshifter.Frequency;
116 break;
118 default:
119 throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
120 param};
123 void Fshifter_getParamfv(const EffectProps *props, ALenum param, float *vals)
124 { Fshifter_getParamf(props, param, vals); }
126 EffectProps genDefaultProps() noexcept
128 EffectProps props{};
129 props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
130 props.Fshifter.LeftDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
131 props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
132 return props;
135 } // namespace
137 DEFINE_ALEFFECT_VTABLE(Fshifter);
139 const EffectProps FshifterEffectProps{genDefaultProps()};
141 #ifdef ALSOFT_EAX
142 namespace {
144 using EaxFrequencyShifterEffectDirtyFlagsValue = std::uint_least8_t;
146 struct EaxFrequencyShifterEffectDirtyFlags
148 using EaxIsBitFieldStruct = bool;
150 EaxFrequencyShifterEffectDirtyFlagsValue flFrequency : 1;
151 EaxFrequencyShifterEffectDirtyFlagsValue ulLeftDirection : 1;
152 EaxFrequencyShifterEffectDirtyFlagsValue ulRightDirection : 1;
153 }; // EaxFrequencyShifterEffectDirtyFlags
156 class EaxFrequencyShifterEffect final :
157 public EaxEffect
159 public:
160 EaxFrequencyShifterEffect();
163 // [[nodiscard]]
164 bool dispatch(
165 const EaxEaxCall& eax_call) override;
168 private:
169 EAXFREQUENCYSHIFTERPROPERTIES eax_{};
170 EAXFREQUENCYSHIFTERPROPERTIES eax_d_{};
171 EaxFrequencyShifterEffectDirtyFlags eax_dirty_flags_{};
174 void set_eax_defaults();
177 void set_efx_frequency();
179 void set_efx_left_direction();
181 void set_efx_right_direction();
183 void set_efx_defaults();
186 // [[nodiscard]]
187 bool get(
188 const EaxEaxCall& eax_call);
191 void validate_frequency(
192 float flFrequency);
194 void validate_left_direction(
195 unsigned long ulLeftDirection);
197 void validate_right_direction(
198 unsigned long ulRightDirection);
200 void validate_all(
201 const EAXFREQUENCYSHIFTERPROPERTIES& all);
204 void defer_frequency(
205 float flFrequency);
207 void defer_left_direction(
208 unsigned long ulLeftDirection);
210 void defer_right_direction(
211 unsigned long ulRightDirection);
213 void defer_all(
214 const EAXFREQUENCYSHIFTERPROPERTIES& all);
217 void defer_frequency(
218 const EaxEaxCall& eax_call);
220 void defer_left_direction(
221 const EaxEaxCall& eax_call);
223 void defer_right_direction(
224 const EaxEaxCall& eax_call);
226 void defer_all(
227 const EaxEaxCall& eax_call);
230 // [[nodiscard]]
231 bool apply_deferred();
233 // [[nodiscard]]
234 bool set(
235 const EaxEaxCall& eax_call);
236 }; // EaxFrequencyShifterEffect
239 class EaxFrequencyShifterEffectException :
240 public EaxException
242 public:
243 explicit EaxFrequencyShifterEffectException(
244 const char* message)
246 EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
249 }; // EaxFrequencyShifterEffectException
252 EaxFrequencyShifterEffect::EaxFrequencyShifterEffect()
253 : EaxEffect{AL_EFFECT_FREQUENCY_SHIFTER}
255 set_eax_defaults();
256 set_efx_defaults();
259 // [[nodiscard]]
260 bool EaxFrequencyShifterEffect::dispatch(
261 const EaxEaxCall& eax_call)
263 return eax_call.is_get() ? get(eax_call) : set(eax_call);
266 void EaxFrequencyShifterEffect::set_eax_defaults()
268 eax_.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
269 eax_.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
270 eax_.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
272 eax_d_ = eax_;
275 void EaxFrequencyShifterEffect::set_efx_frequency()
277 const auto frequency = clamp(
278 eax_.flFrequency,
279 AL_FREQUENCY_SHIFTER_MIN_FREQUENCY,
280 AL_FREQUENCY_SHIFTER_MAX_FREQUENCY);
282 al_effect_props_.Fshifter.Frequency = frequency;
285 void EaxFrequencyShifterEffect::set_efx_left_direction()
287 const auto left_direction = clamp(
288 static_cast<ALint>(eax_.ulLeftDirection),
289 AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION,
290 AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION);
292 const auto efx_left_direction = DirectionFromEmum(left_direction);
293 assert(efx_left_direction.has_value());
294 al_effect_props_.Fshifter.LeftDirection = *efx_left_direction;
297 void EaxFrequencyShifterEffect::set_efx_right_direction()
299 const auto right_direction = clamp(
300 static_cast<ALint>(eax_.ulRightDirection),
301 AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION,
302 AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION);
304 const auto efx_right_direction = DirectionFromEmum(right_direction);
305 assert(efx_right_direction.has_value());
306 al_effect_props_.Fshifter.RightDirection = *efx_right_direction;
309 void EaxFrequencyShifterEffect::set_efx_defaults()
311 set_efx_frequency();
312 set_efx_left_direction();
313 set_efx_right_direction();
316 // [[nodiscard]]
317 bool EaxFrequencyShifterEffect::get(
318 const EaxEaxCall& eax_call)
320 switch (eax_call.get_property_id())
322 case EAXFREQUENCYSHIFTER_NONE:
323 break;
325 case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
326 eax_call.set_value<EaxFrequencyShifterEffectException>(eax_);
327 break;
329 case EAXFREQUENCYSHIFTER_FREQUENCY:
330 eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.flFrequency);
331 break;
333 case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
334 eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulLeftDirection);
335 break;
337 case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
338 eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulRightDirection);
339 break;
341 default:
342 throw EaxFrequencyShifterEffectException{"Unsupported property id."};
345 return false;
348 void EaxFrequencyShifterEffect::validate_frequency(
349 float flFrequency)
351 eax_validate_range<EaxFrequencyShifterEffectException>(
352 "Frequency",
353 flFrequency,
354 EAXFREQUENCYSHIFTER_MINFREQUENCY,
355 EAXFREQUENCYSHIFTER_MAXFREQUENCY);
358 void EaxFrequencyShifterEffect::validate_left_direction(
359 unsigned long ulLeftDirection)
361 eax_validate_range<EaxFrequencyShifterEffectException>(
362 "Left Direction",
363 ulLeftDirection,
364 EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
365 EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
368 void EaxFrequencyShifterEffect::validate_right_direction(
369 unsigned long ulRightDirection)
371 eax_validate_range<EaxFrequencyShifterEffectException>(
372 "Right Direction",
373 ulRightDirection,
374 EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
375 EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
378 void EaxFrequencyShifterEffect::validate_all(
379 const EAXFREQUENCYSHIFTERPROPERTIES& all)
381 validate_frequency(all.flFrequency);
382 validate_left_direction(all.ulLeftDirection);
383 validate_right_direction(all.ulRightDirection);
386 void EaxFrequencyShifterEffect::defer_frequency(
387 float flFrequency)
389 eax_d_.flFrequency = flFrequency;
390 eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
393 void EaxFrequencyShifterEffect::defer_left_direction(
394 unsigned long ulLeftDirection)
396 eax_d_.ulLeftDirection = ulLeftDirection;
397 eax_dirty_flags_.ulLeftDirection = (eax_.ulLeftDirection != eax_d_.ulLeftDirection);
400 void EaxFrequencyShifterEffect::defer_right_direction(
401 unsigned long ulRightDirection)
403 eax_d_.ulRightDirection = ulRightDirection;
404 eax_dirty_flags_.ulRightDirection = (eax_.ulRightDirection != eax_d_.ulRightDirection);
407 void EaxFrequencyShifterEffect::defer_all(
408 const EAXFREQUENCYSHIFTERPROPERTIES& all)
410 defer_frequency(all.flFrequency);
411 defer_left_direction(all.ulLeftDirection);
412 defer_right_direction(all.ulRightDirection);
415 void EaxFrequencyShifterEffect::defer_frequency(
416 const EaxEaxCall& eax_call)
418 const auto& frequency =
419 eax_call.get_value<
420 EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::flFrequency)>();
422 validate_frequency(frequency);
423 defer_frequency(frequency);
426 void EaxFrequencyShifterEffect::defer_left_direction(
427 const EaxEaxCall& eax_call)
429 const auto& left_direction =
430 eax_call.get_value<
431 EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulLeftDirection)>();
433 validate_left_direction(left_direction);
434 defer_left_direction(left_direction);
437 void EaxFrequencyShifterEffect::defer_right_direction(
438 const EaxEaxCall& eax_call)
440 const auto& right_direction =
441 eax_call.get_value<
442 EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulRightDirection)>();
444 validate_right_direction(right_direction);
445 defer_right_direction(right_direction);
448 void EaxFrequencyShifterEffect::defer_all(
449 const EaxEaxCall& eax_call)
451 const auto& all =
452 eax_call.get_value<
453 EaxFrequencyShifterEffectException, const EAXFREQUENCYSHIFTERPROPERTIES>();
455 validate_all(all);
456 defer_all(all);
459 // [[nodiscard]]
460 bool EaxFrequencyShifterEffect::apply_deferred()
462 if (eax_dirty_flags_ == EaxFrequencyShifterEffectDirtyFlags{})
464 return false;
467 eax_ = eax_d_;
469 if (eax_dirty_flags_.flFrequency)
471 set_efx_frequency();
474 if (eax_dirty_flags_.ulLeftDirection)
476 set_efx_left_direction();
479 if (eax_dirty_flags_.ulRightDirection)
481 set_efx_right_direction();
484 eax_dirty_flags_ = EaxFrequencyShifterEffectDirtyFlags{};
486 return true;
489 // [[nodiscard]]
490 bool EaxFrequencyShifterEffect::set(
491 const EaxEaxCall& eax_call)
493 switch (eax_call.get_property_id())
495 case EAXFREQUENCYSHIFTER_NONE:
496 break;
498 case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
499 defer_all(eax_call);
500 break;
502 case EAXFREQUENCYSHIFTER_FREQUENCY:
503 defer_frequency(eax_call);
504 break;
506 case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
507 defer_left_direction(eax_call);
508 break;
510 case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
511 defer_right_direction(eax_call);
512 break;
514 default:
515 throw EaxFrequencyShifterEffectException{"Unsupported property id."};
518 if (!eax_call.is_deferred())
520 return apply_deferred();
523 return false;
526 } // namespace
528 EaxEffectUPtr eax_create_eax_frequency_shifter_effect()
530 return std::make_unique<EaxFrequencyShifterEffect>();
533 #endif // ALSOFT_EAX