diff options
author | Chris Robinson <[email protected]> | 2023-03-10 19:58:45 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-03-10 19:58:45 -0800 |
commit | 8c3948c4de4b84805664775bbfe64516e1100ad9 (patch) | |
tree | c3325fe665867cf225d7aa1c8dde4b0b35c7576b | |
parent | 605fa7815948cdef42877286f85cc23ed5b3760d (diff) |
Rework EAX effect handling
Allocate a base EaxEffect object once for all effect types, instead of
reallocating different derived types on effect changes. The reverb and null
effects have been converted to the new interface, the others are currently
broken/unsupported, but will be restored shortly.
-rw-r--r-- | al/auxeffectslot.cpp | 142 | ||||
-rw-r--r-- | al/auxeffectslot.h | 8 | ||||
-rw-r--r-- | al/eax/effect.h | 297 | ||||
-rw-r--r-- | al/effects/effects.cpp | 53 | ||||
-rw-r--r-- | al/effects/effects.h | 5 | ||||
-rw-r--r-- | al/effects/null.cpp | 66 | ||||
-rw-r--r-- | al/effects/reverb.cpp | 1913 |
7 files changed, 1078 insertions, 1406 deletions
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 81929702..e716beb7 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -1052,53 +1052,45 @@ void ALeffectslot::eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue in if(index >= EAX_MAX_FXSLOTS) eax_fail("Index out of range."); - mPropsDirty = true; eax_al_context_ = &al_context; eax_fx_slot_index_ = index; - eax_version_ = eax_al_context_->eax_get_version(); eax_fx_slot_set_defaults(); + + eax_effect_ = std::make_unique<EaxEffect>(); + if(index == 0) eax_effect_->init<EaxReverbCommitter>(); + //else if(index == 1) eax_effect_->init<EaxChorusCommitter>(); + else eax_effect_->init<EaxNullCommitter>(); } void ALeffectslot::eax_commit() { - auto df = EaxDirtyFlags{}; - - switch(eax_version_) + if(eax_df_ != EaxDirtyFlags{}) { - case 1: - case 2: - case 3: - eax5_fx_slot_commit(eax123_, df); - break; - case 4: - eax4_fx_slot_commit(df); - break; - case 5: - eax5_fx_slot_commit(eax5_, df); - break; - default: - eax_fail_unknown_version(); - } - - if(df == EaxDirtyFlags{}) { - if(eax_effect_ != nullptr && eax_effect_->commit()) - eax_set_efx_slot_effect(*eax_effect_); - - return; - } + auto df = EaxDirtyFlags{}; + switch(eax_version_) + { + case 1: + case 2: + case 3: + eax5_fx_slot_commit(eax123_, df); + break; + case 4: + eax4_fx_slot_commit(df); + break; + case 5: + eax5_fx_slot_commit(eax5_, df); + break; + } + eax_df_ = EaxDirtyFlags{}; - if((df & eax_load_effect_dirty_bit) != EaxDirtyFlags{}) - eax_fx_slot_load_effect(); - else { - if(eax_effect_ != nullptr && eax_effect_->commit()) - eax_set_efx_slot_effect(*eax_effect_); + if((df & eax_volume_dirty_bit) != EaxDirtyFlags{}) + eax_fx_slot_set_volume(); + if((df & eax_flags_dirty_bit) != EaxDirtyFlags{}) + eax_fx_slot_set_flags(); } - if((df & eax_volume_dirty_bit) != EaxDirtyFlags{}) - eax_fx_slot_set_volume(); - - if((df & eax_flags_dirty_bit) != EaxDirtyFlags{}) - eax_fx_slot_set_flags(); + if(eax_effect_->do_commit(eax_version_)) + eax_set_efx_slot_effect(*eax_effect_); } [[noreturn]] void ALeffectslot::eax_fail(const char* message) @@ -1192,46 +1184,14 @@ void ALeffectslot::eax5_fx_slot_set_defaults(Eax5Props& props) noexcept props.flOcclusionLFRatio = EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO; } -void ALeffectslot::eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept -{ - static_cast<Eax4Props&>(eax_) = props; - eax_.lOcclusion = EAXFXSLOT_DEFAULTOCCLUSION; - eax_.flOcclusionLFRatio = EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO; -} - -void ALeffectslot::eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept -{ - eax_ = props; -} - -void ALeffectslot::eax_fx_slot_set_current_defaults() -{ - switch(eax_version_) - { - case 1: - case 2: - case 3: - eax5_fx_slot_set_current_defaults(eax123_.i); - break; - case 4: - eax4_fx_slot_set_current_defaults(eax4_.i); - break; - case 5: - eax5_fx_slot_set_current_defaults(eax5_.i); - break; - default: - eax_fail_unknown_version(); - } - - eax_df_ = ~EaxDirtyFlags{}; -} - void ALeffectslot::eax_fx_slot_set_defaults() { eax5_fx_slot_set_defaults(eax123_.i); eax4_fx_slot_set_defaults(eax4_.i); eax5_fx_slot_set_defaults(eax5_.i); - eax_fx_slot_set_current_defaults(); + eax_ = eax5_.i; + eax_version_ = 5; + eax_df_ = EaxDirtyFlags{}; } void ALeffectslot::eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props) const @@ -1306,7 +1266,7 @@ bool ALeffectslot::eax_get(const EaxCall& call) eax_fx_slot_get(call); break; case EaxCallPropertySetId::fx_slot_effect: - eax_dispatch_effect(call); + eax_effect_->get(call); break; default: eax_fail_unknown_property_id(); @@ -1315,16 +1275,11 @@ bool ALeffectslot::eax_get(const EaxCall& call) return false; } -void ALeffectslot::eax_fx_slot_load_effect() +void ALeffectslot::eax_fx_slot_load_effect(int version, ALenum altype) { - eax_effect_ = nullptr; - const auto efx_effect_type = eax_get_efx_effect_type(eax_.guidLoadEffect); - - if(!IsValidEffectType(efx_effect_type)) - eax_fail("Invalid effect type."); - - eax_effect_ = eax_create_eax_effect(efx_effect_type, eax_version_); - eax_set_efx_slot_effect(*eax_effect_); + if(!IsValidEffectType(altype)) + altype = AL_EFFECT_NULL; + eax_effect_->set_defaults(version, altype); } void ALeffectslot::eax_fx_slot_set_volume() @@ -1395,10 +1350,14 @@ bool ALeffectslot::eax4_fx_slot_set(const EaxCall& call) break; case EAXFXSLOT_ALLPARAMETERS: eax4_fx_slot_set_all(call); + if((eax_df_ & eax_load_effect_dirty_bit)) + eax_fx_slot_load_effect(4, eax_get_efx_effect_type(dst.guidLoadEffect)); break; case EAXFXSLOT_LOADEFFECT: eax4_fx_slot_ensure_unlocked(); eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call, dst.guidLoadEffect, eax_df_); + if((eax_df_ & eax_load_effect_dirty_bit)) + eax_fx_slot_load_effect(4, eax_get_efx_effect_type(dst.guidLoadEffect)); break; case EAXFXSLOT_VOLUME: eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, eax_df_); @@ -1428,9 +1387,13 @@ bool ALeffectslot::eax5_fx_slot_set(const EaxCall& call) break; case EAXFXSLOT_ALLPARAMETERS: eax5_fx_slot_set_all(call); + if((eax_df_ & eax_load_effect_dirty_bit)) + eax_fx_slot_load_effect(5, eax_get_efx_effect_type(dst.guidLoadEffect)); break; case EAXFXSLOT_LOADEFFECT: eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call, dst.guidLoadEffect, eax_df_); + if((eax_df_ & eax_load_effect_dirty_bit)) + eax_fx_slot_load_effect(5, eax_get_efx_effect_type(dst.guidLoadEffect)); break; case EAXFXSLOT_VOLUME: eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, eax_df_); @@ -1477,16 +1440,13 @@ bool ALeffectslot::eax_set(const EaxCall& call) switch(call.get_property_set_id()) { case EaxCallPropertySetId::fx_slot: return eax_fx_slot_set(call); - case EaxCallPropertySetId::fx_slot_effect: eax_dispatch_effect(call); return false; + case EaxCallPropertySetId::fx_slot_effect: eax_effect_->set(call); return false; default: eax_fail_unknown_property_id(); } } void ALeffectslot::eax4_fx_slot_commit(EaxDirtyFlags& dst_df) { - if(eax_df_ == EaxDirtyFlags{}) - return; - eax_fx_slot_commit_property<eax_load_effect_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::guidLoadEffect); eax_fx_slot_commit_property<eax_volume_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::lVolume); eax_fx_slot_commit_property<eax_lock_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::lLock); @@ -1503,28 +1463,16 @@ void ALeffectslot::eax4_fx_slot_commit(EaxDirtyFlags& dst_df) dst_df |= eax_occlusion_lf_ratio_dirty_bit; dst_i.flOcclusionLFRatio = EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO; } - - eax_df_ = EaxDirtyFlags{}; } void ALeffectslot::eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df) { - if(eax_df_ == EaxDirtyFlags{}) - return; - eax_fx_slot_commit_property<eax_load_effect_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::guidLoadEffect); eax_fx_slot_commit_property<eax_volume_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::lVolume); eax_fx_slot_commit_property<eax_lock_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::lLock); eax_fx_slot_commit_property<eax_flags_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::ulFlags); eax_fx_slot_commit_property<eax_occlusion_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::lOcclusion); eax_fx_slot_commit_property<eax_occlusion_lf_ratio_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::flOcclusionLFRatio); - eax_df_ = EaxDirtyFlags{}; -} - -void ALeffectslot::eax_dispatch_effect(const EaxCall& call) -{ - if(eax_effect_ != nullptr) - eax_effect_->dispatch(call); } void ALeffectslot::eax_set_efx_slot_effect(EaxEffect &effect) diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 9b6403f4..10f69270 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -132,7 +132,7 @@ private: void operator()(const GUID& guidLoadEffect) const { if (guidLoadEffect != EAX_NULL_GUID && - guidLoadEffect != EAX_REVERB_EFFECT && + guidLoadEffect != EAX_REVERB_EFFECT /*&& guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT && guidLoadEffect != EAX_AUTOWAH_EFFECT && guidLoadEffect != EAX_CHORUS_EFFECT && @@ -143,7 +143,7 @@ private: guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT && guidLoadEffect != EAX_VOCALMORPHER_EFFECT && guidLoadEffect != EAX_PITCHSHIFTER_EFFECT && - guidLoadEffect != EAX_RINGMODULATOR_EFFECT) + guidLoadEffect != EAX_RINGMODULATOR_EFFECT*/) { eax_fail_unknown_effect_id(); } @@ -299,7 +299,7 @@ private: // Returns `true` if all sources should be updated, or `false` otherwise. bool eax_get(const EaxCall& call); - void eax_fx_slot_load_effect(); + void eax_fx_slot_load_effect(int version, ALenum altype); void eax_fx_slot_set_volume(); void eax_fx_slot_set_environment_flag(); void eax_fx_slot_set_flags(); @@ -339,8 +339,6 @@ private: void eax4_fx_slot_commit(EaxDirtyFlags& dst_df); void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df); - void eax_dispatch_effect(const EaxCall& call); - // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)` void eax_set_efx_slot_effect(EaxEffect &effect); diff --git a/al/eax/effect.h b/al/eax/effect.h index a9dcd14d..15fa34dc 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -39,14 +39,143 @@ struct EaxEffectProps { }; }; +constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props) +{ + switch(props.mType) + { + case EaxEffectType::None: break; + case EaxEffectType::Reverb: return AL_EFFECT_EAXREVERB; + case EaxEffectType::Chorus: return AL_EFFECT_CHORUS; + case EaxEffectType::Autowah: return AL_EFFECT_AUTOWAH; + case EaxEffectType::Compressor: return AL_EFFECT_COMPRESSOR; + case EaxEffectType::Distortion: return AL_EFFECT_DISTORTION; + case EaxEffectType::Echo: return AL_EFFECT_ECHO; + case EaxEffectType::Equalizer: return AL_EFFECT_EQUALIZER; + case EaxEffectType::Flanger: return AL_EFFECT_FLANGER; + case EaxEffectType::FrequencyShifter: return AL_EFFECT_FREQUENCY_SHIFTER; + case EaxEffectType::Modulator: return AL_EFFECT_RING_MODULATOR; + case EaxEffectType::PitchShifter: return AL_EFFECT_PITCH_SHIFTER; + case EaxEffectType::VocalMorpher: return AL_EFFECT_VOCAL_MORPHER; + } + return AL_EFFECT_NULL; +} + +struct EaxReverbCommitter { + struct Exception; + + EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops) + : props_{eaxprops}, al_effect_props_{alprops} + { } + + EaxEffectProps &props_; + EffectProps &al_effect_props_; + + [[noreturn]] static void fail(const char* message); + [[noreturn]] static void fail_unknown_property_id() + { fail(EaxEffectErrorMessages::unknown_property_id()); } + + template<typename TValidator, typename TProperty> + static void defer(const EaxCall& call, TProperty& property) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + property = value; + } + + template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty> + static void defer(const EaxCall& call, TProperties& properties, TProperty&) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + TDeferrer{}(properties, value); + } + + template<typename TValidator, typename TProperty> + static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + if (value == property) + return; + property = value; + properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; + } + + + bool commit(const EAX_REVERBPROPERTIES &props); + bool commit(const EAX20LISTENERPROPERTIES &props); + bool commit(const EAXREVERBPROPERTIES &props); + bool commit(const EaxEffectProps &props); + + static void SetDefaults(EAX_REVERBPROPERTIES &props); + static void SetDefaults(EAX20LISTENERPROPERTIES &props); + static void SetDefaults(EAXREVERBPROPERTIES &props); + static void SetDefaults(EaxEffectProps &props); + + static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props); + static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props); + static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props); + static void Get(const EaxCall &call, const EaxEffectProps &props); + + static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props); + static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props); + static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props); + static void Set(const EaxCall &call, EaxEffectProps &props); + + static void translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept; + static void translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept; + static void translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept; +}; + +template<typename T> +struct EaxCommitter { + struct Exception; + + EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops) + : props_{eaxprops}, al_effect_props_{alprops} + { } + + EaxEffectProps &props_; + EffectProps &al_effect_props_; + + template<typename TValidator, typename TProperty> + static void defer(const EaxCall& call, TProperty& property) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + property = value; + } + + template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty> + static void defer(const EaxCall& call, TProperties& properties, TProperty&) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + TDeferrer{}(properties, value); + } + + [[noreturn]] static void fail(const char *message); + [[noreturn]] static void fail_unknown_property_id() + { fail(EaxEffectErrorMessages::unknown_property_id()); } + + bool commit(const EaxEffectProps &props); + + static void SetDefaults(EaxEffectProps &props); + static void Get(const EaxCall &call, const EaxEffectProps &props); + static void Set(const EaxCall &call, EaxEffectProps &props); +}; + +struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> { + using EaxCommitter<EaxNullCommitter>::EaxCommitter; +}; + + class EaxEffect { public: - EaxEffect(ALenum type, int eax_version) noexcept - : al_effect_type_{type}, version_{eax_version} - { } + EaxEffect() noexcept = default; virtual ~EaxEffect() = default; - const ALenum al_effect_type_; + ALenum al_effect_type_{AL_EFFECT_NULL}; EffectProps al_effect_props_{}; using Props1 = EAX_REVERBPROPERTIES; @@ -74,7 +203,7 @@ public: Props4 d; // Deferred. }; - int version_; + int version_{}; bool changed_{}; Props4 props_{}; State1 state1_{}; @@ -83,10 +212,146 @@ public: State4 state4_{}; State4 state5_{}; - virtual void dispatch(const EaxCall& call) = 0; + [[deprecated]] virtual void dispatch(const EaxCall& /*call*/) { } // Returns "true" if any immediated property was changed. - /*[[nodiscard]]*/ virtual bool commit() = 0; + /*[[nodiscard]]*/ [[deprecated]] virtual bool commit() { return false; } + + template<typename T, typename ...Args> + void call_set_defaults(Args&& ...args) + { return T::SetDefaults(std::forward<Args>(args)...); } + + void call_set_defaults(const ALenum altype, EaxEffectProps &props) + { + if(altype == AL_EFFECT_EAXREVERB) + return call_set_defaults<EaxReverbCommitter>(props); + return call_set_defaults<EaxNullCommitter>(props); + } + + template<typename T> + void init() + { + call_set_defaults<EaxReverbCommitter>(state1_.d); + state1_.i = state1_.d; + call_set_defaults<EaxReverbCommitter>(state2_.d); + state2_.i = state2_.d; + call_set_defaults<EaxReverbCommitter>(state3_.d); + state3_.i = state3_.d; + call_set_defaults<T>(state4_.d); + state4_.i = state4_.d; + call_set_defaults<T>(state5_.d); + state5_.i = state5_.d; + } + + void set_defaults(int eax_version, ALenum altype) + { + switch(eax_version) + { + case 1: call_set_defaults<EaxReverbCommitter>(state1_.d); break; + case 2: call_set_defaults<EaxReverbCommitter>(state2_.d); break; + case 3: call_set_defaults<EaxReverbCommitter>(state3_.d); break; + case 4: call_set_defaults(altype, state4_.d); break; + case 5: call_set_defaults(altype, state5_.d); break; + } + changed_ = true; + } + + + template<typename T, typename ...Args> + void do_set(Args&& ...args) + { return T::Set(std::forward<Args>(args)...); } + + void do_set(const EaxCall &call, EaxEffectProps &props) + { + if(props.mType == EaxEffectType::Reverb) + return do_set<EaxReverbCommitter>(call, props); + return do_set<EaxNullCommitter>(call, props); + } + + void set(const EaxCall &call) + { + switch(call.get_version()) + { + case 1: do_set<EaxReverbCommitter>(call, state1_.d); break; + case 2: do_set<EaxReverbCommitter>(call, state2_.d); break; + case 3: do_set<EaxReverbCommitter>(call, state3_.d); break; + case 4: do_set(call, state4_.d); break; + case 5: do_set(call, state5_.d); break; + } + changed_ = true; + } + + + template<typename T, typename ...Args> + void do_get(Args&& ...args) + { return T::Get(std::forward<Args>(args)...); } + + void do_get(const EaxCall &call, const EaxEffectProps &props) + { + if(props.mType == EaxEffectType::Reverb) + return do_get<EaxReverbCommitter>(call, props); + return do_get<EaxNullCommitter>(call, props); + } + + void get(const EaxCall &call) + { + switch(call.get_version()) + { + case 1: do_get<EaxReverbCommitter>(call, state1_.d); break; + case 2: do_get<EaxReverbCommitter>(call, state2_.d); break; + case 3: do_get<EaxReverbCommitter>(call, state3_.d); break; + case 4: do_get(call, state4_.d); break; + case 5: do_get(call, state5_.d); break; + } + } + + + template<typename T, typename ...Args> + bool call_commit(Args&& ...args) + { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); } + + bool call_commit(const EaxEffectProps &props) + { + if(props.mType == EaxEffectType::Reverb) + return call_commit<EaxReverbCommitter>(props); + return call_commit<EaxNullCommitter>(props); + } + + bool do_commit(int eax_version) + { + changed_ |= version_ != eax_version; + if(!changed_) return false; + + bool ret{version_ != eax_version}; + version_ = eax_version; + changed_ = false; + + switch(eax_version) + { + case 1: + state1_.i = state1_.d; + ret |= call_commit<EaxReverbCommitter>(state1_.d); + break; + case 2: + state2_.i = state2_.d; + ret |= call_commit<EaxReverbCommitter>(state2_.d); + break; + case 3: + state3_.i = state3_.d; + ret |= call_commit<EaxReverbCommitter>(state3_.d); + break; + case 4: + state4_.i = state4_.d; + ret |= call_commit(state4_.d); + break; + case 5: + state5_.i = state5_.d; + ret |= call_commit(state5_.d); + break; + } + al_effect_type_ = EnumFromEaxEffectType(props_); + return ret; + } }; // EaxEffect // Base class for EAX4+ effects. @@ -94,9 +359,7 @@ template<typename TException> class EaxEffect4 : public EaxEffect { public: - EaxEffect4(ALenum type, int eax_version) - : EaxEffect{type, clamp(eax_version, 4, 5)} - { } + EaxEffect4(ALenum, int) { } void initialize() { @@ -203,18 +466,4 @@ EaxEffectUPtr eax_create_eax4_effect(int eax_version) return effect; } -EaxEffectUPtr eax_create_eax_null_effect(int eax_version); -EaxEffectUPtr eax_create_eax_chorus_effect(int eax_version); -EaxEffectUPtr eax_create_eax_distortion_effect(int eax_version); -EaxEffectUPtr eax_create_eax_echo_effect(int eax_version); -EaxEffectUPtr eax_create_eax_flanger_effect(int eax_version); -EaxEffectUPtr eax_create_eax_frequency_shifter_effect(int eax_version); -EaxEffectUPtr eax_create_eax_vocal_morpher_effect(int eax_version); -EaxEffectUPtr eax_create_eax_pitch_shifter_effect(int eax_version); -EaxEffectUPtr eax_create_eax_ring_modulator_effect(int eax_version); -EaxEffectUPtr eax_create_eax_auto_wah_effect(int eax_version); -EaxEffectUPtr eax_create_eax_compressor_effect(int eax_version); -EaxEffectUPtr eax_create_eax_equalizer_effect(int eax_version); -EaxEffectUPtr eax_create_eax_reverb_effect(int eax_version); - #endif // !EAX_EFFECT_INCLUDED diff --git a/al/effects/effects.cpp b/al/effects/effects.cpp index 820f1517..4a67b5ff 100644 --- a/al/effects/effects.cpp +++ b/al/effects/effects.cpp @@ -6,57 +6,4 @@ #include "AL/efx.h" #include "effects.h" -EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type, int eax_version) -{ -#define EAX_PREFIX "[EAX_MAKE_EAX_EFFECT] " - - switch (al_effect_type) - { - case AL_EFFECT_NULL: - return eax_create_eax_null_effect(eax_version); - - case AL_EFFECT_CHORUS: - return eax_create_eax_chorus_effect(eax_version); - - case AL_EFFECT_DISTORTION: - return eax_create_eax_distortion_effect(eax_version); - - case AL_EFFECT_ECHO: - return eax_create_eax_echo_effect(eax_version); - - case AL_EFFECT_FLANGER: - return eax_create_eax_flanger_effect(eax_version); - - case AL_EFFECT_FREQUENCY_SHIFTER: - return eax_create_eax_frequency_shifter_effect(eax_version); - - case AL_EFFECT_VOCAL_MORPHER: - return eax_create_eax_vocal_morpher_effect(eax_version); - - case AL_EFFECT_PITCH_SHIFTER: - return eax_create_eax_pitch_shifter_effect(eax_version); - - case AL_EFFECT_RING_MODULATOR: - return eax_create_eax_ring_modulator_effect(eax_version); - - case AL_EFFECT_AUTOWAH: - return eax_create_eax_auto_wah_effect(eax_version); - - case AL_EFFECT_COMPRESSOR: - return eax_create_eax_compressor_effect(eax_version); - - case AL_EFFECT_EQUALIZER: - return eax_create_eax_equalizer_effect(eax_version); - - case AL_EFFECT_EAXREVERB: - return eax_create_eax_reverb_effect(eax_version); - - default: - assert(false && "Unsupported AL effect type."); - return nullptr; - } - -#undef EAX_PREFIX -} - #endif // ALSOFT_EAX diff --git a/al/effects/effects.h b/al/effects/effects.h index 70960a7f..9d57dd82 100644 --- a/al/effects/effects.h +++ b/al/effects/effects.h @@ -85,9 +85,4 @@ extern const EffectVtable VmorpherEffectVtable; extern const EffectVtable DedicatedEffectVtable; extern const EffectVtable ConvolutionEffectVtable; - -#ifdef ALSOFT_EAX -EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type, int eax_version); -#endif // ALSOFT_EAX - #endif /* AL_EFFECTS_EFFECTS_H */ diff --git a/al/effects/null.cpp b/al/effects/null.cpp index 8b11f20c..e80ab9f8 100644 --- a/al/effects/null.cpp +++ b/al/effects/null.cpp @@ -100,64 +100,50 @@ const EffectProps NullEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -class EaxNullEffectException : public EaxException -{ -public: - explicit EaxNullEffectException(const char* message) - : EaxException{"EAX_NULL_EFFECT", message} - {} -}; // EaxNullEffectException - -class EaxNullEffect final : public EaxEffect4<EaxNullEffectException> -{ -public: - EaxNullEffect(int eax_version); - -private: - void set_defaults(Props4& props) override; - - void set_efx_defaults() override; +using NullCommitter = EaxCommitter<EaxNullCommitter>; - void get(const EaxCall& call, const Props4& props) override; - void set(const EaxCall& call, Props4& props) override; - bool commit_props(const Props4& props) override; -}; // EaxCompressorEffect +} // namespace -EaxNullEffect::EaxNullEffect(int eax_version) - : EaxEffect4{AL_EFFECT_NULL, eax_version} -{} +template<> +struct NullCommitter::Exception : public EaxException +{ + explicit Exception(const char *message) : EaxException{"EAX_NULL_EFFECT", message} + { } +}; -void EaxNullEffect::set_defaults(Props4& props) +template<> +[[noreturn]] void NullCommitter::fail(const char *message) { - props.mType = EaxEffectType::None; + throw Exception{message}; } -void EaxNullEffect::set_efx_defaults() +template<> +bool NullCommitter::commit(const EaxEffectProps &props) { + const bool ret{props.mType != props_.mType}; + props_ = props; + return ret; } -void EaxNullEffect::get(const EaxCall& call, const Props4&) +template<> +void NullCommitter::SetDefaults(EaxEffectProps &props) { - if(call.get_property_id() != 0) - fail_unknown_property_id(); + props = EaxEffectProps{}; + props.mType = EaxEffectType::None; } -void EaxNullEffect::set(const EaxCall& call, Props4&) +template<> +void NullCommitter::Get(const EaxCall &call, const EaxEffectProps&) { if(call.get_property_id() != 0) fail_unknown_property_id(); } -bool EaxNullEffect::commit_props(const Props4&) +template<> +void NullCommitter::Set(const EaxCall &call, EaxEffectProps&) { - return false; -} - -} // namespace - -EaxEffectUPtr eax_create_eax_null_effect(int eax_version) -{ - return std::make_unique<EaxNullEffect>(eax_version); + if(call.get_property_id() != 0) + fail_unknown_property_id(); } #endif // ALSOFT_EAX diff --git a/al/effects/reverb.cpp b/al/effects/reverb.cpp index acd2fd06..b154e3ff 100644 --- a/al/effects/reverb.cpp +++ b/al/effects/reverb.cpp @@ -574,1402 +574,951 @@ public: {} }; // EaxReverbEffectException -class EaxReverbEffect final : public EaxEffect -{ -public: - EaxReverbEffect(int eax_version) noexcept; +struct EnvironmentValidator1 { + void operator()(unsigned long ulEnvironment) const + { + eax_validate_range<EaxReverbEffectException>( + "Environment", + ulEnvironment, + EAXREVERB_MINENVIRONMENT, + EAX1REVERB_MAXENVIRONMENT); + } +}; // EnvironmentValidator1 - void dispatch(const EaxCall& call) override; - /*[[nodiscard]]*/ bool commit() override; +struct VolumeValidator { + void operator()(float volume) const + { + eax_validate_range<EaxReverbEffectException>( + "Volume", + volume, + EAX1REVERB_MINVOLUME, + EAX1REVERB_MAXVOLUME); + } +}; // VolumeValidator -private: - static constexpr auto initial_room2 = -10'000L; +struct DecayTimeValidator { + void operator()(float flDecayTime) const + { + eax_validate_range<EaxReverbEffectException>( + "Decay Time", + flDecayTime, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); + } +}; // DecayTimeValidator - using Exception = EaxReverbEffectException; +struct DampingValidator { + void operator()(float damping) const + { + eax_validate_range<EaxReverbEffectException>( + "Damping", + damping, + EAX1REVERB_MINDAMPING, + EAX1REVERB_MAXDAMPING); + } +}; // DampingValidator - struct EnvironmentValidator1 { - void operator()(unsigned long ulEnvironment) const - { - eax_validate_range<Exception>( - "Environment", - ulEnvironment, - EAXREVERB_MINENVIRONMENT, - EAX1REVERB_MAXENVIRONMENT); - } - }; // EnvironmentValidator1 +struct AllValidator1 { + void operator()(const EAX_REVERBPROPERTIES& all) const + { + EnvironmentValidator1{}(all.environment); + VolumeValidator{}(all.fVolume); + DecayTimeValidator{}(all.fDecayTime_sec); + DampingValidator{}(all.fDamping); + } +}; // AllValidator1 - struct VolumeValidator { - void operator()(float volume) const - { - eax_validate_range<Exception>( - "Volume", - volume, - EAX1REVERB_MINVOLUME, - EAX1REVERB_MAXVOLUME); - } - }; // VolumeValidator +struct RoomValidator { + void operator()(long lRoom) const + { + eax_validate_range<EaxReverbEffectException>( + "Room", + lRoom, + EAXREVERB_MINROOM, + EAXREVERB_MAXROOM); + } +}; // RoomValidator - struct DecayTimeValidator { - void operator()(float flDecayTime) const - { - eax_validate_range<Exception>( - "Decay Time", - flDecayTime, - EAXREVERB_MINDECAYTIME, - EAXREVERB_MAXDECAYTIME); - } - }; // DecayTimeValidator +struct RoomHFValidator { + void operator()(long lRoomHF) const + { + eax_validate_range<EaxReverbEffectException>( + "Room HF", + lRoomHF, + EAXREVERB_MINROOMHF, + EAXREVERB_MAXROOMHF); + } +}; // RoomHFValidator - struct DampingValidator { - void operator()(float damping) const - { - eax_validate_range<Exception>( - "Damping", - damping, - EAX1REVERB_MINDAMPING, - EAX1REVERB_MAXDAMPING); - } - }; // DampingValidator +struct RoomRolloffFactorValidator { + void operator()(float flRoomRolloffFactor) const + { + eax_validate_range<EaxReverbEffectException>( + "Room Rolloff Factor", + flRoomRolloffFactor, + EAXREVERB_MINROOMROLLOFFFACTOR, + EAXREVERB_MAXROOMROLLOFFFACTOR); + } +}; // RoomRolloffFactorValidator - struct AllValidator1 { - void operator()(const EAX_REVERBPROPERTIES& all) const - { - EnvironmentValidator1{}(all.environment); - VolumeValidator{}(all.fVolume); - DecayTimeValidator{}(all.fDecayTime_sec); - DampingValidator{}(all.fDamping); - } - }; // AllValidator1 +struct DecayHFRatioValidator { + void operator()(float flDecayHFRatio) const + { + eax_validate_range<EaxReverbEffectException>( + "Decay HF Ratio", + flDecayHFRatio, + EAXREVERB_MINDECAYHFRATIO, + EAXREVERB_MAXDECAYHFRATIO); + } +}; // DecayHFRatioValidator - struct RoomValidator { - void operator()(long lRoom) const - { - eax_validate_range<Exception>( - "Room", - lRoom, - EAXREVERB_MINROOM, - EAXREVERB_MAXROOM); - } - }; // RoomValidator +struct ReflectionsValidator { + void operator()(long lReflections) const + { + eax_validate_range<EaxReverbEffectException>( + "Reflections", + lReflections, + EAXREVERB_MINREFLECTIONS, + EAXREVERB_MAXREFLECTIONS); + } +}; // ReflectionsValidator - struct RoomHFValidator { - void operator()(long lRoomHF) const - { - eax_validate_range<Exception>( - "Room HF", - lRoomHF, - EAXREVERB_MINROOMHF, - EAXREVERB_MAXROOMHF); - } - }; // RoomHFValidator +struct ReflectionsDelayValidator { + void operator()(float flReflectionsDelay) const + { + eax_validate_range<EaxReverbEffectException>( + "Reflections Delay", + flReflectionsDelay, + EAXREVERB_MINREFLECTIONSDELAY, + EAXREVERB_MAXREFLECTIONSDELAY); + } +}; // ReflectionsDelayValidator + +struct ReverbValidator { + void operator()(long lReverb) const + { + eax_validate_range<EaxReverbEffectException>( + "Reverb", + lReverb, + EAXREVERB_MINREVERB, + EAXREVERB_MAXREVERB); + } +}; // ReverbValidator + +struct ReverbDelayValidator { + void operator()(float flReverbDelay) const + { + eax_validate_range<EaxReverbEffectException>( + "Reverb Delay", + flReverbDelay, + EAXREVERB_MINREVERBDELAY, + EAXREVERB_MAXREVERBDELAY); + } +}; // ReverbDelayValidator + +struct EnvironmentSizeValidator { + void operator()(float flEnvironmentSize) const + { + eax_validate_range<EaxReverbEffectException>( + "Environment Size", + flEnvironmentSize, + EAXREVERB_MINENVIRONMENTSIZE, + EAXREVERB_MAXENVIRONMENTSIZE); + } +}; // EnvironmentSizeValidator + +struct EnvironmentDiffusionValidator { + void operator()(float flEnvironmentDiffusion) const + { + eax_validate_range<EaxReverbEffectException>( + "Environment Diffusion", + flEnvironmentDiffusion, + EAXREVERB_MINENVIRONMENTDIFFUSION, + EAXREVERB_MAXENVIRONMENTDIFFUSION); + } +}; // EnvironmentDiffusionValidator + +struct AirAbsorptionHFValidator { + void operator()(float flAirAbsorptionHF) const + { + eax_validate_range<EaxReverbEffectException>( + "Air Absorbtion HF", + flAirAbsorptionHF, + EAXREVERB_MINAIRABSORPTIONHF, + EAXREVERB_MAXAIRABSORPTIONHF); + } +}; // AirAbsorptionHFValidator + +struct FlagsValidator2 { + void operator()(unsigned long ulFlags) const + { + eax_validate_range<EaxReverbEffectException>( + "Flags", + ulFlags, + 0UL, + ~EAX2LISTENERFLAGS_RESERVED); + } +}; // FlagsValidator2 + +struct AllValidator2 { + void operator()(const EAX20LISTENERPROPERTIES& all) const + { + RoomValidator{}(all.lRoom); + RoomHFValidator{}(all.lRoomHF); + RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); + DecayTimeValidator{}(all.flDecayTime); + DecayHFRatioValidator{}(all.flDecayHFRatio); + ReflectionsValidator{}(all.lReflections); + ReflectionsDelayValidator{}(all.flReflectionsDelay); + ReverbValidator{}(all.lReverb); + ReverbDelayValidator{}(all.flReverbDelay); + EnvironmentValidator1{}(all.dwEnvironment); + EnvironmentSizeValidator{}(all.flEnvironmentSize); + EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); + AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); + FlagsValidator2{}(all.dwFlags); + } +}; // AllValidator2 + +struct EnvironmentValidator3 { + void operator()(unsigned long ulEnvironment) const + { + eax_validate_range<EaxReverbEffectException>( + "Environment", + ulEnvironment, + EAXREVERB_MINENVIRONMENT, + EAX30REVERB_MAXENVIRONMENT); + } +}; // EnvironmentValidator1 + +struct RoomLFValidator { + void operator()(long lRoomLF) const + { + eax_validate_range<EaxReverbEffectException>( + "Room LF", + lRoomLF, + EAXREVERB_MINROOMLF, + EAXREVERB_MAXROOMLF); + } +}; // RoomLFValidator + +struct DecayLFRatioValidator { + void operator()(float flDecayLFRatio) const + { + eax_validate_range<EaxReverbEffectException>( + "Decay LF Ratio", + flDecayLFRatio, + EAXREVERB_MINDECAYLFRATIO, + EAXREVERB_MAXDECAYLFRATIO); + } +}; // DecayLFRatioValidator + +struct VectorValidator { + void operator()(const EAXVECTOR&) const + {} +}; // VectorValidator - struct RoomRolloffFactorValidator { - void operator()(float flRoomRolloffFactor) const +struct EchoTimeValidator { + void operator()(float flEchoTime) const + { + eax_validate_range<EaxReverbEffectException>( + "Echo Time", + flEchoTime, + EAXREVERB_MINECHOTIME, + EAXREVERB_MAXECHOTIME); + } +}; // EchoTimeValidator + +struct EchoDepthValidator { + void operator()(float flEchoDepth) const + { + eax_validate_range<EaxReverbEffectException>( + "Echo Depth", + flEchoDepth, + EAXREVERB_MINECHODEPTH, + EAXREVERB_MAXECHODEPTH); + } +}; // EchoDepthValidator + +struct ModulationTimeValidator { + void operator()(float flModulationTime) const + { + eax_validate_range<EaxReverbEffectException>( + "Modulation Time", + flModulationTime, + EAXREVERB_MINMODULATIONTIME, + EAXREVERB_MAXMODULATIONTIME); + } +}; // ModulationTimeValidator + +struct ModulationDepthValidator { + void operator()(float flModulationDepth) const + { + eax_validate_range<EaxReverbEffectException>( + "Modulation Depth", + flModulationDepth, + EAXREVERB_MINMODULATIONDEPTH, + EAXREVERB_MAXMODULATIONDEPTH); + } +}; // ModulationDepthValidator + +struct HFReferenceValidator { + void operator()(float flHFReference) const + { + eax_validate_range<EaxReverbEffectException>( + "HF Reference", + flHFReference, + EAXREVERB_MINHFREFERENCE, + EAXREVERB_MAXHFREFERENCE); + } +}; // HFReferenceValidator + +struct LFReferenceValidator { + void operator()(float flLFReference) const + { + eax_validate_range<EaxReverbEffectException>( + "LF Reference", + flLFReference, + EAXREVERB_MINLFREFERENCE, + EAXREVERB_MAXLFREFERENCE); + } +}; // LFReferenceValidator + +struct FlagsValidator3 { + void operator()(unsigned long ulFlags) const + { + eax_validate_range<EaxReverbEffectException>( + "Flags", + ulFlags, + 0UL, + ~EAXREVERBFLAGS_RESERVED); + } +}; // FlagsValidator3 + +struct AllValidator3 { + void operator()(const EAXREVERBPROPERTIES& all) const + { + EnvironmentValidator3{}(all.ulEnvironment); + EnvironmentSizeValidator{}(all.flEnvironmentSize); + EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); + RoomValidator{}(all.lRoom); + RoomHFValidator{}(all.lRoomHF); + RoomLFValidator{}(all.lRoomLF); + DecayTimeValidator{}(all.flDecayTime); + DecayHFRatioValidator{}(all.flDecayHFRatio); + DecayLFRatioValidator{}(all.flDecayLFRatio); + ReflectionsValidator{}(all.lReflections); + ReflectionsDelayValidator{}(all.flReflectionsDelay); + VectorValidator{}(all.vReflectionsPan); + ReverbValidator{}(all.lReverb); + ReverbDelayValidator{}(all.flReverbDelay); + VectorValidator{}(all.vReverbPan); + EchoTimeValidator{}(all.flEchoTime); + EchoDepthValidator{}(all.flEchoDepth); + ModulationTimeValidator{}(all.flModulationTime); + ModulationDepthValidator{}(all.flModulationDepth); + AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); + HFReferenceValidator{}(all.flHFReference); + LFReferenceValidator{}(all.flLFReference); + RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); + FlagsValidator3{}(all.ulFlags); + } +}; // AllValidator3 + +struct EnvironmentDeferrer2 { + void operator()(EAX20LISTENERPROPERTIES& props, unsigned long dwEnvironment) const + { + props = EAX2REVERB_PRESETS[dwEnvironment]; + } +}; // EnvironmentDeferrer2 + +struct EnvironmentSizeDeferrer2 { + void operator()(EAX20LISTENERPROPERTIES& props, float flEnvironmentSize) const + { + if (props.flEnvironmentSize == flEnvironmentSize) { - eax_validate_range<Exception>( - "Room Rolloff Factor", - flRoomRolloffFactor, - EAXREVERB_MINROOMROLLOFFFACTOR, - EAXREVERB_MAXROOMROLLOFFFACTOR); + return; } - }; // RoomRolloffFactorValidator - struct DecayHFRatioValidator { - void operator()(float flDecayHFRatio) const + const auto scale = flEnvironmentSize / props.flEnvironmentSize; + props.flEnvironmentSize = flEnvironmentSize; + + if ((props.dwFlags & EAX2LISTENERFLAGS_DECAYTIMESCALE) != 0) { - eax_validate_range<Exception>( - "Decay HF Ratio", - flDecayHFRatio, - EAXREVERB_MINDECAYHFRATIO, - EAXREVERB_MAXDECAYHFRATIO); + props.flDecayTime = clamp( + props.flDecayTime * scale, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); } - }; // DecayHFRatioValidator - struct ReflectionsValidator { - void operator()(long lReflections) const + if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSSCALE) != 0 && + (props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - eax_validate_range<Exception>( - "Reflections", - lReflections, + props.lReflections = clamp( + props.lReflections - static_cast<long>(gain_to_level_mb(scale)), EAXREVERB_MINREFLECTIONS, EAXREVERB_MAXREFLECTIONS); } - }; // ReflectionsValidator - struct ReflectionsDelayValidator { - void operator()(float flReflectionsDelay) const + if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - eax_validate_range<Exception>( - "Reflections Delay", - flReflectionsDelay, + props.flReflectionsDelay = clamp( + props.flReflectionsDelay * scale, EAXREVERB_MINREFLECTIONSDELAY, EAXREVERB_MAXREFLECTIONSDELAY); } - }; // ReflectionsDelayValidator - struct ReverbValidator { - void operator()(long lReverb) const + if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBSCALE) != 0) { - eax_validate_range<Exception>( - "Reverb", - lReverb, + const auto log_scalar = ((props.dwFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; + + props.lReverb = clamp( + props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), EAXREVERB_MINREVERB, EAXREVERB_MAXREVERB); } - }; // ReverbValidator - struct ReverbDelayValidator { - void operator()(float flReverbDelay) const + if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBDELAYSCALE) != 0) { - eax_validate_range<Exception>( - "Reverb Delay", - flReverbDelay, + props.flReverbDelay = clamp( + props.flReverbDelay * scale, EAXREVERB_MINREVERBDELAY, EAXREVERB_MAXREVERBDELAY); } - }; // ReverbDelayValidator + } +}; // EnvironmentSizeDeferrer2 - struct EnvironmentSizeValidator { - void operator()(float flEnvironmentSize) const +struct EnvironmentDeferrer3 { + void operator()(EAXREVERBPROPERTIES& props, unsigned long ulEnvironment) const + { + if (ulEnvironment == EAX_ENVIRONMENT_UNDEFINED) { - eax_validate_range<Exception>( - "Environment Size", - flEnvironmentSize, - EAXREVERB_MINENVIRONMENTSIZE, - EAXREVERB_MAXENVIRONMENTSIZE); + props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; + return; } - }; // EnvironmentSizeValidator - struct EnvironmentDiffusionValidator { - void operator()(float flEnvironmentDiffusion) const - { - eax_validate_range<Exception>( - "Environment Diffusion", - flEnvironmentDiffusion, - EAXREVERB_MINENVIRONMENTDIFFUSION, - EAXREVERB_MAXENVIRONMENTDIFFUSION); - } - }; // EnvironmentDiffusionValidator + props = EAXREVERB_PRESETS[ulEnvironment]; + } +}; // EnvironmentDeferrer3 - struct AirAbsorptionHFValidator { - void operator()(float flAirAbsorptionHF) const +struct EnvironmentSizeDeferrer3 { + void operator()(EAXREVERBPROPERTIES& props, float flEnvironmentSize) const + { + if (props.flEnvironmentSize == flEnvironmentSize) { - eax_validate_range<Exception>( - "Air Absorbtion HF", - flAirAbsorptionHF, - EAXREVERB_MINAIRABSORPTIONHF, - EAXREVERB_MAXAIRABSORPTIONHF); + return; } - }; // AirAbsorptionHFValidator - struct FlagsValidator2 { - void operator()(unsigned long ulFlags) const + const auto scale = flEnvironmentSize / props.flEnvironmentSize; + props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; + props.flEnvironmentSize = flEnvironmentSize; + + if ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) { - eax_validate_range<Exception>( - "Flags", - ulFlags, - 0UL, - ~EAX2LISTENERFLAGS_RESERVED); + props.flDecayTime = clamp( + props.flDecayTime * scale, + EAXREVERB_MINDECAYTIME, + EAXREVERB_MAXDECAYTIME); } - }; // FlagsValidator2 - struct AllValidator2 { - void operator()(const EAX20LISTENERPROPERTIES& all) const + if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0 && + (props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - RoomValidator{}(all.lRoom); - RoomHFValidator{}(all.lRoomHF); - RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); - DecayTimeValidator{}(all.flDecayTime); - DecayHFRatioValidator{}(all.flDecayHFRatio); - ReflectionsValidator{}(all.lReflections); - ReflectionsDelayValidator{}(all.flReflectionsDelay); - ReverbValidator{}(all.lReverb); - ReverbDelayValidator{}(all.flReverbDelay); - EnvironmentValidator1{}(all.dwEnvironment); - EnvironmentSizeValidator{}(all.flEnvironmentSize); - EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); - AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); - FlagsValidator2{}(all.dwFlags); + props.lReflections = clamp( + props.lReflections - static_cast<long>(gain_to_level_mb(scale)), + EAXREVERB_MINREFLECTIONS, + EAXREVERB_MAXREFLECTIONS); } - }; // AllValidator2 - struct EnvironmentValidator3 { - void operator()(unsigned long ulEnvironment) const + if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - eax_validate_range<Exception>( - "Environment", - ulEnvironment, - EAXREVERB_MINENVIRONMENT, - EAX30REVERB_MAXENVIRONMENT); + props.flReflectionsDelay = clamp( + props.flReflectionsDelay * scale, + EAXREVERB_MINREFLECTIONSDELAY, + EAXREVERB_MAXREFLECTIONSDELAY); } - }; // EnvironmentValidator1 - struct RoomLFValidator { - void operator()(long lRoomLF) const + if ((props.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) { - eax_validate_range<Exception>( - "Room LF", - lRoomLF, - EAXREVERB_MINROOMLF, - EAXREVERB_MAXROOMLF); + const auto log_scalar = ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; + props.lReverb = clamp( + props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), + EAXREVERB_MINREVERB, + EAXREVERB_MAXREVERB); } - }; // RoomLFValidator - struct DecayLFRatioValidator { - void operator()(float flDecayLFRatio) const + if ((props.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) { - eax_validate_range<Exception>( - "Decay LF Ratio", - flDecayLFRatio, - EAXREVERB_MINDECAYLFRATIO, - EAXREVERB_MAXDECAYLFRATIO); + props.flReverbDelay = clamp( + props.flReverbDelay * scale, + EAXREVERB_MINREVERBDELAY, + EAXREVERB_MAXREVERBDELAY); } - }; // DecayLFRatioValidator - - struct VectorValidator { - void operator()(const EAXVECTOR&) const - {} - }; // VectorValidator - struct EchoTimeValidator { - void operator()(float flEchoTime) const + if ((props.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) { - eax_validate_range<Exception>( - "Echo Time", - flEchoTime, + props.flEchoTime = clamp( + props.flEchoTime * scale, EAXREVERB_MINECHOTIME, EAXREVERB_MAXECHOTIME); } - }; // EchoTimeValidator - - struct EchoDepthValidator { - void operator()(float flEchoDepth) const - { - eax_validate_range<Exception>( - "Echo Depth", - flEchoDepth, - EAXREVERB_MINECHODEPTH, - EAXREVERB_MAXECHODEPTH); - } - }; // EchoDepthValidator - struct ModulationTimeValidator { - void operator()(float flModulationTime) const + if ((props.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) { - eax_validate_range<Exception>( - "Modulation Time", - flModulationTime, + props.flModulationTime = clamp( + props.flModulationTime * scale, EAXREVERB_MINMODULATIONTIME, EAXREVERB_MAXMODULATIONTIME); } - }; // ModulationTimeValidator - - struct ModulationDepthValidator { - void operator()(float flModulationDepth) const - { - eax_validate_range<Exception>( - "Modulation Depth", - flModulationDepth, - EAXREVERB_MINMODULATIONDEPTH, - EAXREVERB_MAXMODULATIONDEPTH); - } - }; // ModulationDepthValidator - - struct HFReferenceValidator { - void operator()(float flHFReference) const - { - eax_validate_range<Exception>( - "HF Reference", - flHFReference, - EAXREVERB_MINHFREFERENCE, - EAXREVERB_MAXHFREFERENCE); - } - }; // HFReferenceValidator - - struct LFReferenceValidator { - void operator()(float flLFReference) const - { - eax_validate_range<Exception>( - "LF Reference", - flLFReference, - EAXREVERB_MINLFREFERENCE, - EAXREVERB_MAXLFREFERENCE); - } - }; // LFReferenceValidator - - struct FlagsValidator3 { - void operator()(unsigned long ulFlags) const - { - eax_validate_range<Exception>( - "Flags", - ulFlags, - 0UL, - ~EAXREVERBFLAGS_RESERVED); - } - }; // FlagsValidator3 - - struct AllValidator3 { - void operator()(const EAXREVERBPROPERTIES& all) const - { - EnvironmentValidator3{}(all.ulEnvironment); - EnvironmentSizeValidator{}(all.flEnvironmentSize); - EnvironmentDiffusionValidator{}(all.flEnvironmentDiffusion); - RoomValidator{}(all.lRoom); - RoomHFValidator{}(all.lRoomHF); - RoomLFValidator{}(all.lRoomLF); - DecayTimeValidator{}(all.flDecayTime); - DecayHFRatioValidator{}(all.flDecayHFRatio); - DecayLFRatioValidator{}(all.flDecayLFRatio); - ReflectionsValidator{}(all.lReflections); - ReflectionsDelayValidator{}(all.flReflectionsDelay); - VectorValidator{}(all.vReflectionsPan); - ReverbValidator{}(all.lReverb); - ReverbDelayValidator{}(all.flReverbDelay); - VectorValidator{}(all.vReverbPan); - EchoTimeValidator{}(all.flEchoTime); - EchoDepthValidator{}(all.flEchoDepth); - ModulationTimeValidator{}(all.flModulationTime); - ModulationDepthValidator{}(all.flModulationDepth); - AirAbsorptionHFValidator{}(all.flAirAbsorptionHF); - HFReferenceValidator{}(all.flHFReference); - LFReferenceValidator{}(all.flLFReference); - RoomRolloffFactorValidator{}(all.flRoomRolloffFactor); - FlagsValidator3{}(all.ulFlags); - } - }; // AllValidator3 - - struct EnvironmentDeferrer2 { - void operator()(EAX20LISTENERPROPERTIES& props, unsigned long dwEnvironment) const - { - props = EAX2REVERB_PRESETS[dwEnvironment]; - } - }; // EnvironmentDeferrer2 - - struct EnvironmentSizeDeferrer2 { - void operator()(EAX20LISTENERPROPERTIES& props, float flEnvironmentSize) const - { - if (props.flEnvironmentSize == flEnvironmentSize) - { - return; - } - - const auto scale = flEnvironmentSize / props.flEnvironmentSize; - props.flEnvironmentSize = flEnvironmentSize; - - if ((props.dwFlags & EAX2LISTENERFLAGS_DECAYTIMESCALE) != 0) - { - props.flDecayTime = clamp( - props.flDecayTime * scale, - EAXREVERB_MINDECAYTIME, - EAXREVERB_MAXDECAYTIME); - } - - if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSSCALE) != 0 && - (props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) - { - props.lReflections = clamp( - props.lReflections - static_cast<long>(gain_to_level_mb(scale)), - EAXREVERB_MINREFLECTIONS, - EAXREVERB_MAXREFLECTIONS); - } - - if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) - { - props.flReflectionsDelay = clamp( - props.flReflectionsDelay * scale, - EAXREVERB_MINREFLECTIONSDELAY, - EAXREVERB_MAXREFLECTIONSDELAY); - } - - if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBSCALE) != 0) - { - const auto log_scalar = ((props.dwFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - - props.lReverb = clamp( - props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), - EAXREVERB_MINREVERB, - EAXREVERB_MAXREVERB); - } - - if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBDELAYSCALE) != 0) - { - props.flReverbDelay = clamp( - props.flReverbDelay * scale, - EAXREVERB_MINREVERBDELAY, - EAXREVERB_MAXREVERBDELAY); - } - } - }; // EnvironmentSizeDeferrer2 - - struct EnvironmentDeferrer3 { - void operator()(EAXREVERBPROPERTIES& props, unsigned long ulEnvironment) const - { - if (ulEnvironment == EAX_ENVIRONMENT_UNDEFINED) - { - props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; - return; - } - - props = EAXREVERB_PRESETS[ulEnvironment]; - } - }; // EnvironmentDeferrer3 - - struct EnvironmentSizeDeferrer3 { - void operator()(EAXREVERBPROPERTIES& props, float flEnvironmentSize) const - { - if (props.flEnvironmentSize == flEnvironmentSize) - { - return; - } - - const auto scale = flEnvironmentSize / props.flEnvironmentSize; - props.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; - props.flEnvironmentSize = flEnvironmentSize; - - if ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) - { - props.flDecayTime = clamp( - props.flDecayTime * scale, - EAXREVERB_MINDECAYTIME, - EAXREVERB_MAXDECAYTIME); - } - - if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0 && - (props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) - { - props.lReflections = clamp( - props.lReflections - static_cast<long>(gain_to_level_mb(scale)), - EAXREVERB_MINREFLECTIONS, - EAXREVERB_MAXREFLECTIONS); - } - - if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) - { - props.flReflectionsDelay = clamp( - props.flReflectionsDelay * scale, - EAXREVERB_MINREFLECTIONSDELAY, - EAXREVERB_MAXREFLECTIONSDELAY); - } - - if ((props.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) - { - const auto log_scalar = ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - props.lReverb = clamp( - props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), - EAXREVERB_MINREVERB, - EAXREVERB_MAXREVERB); - } - - if ((props.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) - { - props.flReverbDelay = clamp( - props.flReverbDelay * scale, - EAXREVERB_MINREVERBDELAY, - EAXREVERB_MAXREVERBDELAY); - } - - if ((props.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) - { - props.flEchoTime = clamp( - props.flEchoTime * scale, - EAXREVERB_MINECHOTIME, - EAXREVERB_MAXECHOTIME); - } - - if ((props.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) - { - props.flModulationTime = clamp( - props.flModulationTime * scale, - EAXREVERB_MINMODULATIONTIME, - EAXREVERB_MAXMODULATIONTIME); - } - } - }; // EnvironmentSizeDeferrer3 - - - [[noreturn]] static void fail(const char* message); - [[noreturn]] static void fail_unknown_property_id(); - [[noreturn]] static void fail_unknown_version(); - - static void set_defaults(State1& state) noexcept; - static void set_defaults(State2& state) noexcept; - static void set_defaults(State3& state) noexcept; - void set_defaults() noexcept; - - void set_current_defaults(); - - void set_efx_density_from_environment_size() noexcept; - void set_efx_diffusion() noexcept; - void set_efx_gain() noexcept; - void set_efx_gain_hf() noexcept; - void set_efx_gain_lf() noexcept; - void set_efx_decay_time() noexcept; - void set_efx_decay_hf_ratio() noexcept; - void set_efx_decay_lf_ratio() noexcept; - void set_efx_reflections_gain() noexcept; - void set_efx_reflections_delay() noexcept; - void set_efx_reflections_pan() noexcept; - void set_efx_late_reverb_gain() noexcept; - void set_efx_late_reverb_delay() noexcept; - void set_efx_late_reverb_pan() noexcept; - void set_efx_echo_time() noexcept; - void set_efx_echo_depth() noexcept; - void set_efx_modulation_time() noexcept; - void set_efx_modulation_depth() noexcept; - void set_efx_air_absorption_gain_hf() noexcept; - void set_efx_hf_reference() noexcept; - void set_efx_lf_reference() noexcept; - void set_efx_room_rolloff_factor() noexcept; - void set_efx_flags() noexcept; - void set_efx_defaults() noexcept; - - static void get1(const EaxCall& call, const Props1& props); - static void get2(const EaxCall& call, const Props2& props); - static void get3(const EaxCall& call, const Props3& props); - void get(const EaxCall& call); - - template<typename TValidator, typename TProperty> - static void defer(const EaxCall& call, TProperty& property) - { - const auto& value = call.get_value<Exception, const TProperty>(); - TValidator{}(value); - property = value; - } - - template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty> - static void defer(const EaxCall& call, TProperties& properties, TProperty&) - { - const auto& value = call.get_value<Exception, const TProperty>(); - TValidator{}(value); - TDeferrer{}(properties, value); - } - - template<typename TValidator, typename TProperty> - static void defer3(const EaxCall& call, Props3& properties, TProperty& property) - { - const auto& value = call.get_value<Exception, const TProperty>(); - TValidator{}(value); - if (value == property) - return; - property = value; - properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED; } +}; // EnvironmentSizeDeferrer3 - static void set1(const EaxCall& call, Props1& props); - static void set2(const EaxCall& call, Props2& props); - static void set3(const EaxCall& call, Props3& props); - void set(const EaxCall& call); +} // namespace - static void translate(const Props1& src, Props4& dst) noexcept; - static void translate(const Props2& src, Props4& dst) noexcept; - static void translate(const Props3& src, Props4& dst) noexcept; -}; // EaxReverbEffect -EaxReverbEffect::EaxReverbEffect(int eax_version) noexcept - : EaxEffect{AL_EFFECT_EAXREVERB, eax_version} +struct EaxReverbCommitter::Exception : public EaxReverbEffectException { - set_defaults(); - set_current_defaults(); - set_efx_defaults(); -} + using EaxReverbEffectException::EaxReverbEffectException; +}; -void EaxReverbEffect::dispatch(const EaxCall& call) -{ - call.is_get() ? get(call) : set(call); -} - -[[noreturn]] void EaxReverbEffect::fail(const char* message) +[[noreturn]] void EaxReverbCommitter::fail(const char* message) { throw Exception{message}; } -[[noreturn]] void EaxReverbEffect::fail_unknown_property_id() +void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept { - fail(EaxEffectErrorMessages::unknown_property_id()); + assert(src.environment <= EAX1REVERB_MAXENVIRONMENT); + dst.mType = EaxEffectType::Reverb; + dst.mReverb = EAXREVERB_PRESETS[src.environment]; + dst.mReverb.flDecayTime = src.fDecayTime_sec; + dst.mReverb.flDecayHFRatio = src.fDamping; + dst.mReverb.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0); } -[[noreturn]] void EaxReverbEffect::fail_unknown_version() +void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept { - fail(EaxEffectErrorMessages::unknown_version()); + assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT); + const auto& env = EAXREVERB_PRESETS[src.dwEnvironment]; + dst.mType = EaxEffectType::Reverb; + dst.mReverb.ulEnvironment = src.dwEnvironment; + dst.mReverb.flEnvironmentSize = src.flEnvironmentSize; + dst.mReverb.flEnvironmentDiffusion = src.flEnvironmentDiffusion; + dst.mReverb.lRoom = src.lRoom; + dst.mReverb.lRoomHF = src.lRoomHF; + dst.mReverb.lRoomLF = env.lRoomLF; + dst.mReverb.flDecayTime = src.flDecayTime; + dst.mReverb.flDecayHFRatio = src.flDecayHFRatio; + dst.mReverb.flDecayLFRatio = env.flDecayLFRatio; + dst.mReverb.lReflections = src.lReflections; + dst.mReverb.flReflectionsDelay = src.flReflectionsDelay; + dst.mReverb.vReflectionsPan = env.vReflectionsPan; + dst.mReverb.lReverb = src.lReverb; + dst.mReverb.flReverbDelay = src.flReverbDelay; + dst.mReverb.vReverbPan = env.vReverbPan; + dst.mReverb.flEchoTime = env.flEchoTime; + dst.mReverb.flEchoDepth = env.flEchoDepth; + dst.mReverb.flModulationTime = env.flModulationTime; + dst.mReverb.flModulationDepth = env.flModulationDepth; + dst.mReverb.flAirAbsorptionHF = src.flAirAbsorptionHF; + dst.mReverb.flHFReference = env.flHFReference; + dst.mReverb.flLFReference = env.flLFReference; + dst.mReverb.flRoomRolloffFactor = src.flRoomRolloffFactor; + dst.mReverb.ulFlags = src.dwFlags; } -void EaxReverbEffect::set_defaults(State1& state) noexcept +void EaxReverbCommitter::translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept { - state.i = EAX1REVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; - state.d = state.i; + dst.mType = EaxEffectType::Reverb; + dst.mReverb = src; } -void EaxReverbEffect::set_defaults(State2& state) noexcept +bool EaxReverbCommitter::commit(const EAX_REVERBPROPERTIES &props) { - state.i = EAX2REVERB_PRESETS[EAX2_ENVIRONMENT_GENERIC]; - state.i.lRoom = initial_room2; - state.d = state.i; + EaxEffectProps dst{}; + translate(props, dst); + return commit(dst); } -void EaxReverbEffect::set_defaults(State3& state) noexcept +bool EaxReverbCommitter::commit(const EAX20LISTENERPROPERTIES &props) { - state.i = EAXREVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; - state.d = state.i; + EaxEffectProps dst{}; + translate(props, dst); + return commit(dst); } -void EaxReverbEffect::set_defaults() noexcept +bool EaxReverbCommitter::commit(const EAXREVERBPROPERTIES &props) { - set_defaults(state1_); - set_defaults(state2_); - set_defaults(state3_); - translate(state3_.i, state4_.i); - state4_.d = state4_.i; - translate(state3_.i, state5_.i); - state5_.d = state5_.i; + EaxEffectProps dst{}; + translate(props, dst); + return commit(dst); } -void EaxReverbEffect::set_current_defaults() +bool EaxReverbCommitter::commit(const EaxEffectProps &props) { - switch (version_) - { - case 1: translate(state1_.i, props_); break; - case 2: translate(state2_.i, props_); break; - case 3: translate(state3_.i, props_); break; - case 4: props_ = state4_.i; break; - case 5: props_ = state5_.i; break; - default: fail_unknown_version(); - } -} + const auto orig = props_; + props_ = props; + if(orig.mType == props_.mType && memcmp(&orig.mReverb, &props_.mReverb, sizeof(props_.mReverb)) == 0) + return false; -void EaxReverbEffect::set_efx_density_from_environment_size() noexcept -{ const auto size = props_.mReverb.flEnvironmentSize; const auto density = (size * size * size) / 16.0F; - al_effect_props_.Reverb.Density = clamp( - density, - AL_EAXREVERB_MIN_DENSITY, - AL_EAXREVERB_MAX_DENSITY); -} - -void EaxReverbEffect::set_efx_diffusion() noexcept -{ - al_effect_props_.Reverb.Diffusion = clamp( - props_.mReverb.flEnvironmentDiffusion, - AL_EAXREVERB_MIN_DIFFUSION, - AL_EAXREVERB_MAX_DIFFUSION); -} - -void EaxReverbEffect::set_efx_gain() noexcept -{ + al_effect_props_.Reverb.Density = clamp(density, + AL_EAXREVERB_MIN_DENSITY, AL_EAXREVERB_MAX_DENSITY); + al_effect_props_.Reverb.Diffusion = clamp(props_.mReverb.flEnvironmentDiffusion, + AL_EAXREVERB_MIN_DIFFUSION, AL_EAXREVERB_MAX_DIFFUSION); al_effect_props_.Reverb.Gain = clamp( level_mb_to_gain(static_cast<float>(props_.mReverb.lRoom)), - AL_EAXREVERB_MIN_GAIN, - AL_EAXREVERB_MAX_GAIN); -} - -void EaxReverbEffect::set_efx_gain_hf() noexcept -{ + AL_EAXREVERB_MIN_GAIN, AL_EAXREVERB_MAX_GAIN); al_effect_props_.Reverb.GainHF = clamp( level_mb_to_gain(static_cast<float>(props_.mReverb.lRoomHF)), - AL_EAXREVERB_MIN_GAINHF, - AL_EAXREVERB_MAX_GAINHF); -} - -void EaxReverbEffect::set_efx_gain_lf() noexcept -{ + AL_EAXREVERB_MIN_GAINHF, AL_EAXREVERB_MAX_GAINHF); al_effect_props_.Reverb.GainLF = clamp( level_mb_to_gain(static_cast<float>(props_.mReverb.lRoomLF)), - AL_EAXREVERB_MIN_GAINLF, - AL_EAXREVERB_MAX_GAINLF); -} - -void EaxReverbEffect::set_efx_decay_time() noexcept -{ - al_effect_props_.Reverb.DecayTime = clamp( - props_.mReverb.flDecayTime, - AL_EAXREVERB_MIN_DECAY_TIME, - AL_EAXREVERB_MAX_DECAY_TIME); -} - -void EaxReverbEffect::set_efx_decay_hf_ratio() noexcept -{ - al_effect_props_.Reverb.DecayHFRatio = clamp( - props_.mReverb.flDecayHFRatio, - AL_EAXREVERB_MIN_DECAY_HFRATIO, - AL_EAXREVERB_MAX_DECAY_HFRATIO); -} - -void EaxReverbEffect::set_efx_decay_lf_ratio() noexcept -{ - al_effect_props_.Reverb.DecayLFRatio = clamp( - props_.mReverb.flDecayLFRatio, - AL_EAXREVERB_MIN_DECAY_LFRATIO, - AL_EAXREVERB_MAX_DECAY_LFRATIO); -} - -void EaxReverbEffect::set_efx_reflections_gain() noexcept -{ + AL_EAXREVERB_MIN_GAINLF, AL_EAXREVERB_MAX_GAINLF); + al_effect_props_.Reverb.DecayTime = clamp(props_.mReverb.flDecayTime, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + al_effect_props_.Reverb.DecayHFRatio = clamp(props_.mReverb.flDecayHFRatio, + AL_EAXREVERB_MIN_DECAY_HFRATIO, AL_EAXREVERB_MAX_DECAY_HFRATIO); + al_effect_props_.Reverb.DecayLFRatio = clamp(props_.mReverb.flDecayLFRatio, + AL_EAXREVERB_MIN_DECAY_LFRATIO, AL_EAXREVERB_MAX_DECAY_LFRATIO); al_effect_props_.Reverb.ReflectionsGain = clamp( level_mb_to_gain(static_cast<float>(props_.mReverb.lReflections)), - AL_EAXREVERB_MIN_REFLECTIONS_GAIN, - AL_EAXREVERB_MAX_REFLECTIONS_GAIN); -} - -void EaxReverbEffect::set_efx_reflections_delay() noexcept -{ - al_effect_props_.Reverb.ReflectionsDelay = clamp( - props_.mReverb.flReflectionsDelay, - AL_EAXREVERB_MIN_REFLECTIONS_DELAY, - AL_EAXREVERB_MAX_REFLECTIONS_DELAY); -} - -void EaxReverbEffect::set_efx_reflections_pan() noexcept -{ + AL_EAXREVERB_MIN_REFLECTIONS_GAIN, AL_EAXREVERB_MAX_REFLECTIONS_GAIN); + al_effect_props_.Reverb.ReflectionsDelay = clamp(props_.mReverb.flReflectionsDelay, + AL_EAXREVERB_MIN_REFLECTIONS_DELAY, AL_EAXREVERB_MAX_REFLECTIONS_DELAY); al_effect_props_.Reverb.ReflectionsPan[0] = props_.mReverb.vReflectionsPan.x; al_effect_props_.Reverb.ReflectionsPan[1] = props_.mReverb.vReflectionsPan.y; al_effect_props_.Reverb.ReflectionsPan[2] = props_.mReverb.vReflectionsPan.z; -} - -void EaxReverbEffect::set_efx_late_reverb_gain() noexcept -{ al_effect_props_.Reverb.LateReverbGain = clamp( level_mb_to_gain(static_cast<float>(props_.mReverb.lReverb)), - AL_EAXREVERB_MIN_LATE_REVERB_GAIN, - AL_EAXREVERB_MAX_LATE_REVERB_GAIN); -} - -void EaxReverbEffect::set_efx_late_reverb_delay() noexcept -{ - al_effect_props_.Reverb.LateReverbDelay = clamp( - props_.mReverb.flReverbDelay, - AL_EAXREVERB_MIN_LATE_REVERB_DELAY, - AL_EAXREVERB_MAX_LATE_REVERB_DELAY); -} - -void EaxReverbEffect::set_efx_late_reverb_pan() noexcept -{ + AL_EAXREVERB_MIN_LATE_REVERB_GAIN, AL_EAXREVERB_MAX_LATE_REVERB_GAIN); + al_effect_props_.Reverb.LateReverbDelay = clamp(props_.mReverb.flReverbDelay, + AL_EAXREVERB_MIN_LATE_REVERB_DELAY, AL_EAXREVERB_MAX_LATE_REVERB_DELAY); al_effect_props_.Reverb.LateReverbPan[0] = props_.mReverb.vReverbPan.x; al_effect_props_.Reverb.LateReverbPan[1] = props_.mReverb.vReverbPan.y; al_effect_props_.Reverb.LateReverbPan[2] = props_.mReverb.vReverbPan.z; -} - -void EaxReverbEffect::set_efx_echo_time() noexcept -{ - al_effect_props_.Reverb.EchoTime = clamp( - props_.mReverb.flEchoTime, - AL_EAXREVERB_MIN_ECHO_TIME, - AL_EAXREVERB_MAX_ECHO_TIME); -} - -void EaxReverbEffect::set_efx_echo_depth() noexcept -{ - al_effect_props_.Reverb.EchoDepth = clamp( - props_.mReverb.flEchoDepth, - AL_EAXREVERB_MIN_ECHO_DEPTH, - AL_EAXREVERB_MAX_ECHO_DEPTH); -} - -void EaxReverbEffect::set_efx_modulation_time() noexcept -{ - al_effect_props_.Reverb.ModulationTime = clamp( - props_.mReverb.flModulationTime, - AL_EAXREVERB_MIN_MODULATION_TIME, - AL_EAXREVERB_MAX_MODULATION_TIME); -} - -void EaxReverbEffect::set_efx_modulation_depth() noexcept -{ - al_effect_props_.Reverb.ModulationDepth = clamp( - props_.mReverb.flModulationDepth, - AL_EAXREVERB_MIN_MODULATION_DEPTH, - AL_EAXREVERB_MAX_MODULATION_DEPTH); -} - -void EaxReverbEffect::set_efx_air_absorption_gain_hf() noexcept -{ + al_effect_props_.Reverb.EchoTime = clamp(props_.mReverb.flEchoTime, + AL_EAXREVERB_MIN_ECHO_TIME, AL_EAXREVERB_MAX_ECHO_TIME); + al_effect_props_.Reverb.EchoDepth = clamp(props_.mReverb.flEchoDepth, + AL_EAXREVERB_MIN_ECHO_DEPTH, AL_EAXREVERB_MAX_ECHO_DEPTH); + al_effect_props_.Reverb.ModulationTime = clamp(props_.mReverb.flModulationTime, + AL_EAXREVERB_MIN_MODULATION_TIME, AL_EAXREVERB_MAX_MODULATION_TIME); + al_effect_props_.Reverb.ModulationDepth = clamp(props_.mReverb.flModulationDepth, + AL_EAXREVERB_MIN_MODULATION_DEPTH, AL_EAXREVERB_MAX_MODULATION_DEPTH); al_effect_props_.Reverb.AirAbsorptionGainHF = clamp( level_mb_to_gain(props_.mReverb.flAirAbsorptionHF), - AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, - AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF); + AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF); + al_effect_props_.Reverb.HFReference = clamp(props_.mReverb.flHFReference, + AL_EAXREVERB_MIN_HFREFERENCE, AL_EAXREVERB_MAX_HFREFERENCE); + al_effect_props_.Reverb.LFReference = clamp(props_.mReverb.flLFReference, + AL_EAXREVERB_MIN_LFREFERENCE, AL_EAXREVERB_MAX_LFREFERENCE); + al_effect_props_.Reverb.RoomRolloffFactor = clamp(props_.mReverb.flRoomRolloffFactor, + AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR, AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR); + al_effect_props_.Reverb.DecayHFLimit = ((props_.mReverb.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); + return true; } -void EaxReverbEffect::set_efx_hf_reference() noexcept +void EaxReverbCommitter::SetDefaults(EAX_REVERBPROPERTIES &props) { - al_effect_props_.Reverb.HFReference = clamp( - props_.mReverb.flHFReference, - AL_EAXREVERB_MIN_HFREFERENCE, - AL_EAXREVERB_MAX_HFREFERENCE); + props = EAX1REVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; } -void EaxReverbEffect::set_efx_lf_reference() noexcept +void EaxReverbCommitter::SetDefaults(EAX20LISTENERPROPERTIES &props) { - al_effect_props_.Reverb.LFReference = clamp( - props_.mReverb.flLFReference, - AL_EAXREVERB_MIN_LFREFERENCE, - AL_EAXREVERB_MAX_LFREFERENCE); + props = EAX2REVERB_PRESETS[EAX2_ENVIRONMENT_GENERIC]; + props.lRoom = -10'000L; } -void EaxReverbEffect::set_efx_room_rolloff_factor() noexcept +void EaxReverbCommitter::SetDefaults(EAXREVERBPROPERTIES &props) { - al_effect_props_.Reverb.RoomRolloffFactor = clamp( - props_.mReverb.flRoomRolloffFactor, - AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR, - AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR); + props = EAXREVERB_PRESETS[EAX_ENVIRONMENT_GENERIC]; } -void EaxReverbEffect::set_efx_flags() noexcept +void EaxReverbCommitter::SetDefaults(EaxEffectProps &props) { - al_effect_props_.Reverb.DecayHFLimit = ((props_.mReverb.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); + props.mType = EaxEffectType::Reverb; + SetDefaults(props.mReverb); } -void EaxReverbEffect::set_efx_defaults() noexcept -{ - set_efx_density_from_environment_size(); - set_efx_diffusion(); - set_efx_gain(); - set_efx_gain_hf(); - set_efx_gain_lf(); - set_efx_decay_time(); - set_efx_decay_hf_ratio(); - set_efx_decay_lf_ratio(); - set_efx_reflections_gain(); - set_efx_reflections_delay(); - set_efx_reflections_pan(); - set_efx_late_reverb_gain(); - set_efx_late_reverb_delay(); - set_efx_late_reverb_pan(); - set_efx_echo_time(); - set_efx_echo_depth(); - set_efx_modulation_time(); - set_efx_modulation_depth(); - set_efx_air_absorption_gain_hf(); - set_efx_hf_reference(); - set_efx_lf_reference(); - set_efx_room_rolloff_factor(); - set_efx_flags(); -} -void EaxReverbEffect::get1(const EaxCall& call, const Props1& props) +void EaxReverbCommitter::Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props) { switch(call.get_property_id()) { - case DSPROPERTY_EAX_ALL: call.set_value<Exception>(props); break; - case DSPROPERTY_EAX_ENVIRONMENT: call.set_value<Exception>(props.environment); break; - case DSPROPERTY_EAX_VOLUME: call.set_value<Exception>(props.fVolume); break; - case DSPROPERTY_EAX_DECAYTIME: call.set_value<Exception>(props.fDecayTime_sec); break; - case DSPROPERTY_EAX_DAMPING: call.set_value<Exception>(props.fDamping); break; - default: fail_unknown_property_id(); + case DSPROPERTY_EAX_ALL: call.set_value<Exception>(props); break; + case DSPROPERTY_EAX_ENVIRONMENT: call.set_value<Exception>(props.environment); break; + case DSPROPERTY_EAX_VOLUME: call.set_value<Exception>(props.fVolume); break; + case DSPROPERTY_EAX_DECAYTIME: call.set_value<Exception>(props.fDecayTime_sec); break; + case DSPROPERTY_EAX_DAMPING: call.set_value<Exception>(props.fDamping); break; + default: fail_unknown_property_id(); } } -void EaxReverbEffect::get2(const EaxCall& call, const Props2& props) +void EaxReverbCommitter::Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props) { switch(call.get_property_id()) { - case DSPROPERTY_EAX20LISTENER_NONE: break; - case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: call.set_value<Exception>(props); break; - case DSPROPERTY_EAX20LISTENER_ROOM: call.set_value<Exception>(props.lRoom); break; - case DSPROPERTY_EAX20LISTENER_ROOMHF: call.set_value<Exception>(props.lRoomHF); break; - case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: call.set_value<Exception>(props.flRoomRolloffFactor); break; - case DSPROPERTY_EAX20LISTENER_DECAYTIME: call.set_value<Exception>(props.flDecayTime); break; - case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: call.set_value<Exception>(props.flDecayHFRatio); break; - case DSPROPERTY_EAX20LISTENER_REFLECTIONS: call.set_value<Exception>(props.lReflections); break; - case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: call.set_value<Exception>(props.flReflectionsDelay); break; - case DSPROPERTY_EAX20LISTENER_REVERB: call.set_value<Exception>(props.lReverb); break; - case DSPROPERTY_EAX20LISTENER_REVERBDELAY: call.set_value<Exception>(props.flReverbDelay); break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: call.set_value<Exception>(props.dwEnvironment); break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: call.set_value<Exception>(props.flEnvironmentSize); break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: call.set_value<Exception>(props.flEnvironmentDiffusion); break; - case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: call.set_value<Exception>(props.flAirAbsorptionHF); break; - case DSPROPERTY_EAX20LISTENER_FLAGS: call.set_value<Exception>(props.dwFlags); break; - default: fail_unknown_property_id(); + case DSPROPERTY_EAX20LISTENER_NONE: break; + case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: call.set_value<Exception>(props); break; + case DSPROPERTY_EAX20LISTENER_ROOM: call.set_value<Exception>(props.lRoom); break; + case DSPROPERTY_EAX20LISTENER_ROOMHF: call.set_value<Exception>(props.lRoomHF); break; + case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: call.set_value<Exception>(props.flRoomRolloffFactor); break; + case DSPROPERTY_EAX20LISTENER_DECAYTIME: call.set_value<Exception>(props.flDecayTime); break; + case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: call.set_value<Exception>(props.flDecayHFRatio); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONS: call.set_value<Exception>(props.lReflections); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: call.set_value<Exception>(props.flReflectionsDelay); break; + case DSPROPERTY_EAX20LISTENER_REVERB: call.set_value<Exception>(props.lReverb); break; + case DSPROPERTY_EAX20LISTENER_REVERBDELAY: call.set_value<Exception>(props.flReverbDelay); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: call.set_value<Exception>(props.dwEnvironment); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: call.set_value<Exception>(props.flEnvironmentSize); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: call.set_value<Exception>(props.flEnvironmentDiffusion); break; + case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: call.set_value<Exception>(props.flAirAbsorptionHF); break; + case DSPROPERTY_EAX20LISTENER_FLAGS: call.set_value<Exception>(props.dwFlags); break; + default: fail_unknown_property_id(); } } -void EaxReverbEffect::get3(const EaxCall& call, const Props3& props) +void EaxReverbCommitter::Get(const EaxCall &call, const EAXREVERBPROPERTIES &props) { switch(call.get_property_id()) { - case EAXREVERB_NONE: break; - case EAXREVERB_ALLPARAMETERS: call.set_value<Exception>(props); break; - case EAXREVERB_ENVIRONMENT: call.set_value<Exception>(props.ulEnvironment); break; - case EAXREVERB_ENVIRONMENTSIZE: call.set_value<Exception>(props.flEnvironmentSize); break; - case EAXREVERB_ENVIRONMENTDIFFUSION: call.set_value<Exception>(props.flEnvironmentDiffusion); break; - case EAXREVERB_ROOM: call.set_value<Exception>(props.lRoom); break; - case EAXREVERB_ROOMHF: call.set_value<Exception>(props.lRoomHF); break; - case EAXREVERB_ROOMLF: call.set_value<Exception>(props.lRoomLF); break; - case EAXREVERB_DECAYTIME: call.set_value<Exception>(props.flDecayTime); break; - case EAXREVERB_DECAYHFRATIO: call.set_value<Exception>(props.flDecayHFRatio); break; - case EAXREVERB_DECAYLFRATIO: call.set_value<Exception>(props.flDecayLFRatio); break; - case EAXREVERB_REFLECTIONS: call.set_value<Exception>(props.lReflections); break; - case EAXREVERB_REFLECTIONSDELAY: call.set_value<Exception>(props.flReflectionsDelay); break; - case EAXREVERB_REFLECTIONSPAN: call.set_value<Exception>(props.vReflectionsPan); break; - case EAXREVERB_REVERB: call.set_value<Exception>(props.lReverb); break; - case EAXREVERB_REVERBDELAY: call.set_value<Exception>(props.flReverbDelay); break; - case EAXREVERB_REVERBPAN: call.set_value<Exception>(props.vReverbPan); break; - case EAXREVERB_ECHOTIME: call.set_value<Exception>(props.flEchoTime); break; - case EAXREVERB_ECHODEPTH: call.set_value<Exception>(props.flEchoDepth); break; - case EAXREVERB_MODULATIONTIME: call.set_value<Exception>(props.flModulationTime); break; - case EAXREVERB_MODULATIONDEPTH: call.set_value<Exception>(props.flModulationDepth); break; - case EAXREVERB_AIRABSORPTIONHF: call.set_value<Exception>(props.flAirAbsorptionHF); break; - case EAXREVERB_HFREFERENCE: call.set_value<Exception>(props.flHFReference); break; - case EAXREVERB_LFREFERENCE: call.set_value<Exception>(props.flLFReference); break; - case EAXREVERB_ROOMROLLOFFFACTOR: call.set_value<Exception>(props.flRoomRolloffFactor); break; - case EAXREVERB_FLAGS: call.set_value<Exception>(props.ulFlags); break; - default: fail_unknown_property_id(); + case EAXREVERB_NONE: break; + case EAXREVERB_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXREVERB_ENVIRONMENT: call.set_value<Exception>(props.ulEnvironment); break; + case EAXREVERB_ENVIRONMENTSIZE: call.set_value<Exception>(props.flEnvironmentSize); break; + case EAXREVERB_ENVIRONMENTDIFFUSION: call.set_value<Exception>(props.flEnvironmentDiffusion); break; + case EAXREVERB_ROOM: call.set_value<Exception>(props.lRoom); break; + case EAXREVERB_ROOMHF: call.set_value<Exception>(props.lRoomHF); break; + case EAXREVERB_ROOMLF: call.set_value<Exception>(props.lRoomLF); break; + case EAXREVERB_DECAYTIME: call.set_value<Exception>(props.flDecayTime); break; + case EAXREVERB_DECAYHFRATIO: call.set_value<Exception>(props.flDecayHFRatio); break; + case EAXREVERB_DECAYLFRATIO: call.set_value<Exception>(props.flDecayLFRatio); break; + case EAXREVERB_REFLECTIONS: call.set_value<Exception>(props.lReflections); break; + case EAXREVERB_REFLECTIONSDELAY: call.set_value<Exception>(props.flReflectionsDelay); break; + case EAXREVERB_REFLECTIONSPAN: call.set_value<Exception>(props.vReflectionsPan); break; + case EAXREVERB_REVERB: call.set_value<Exception>(props.lReverb); break; + case EAXREVERB_REVERBDELAY: call.set_value<Exception>(props.flReverbDelay); break; + case EAXREVERB_REVERBPAN: call.set_value<Exception>(props.vReverbPan); break; + case EAXREVERB_ECHOTIME: call.set_value<Exception>(props.flEchoTime); break; + case EAXREVERB_ECHODEPTH: call.set_value<Exception>(props.flEchoDepth); break; + case EAXREVERB_MODULATIONTIME: call.set_value<Exception>(props.flModulationTime); break; + case EAXREVERB_MODULATIONDEPTH: call.set_value<Exception>(props.flModulationDepth); break; + case EAXREVERB_AIRABSORPTIONHF: call.set_value<Exception>(props.flAirAbsorptionHF); break; + case EAXREVERB_HFREFERENCE: call.set_value<Exception>(props.flHFReference); break; + case EAXREVERB_LFREFERENCE: call.set_value<Exception>(props.flLFReference); break; + case EAXREVERB_ROOMROLLOFFFACTOR: call.set_value<Exception>(props.flRoomRolloffFactor); break; + case EAXREVERB_FLAGS: call.set_value<Exception>(props.ulFlags); break; + default: fail_unknown_property_id(); } } -void EaxReverbEffect::get(const EaxCall& call) +void EaxReverbCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { - switch(call.get_version()) - { - case 1: get1(call, state1_.i); break; - case 2: get2(call, state2_.i); break; - case 3: get3(call, state3_.i); break; - case 4: get3(call, state4_.i.mReverb); break; - case 5: get3(call, state5_.i.mReverb); break; - default: fail_unknown_version(); - } + Get(call, props.mReverb); } -/*[[nodiscard]]*/ bool EaxReverbEffect::commit() -{ - if(!changed_) - return false; - changed_ = false; - - const auto props = props_; - switch(version_) - { - case 1: - state1_.i = state1_.d; - translate(state1_.d, props_); - break; - case 2: - state2_.i = state2_.d; - translate(state2_.d, props_); - break; - case 3: - state3_.i = state3_.d; - translate(state3_.d, props_); - break; - case 4: - state4_.i = state4_.d; - props_ = state4_.d; - break; - case 5: - state5_.i = state5_.d; - props_ = state5_.d; - break; - - default: - fail_unknown_version(); - } - - auto is_dirty = false; - - if (props_.mReverb.flEnvironmentSize != props.mReverb.flEnvironmentSize) - { - is_dirty = true; - set_efx_density_from_environment_size(); - } - - if (props_.mReverb.flEnvironmentDiffusion != props.mReverb.flEnvironmentDiffusion) - { - is_dirty = true; - set_efx_diffusion(); - } - - if (props_.mReverb.lRoom != props.mReverb.lRoom) - { - is_dirty = true; - set_efx_gain(); - } - - if (props_.mReverb.lRoomHF != props.mReverb.lRoomHF) - { - is_dirty = true; - set_efx_gain_hf(); - } - - if (props_.mReverb.lRoomLF != props.mReverb.lRoomLF) - { - is_dirty = true; - set_efx_gain_lf(); - } - - if (props_.mReverb.flDecayTime != props.mReverb.flDecayTime) - { - is_dirty = true; - set_efx_decay_time(); - } - - if (props_.mReverb.flDecayHFRatio != props.mReverb.flDecayHFRatio) - { - is_dirty = true; - set_efx_decay_hf_ratio(); - } - - if (props_.mReverb.flDecayLFRatio != props.mReverb.flDecayLFRatio) - { - is_dirty = true; - set_efx_decay_lf_ratio(); - } - - if (props_.mReverb.lReflections != props.mReverb.lReflections) - { - is_dirty = true; - set_efx_reflections_gain(); - } - - if (props_.mReverb.flReflectionsDelay != props.mReverb.flReflectionsDelay) - { - is_dirty = true; - set_efx_reflections_delay(); - } - - if (props_.mReverb.vReflectionsPan != props.mReverb.vReflectionsPan) - { - is_dirty = true; - set_efx_reflections_pan(); - } - - if (props_.mReverb.lReverb != props.mReverb.lReverb) - { - is_dirty = true; - set_efx_late_reverb_gain(); - } - - if (props_.mReverb.flReverbDelay != props.mReverb.flReverbDelay) - { - is_dirty = true; - set_efx_late_reverb_delay(); - } - - if (props_.mReverb.vReverbPan != props.mReverb.vReverbPan) - { - is_dirty = true; - set_efx_late_reverb_pan(); - } - - if (props_.mReverb.flEchoTime != props.mReverb.flEchoTime) - { - is_dirty = true; - set_efx_echo_time(); - } - - if (props_.mReverb.flEchoDepth != props.mReverb.flEchoDepth) - { - is_dirty = true; - set_efx_echo_depth(); - } - - if (props_.mReverb.flModulationTime != props.mReverb.flModulationTime) - { - is_dirty = true; - set_efx_modulation_time(); - } - - if (props_.mReverb.flModulationDepth != props.mReverb.flModulationDepth) - { - is_dirty = true; - set_efx_modulation_depth(); - } - - if (props_.mReverb.flAirAbsorptionHF != props.mReverb.flAirAbsorptionHF) - { - is_dirty = true; - set_efx_air_absorption_gain_hf(); - } - - if (props_.mReverb.flHFReference != props.mReverb.flHFReference) - { - is_dirty = true; - set_efx_hf_reference(); - } - - if (props_.mReverb.flLFReference != props.mReverb.flLFReference) - { - is_dirty = true; - set_efx_lf_reference(); - } - if (props_.mReverb.flRoomRolloffFactor != props.mReverb.flRoomRolloffFactor) - { - is_dirty = true; - set_efx_room_rolloff_factor(); - } - - if (props_.mReverb.ulFlags != props.mReverb.ulFlags) - { - is_dirty = true; - set_efx_flags(); - } - - return is_dirty; -} - -void EaxReverbEffect::set1(const EaxCall& call, Props1& props) +void EaxReverbCommitter::Set(const EaxCall &call, EAX_REVERBPROPERTIES &props) { - switch (call.get_property_id()) + switch(call.get_property_id()) { - case DSPROPERTY_EAX_ALL: defer<AllValidator1>(call, props); break; - case DSPROPERTY_EAX_ENVIRONMENT: defer<EnvironmentValidator1>(call, props.environment); break; - case DSPROPERTY_EAX_VOLUME: defer<VolumeValidator>(call, props.fVolume); break; - case DSPROPERTY_EAX_DECAYTIME: defer<DecayTimeValidator>(call, props.fDecayTime_sec); break; - case DSPROPERTY_EAX_DAMPING: defer<DampingValidator>(call, props.fDamping); break; - default: fail_unknown_property_id(); + case DSPROPERTY_EAX_ALL: defer<AllValidator1>(call, props); break; + case DSPROPERTY_EAX_ENVIRONMENT: defer<EnvironmentValidator1>(call, props.environment); break; + case DSPROPERTY_EAX_VOLUME: defer<VolumeValidator>(call, props.fVolume); break; + case DSPROPERTY_EAX_DECAYTIME: defer<DecayTimeValidator>(call, props.fDecayTime_sec); break; + case DSPROPERTY_EAX_DAMPING: defer<DampingValidator>(call, props.fDamping); break; + default: fail_unknown_property_id(); } } -void EaxReverbEffect::set2(const EaxCall& call, Props2& props) +void EaxReverbCommitter::Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props) { - switch (call.get_property_id()) + switch(call.get_property_id()) { - case DSPROPERTY_EAX20LISTENER_NONE: - break; + case DSPROPERTY_EAX20LISTENER_NONE: + break; - case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: - defer<AllValidator2>(call, props); - break; + case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: + defer<AllValidator2>(call, props); + break; - case DSPROPERTY_EAX20LISTENER_ROOM: - defer<RoomValidator>(call, props.lRoom); - break; + case DSPROPERTY_EAX20LISTENER_ROOM: + defer<RoomValidator>(call, props.lRoom); + break; - case DSPROPERTY_EAX20LISTENER_ROOMHF: - defer<RoomHFValidator>(call, props.lRoomHF); - break; + case DSPROPERTY_EAX20LISTENER_ROOMHF: + defer<RoomHFValidator>(call, props.lRoomHF); + break; - case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: - defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor); - break; + case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: + defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor); + break; - case DSPROPERTY_EAX20LISTENER_DECAYTIME: - defer<DecayTimeValidator>(call, props.flDecayTime); - break; + case DSPROPERTY_EAX20LISTENER_DECAYTIME: + defer<DecayTimeValidator>(call, props.flDecayTime); + break; - case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: - defer<DecayHFRatioValidator>(call, props.flDecayHFRatio); - break; + case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: + defer<DecayHFRatioValidator>(call, props.flDecayHFRatio); + break; - case DSPROPERTY_EAX20LISTENER_REFLECTIONS: - defer<ReflectionsValidator>(call, props.lReflections); - break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONS: + defer<ReflectionsValidator>(call, props.lReflections); + break; - case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: - defer<ReflectionsDelayValidator>(call, props.flReverbDelay); - break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: + defer<ReflectionsDelayValidator>(call, props.flReverbDelay); + break; - case DSPROPERTY_EAX20LISTENER_REVERB: - defer<ReverbValidator>(call, props.lReverb); - break; + case DSPROPERTY_EAX20LISTENER_REVERB: + defer<ReverbValidator>(call, props.lReverb); + break; - case DSPROPERTY_EAX20LISTENER_REVERBDELAY: - defer<ReverbDelayValidator>(call, props.flReverbDelay); - break; + case DSPROPERTY_EAX20LISTENER_REVERBDELAY: + defer<ReverbDelayValidator>(call, props.flReverbDelay); + break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: - defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment); - break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: + defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment); + break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: - defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize); - break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: + defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize); + break; - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: - defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion); - break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: + defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion); + break; - case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: - defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF); - break; + case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: + defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF); + break; - case DSPROPERTY_EAX20LISTENER_FLAGS: - defer<FlagsValidator2>(call, props.dwFlags); - break; + case DSPROPERTY_EAX20LISTENER_FLAGS: + defer<FlagsValidator2>(call, props.dwFlags); + break; - default: - fail_unknown_property_id(); + default: + fail_unknown_property_id(); } } -void EaxReverbEffect::set3(const EaxCall& call, Props3& props) +void EaxReverbCommitter::Set(const EaxCall &call, EAXREVERBPROPERTIES &props) { switch(call.get_property_id()) { - case EAXREVERB_NONE: - break; - - case EAXREVERB_ALLPARAMETERS: - defer<AllValidator3>(call, props); - break; + case EAXREVERB_NONE: + break; - case EAXREVERB_ENVIRONMENT: - defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment); - break; + case EAXREVERB_ALLPARAMETERS: + defer<AllValidator3>(call, props); + break; - case EAXREVERB_ENVIRONMENTSIZE: - defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize); - break; + case EAXREVERB_ENVIRONMENT: + defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment); + break; - case EAXREVERB_ENVIRONMENTDIFFUSION: - defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion); - break; + case EAXREVERB_ENVIRONMENTSIZE: + defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize); + break; - case EAXREVERB_ROOM: - defer3<RoomValidator>(call, props, props.lRoom); - break; + case EAXREVERB_ENVIRONMENTDIFFUSION: + defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion); + break; - case EAXREVERB_ROOMHF: - defer3<RoomHFValidator>(call, props, props.lRoomHF); - break; + case EAXREVERB_ROOM: + defer3<RoomValidator>(call, props, props.lRoom); + break; - case EAXREVERB_ROOMLF: - defer3<RoomLFValidator>(call, props, props.lRoomLF); - break; + case EAXREVERB_ROOMHF: + defer3<RoomHFValidator>(call, props, props.lRoomHF); + break; - case EAXREVERB_DECAYTIME: - defer3<DecayTimeValidator>(call, props, props.flDecayTime); - break; + case EAXREVERB_ROOMLF: + defer3<RoomLFValidator>(call, props, props.lRoomLF); + break; - case EAXREVERB_DECAYHFRATIO: - defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio); - break; + case EAXREVERB_DECAYTIME: + defer3<DecayTimeValidator>(call, props, props.flDecayTime); + break; - case EAXREVERB_DECAYLFRATIO: - defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio); - break; + case EAXREVERB_DECAYHFRATIO: + defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio); + break; - case EAXREVERB_REFLECTIONS: - defer3<ReflectionsValidator>(call, props, props.lReflections); - break; + case EAXREVERB_DECAYLFRATIO: + defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio); + break; - case EAXREVERB_REFLECTIONSDELAY: - defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay); - break; + case EAXREVERB_REFLECTIONS: + defer3<ReflectionsValidator>(call, props, props.lReflections); + break; - case EAXREVERB_REFLECTIONSPAN: - defer3<VectorValidator>(call, props, props.vReflectionsPan); - break; + case EAXREVERB_REFLECTIONSDELAY: + defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay); + break; - case EAXREVERB_REVERB: - defer3<ReverbValidator>(call, props, props.lReverb); - break; + case EAXREVERB_REFLECTIONSPAN: + defer3<VectorValidator>(call, props, props.vReflectionsPan); + break; - case EAXREVERB_REVERBDELAY: - defer3<ReverbDelayValidator>(call, props, props.flReverbDelay); - break; + case EAXREVERB_REVERB: + defer3<ReverbValidator>(call, props, props.lReverb); + break; - case EAXREVERB_REVERBPAN: - defer3<VectorValidator>(call, props, props.vReverbPan); - break; + case EAXREVERB_REVERBDELAY: + defer3<ReverbDelayValidator>(call, props, props.flReverbDelay); + break; - case EAXREVERB_ECHOTIME: - defer3<EchoTimeValidator>(call, props, props.flEchoTime); - break; + case EAXREVERB_REVERBPAN: + defer3<VectorValidator>(call, props, props.vReverbPan); + break; - case EAXREVERB_ECHODEPTH: - defer3<EchoDepthValidator>(call, props, props.flEchoDepth); - break; + case EAXREVERB_ECHOTIME: + defer3<EchoTimeValidator>(call, props, props.flEchoTime); + break; - case EAXREVERB_MODULATIONTIME: - defer3<ModulationTimeValidator>(call, props, props.flModulationTime); - break; + case EAXREVERB_ECHODEPTH: + defer3<EchoDepthValidator>(call, props, props.flEchoDepth); + break; - case EAXREVERB_MODULATIONDEPTH: - defer3<ModulationDepthValidator>(call, props, props.flModulationDepth); - break; + case EAXREVERB_MODULATIONTIME: + defer3<ModulationTimeValidator>(call, props, props.flModulationTime); + break; - case EAXREVERB_AIRABSORPTIONHF: - defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF); - break; + case EAXREVERB_MODULATIONDEPTH: + defer3<ModulationDepthValidator>(call, props, props.flModulationDepth); + break; - case EAXREVERB_HFREFERENCE: - defer3<HFReferenceValidator>(call, props, props.flHFReference); - break; + case EAXREVERB_AIRABSORPTIONHF: + defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF); + break; - case EAXREVERB_LFREFERENCE: - defer3<LFReferenceValidator>(call, props, props.flLFReference); - break; + case EAXREVERB_HFREFERENCE: + defer3<HFReferenceValidator>(call, props, props.flHFReference); + break; - case EAXREVERB_ROOMROLLOFFFACTOR: - defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor); - break; + case EAXREVERB_LFREFERENCE: + defer3<LFReferenceValidator>(call, props, props.flLFReference); + break; - case EAXREVERB_FLAGS: - defer3<FlagsValidator3>(call, props, props.ulFlags); - break; + case EAXREVERB_ROOMROLLOFFFACTOR: + defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor); + break; - default: - fail_unknown_property_id(); - } -} + case EAXREVERB_FLAGS: + defer3<FlagsValidator3>(call, props, props.ulFlags); + break; -void EaxReverbEffect::set(const EaxCall& call) -{ - const auto version = call.get_version(); - switch(version) - { - case 1: set1(call, state1_.d); break; - case 2: set2(call, state2_.d); break; - case 3: set3(call, state3_.d); break; - case 4: set3(call, state4_.d.mReverb); break; - case 5: set3(call, state5_.d.mReverb); break; - default: fail_unknown_version(); + default: + fail_unknown_property_id(); } - changed_ = true; - version_ = version; -} - -void EaxReverbEffect::translate(const Props1& src, Props4& dst) noexcept -{ - assert(src.environment <= EAX1REVERB_MAXENVIRONMENT); - dst.mType = EaxEffectType::Reverb; - dst.mReverb = EAXREVERB_PRESETS[src.environment]; - dst.mReverb.flDecayTime = src.fDecayTime_sec; - dst.mReverb.flDecayHFRatio = src.fDamping; - dst.mReverb.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0); -} - -void EaxReverbEffect::translate(const Props2& src, Props4& dst) noexcept -{ - assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT); - const auto& env = EAXREVERB_PRESETS[src.dwEnvironment]; - dst.mType = EaxEffectType::Reverb; - dst.mReverb.ulEnvironment = src.dwEnvironment; - dst.mReverb.flEnvironmentSize = src.flEnvironmentSize; - dst.mReverb.flEnvironmentDiffusion = src.flEnvironmentDiffusion; - dst.mReverb.lRoom = src.lRoom; - dst.mReverb.lRoomHF = src.lRoomHF; - dst.mReverb.lRoomLF = env.lRoomLF; - dst.mReverb.flDecayTime = src.flDecayTime; - dst.mReverb.flDecayHFRatio = src.flDecayHFRatio; - dst.mReverb.flDecayLFRatio = env.flDecayLFRatio; - dst.mReverb.lReflections = src.lReflections; - dst.mReverb.flReflectionsDelay = src.flReflectionsDelay; - dst.mReverb.vReflectionsPan = env.vReflectionsPan; - dst.mReverb.lReverb = src.lReverb; - dst.mReverb.flReverbDelay = src.flReverbDelay; - dst.mReverb.vReverbPan = env.vReverbPan; - dst.mReverb.flEchoTime = env.flEchoTime; - dst.mReverb.flEchoDepth = env.flEchoDepth; - dst.mReverb.flModulationTime = env.flModulationTime; - dst.mReverb.flModulationDepth = env.flModulationDepth; - dst.mReverb.flAirAbsorptionHF = src.flAirAbsorptionHF; - dst.mReverb.flHFReference = env.flHFReference; - dst.mReverb.flLFReference = env.flLFReference; - dst.mReverb.flRoomRolloffFactor = src.flRoomRolloffFactor; - dst.mReverb.ulFlags = src.dwFlags; } -void EaxReverbEffect::translate(const Props3& src, Props4& dst) noexcept -{ - dst.mType = EaxEffectType::Reverb; - dst.mReverb = src; -} - -} // namespace - -EaxEffectUPtr eax_create_eax_reverb_effect(int eax_version) +void EaxReverbCommitter::Set(const EaxCall &call, EaxEffectProps &props) { - return std::make_unique<EaxReverbEffect>(eax_version); + Set(call, props.mReverb); } #endif // ALSOFT_EAX |