Update OpenAL-Soft to 1.22.0

This commit is contained in:
Alex Szpakowski
2022-04-30 21:02:11 -03:00
parent 4f72a5e5d9
commit 2b15394df5
229 changed files with 30602 additions and 7654 deletions
+440 -1
View File
@@ -8,9 +8,17 @@
#include "AL/efx.h"
#include "effects/base.h"
#include "alc/effects/base.h"
#include "effects.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
void Autowah_setParamf(EffectProps *props, ALenum param, float val)
@@ -107,3 +115,434 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Autowah);
const EffectProps AutowahEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxAutoWahEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxAutoWahEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxAutoWahEffectDirtyFlagsValue flAttackTime : 1;
EaxAutoWahEffectDirtyFlagsValue flReleaseTime : 1;
EaxAutoWahEffectDirtyFlagsValue lResonance : 1;
EaxAutoWahEffectDirtyFlagsValue lPeakLevel : 1;
}; // EaxAutoWahEffectDirtyFlags
class EaxAutoWahEffect final :
public EaxEffect
{
public:
EaxAutoWahEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXAUTOWAHPROPERTIES eax_{};
EAXAUTOWAHPROPERTIES eax_d_{};
EaxAutoWahEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_attack_time();
void set_efx_release_time();
void set_efx_resonance();
void set_efx_peak_gain();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_attack_time(
float flAttackTime);
void validate_release_time(
float flReleaseTime);
void validate_resonance(
long lResonance);
void validate_peak_level(
long lPeakLevel);
void validate_all(
const EAXAUTOWAHPROPERTIES& eax_all);
void defer_attack_time(
float flAttackTime);
void defer_release_time(
float flReleaseTime);
void defer_resonance(
long lResonance);
void defer_peak_level(
long lPeakLevel);
void defer_all(
const EAXAUTOWAHPROPERTIES& eax_all);
void defer_attack_time(
const EaxEaxCall& eax_call);
void defer_release_time(
const EaxEaxCall& eax_call);
void defer_resonance(
const EaxEaxCall& eax_call);
void defer_peak_level(
const EaxEaxCall& eax_call);
void defer_all(
const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxAutoWahEffect
class EaxAutoWahEffectException :
public EaxException
{
public:
explicit EaxAutoWahEffectException(
const char* message)
:
EaxException{"EAX_AUTO_WAH_EFFECT", message}
{
}
}; // EaxAutoWahEffectException
EaxAutoWahEffect::EaxAutoWahEffect()
: EaxEffect{AL_EFFECT_AUTOWAH}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxAutoWahEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxAutoWahEffect::set_eax_defaults()
{
eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
eax_d_ = eax_;
}
void EaxAutoWahEffect::set_efx_attack_time()
{
const auto attack_time = clamp(
eax_.flAttackTime,
AL_AUTOWAH_MIN_ATTACK_TIME,
AL_AUTOWAH_MAX_ATTACK_TIME);
al_effect_props_.Autowah.AttackTime = attack_time;
}
void EaxAutoWahEffect::set_efx_release_time()
{
const auto release_time = clamp(
eax_.flReleaseTime,
AL_AUTOWAH_MIN_RELEASE_TIME,
AL_AUTOWAH_MAX_RELEASE_TIME);
al_effect_props_.Autowah.ReleaseTime = release_time;
}
void EaxAutoWahEffect::set_efx_resonance()
{
const auto resonance = clamp(
level_mb_to_gain(static_cast<float>(eax_.lResonance)),
AL_AUTOWAH_MIN_RESONANCE,
AL_AUTOWAH_MAX_RESONANCE);
al_effect_props_.Autowah.Resonance = resonance;
}
void EaxAutoWahEffect::set_efx_peak_gain()
{
const auto peak_gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lPeakLevel)),
AL_AUTOWAH_MIN_PEAK_GAIN,
AL_AUTOWAH_MAX_PEAK_GAIN);
al_effect_props_.Autowah.PeakGain = peak_gain;
}
void EaxAutoWahEffect::set_efx_defaults()
{
set_efx_attack_time();
set_efx_release_time();
set_efx_resonance();
set_efx_peak_gain();
}
void EaxAutoWahEffect::get(const EaxEaxCall& eax_call)
{
switch (eax_call.get_property_id())
{
case EAXAUTOWAH_NONE:
break;
case EAXAUTOWAH_ALLPARAMETERS:
eax_call.set_value<EaxAutoWahEffectException>(eax_);
break;
case EAXAUTOWAH_ATTACKTIME:
eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
break;
case EAXAUTOWAH_RELEASETIME:
eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
break;
case EAXAUTOWAH_RESONANCE:
eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
break;
case EAXAUTOWAH_PEAKLEVEL:
eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
break;
default:
throw EaxAutoWahEffectException{"Unsupported property id."};
}
}
void EaxAutoWahEffect::validate_attack_time(
float flAttackTime)
{
eax_validate_range<EaxAutoWahEffectException>(
"Attack Time",
flAttackTime,
EAXAUTOWAH_MINATTACKTIME,
EAXAUTOWAH_MAXATTACKTIME);
}
void EaxAutoWahEffect::validate_release_time(
float flReleaseTime)
{
eax_validate_range<EaxAutoWahEffectException>(
"Release Time",
flReleaseTime,
EAXAUTOWAH_MINRELEASETIME,
EAXAUTOWAH_MAXRELEASETIME);
}
void EaxAutoWahEffect::validate_resonance(
long lResonance)
{
eax_validate_range<EaxAutoWahEffectException>(
"Resonance",
lResonance,
EAXAUTOWAH_MINRESONANCE,
EAXAUTOWAH_MAXRESONANCE);
}
void EaxAutoWahEffect::validate_peak_level(
long lPeakLevel)
{
eax_validate_range<EaxAutoWahEffectException>(
"Peak Level",
lPeakLevel,
EAXAUTOWAH_MINPEAKLEVEL,
EAXAUTOWAH_MAXPEAKLEVEL);
}
void EaxAutoWahEffect::validate_all(
const EAXAUTOWAHPROPERTIES& eax_all)
{
validate_attack_time(eax_all.flAttackTime);
validate_release_time(eax_all.flReleaseTime);
validate_resonance(eax_all.lResonance);
validate_peak_level(eax_all.lPeakLevel);
}
void EaxAutoWahEffect::defer_attack_time(
float flAttackTime)
{
eax_d_.flAttackTime = flAttackTime;
eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime);
}
void EaxAutoWahEffect::defer_release_time(
float flReleaseTime)
{
eax_d_.flReleaseTime = flReleaseTime;
eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime);
}
void EaxAutoWahEffect::defer_resonance(
long lResonance)
{
eax_d_.lResonance = lResonance;
eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance);
}
void EaxAutoWahEffect::defer_peak_level(
long lPeakLevel)
{
eax_d_.lPeakLevel = lPeakLevel;
eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel);
}
void EaxAutoWahEffect::defer_all(
const EAXAUTOWAHPROPERTIES& eax_all)
{
validate_all(eax_all);
defer_attack_time(eax_all.flAttackTime);
defer_release_time(eax_all.flReleaseTime);
defer_resonance(eax_all.lResonance);
defer_peak_level(eax_all.lPeakLevel);
}
void EaxAutoWahEffect::defer_attack_time(
const EaxEaxCall& eax_call)
{
const auto& attack_time =
eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
validate_attack_time(attack_time);
defer_attack_time(attack_time);
}
void EaxAutoWahEffect::defer_release_time(
const EaxEaxCall& eax_call)
{
const auto& release_time =
eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
validate_release_time(release_time);
defer_release_time(release_time);
}
void EaxAutoWahEffect::defer_resonance(
const EaxEaxCall& eax_call)
{
const auto& resonance =
eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
validate_resonance(resonance);
defer_resonance(resonance);
}
void EaxAutoWahEffect::defer_peak_level(
const EaxEaxCall& eax_call)
{
const auto& peak_level =
eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
validate_peak_level(peak_level);
defer_peak_level(peak_level);
}
void EaxAutoWahEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxAutoWahEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.flAttackTime)
{
set_efx_attack_time();
}
if (eax_dirty_flags_.flReleaseTime)
{
set_efx_release_time();
}
if (eax_dirty_flags_.lResonance)
{
set_efx_resonance();
}
if (eax_dirty_flags_.lPeakLevel)
{
set_efx_peak_gain();
}
eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{};
return true;
}
void EaxAutoWahEffect::set(const EaxEaxCall& eax_call)
{
switch (eax_call.get_property_id())
{
case EAXAUTOWAH_NONE:
break;
case EAXAUTOWAH_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXAUTOWAH_ATTACKTIME:
defer_attack_time(eax_call);
break;
case EAXAUTOWAH_RELEASETIME:
defer_release_time(eax_call);
break;
case EAXAUTOWAH_RESONANCE:
defer_resonance(eax_call);
break;
case EAXAUTOWAH_PEAKLEVEL:
defer_peak_level(eax_call);
break;
default:
throw EaxAutoWahEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_auto_wah_effect()
{
return std::make_unique<::EaxAutoWahEffect>();
}
#endif // ALSOFT_EAX
File diff suppressed because it is too large Load Diff
+225 -1
View File
@@ -4,8 +4,15 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -70,3 +77,220 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Compressor);
const EffectProps CompressorEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxCompressorEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxCompressorEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxCompressorEffectDirtyFlagsValue ulOnOff : 1;
}; // EaxCompressorEffectDirtyFlags
class EaxCompressorEffect final :
public EaxEffect
{
public:
EaxCompressorEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXAGCCOMPRESSORPROPERTIES eax_{};
EAXAGCCOMPRESSORPROPERTIES eax_d_{};
EaxCompressorEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_on_off();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_on_off(unsigned long ulOnOff);
void validate_all(const EAXAGCCOMPRESSORPROPERTIES& eax_all);
void defer_on_off(unsigned long ulOnOff);
void defer_all(const EAXAGCCOMPRESSORPROPERTIES& eax_all);
void defer_on_off(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxCompressorEffect
class EaxCompressorEffectException :
public EaxException
{
public:
explicit EaxCompressorEffectException(
const char* message)
:
EaxException{"EAX_COMPRESSOR_EFFECT", message}
{
}
}; // EaxCompressorEffectException
EaxCompressorEffect::EaxCompressorEffect()
: EaxEffect{AL_EFFECT_COMPRESSOR}
{
set_eax_defaults();
set_efx_defaults();
}
// [[nodiscard]]
void EaxCompressorEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxCompressorEffect::set_eax_defaults()
{
eax_.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF;
eax_d_ = eax_;
}
void EaxCompressorEffect::set_efx_on_off()
{
const auto on_off = clamp(
static_cast<ALint>(eax_.ulOnOff),
AL_COMPRESSOR_MIN_ONOFF,
AL_COMPRESSOR_MAX_ONOFF);
al_effect_props_.Compressor.OnOff = (on_off != AL_FALSE);
}
void EaxCompressorEffect::set_efx_defaults()
{
set_efx_on_off();
}
void EaxCompressorEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXAGCCOMPRESSOR_NONE:
break;
case EAXAGCCOMPRESSOR_ALLPARAMETERS:
eax_call.set_value<EaxCompressorEffectException>(eax_);
break;
case EAXAGCCOMPRESSOR_ONOFF:
eax_call.set_value<EaxCompressorEffectException>(eax_.ulOnOff);
break;
default:
throw EaxCompressorEffectException{"Unsupported property id."};
}
}
void EaxCompressorEffect::validate_on_off(
unsigned long ulOnOff)
{
eax_validate_range<EaxCompressorEffectException>(
"On-Off",
ulOnOff,
EAXAGCCOMPRESSOR_MINONOFF,
EAXAGCCOMPRESSOR_MAXONOFF);
}
void EaxCompressorEffect::validate_all(
const EAXAGCCOMPRESSORPROPERTIES& eax_all)
{
validate_on_off(eax_all.ulOnOff);
}
void EaxCompressorEffect::defer_on_off(
unsigned long ulOnOff)
{
eax_d_.ulOnOff = ulOnOff;
eax_dirty_flags_.ulOnOff = (eax_.ulOnOff != eax_d_.ulOnOff);
}
void EaxCompressorEffect::defer_all(
const EAXAGCCOMPRESSORPROPERTIES& eax_all)
{
defer_on_off(eax_all.ulOnOff);
}
void EaxCompressorEffect::defer_on_off(
const EaxEaxCall& eax_call)
{
const auto& on_off =
eax_call.get_value<EaxCompressorEffectException, const decltype(EAXAGCCOMPRESSORPROPERTIES::ulOnOff)>();
validate_on_off(on_off);
defer_on_off(on_off);
}
void EaxCompressorEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxCompressorEffectException, const EAXAGCCOMPRESSORPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxCompressorEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxCompressorEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.ulOnOff)
{
set_efx_on_off();
}
eax_dirty_flags_ = EaxCompressorEffectDirtyFlags{};
return true;
}
void EaxCompressorEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXAGCCOMPRESSOR_NONE:
break;
case EAXAGCCOMPRESSOR_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXAGCCOMPRESSOR_ONOFF:
defer_on_off(eax_call);
break;
default:
throw EaxCompressorEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_compressor_effect()
{
return std::make_unique<EaxCompressorEffect>();
}
#endif // ALSOFT_EAX
+2 -2
View File
@@ -2,10 +2,10 @@
#include "config.h"
#include "AL/al.h"
#include "inprogext.h"
#include "alc/inprogext.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
namespace {
+2 -2
View File
@@ -4,10 +4,10 @@
#include <cmath>
#include "AL/al.h"
#include "AL/efx.h"
#include "AL/alext.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
namespace {
+458 -1
View File
@@ -4,8 +4,15 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -112,3 +119,453 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Distortion);
const EffectProps DistortionEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxDistortionEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxDistortionEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxDistortionEffectDirtyFlagsValue flEdge : 1;
EaxDistortionEffectDirtyFlagsValue lGain : 1;
EaxDistortionEffectDirtyFlagsValue flLowPassCutOff : 1;
EaxDistortionEffectDirtyFlagsValue flEQCenter : 1;
EaxDistortionEffectDirtyFlagsValue flEQBandwidth : 1;
}; // EaxDistortionEffectDirtyFlags
class EaxDistortionEffect final :
public EaxEffect
{
public:
EaxDistortionEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXDISTORTIONPROPERTIES eax_{};
EAXDISTORTIONPROPERTIES eax_d_{};
EaxDistortionEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_edge();
void set_efx_gain();
void set_efx_lowpass_cutoff();
void set_efx_eq_center();
void set_efx_eq_bandwidth();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_edge(float flEdge);
void validate_gain(long lGain);
void validate_lowpass_cutoff(float flLowPassCutOff);
void validate_eq_center(float flEQCenter);
void validate_eq_bandwidth(float flEQBandwidth);
void validate_all(const EAXDISTORTIONPROPERTIES& eax_all);
void defer_edge(float flEdge);
void defer_gain(long lGain);
void defer_low_pass_cutoff(float flLowPassCutOff);
void defer_eq_center(float flEQCenter);
void defer_eq_bandwidth(float flEQBandwidth);
void defer_all(const EAXDISTORTIONPROPERTIES& eax_all);
void defer_edge(const EaxEaxCall& eax_call);
void defer_gain(const EaxEaxCall& eax_call);
void defer_low_pass_cutoff(const EaxEaxCall& eax_call);
void defer_eq_center(const EaxEaxCall& eax_call);
void defer_eq_bandwidth(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxDistortionEffect
class EaxDistortionEffectException :
public EaxException
{
public:
explicit EaxDistortionEffectException(
const char* message)
:
EaxException{"EAX_DISTORTION_EFFECT", message}
{
}
}; // EaxDistortionEffectException
EaxDistortionEffect::EaxDistortionEffect()
: EaxEffect{AL_EFFECT_DISTORTION}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxDistortionEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxDistortionEffect::set_eax_defaults()
{
eax_.flEdge = EAXDISTORTION_DEFAULTEDGE;
eax_.lGain = EAXDISTORTION_DEFAULTGAIN;
eax_.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
eax_.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
eax_.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
eax_d_ = eax_;
}
void EaxDistortionEffect::set_efx_edge()
{
const auto edge = clamp(
eax_.flEdge,
AL_DISTORTION_MIN_EDGE,
AL_DISTORTION_MAX_EDGE);
al_effect_props_.Distortion.Edge = edge;
}
void EaxDistortionEffect::set_efx_gain()
{
const auto gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lGain)),
AL_DISTORTION_MIN_GAIN,
AL_DISTORTION_MAX_GAIN);
al_effect_props_.Distortion.Gain = gain;
}
void EaxDistortionEffect::set_efx_lowpass_cutoff()
{
const auto lowpass_cutoff = clamp(
eax_.flLowPassCutOff,
AL_DISTORTION_MIN_LOWPASS_CUTOFF,
AL_DISTORTION_MAX_LOWPASS_CUTOFF);
al_effect_props_.Distortion.LowpassCutoff = lowpass_cutoff;
}
void EaxDistortionEffect::set_efx_eq_center()
{
const auto eq_center = clamp(
eax_.flEQCenter,
AL_DISTORTION_MIN_EQCENTER,
AL_DISTORTION_MAX_EQCENTER);
al_effect_props_.Distortion.EQCenter = eq_center;
}
void EaxDistortionEffect::set_efx_eq_bandwidth()
{
const auto eq_bandwidth = clamp(
eax_.flEdge,
AL_DISTORTION_MIN_EQBANDWIDTH,
AL_DISTORTION_MAX_EQBANDWIDTH);
al_effect_props_.Distortion.EQBandwidth = eq_bandwidth;
}
void EaxDistortionEffect::set_efx_defaults()
{
set_efx_edge();
set_efx_gain();
set_efx_lowpass_cutoff();
set_efx_eq_center();
set_efx_eq_bandwidth();
}
void EaxDistortionEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXDISTORTION_NONE:
break;
case EAXDISTORTION_ALLPARAMETERS:
eax_call.set_value<EaxDistortionEffectException>(eax_);
break;
case EAXDISTORTION_EDGE:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEdge);
break;
case EAXDISTORTION_GAIN:
eax_call.set_value<EaxDistortionEffectException>(eax_.lGain);
break;
case EAXDISTORTION_LOWPASSCUTOFF:
eax_call.set_value<EaxDistortionEffectException>(eax_.flLowPassCutOff);
break;
case EAXDISTORTION_EQCENTER:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEQCenter);
break;
case EAXDISTORTION_EQBANDWIDTH:
eax_call.set_value<EaxDistortionEffectException>(eax_.flEQBandwidth);
break;
default:
throw EaxDistortionEffectException{"Unsupported property id."};
}
}
void EaxDistortionEffect::validate_edge(
float flEdge)
{
eax_validate_range<EaxDistortionEffectException>(
"Edge",
flEdge,
EAXDISTORTION_MINEDGE,
EAXDISTORTION_MAXEDGE);
}
void EaxDistortionEffect::validate_gain(
long lGain)
{
eax_validate_range<EaxDistortionEffectException>(
"Gain",
lGain,
EAXDISTORTION_MINGAIN,
EAXDISTORTION_MAXGAIN);
}
void EaxDistortionEffect::validate_lowpass_cutoff(
float flLowPassCutOff)
{
eax_validate_range<EaxDistortionEffectException>(
"Low-pass Cut-off",
flLowPassCutOff,
EAXDISTORTION_MINLOWPASSCUTOFF,
EAXDISTORTION_MAXLOWPASSCUTOFF);
}
void EaxDistortionEffect::validate_eq_center(
float flEQCenter)
{
eax_validate_range<EaxDistortionEffectException>(
"EQ Center",
flEQCenter,
EAXDISTORTION_MINEQCENTER,
EAXDISTORTION_MAXEQCENTER);
}
void EaxDistortionEffect::validate_eq_bandwidth(
float flEQBandwidth)
{
eax_validate_range<EaxDistortionEffectException>(
"EQ Bandwidth",
flEQBandwidth,
EAXDISTORTION_MINEQBANDWIDTH,
EAXDISTORTION_MAXEQBANDWIDTH);
}
void EaxDistortionEffect::validate_all(
const EAXDISTORTIONPROPERTIES& eax_all)
{
validate_edge(eax_all.flEdge);
validate_gain(eax_all.lGain);
validate_lowpass_cutoff(eax_all.flLowPassCutOff);
validate_eq_center(eax_all.flEQCenter);
validate_eq_bandwidth(eax_all.flEQBandwidth);
}
void EaxDistortionEffect::defer_edge(
float flEdge)
{
eax_d_.flEdge = flEdge;
eax_dirty_flags_.flEdge = (eax_.flEdge != eax_d_.flEdge);
}
void EaxDistortionEffect::defer_gain(
long lGain)
{
eax_d_.lGain = lGain;
eax_dirty_flags_.lGain = (eax_.lGain != eax_d_.lGain);
}
void EaxDistortionEffect::defer_low_pass_cutoff(
float flLowPassCutOff)
{
eax_d_.flLowPassCutOff = flLowPassCutOff;
eax_dirty_flags_.flLowPassCutOff = (eax_.flLowPassCutOff != eax_d_.flLowPassCutOff);
}
void EaxDistortionEffect::defer_eq_center(
float flEQCenter)
{
eax_d_.flEQCenter = flEQCenter;
eax_dirty_flags_.flEQCenter = (eax_.flEQCenter != eax_d_.flEQCenter);
}
void EaxDistortionEffect::defer_eq_bandwidth(
float flEQBandwidth)
{
eax_d_.flEQBandwidth = flEQBandwidth;
eax_dirty_flags_.flEQBandwidth = (eax_.flEQBandwidth != eax_d_.flEQBandwidth);
}
void EaxDistortionEffect::defer_all(
const EAXDISTORTIONPROPERTIES& eax_all)
{
defer_edge(eax_all.flEdge);
defer_gain(eax_all.lGain);
defer_low_pass_cutoff(eax_all.flLowPassCutOff);
defer_eq_center(eax_all.flEQCenter);
defer_eq_bandwidth(eax_all.flEQBandwidth);
}
void EaxDistortionEffect::defer_edge(
const EaxEaxCall& eax_call)
{
const auto& edge =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEdge)>();
validate_edge(edge);
defer_edge(edge);
}
void EaxDistortionEffect::defer_gain(
const EaxEaxCall& eax_call)
{
const auto& gain =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::lGain)>();
validate_gain(gain);
defer_gain(gain);
}
void EaxDistortionEffect::defer_low_pass_cutoff(
const EaxEaxCall& eax_call)
{
const auto& lowpass_cutoff =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flLowPassCutOff)>();
validate_lowpass_cutoff(lowpass_cutoff);
defer_low_pass_cutoff(lowpass_cutoff);
}
void EaxDistortionEffect::defer_eq_center(
const EaxEaxCall& eax_call)
{
const auto& eq_center =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQCenter)>();
validate_eq_center(eq_center);
defer_eq_center(eq_center);
}
void EaxDistortionEffect::defer_eq_bandwidth(
const EaxEaxCall& eax_call)
{
const auto& eq_bandwidth =
eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQBandwidth)>();
validate_eq_bandwidth(eq_bandwidth);
defer_eq_bandwidth(eq_bandwidth);
}
void EaxDistortionEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxDistortionEffectException, const EAXDISTORTIONPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxDistortionEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxDistortionEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.flEdge)
{
set_efx_edge();
}
if (eax_dirty_flags_.lGain)
{
set_efx_gain();
}
if (eax_dirty_flags_.flLowPassCutOff)
{
set_efx_lowpass_cutoff();
}
if (eax_dirty_flags_.flEQCenter)
{
set_efx_eq_center();
}
if (eax_dirty_flags_.flEQBandwidth)
{
set_efx_eq_bandwidth();
}
eax_dirty_flags_ = EaxDistortionEffectDirtyFlags{};
return true;
}
void EaxDistortionEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXDISTORTION_NONE:
break;
case EAXDISTORTION_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXDISTORTION_EDGE:
defer_edge(eax_call);
break;
case EAXDISTORTION_GAIN:
defer_gain(eax_call);
break;
case EAXDISTORTION_LOWPASSCUTOFF:
defer_low_pass_cutoff(eax_call);
break;
case EAXDISTORTION_EQCENTER:
defer_eq_center(eax_call);
break;
case EAXDISTORTION_EQBANDWIDTH:
defer_eq_bandwidth(eax_call);
break;
default:
throw EaxDistortionEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_distortion_effect()
{
return std::make_unique<EaxDistortionEffect>();
}
#endif // ALSOFT_EAX
+459 -1
View File
@@ -4,8 +4,15 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -109,3 +116,454 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Echo);
const EffectProps EchoEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxEchoEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxEchoEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxEchoEffectDirtyFlagsValue flDelay : 1;
EaxEchoEffectDirtyFlagsValue flLRDelay : 1;
EaxEchoEffectDirtyFlagsValue flDamping : 1;
EaxEchoEffectDirtyFlagsValue flFeedback : 1;
EaxEchoEffectDirtyFlagsValue flSpread : 1;
}; // EaxEchoEffectDirtyFlags
class EaxEchoEffect final :
public EaxEffect
{
public:
EaxEchoEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXECHOPROPERTIES eax_{};
EAXECHOPROPERTIES eax_d_{};
EaxEchoEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_delay();
void set_efx_lr_delay();
void set_efx_damping();
void set_efx_feedback();
void set_efx_spread();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_delay(float flDelay);
void validate_lr_delay(float flLRDelay);
void validate_damping(float flDamping);
void validate_feedback(float flFeedback);
void validate_spread(float flSpread);
void validate_all(const EAXECHOPROPERTIES& all);
void defer_delay(float flDelay);
void defer_lr_delay(float flLRDelay);
void defer_damping(float flDamping);
void defer_feedback(float flFeedback);
void defer_spread(float flSpread);
void defer_all(const EAXECHOPROPERTIES& all);
void defer_delay(const EaxEaxCall& eax_call);
void defer_lr_delay(const EaxEaxCall& eax_call);
void defer_damping(const EaxEaxCall& eax_call);
void defer_feedback(const EaxEaxCall& eax_call);
void defer_spread(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxEchoEffect
class EaxEchoEffectException :
public EaxException
{
public:
explicit EaxEchoEffectException(
const char* message)
:
EaxException{"EAX_ECHO_EFFECT", message}
{
}
}; // EaxEchoEffectException
EaxEchoEffect::EaxEchoEffect()
: EaxEffect{AL_EFFECT_ECHO}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxEchoEffect::dispatch(
const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxEchoEffect::set_eax_defaults()
{
eax_.flDelay = EAXECHO_DEFAULTDELAY;
eax_.flLRDelay = EAXECHO_DEFAULTLRDELAY;
eax_.flDamping = EAXECHO_DEFAULTDAMPING;
eax_.flFeedback = EAXECHO_DEFAULTFEEDBACK;
eax_.flSpread = EAXECHO_DEFAULTSPREAD;
eax_d_ = eax_;
}
void EaxEchoEffect::set_efx_delay()
{
const auto delay = clamp(
eax_.flDelay,
AL_ECHO_MIN_DELAY,
AL_ECHO_MAX_DELAY);
al_effect_props_.Echo.Delay = delay;
}
void EaxEchoEffect::set_efx_lr_delay()
{
const auto lr_delay = clamp(
eax_.flLRDelay,
AL_ECHO_MIN_LRDELAY,
AL_ECHO_MAX_LRDELAY);
al_effect_props_.Echo.LRDelay = lr_delay;
}
void EaxEchoEffect::set_efx_damping()
{
const auto damping = clamp(
eax_.flDamping,
AL_ECHO_MIN_DAMPING,
AL_ECHO_MAX_DAMPING);
al_effect_props_.Echo.Damping = damping;
}
void EaxEchoEffect::set_efx_feedback()
{
const auto feedback = clamp(
eax_.flFeedback,
AL_ECHO_MIN_FEEDBACK,
AL_ECHO_MAX_FEEDBACK);
al_effect_props_.Echo.Feedback = feedback;
}
void EaxEchoEffect::set_efx_spread()
{
const auto spread = clamp(
eax_.flSpread,
AL_ECHO_MIN_SPREAD,
AL_ECHO_MAX_SPREAD);
al_effect_props_.Echo.Spread = spread;
}
void EaxEchoEffect::set_efx_defaults()
{
set_efx_delay();
set_efx_lr_delay();
set_efx_damping();
set_efx_feedback();
set_efx_spread();
}
void EaxEchoEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXECHO_NONE:
break;
case EAXECHO_ALLPARAMETERS:
eax_call.set_value<EaxEchoEffectException>(eax_);
break;
case EAXECHO_DELAY:
eax_call.set_value<EaxEchoEffectException>(eax_.flDelay);
break;
case EAXECHO_LRDELAY:
eax_call.set_value<EaxEchoEffectException>(eax_.flLRDelay);
break;
case EAXECHO_DAMPING:
eax_call.set_value<EaxEchoEffectException>(eax_.flDamping);
break;
case EAXECHO_FEEDBACK:
eax_call.set_value<EaxEchoEffectException>(eax_.flFeedback);
break;
case EAXECHO_SPREAD:
eax_call.set_value<EaxEchoEffectException>(eax_.flSpread);
break;
default:
throw EaxEchoEffectException{"Unsupported property id."};
}
}
void EaxEchoEffect::validate_delay(
float flDelay)
{
eax_validate_range<EaxEchoEffectException>(
"Delay",
flDelay,
EAXECHO_MINDELAY,
EAXECHO_MAXDELAY);
}
void EaxEchoEffect::validate_lr_delay(
float flLRDelay)
{
eax_validate_range<EaxEchoEffectException>(
"LR Delay",
flLRDelay,
EAXECHO_MINLRDELAY,
EAXECHO_MAXLRDELAY);
}
void EaxEchoEffect::validate_damping(
float flDamping)
{
eax_validate_range<EaxEchoEffectException>(
"Damping",
flDamping,
EAXECHO_MINDAMPING,
EAXECHO_MAXDAMPING);
}
void EaxEchoEffect::validate_feedback(
float flFeedback)
{
eax_validate_range<EaxEchoEffectException>(
"Feedback",
flFeedback,
EAXECHO_MINFEEDBACK,
EAXECHO_MAXFEEDBACK);
}
void EaxEchoEffect::validate_spread(
float flSpread)
{
eax_validate_range<EaxEchoEffectException>(
"Spread",
flSpread,
EAXECHO_MINSPREAD,
EAXECHO_MAXSPREAD);
}
void EaxEchoEffect::validate_all(
const EAXECHOPROPERTIES& all)
{
validate_delay(all.flDelay);
validate_lr_delay(all.flLRDelay);
validate_damping(all.flDamping);
validate_feedback(all.flFeedback);
validate_spread(all.flSpread);
}
void EaxEchoEffect::defer_delay(
float flDelay)
{
eax_d_.flDelay = flDelay;
eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay);
}
void EaxEchoEffect::defer_lr_delay(
float flLRDelay)
{
eax_d_.flLRDelay = flLRDelay;
eax_dirty_flags_.flLRDelay = (eax_.flLRDelay != eax_d_.flLRDelay);
}
void EaxEchoEffect::defer_damping(
float flDamping)
{
eax_d_.flDamping = flDamping;
eax_dirty_flags_.flDamping = (eax_.flDamping != eax_d_.flDamping);
}
void EaxEchoEffect::defer_feedback(
float flFeedback)
{
eax_d_.flFeedback = flFeedback;
eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback);
}
void EaxEchoEffect::defer_spread(
float flSpread)
{
eax_d_.flSpread = flSpread;
eax_dirty_flags_.flSpread = (eax_.flSpread != eax_d_.flSpread);
}
void EaxEchoEffect::defer_all(
const EAXECHOPROPERTIES& all)
{
defer_delay(all.flDelay);
defer_lr_delay(all.flLRDelay);
defer_damping(all.flDamping);
defer_feedback(all.flFeedback);
defer_spread(all.flSpread);
}
void EaxEchoEffect::defer_delay(
const EaxEaxCall& eax_call)
{
const auto& delay =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDelay)>();
validate_delay(delay);
defer_delay(delay);
}
void EaxEchoEffect::defer_lr_delay(
const EaxEaxCall& eax_call)
{
const auto& lr_delay =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flLRDelay)>();
validate_lr_delay(lr_delay);
defer_lr_delay(lr_delay);
}
void EaxEchoEffect::defer_damping(
const EaxEaxCall& eax_call)
{
const auto& damping =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDamping)>();
validate_damping(damping);
defer_damping(damping);
}
void EaxEchoEffect::defer_feedback(
const EaxEaxCall& eax_call)
{
const auto& feedback =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flFeedback)>();
validate_feedback(feedback);
defer_feedback(feedback);
}
void EaxEchoEffect::defer_spread(
const EaxEaxCall& eax_call)
{
const auto& spread =
eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flSpread)>();
validate_spread(spread);
defer_spread(spread);
}
void EaxEchoEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxEchoEffectException, const EAXECHOPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxEchoEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxEchoEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.flDelay)
{
set_efx_delay();
}
if (eax_dirty_flags_.flLRDelay)
{
set_efx_lr_delay();
}
if (eax_dirty_flags_.flDamping)
{
set_efx_damping();
}
if (eax_dirty_flags_.flFeedback)
{
set_efx_feedback();
}
if (eax_dirty_flags_.flSpread)
{
set_efx_spread();
}
eax_dirty_flags_ = EaxEchoEffectDirtyFlags{};
return true;
}
void EaxEchoEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXECHO_NONE:
break;
case EAXECHO_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXECHO_DELAY:
defer_delay(eax_call);
break;
case EAXECHO_LRDELAY:
defer_lr_delay(eax_call);
break;
case EAXECHO_DAMPING:
defer_damping(eax_call);
break;
case EAXECHO_FEEDBACK:
defer_feedback(eax_call);
break;
case EAXECHO_SPREAD:
defer_spread(eax_call);
break;
default:
throw EaxEchoEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_echo_effect()
{
return std::make_unique<EaxEchoEffect>();
}
#endif // ALSOFT_EAX
+66
View File
@@ -0,0 +1,66 @@
#include "config.h"
#ifdef ALSOFT_EAX
#include "effects.h"
#include <cassert>
#include "AL/efx.h"
EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type)
{
#define EAX_PREFIX "[EAX_MAKE_EAX_EFFECT] "
switch (al_effect_type)
{
case AL_EFFECT_NULL:
return eax_create_eax_null_effect();
case AL_EFFECT_CHORUS:
return eax_create_eax_chorus_effect();
case AL_EFFECT_DISTORTION:
return eax_create_eax_distortion_effect();
case AL_EFFECT_ECHO:
return eax_create_eax_echo_effect();
case AL_EFFECT_FLANGER:
return eax_create_eax_flanger_effect();
case AL_EFFECT_FREQUENCY_SHIFTER:
return eax_create_eax_frequency_shifter_effect();
case AL_EFFECT_VOCAL_MORPHER:
return eax_create_eax_vocal_morpher_effect();
case AL_EFFECT_PITCH_SHIFTER:
return eax_create_eax_pitch_shifter_effect();
case AL_EFFECT_RING_MODULATOR:
return eax_create_eax_ring_modulator_effect();
case AL_EFFECT_AUTOWAH:
return eax_create_eax_auto_wah_effect();
case AL_EFFECT_COMPRESSOR:
return eax_create_eax_compressor_effect();
case AL_EFFECT_EQUALIZER:
return eax_create_eax_equalizer_effect();
case AL_EFFECT_EAXREVERB:
return eax_create_eax_reverb_effect();
default:
assert(false && "Unsupported AL effect type.");
return nullptr;
}
#undef EAX_PREFIX
}
#endif // ALSOFT_EAX
+13
View File
@@ -5,6 +5,10 @@
#include "core/except.h"
#ifdef ALSOFT_EAX
#include "al/eax_effect.h"
#endif // ALSOFT_EAX
union EffectProps;
@@ -12,7 +16,11 @@ class effect_exception final : public al::base_exception {
ALenum mErrorCode;
public:
#ifdef __USE_MINGW_ANSI_STDIO
[[gnu::format(gnu_printf, 3, 4)]]
#else
[[gnu::format(printf, 3, 4)]]
#endif
effect_exception(ALenum code, const char *msg, ...);
ALenum errorCode() const noexcept { return mErrorCode; }
@@ -76,4 +84,9 @@ extern const EffectVtable VmorpherEffectVtable;
extern const EffectVtable DedicatedEffectVtable;
extern const EffectVtable ConvolutionEffectVtable;
#ifdef ALSOFT_EAX
EaxEffectUPtr eax_create_eax_effect(ALenum al_effect_type);
#endif // ALSOFT_EAX
#endif /* AL_EFFECTS_EFFECTS_H */
+753 -1
View File
@@ -4,8 +4,15 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -167,3 +174,748 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Equalizer);
const EffectProps EqualizerEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxEqualizerEffectDirtyFlagsValue = std::uint_least16_t;
struct EaxEqualizerEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxEqualizerEffectDirtyFlagsValue lLowGain : 1;
EaxEqualizerEffectDirtyFlagsValue flLowCutOff : 1;
EaxEqualizerEffectDirtyFlagsValue lMid1Gain : 1;
EaxEqualizerEffectDirtyFlagsValue flMid1Center : 1;
EaxEqualizerEffectDirtyFlagsValue flMid1Width : 1;
EaxEqualizerEffectDirtyFlagsValue lMid2Gain : 1;
EaxEqualizerEffectDirtyFlagsValue flMid2Center : 1;
EaxEqualizerEffectDirtyFlagsValue flMid2Width : 1;
EaxEqualizerEffectDirtyFlagsValue lHighGain : 1;
EaxEqualizerEffectDirtyFlagsValue flHighCutOff : 1;
}; // EaxEqualizerEffectDirtyFlags
class EaxEqualizerEffect final :
public EaxEffect
{
public:
EaxEqualizerEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXEQUALIZERPROPERTIES eax_{};
EAXEQUALIZERPROPERTIES eax_d_{};
EaxEqualizerEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_low_gain();
void set_efx_low_cutoff();
void set_efx_mid1_gain();
void set_efx_mid1_center();
void set_efx_mid1_width();
void set_efx_mid2_gain();
void set_efx_mid2_center();
void set_efx_mid2_width();
void set_efx_high_gain();
void set_efx_high_cutoff();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_low_gain(long lLowGain);
void validate_low_cutoff(float flLowCutOff);
void validate_mid1_gain(long lMid1Gain);
void validate_mid1_center(float flMid1Center);
void validate_mid1_width(float flMid1Width);
void validate_mid2_gain(long lMid2Gain);
void validate_mid2_center(float flMid2Center);
void validate_mid2_width(float flMid2Width);
void validate_high_gain(long lHighGain);
void validate_high_cutoff(float flHighCutOff);
void validate_all(const EAXEQUALIZERPROPERTIES& all);
void defer_low_gain(long lLowGain);
void defer_low_cutoff(float flLowCutOff);
void defer_mid1_gain(long lMid1Gain);
void defer_mid1_center(float flMid1Center);
void defer_mid1_width(float flMid1Width);
void defer_mid2_gain(long lMid2Gain);
void defer_mid2_center(float flMid2Center);
void defer_mid2_width(float flMid2Width);
void defer_high_gain(long lHighGain);
void defer_high_cutoff(float flHighCutOff);
void defer_all(const EAXEQUALIZERPROPERTIES& all);
void defer_low_gain(const EaxEaxCall& eax_call);
void defer_low_cutoff(const EaxEaxCall& eax_call);
void defer_mid1_gain(const EaxEaxCall& eax_call);
void defer_mid1_center(const EaxEaxCall& eax_call);
void defer_mid1_width(const EaxEaxCall& eax_call);
void defer_mid2_gain(const EaxEaxCall& eax_call);
void defer_mid2_center(const EaxEaxCall& eax_call);
void defer_mid2_width(const EaxEaxCall& eax_call);
void defer_high_gain(const EaxEaxCall& eax_call);
void defer_high_cutoff(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxEqualizerEffect
class EaxEqualizerEffectException :
public EaxException
{
public:
explicit EaxEqualizerEffectException(
const char* message)
:
EaxException{"EAX_EQUALIZER_EFFECT", message}
{
}
}; // EaxEqualizerEffectException
EaxEqualizerEffect::EaxEqualizerEffect()
: EaxEffect{AL_EFFECT_EQUALIZER}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxEqualizerEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxEqualizerEffect::set_eax_defaults()
{
eax_.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN;
eax_.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF;
eax_.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN;
eax_.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER;
eax_.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH;
eax_.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN;
eax_.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER;
eax_.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH;
eax_.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN;
eax_.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF;
eax_d_ = eax_;
}
void EaxEqualizerEffect::set_efx_low_gain()
{
const auto low_gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lLowGain)),
AL_EQUALIZER_MIN_LOW_GAIN,
AL_EQUALIZER_MAX_LOW_GAIN);
al_effect_props_.Equalizer.LowGain = low_gain;
}
void EaxEqualizerEffect::set_efx_low_cutoff()
{
const auto low_cutoff = clamp(
eax_.flLowCutOff,
AL_EQUALIZER_MIN_LOW_CUTOFF,
AL_EQUALIZER_MAX_LOW_CUTOFF);
al_effect_props_.Equalizer.LowCutoff = low_cutoff;
}
void EaxEqualizerEffect::set_efx_mid1_gain()
{
const auto mid1_gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lMid1Gain)),
AL_EQUALIZER_MIN_MID1_GAIN,
AL_EQUALIZER_MAX_MID1_GAIN);
al_effect_props_.Equalizer.Mid1Gain = mid1_gain;
}
void EaxEqualizerEffect::set_efx_mid1_center()
{
const auto mid1_center = clamp(
eax_.flMid1Center,
AL_EQUALIZER_MIN_MID1_CENTER,
AL_EQUALIZER_MAX_MID1_CENTER);
al_effect_props_.Equalizer.Mid1Center = mid1_center;
}
void EaxEqualizerEffect::set_efx_mid1_width()
{
const auto mid1_width = clamp(
eax_.flMid1Width,
AL_EQUALIZER_MIN_MID1_WIDTH,
AL_EQUALIZER_MAX_MID1_WIDTH);
al_effect_props_.Equalizer.Mid1Width = mid1_width;
}
void EaxEqualizerEffect::set_efx_mid2_gain()
{
const auto mid2_gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lMid2Gain)),
AL_EQUALIZER_MIN_MID2_GAIN,
AL_EQUALIZER_MAX_MID2_GAIN);
al_effect_props_.Equalizer.Mid2Gain = mid2_gain;
}
void EaxEqualizerEffect::set_efx_mid2_center()
{
const auto mid2_center = clamp(
eax_.flMid2Center,
AL_EQUALIZER_MIN_MID2_CENTER,
AL_EQUALIZER_MAX_MID2_CENTER);
al_effect_props_.Equalizer.Mid2Center = mid2_center;
}
void EaxEqualizerEffect::set_efx_mid2_width()
{
const auto mid2_width = clamp(
eax_.flMid2Width,
AL_EQUALIZER_MIN_MID2_WIDTH,
AL_EQUALIZER_MAX_MID2_WIDTH);
al_effect_props_.Equalizer.Mid2Width = mid2_width;
}
void EaxEqualizerEffect::set_efx_high_gain()
{
const auto high_gain = clamp(
level_mb_to_gain(static_cast<float>(eax_.lHighGain)),
AL_EQUALIZER_MIN_HIGH_GAIN,
AL_EQUALIZER_MAX_HIGH_GAIN);
al_effect_props_.Equalizer.HighGain = high_gain;
}
void EaxEqualizerEffect::set_efx_high_cutoff()
{
const auto high_cutoff = clamp(
eax_.flHighCutOff,
AL_EQUALIZER_MIN_HIGH_CUTOFF,
AL_EQUALIZER_MAX_HIGH_CUTOFF);
al_effect_props_.Equalizer.HighCutoff = high_cutoff;
}
void EaxEqualizerEffect::set_efx_defaults()
{
set_efx_low_gain();
set_efx_low_cutoff();
set_efx_mid1_gain();
set_efx_mid1_center();
set_efx_mid1_width();
set_efx_mid2_gain();
set_efx_mid2_center();
set_efx_mid2_width();
set_efx_high_gain();
set_efx_high_cutoff();
}
void EaxEqualizerEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXEQUALIZER_NONE:
break;
case EAXEQUALIZER_ALLPARAMETERS:
eax_call.set_value<EaxEqualizerEffectException>(eax_);
break;
case EAXEQUALIZER_LOWGAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lLowGain);
break;
case EAXEQUALIZER_LOWCUTOFF:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flLowCutOff);
break;
case EAXEQUALIZER_MID1GAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lMid1Gain);
break;
case EAXEQUALIZER_MID1CENTER:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid1Center);
break;
case EAXEQUALIZER_MID1WIDTH:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid1Width);
break;
case EAXEQUALIZER_MID2GAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lMid2Gain);
break;
case EAXEQUALIZER_MID2CENTER:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid2Center);
break;
case EAXEQUALIZER_MID2WIDTH:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flMid2Width);
break;
case EAXEQUALIZER_HIGHGAIN:
eax_call.set_value<EaxEqualizerEffectException>(eax_.lHighGain);
break;
case EAXEQUALIZER_HIGHCUTOFF:
eax_call.set_value<EaxEqualizerEffectException>(eax_.flHighCutOff);
break;
default:
throw EaxEqualizerEffectException{"Unsupported property id."};
}
}
void EaxEqualizerEffect::validate_low_gain(
long lLowGain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Low Gain",
lLowGain,
EAXEQUALIZER_MINLOWGAIN,
EAXEQUALIZER_MAXLOWGAIN);
}
void EaxEqualizerEffect::validate_low_cutoff(
float flLowCutOff)
{
eax_validate_range<EaxEqualizerEffectException>(
"Low Cutoff",
flLowCutOff,
EAXEQUALIZER_MINLOWCUTOFF,
EAXEQUALIZER_MAXLOWCUTOFF);
}
void EaxEqualizerEffect::validate_mid1_gain(
long lMid1Gain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Gain",
lMid1Gain,
EAXEQUALIZER_MINMID1GAIN,
EAXEQUALIZER_MAXMID1GAIN);
}
void EaxEqualizerEffect::validate_mid1_center(
float flMid1Center)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Center",
flMid1Center,
EAXEQUALIZER_MINMID1CENTER,
EAXEQUALIZER_MAXMID1CENTER);
}
void EaxEqualizerEffect::validate_mid1_width(
float flMid1Width)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid1 Width",
flMid1Width,
EAXEQUALIZER_MINMID1WIDTH,
EAXEQUALIZER_MAXMID1WIDTH);
}
void EaxEqualizerEffect::validate_mid2_gain(
long lMid2Gain)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Gain",
lMid2Gain,
EAXEQUALIZER_MINMID2GAIN,
EAXEQUALIZER_MAXMID2GAIN);
}
void EaxEqualizerEffect::validate_mid2_center(
float flMid2Center)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Center",
flMid2Center,
EAXEQUALIZER_MINMID2CENTER,
EAXEQUALIZER_MAXMID2CENTER);
}
void EaxEqualizerEffect::validate_mid2_width(
float flMid2Width)
{
eax_validate_range<EaxEqualizerEffectException>(
"Mid2 Width",
flMid2Width,
EAXEQUALIZER_MINMID2WIDTH,
EAXEQUALIZER_MAXMID2WIDTH);
}
void EaxEqualizerEffect::validate_high_gain(
long lHighGain)
{
eax_validate_range<EaxEqualizerEffectException>(
"High Gain",
lHighGain,
EAXEQUALIZER_MINHIGHGAIN,
EAXEQUALIZER_MAXHIGHGAIN);
}
void EaxEqualizerEffect::validate_high_cutoff(
float flHighCutOff)
{
eax_validate_range<EaxEqualizerEffectException>(
"High Cutoff",
flHighCutOff,
EAXEQUALIZER_MINHIGHCUTOFF,
EAXEQUALIZER_MAXHIGHCUTOFF);
}
void EaxEqualizerEffect::validate_all(
const EAXEQUALIZERPROPERTIES& all)
{
validate_low_gain(all.lLowGain);
validate_low_cutoff(all.flLowCutOff);
validate_mid1_gain(all.lMid1Gain);
validate_mid1_center(all.flMid1Center);
validate_mid1_width(all.flMid1Width);
validate_mid2_gain(all.lMid2Gain);
validate_mid2_center(all.flMid2Center);
validate_mid2_width(all.flMid2Width);
validate_high_gain(all.lHighGain);
validate_high_cutoff(all.flHighCutOff);
}
void EaxEqualizerEffect::defer_low_gain(
long lLowGain)
{
eax_d_.lLowGain = lLowGain;
eax_dirty_flags_.lLowGain = (eax_.lLowGain != eax_d_.lLowGain);
}
void EaxEqualizerEffect::defer_low_cutoff(
float flLowCutOff)
{
eax_d_.flLowCutOff = flLowCutOff;
eax_dirty_flags_.flLowCutOff = (eax_.flLowCutOff != eax_d_.flLowCutOff);
}
void EaxEqualizerEffect::defer_mid1_gain(
long lMid1Gain)
{
eax_d_.lMid1Gain = lMid1Gain;
eax_dirty_flags_.lMid1Gain = (eax_.lMid1Gain != eax_d_.lMid1Gain);
}
void EaxEqualizerEffect::defer_mid1_center(
float flMid1Center)
{
eax_d_.flMid1Center = flMid1Center;
eax_dirty_flags_.flMid1Center = (eax_.flMid1Center != eax_d_.flMid1Center);
}
void EaxEqualizerEffect::defer_mid1_width(
float flMid1Width)
{
eax_d_.flMid1Width = flMid1Width;
eax_dirty_flags_.flMid1Width = (eax_.flMid1Width != eax_d_.flMid1Width);
}
void EaxEqualizerEffect::defer_mid2_gain(
long lMid2Gain)
{
eax_d_.lMid2Gain = lMid2Gain;
eax_dirty_flags_.lMid2Gain = (eax_.lMid2Gain != eax_d_.lMid2Gain);
}
void EaxEqualizerEffect::defer_mid2_center(
float flMid2Center)
{
eax_d_.flMid2Center = flMid2Center;
eax_dirty_flags_.flMid2Center = (eax_.flMid2Center != eax_d_.flMid2Center);
}
void EaxEqualizerEffect::defer_mid2_width(
float flMid2Width)
{
eax_d_.flMid2Width = flMid2Width;
eax_dirty_flags_.flMid2Width = (eax_.flMid2Width != eax_d_.flMid2Width);
}
void EaxEqualizerEffect::defer_high_gain(
long lHighGain)
{
eax_d_.lHighGain = lHighGain;
eax_dirty_flags_.lHighGain = (eax_.lHighGain != eax_d_.lHighGain);
}
void EaxEqualizerEffect::defer_high_cutoff(
float flHighCutOff)
{
eax_d_.flHighCutOff = flHighCutOff;
eax_dirty_flags_.flHighCutOff = (eax_.flHighCutOff != eax_d_.flHighCutOff);
}
void EaxEqualizerEffect::defer_all(
const EAXEQUALIZERPROPERTIES& all)
{
defer_low_gain(all.lLowGain);
defer_low_cutoff(all.flLowCutOff);
defer_mid1_gain(all.lMid1Gain);
defer_mid1_center(all.flMid1Center);
defer_mid1_width(all.flMid1Width);
defer_mid2_gain(all.lMid2Gain);
defer_mid2_center(all.flMid2Center);
defer_mid2_width(all.flMid2Width);
defer_high_gain(all.lHighGain);
defer_high_cutoff(all.flHighCutOff);
}
void EaxEqualizerEffect::defer_low_gain(
const EaxEaxCall& eax_call)
{
const auto& low_gain =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lLowGain)>();
validate_low_gain(low_gain);
defer_low_gain(low_gain);
}
void EaxEqualizerEffect::defer_low_cutoff(
const EaxEaxCall& eax_call)
{
const auto& low_cutoff =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flLowCutOff)>();
validate_low_cutoff(low_cutoff);
defer_low_cutoff(low_cutoff);
}
void EaxEqualizerEffect::defer_mid1_gain(
const EaxEaxCall& eax_call)
{
const auto& mid1_gain =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lMid1Gain)>();
validate_mid1_gain(mid1_gain);
defer_mid1_gain(mid1_gain);
}
void EaxEqualizerEffect::defer_mid1_center(
const EaxEaxCall& eax_call)
{
const auto& mid1_center =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid1Center)>();
validate_mid1_center(mid1_center);
defer_mid1_center(mid1_center);
}
void EaxEqualizerEffect::defer_mid1_width(
const EaxEaxCall& eax_call)
{
const auto& mid1_width =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid1Width)>();
validate_mid1_width(mid1_width);
defer_mid1_width(mid1_width);
}
void EaxEqualizerEffect::defer_mid2_gain(
const EaxEaxCall& eax_call)
{
const auto& mid2_gain =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lMid2Gain)>();
validate_mid2_gain(mid2_gain);
defer_mid2_gain(mid2_gain);
}
void EaxEqualizerEffect::defer_mid2_center(
const EaxEaxCall& eax_call)
{
const auto& mid2_center =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid2Center)>();
validate_mid2_center(mid2_center);
defer_mid2_center(mid2_center);
}
void EaxEqualizerEffect::defer_mid2_width(
const EaxEaxCall& eax_call)
{
const auto& mid2_width =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flMid2Width)>();
validate_mid2_width(mid2_width);
defer_mid2_width(mid2_width);
}
void EaxEqualizerEffect::defer_high_gain(
const EaxEaxCall& eax_call)
{
const auto& high_gain =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::lHighGain)>();
validate_high_gain(high_gain);
defer_high_gain(high_gain);
}
void EaxEqualizerEffect::defer_high_cutoff(
const EaxEaxCall& eax_call)
{
const auto& high_cutoff =
eax_call.get_value<EaxEqualizerEffectException, const decltype(EAXEQUALIZERPROPERTIES::flHighCutOff)>();
validate_high_cutoff(high_cutoff);
defer_high_cutoff(high_cutoff);
}
void EaxEqualizerEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxEqualizerEffectException, const EAXEQUALIZERPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxEqualizerEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxEqualizerEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.lLowGain)
{
set_efx_low_gain();
}
if (eax_dirty_flags_.flLowCutOff)
{
set_efx_low_cutoff();
}
if (eax_dirty_flags_.lMid1Gain)
{
set_efx_mid1_gain();
}
if (eax_dirty_flags_.flMid1Center)
{
set_efx_mid1_center();
}
if (eax_dirty_flags_.flMid1Width)
{
set_efx_mid1_width();
}
if (eax_dirty_flags_.lMid2Gain)
{
set_efx_mid2_gain();
}
if (eax_dirty_flags_.flMid2Center)
{
set_efx_mid2_center();
}
if (eax_dirty_flags_.flMid2Width)
{
set_efx_mid2_width();
}
if (eax_dirty_flags_.lHighGain)
{
set_efx_high_gain();
}
if (eax_dirty_flags_.flHighCutOff)
{
set_efx_high_cutoff();
}
eax_dirty_flags_ = EaxEqualizerEffectDirtyFlags{};
return true;
}
void EaxEqualizerEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXEQUALIZER_NONE:
break;
case EAXEQUALIZER_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXEQUALIZER_LOWGAIN:
defer_low_gain(eax_call);
break;
case EAXEQUALIZER_LOWCUTOFF:
defer_low_cutoff(eax_call);
break;
case EAXEQUALIZER_MID1GAIN:
defer_mid1_gain(eax_call);
break;
case EAXEQUALIZER_MID1CENTER:
defer_mid1_center(eax_call);
break;
case EAXEQUALIZER_MID1WIDTH:
defer_mid1_width(eax_call);
break;
case EAXEQUALIZER_MID2GAIN:
defer_mid2_gain(eax_call);
break;
case EAXEQUALIZER_MID2CENTER:
defer_mid2_center(eax_call);
break;
case EAXEQUALIZER_MID2WIDTH:
defer_mid2_width(eax_call);
break;
case EAXEQUALIZER_HIGHGAIN:
defer_high_gain(eax_call);
break;
case EAXEQUALIZER_HIGHCUTOFF:
defer_high_cutoff(eax_call);
break;
default:
throw EaxEqualizerEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_equalizer_effect()
{
return std::make_unique<EaxEqualizerEffect>();
}
#endif // ALSOFT_EAX
+352 -1
View File
@@ -1,12 +1,23 @@
#include "config.h"
#include <stdexcept>
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "aloptional.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include <cassert>
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -126,3 +137,343 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Fshifter);
const EffectProps FshifterEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxFrequencyShifterEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxFrequencyShifterEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxFrequencyShifterEffectDirtyFlagsValue flFrequency : 1;
EaxFrequencyShifterEffectDirtyFlagsValue ulLeftDirection : 1;
EaxFrequencyShifterEffectDirtyFlagsValue ulRightDirection : 1;
}; // EaxFrequencyShifterEffectDirtyFlags
class EaxFrequencyShifterEffect final :
public EaxEffect
{
public:
EaxFrequencyShifterEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXFREQUENCYSHIFTERPROPERTIES eax_{};
EAXFREQUENCYSHIFTERPROPERTIES eax_d_{};
EaxFrequencyShifterEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_frequency();
void set_efx_left_direction();
void set_efx_right_direction();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_frequency(float flFrequency);
void validate_left_direction(unsigned long ulLeftDirection);
void validate_right_direction(unsigned long ulRightDirection);
void validate_all(const EAXFREQUENCYSHIFTERPROPERTIES& all);
void defer_frequency(float flFrequency);
void defer_left_direction(unsigned long ulLeftDirection);
void defer_right_direction(unsigned long ulRightDirection);
void defer_all(const EAXFREQUENCYSHIFTERPROPERTIES& all);
void defer_frequency(const EaxEaxCall& eax_call);
void defer_left_direction(const EaxEaxCall& eax_call);
void defer_right_direction(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxFrequencyShifterEffect
class EaxFrequencyShifterEffectException :
public EaxException
{
public:
explicit EaxFrequencyShifterEffectException(
const char* message)
:
EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
{
}
}; // EaxFrequencyShifterEffectException
EaxFrequencyShifterEffect::EaxFrequencyShifterEffect()
: EaxEffect{AL_EFFECT_FREQUENCY_SHIFTER}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxFrequencyShifterEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxFrequencyShifterEffect::set_eax_defaults()
{
eax_.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
eax_.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
eax_.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
eax_d_ = eax_;
}
void EaxFrequencyShifterEffect::set_efx_frequency()
{
const auto frequency = clamp(
eax_.flFrequency,
AL_FREQUENCY_SHIFTER_MIN_FREQUENCY,
AL_FREQUENCY_SHIFTER_MAX_FREQUENCY);
al_effect_props_.Fshifter.Frequency = frequency;
}
void EaxFrequencyShifterEffect::set_efx_left_direction()
{
const auto left_direction = clamp(
static_cast<ALint>(eax_.ulLeftDirection),
AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION,
AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION);
const auto efx_left_direction = DirectionFromEmum(left_direction);
assert(efx_left_direction.has_value());
al_effect_props_.Fshifter.LeftDirection = *efx_left_direction;
}
void EaxFrequencyShifterEffect::set_efx_right_direction()
{
const auto right_direction = clamp(
static_cast<ALint>(eax_.ulRightDirection),
AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION,
AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION);
const auto efx_right_direction = DirectionFromEmum(right_direction);
assert(efx_right_direction.has_value());
al_effect_props_.Fshifter.RightDirection = *efx_right_direction;
}
void EaxFrequencyShifterEffect::set_efx_defaults()
{
set_efx_frequency();
set_efx_left_direction();
set_efx_right_direction();
}
void EaxFrequencyShifterEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXFREQUENCYSHIFTER_NONE:
break;
case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_);
break;
case EAXFREQUENCYSHIFTER_FREQUENCY:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.flFrequency);
break;
case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulLeftDirection);
break;
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulRightDirection);
break;
default:
throw EaxFrequencyShifterEffectException{"Unsupported property id."};
}
}
void EaxFrequencyShifterEffect::validate_frequency(
float flFrequency)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"Frequency",
flFrequency,
EAXFREQUENCYSHIFTER_MINFREQUENCY,
EAXFREQUENCYSHIFTER_MAXFREQUENCY);
}
void EaxFrequencyShifterEffect::validate_left_direction(
unsigned long ulLeftDirection)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"Left Direction",
ulLeftDirection,
EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
}
void EaxFrequencyShifterEffect::validate_right_direction(
unsigned long ulRightDirection)
{
eax_validate_range<EaxFrequencyShifterEffectException>(
"Right Direction",
ulRightDirection,
EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
}
void EaxFrequencyShifterEffect::validate_all(
const EAXFREQUENCYSHIFTERPROPERTIES& all)
{
validate_frequency(all.flFrequency);
validate_left_direction(all.ulLeftDirection);
validate_right_direction(all.ulRightDirection);
}
void EaxFrequencyShifterEffect::defer_frequency(
float flFrequency)
{
eax_d_.flFrequency = flFrequency;
eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
}
void EaxFrequencyShifterEffect::defer_left_direction(
unsigned long ulLeftDirection)
{
eax_d_.ulLeftDirection = ulLeftDirection;
eax_dirty_flags_.ulLeftDirection = (eax_.ulLeftDirection != eax_d_.ulLeftDirection);
}
void EaxFrequencyShifterEffect::defer_right_direction(
unsigned long ulRightDirection)
{
eax_d_.ulRightDirection = ulRightDirection;
eax_dirty_flags_.ulRightDirection = (eax_.ulRightDirection != eax_d_.ulRightDirection);
}
void EaxFrequencyShifterEffect::defer_all(
const EAXFREQUENCYSHIFTERPROPERTIES& all)
{
defer_frequency(all.flFrequency);
defer_left_direction(all.ulLeftDirection);
defer_right_direction(all.ulRightDirection);
}
void EaxFrequencyShifterEffect::defer_frequency(
const EaxEaxCall& eax_call)
{
const auto& frequency =
eax_call.get_value<
EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::flFrequency)>();
validate_frequency(frequency);
defer_frequency(frequency);
}
void EaxFrequencyShifterEffect::defer_left_direction(
const EaxEaxCall& eax_call)
{
const auto& left_direction =
eax_call.get_value<
EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulLeftDirection)>();
validate_left_direction(left_direction);
defer_left_direction(left_direction);
}
void EaxFrequencyShifterEffect::defer_right_direction(
const EaxEaxCall& eax_call)
{
const auto& right_direction =
eax_call.get_value<
EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulRightDirection)>();
validate_right_direction(right_direction);
defer_right_direction(right_direction);
}
void EaxFrequencyShifterEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<
EaxFrequencyShifterEffectException, const EAXFREQUENCYSHIFTERPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxFrequencyShifterEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxFrequencyShifterEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.flFrequency)
{
set_efx_frequency();
}
if (eax_dirty_flags_.ulLeftDirection)
{
set_efx_left_direction();
}
if (eax_dirty_flags_.ulRightDirection)
{
set_efx_right_direction();
}
eax_dirty_flags_ = EaxFrequencyShifterEffectDirtyFlags{};
return true;
}
void EaxFrequencyShifterEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXFREQUENCYSHIFTER_NONE:
break;
case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXFREQUENCYSHIFTER_FREQUENCY:
defer_frequency(eax_call);
break;
case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
defer_left_direction(eax_call);
break;
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
defer_right_direction(eax_call);
break;
default:
throw EaxFrequencyShifterEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_frequency_shifter_effect()
{
return std::make_unique<EaxFrequencyShifterEffect>();
}
#endif // ALSOFT_EAX
+349 -1
View File
@@ -1,12 +1,23 @@
#include "config.h"
#include <stdexcept>
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "aloptional.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include <cassert>
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -132,3 +143,340 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Modulator);
const EffectProps ModulatorEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxRingModulatorEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxRingModulatorEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxRingModulatorEffectDirtyFlagsValue flFrequency : 1;
EaxRingModulatorEffectDirtyFlagsValue flHighPassCutOff : 1;
EaxRingModulatorEffectDirtyFlagsValue ulWaveform : 1;
}; // EaxPitchShifterEffectDirtyFlags
class EaxRingModulatorEffect final :
public EaxEffect
{
public:
EaxRingModulatorEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXRINGMODULATORPROPERTIES eax_{};
EAXRINGMODULATORPROPERTIES eax_d_{};
EaxRingModulatorEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_frequency();
void set_efx_high_pass_cutoff();
void set_efx_waveform();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_frequency(float flFrequency);
void validate_high_pass_cutoff(float flHighPassCutOff);
void validate_waveform(unsigned long ulWaveform);
void validate_all(const EAXRINGMODULATORPROPERTIES& all);
void defer_frequency(float flFrequency);
void defer_high_pass_cutoff(float flHighPassCutOff);
void defer_waveform(unsigned long ulWaveform);
void defer_all(const EAXRINGMODULATORPROPERTIES& all);
void defer_frequency(const EaxEaxCall& eax_call);
void defer_high_pass_cutoff(const EaxEaxCall& eax_call);
void defer_waveform(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxRingModulatorEffect
class EaxRingModulatorEffectException :
public EaxException
{
public:
explicit EaxRingModulatorEffectException(
const char* message)
:
EaxException{"EAX_RING_MODULATOR_EFFECT", message}
{
}
}; // EaxRingModulatorEffectException
EaxRingModulatorEffect::EaxRingModulatorEffect()
: EaxEffect{AL_EFFECT_RING_MODULATOR}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxRingModulatorEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxRingModulatorEffect::set_eax_defaults()
{
eax_.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
eax_.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
eax_.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
eax_d_ = eax_;
}
void EaxRingModulatorEffect::set_efx_frequency()
{
const auto frequency = clamp(
eax_.flFrequency,
AL_RING_MODULATOR_MIN_FREQUENCY,
AL_RING_MODULATOR_MAX_FREQUENCY);
al_effect_props_.Modulator.Frequency = frequency;
}
void EaxRingModulatorEffect::set_efx_high_pass_cutoff()
{
const auto high_pass_cutoff = clamp(
eax_.flHighPassCutOff,
AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF,
AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF);
al_effect_props_.Modulator.HighPassCutoff = high_pass_cutoff;
}
void EaxRingModulatorEffect::set_efx_waveform()
{
const auto waveform = clamp(
static_cast<ALint>(eax_.ulWaveform),
AL_RING_MODULATOR_MIN_WAVEFORM,
AL_RING_MODULATOR_MAX_WAVEFORM);
const auto efx_waveform = WaveformFromEmum(waveform);
assert(efx_waveform.has_value());
al_effect_props_.Modulator.Waveform = *efx_waveform;
}
void EaxRingModulatorEffect::set_efx_defaults()
{
set_efx_frequency();
set_efx_high_pass_cutoff();
set_efx_waveform();
}
void EaxRingModulatorEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXRINGMODULATOR_NONE:
break;
case EAXRINGMODULATOR_ALLPARAMETERS:
eax_call.set_value<EaxRingModulatorEffectException>(eax_);
break;
case EAXRINGMODULATOR_FREQUENCY:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.flFrequency);
break;
case EAXRINGMODULATOR_HIGHPASSCUTOFF:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.flHighPassCutOff);
break;
case EAXRINGMODULATOR_WAVEFORM:
eax_call.set_value<EaxRingModulatorEffectException>(eax_.ulWaveform);
break;
default:
throw EaxRingModulatorEffectException{"Unsupported property id."};
}
}
void EaxRingModulatorEffect::validate_frequency(
float flFrequency)
{
eax_validate_range<EaxRingModulatorEffectException>(
"Frequency",
flFrequency,
EAXRINGMODULATOR_MINFREQUENCY,
EAXRINGMODULATOR_MAXFREQUENCY);
}
void EaxRingModulatorEffect::validate_high_pass_cutoff(
float flHighPassCutOff)
{
eax_validate_range<EaxRingModulatorEffectException>(
"High-Pass Cutoff",
flHighPassCutOff,
EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
}
void EaxRingModulatorEffect::validate_waveform(
unsigned long ulWaveform)
{
eax_validate_range<EaxRingModulatorEffectException>(
"Waveform",
ulWaveform,
EAXRINGMODULATOR_MINWAVEFORM,
EAXRINGMODULATOR_MAXWAVEFORM);
}
void EaxRingModulatorEffect::validate_all(
const EAXRINGMODULATORPROPERTIES& all)
{
validate_frequency(all.flFrequency);
validate_high_pass_cutoff(all.flHighPassCutOff);
validate_waveform(all.ulWaveform);
}
void EaxRingModulatorEffect::defer_frequency(
float flFrequency)
{
eax_d_.flFrequency = flFrequency;
eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
}
void EaxRingModulatorEffect::defer_high_pass_cutoff(
float flHighPassCutOff)
{
eax_d_.flHighPassCutOff = flHighPassCutOff;
eax_dirty_flags_.flHighPassCutOff = (eax_.flHighPassCutOff != eax_d_.flHighPassCutOff);
}
void EaxRingModulatorEffect::defer_waveform(
unsigned long ulWaveform)
{
eax_d_.ulWaveform = ulWaveform;
eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
}
void EaxRingModulatorEffect::defer_all(
const EAXRINGMODULATORPROPERTIES& all)
{
defer_frequency(all.flFrequency);
defer_high_pass_cutoff(all.flHighPassCutOff);
defer_waveform(all.ulWaveform);
}
void EaxRingModulatorEffect::defer_frequency(
const EaxEaxCall& eax_call)
{
const auto& frequency =
eax_call.get_value<
EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flFrequency)>();
validate_frequency(frequency);
defer_frequency(frequency);
}
void EaxRingModulatorEffect::defer_high_pass_cutoff(
const EaxEaxCall& eax_call)
{
const auto& high_pass_cutoff =
eax_call.get_value<
EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flHighPassCutOff)>();
validate_high_pass_cutoff(high_pass_cutoff);
defer_high_pass_cutoff(high_pass_cutoff);
}
void EaxRingModulatorEffect::defer_waveform(
const EaxEaxCall& eax_call)
{
const auto& waveform =
eax_call.get_value<
EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform)>();
validate_waveform(waveform);
defer_waveform(waveform);
}
void EaxRingModulatorEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxRingModulatorEffectException, const EAXRINGMODULATORPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxRingModulatorEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxRingModulatorEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.flFrequency)
{
set_efx_frequency();
}
if (eax_dirty_flags_.flHighPassCutOff)
{
set_efx_high_pass_cutoff();
}
if (eax_dirty_flags_.ulWaveform)
{
set_efx_waveform();
}
eax_dirty_flags_ = EaxRingModulatorEffectDirtyFlags{};
return true;
}
void EaxRingModulatorEffect::set(const EaxEaxCall& eax_call)
{
switch (eax_call.get_property_id())
{
case EAXRINGMODULATOR_NONE:
break;
case EAXRINGMODULATOR_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXRINGMODULATOR_FREQUENCY:
defer_frequency(eax_call);
break;
case EAXRINGMODULATOR_HIGHPASSCUTOFF:
defer_high_pass_cutoff(eax_call);
break;
case EAXRINGMODULATOR_WAVEFORM:
defer_waveform(eax_call);
break;
default:
throw EaxRingModulatorEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_ring_modulator_effect()
{
return std::make_unique<EaxRingModulatorEffect>();
}
#endif // ALSOFT_EAX
+60 -1
View File
@@ -4,8 +4,12 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "al/eax_exception.h"
#endif // ALSOFT_EAX
namespace {
@@ -91,3 +95,58 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Null);
const EffectProps NullEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
class EaxNullEffect final :
public EaxEffect
{
public:
EaxNullEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
}; // EaxNullEffect
class EaxNullEffectException :
public EaxException
{
public:
explicit EaxNullEffectException(
const char* message)
:
EaxException{"EAX_NULL_EFFECT", message}
{
}
}; // EaxNullEffectException
EaxNullEffect::EaxNullEffect()
: EaxEffect{AL_EFFECT_NULL}
{
}
void EaxNullEffect::dispatch(const EaxEaxCall& eax_call)
{
if(eax_call.get_property_id() != 0)
throw EaxNullEffectException{"Unsupported property id."};
}
bool EaxNullEffect::apply_deferred()
{
return false;
}
} // namespace
EaxEffectUPtr eax_create_eax_null_effect()
{
return std::make_unique<EaxNullEffect>();
}
#endif // ALSOFT_EAX
+281 -1
View File
@@ -4,8 +4,15 @@
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -82,3 +89,276 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Pshifter);
const EffectProps PshifterEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxPitchShifterEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxPitchShifterEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxPitchShifterEffectDirtyFlagsValue lCoarseTune : 1;
EaxPitchShifterEffectDirtyFlagsValue lFineTune : 1;
}; // EaxPitchShifterEffectDirtyFlags
class EaxPitchShifterEffect final :
public EaxEffect
{
public:
EaxPitchShifterEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXPITCHSHIFTERPROPERTIES eax_{};
EAXPITCHSHIFTERPROPERTIES eax_d_{};
EaxPitchShifterEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_coarse_tune();
void set_efx_fine_tune();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_coarse_tune(long lCoarseTune);
void validate_fine_tune(long lFineTune);
void validate_all(const EAXPITCHSHIFTERPROPERTIES& all);
void defer_coarse_tune(long lCoarseTune);
void defer_fine_tune(long lFineTune);
void defer_all(const EAXPITCHSHIFTERPROPERTIES& all);
void defer_coarse_tune(const EaxEaxCall& eax_call);
void defer_fine_tune(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxPitchShifterEffect
class EaxPitchShifterEffectException :
public EaxException
{
public:
explicit EaxPitchShifterEffectException(
const char* message)
:
EaxException{"EAX_PITCH_SHIFTER_EFFECT", message}
{
}
}; // EaxPitchShifterEffectException
EaxPitchShifterEffect::EaxPitchShifterEffect()
: EaxEffect{AL_EFFECT_PITCH_SHIFTER}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxPitchShifterEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxPitchShifterEffect::set_eax_defaults()
{
eax_.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE;
eax_.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE;
eax_d_ = eax_;
}
void EaxPitchShifterEffect::set_efx_coarse_tune()
{
const auto coarse_tune = clamp(
static_cast<ALint>(eax_.lCoarseTune),
AL_PITCH_SHIFTER_MIN_COARSE_TUNE,
AL_PITCH_SHIFTER_MAX_COARSE_TUNE);
al_effect_props_.Pshifter.CoarseTune = coarse_tune;
}
void EaxPitchShifterEffect::set_efx_fine_tune()
{
const auto fine_tune = clamp(
static_cast<ALint>(eax_.lFineTune),
AL_PITCH_SHIFTER_MIN_FINE_TUNE,
AL_PITCH_SHIFTER_MAX_FINE_TUNE);
al_effect_props_.Pshifter.FineTune = fine_tune;
}
void EaxPitchShifterEffect::set_efx_defaults()
{
set_efx_coarse_tune();
set_efx_fine_tune();
}
void EaxPitchShifterEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXPITCHSHIFTER_NONE:
break;
case EAXPITCHSHIFTER_ALLPARAMETERS:
eax_call.set_value<EaxPitchShifterEffectException>(eax_);
break;
case EAXPITCHSHIFTER_COARSETUNE:
eax_call.set_value<EaxPitchShifterEffectException>(eax_.lCoarseTune);
break;
case EAXPITCHSHIFTER_FINETUNE:
eax_call.set_value<EaxPitchShifterEffectException>(eax_.lFineTune);
break;
default:
throw EaxPitchShifterEffectException{"Unsupported property id."};
}
}
void EaxPitchShifterEffect::validate_coarse_tune(
long lCoarseTune)
{
eax_validate_range<EaxPitchShifterEffectException>(
"Coarse Tune",
lCoarseTune,
EAXPITCHSHIFTER_MINCOARSETUNE,
EAXPITCHSHIFTER_MAXCOARSETUNE);
}
void EaxPitchShifterEffect::validate_fine_tune(
long lFineTune)
{
eax_validate_range<EaxPitchShifterEffectException>(
"Fine Tune",
lFineTune,
EAXPITCHSHIFTER_MINFINETUNE,
EAXPITCHSHIFTER_MAXFINETUNE);
}
void EaxPitchShifterEffect::validate_all(
const EAXPITCHSHIFTERPROPERTIES& all)
{
validate_coarse_tune(all.lCoarseTune);
validate_fine_tune(all.lFineTune);
}
void EaxPitchShifterEffect::defer_coarse_tune(
long lCoarseTune)
{
eax_d_.lCoarseTune = lCoarseTune;
eax_dirty_flags_.lCoarseTune = (eax_.lCoarseTune != eax_d_.lCoarseTune);
}
void EaxPitchShifterEffect::defer_fine_tune(
long lFineTune)
{
eax_d_.lFineTune = lFineTune;
eax_dirty_flags_.lFineTune = (eax_.lFineTune != eax_d_.lFineTune);
}
void EaxPitchShifterEffect::defer_all(
const EAXPITCHSHIFTERPROPERTIES& all)
{
defer_coarse_tune(all.lCoarseTune);
defer_fine_tune(all.lFineTune);
}
void EaxPitchShifterEffect::defer_coarse_tune(
const EaxEaxCall& eax_call)
{
const auto& coarse_tune =
eax_call.get_value<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lCoarseTune)>();
validate_coarse_tune(coarse_tune);
defer_coarse_tune(coarse_tune);
}
void EaxPitchShifterEffect::defer_fine_tune(
const EaxEaxCall& eax_call)
{
const auto& fine_tune =
eax_call.get_value<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lFineTune)>();
validate_fine_tune(fine_tune);
defer_fine_tune(fine_tune);
}
void EaxPitchShifterEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all =
eax_call.get_value<EaxPitchShifterEffectException, const EAXPITCHSHIFTERPROPERTIES>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxPitchShifterEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxPitchShifterEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.lCoarseTune)
{
set_efx_coarse_tune();
}
if (eax_dirty_flags_.lFineTune)
{
set_efx_fine_tune();
}
eax_dirty_flags_ = EaxPitchShifterEffectDirtyFlags{};
return true;
}
void EaxPitchShifterEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXPITCHSHIFTER_NONE:
break;
case EAXPITCHSHIFTER_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXPITCHSHIFTER_COARSETUNE:
defer_coarse_tune(eax_call);
break;
case EAXPITCHSHIFTER_FINETUNE:
defer_fine_tune(eax_call);
break;
default:
throw EaxPitchShifterEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_pitch_shifter_effect()
{
return std::make_unique<EaxPitchShifterEffect>();
}
#endif // ALSOFT_EAX
File diff suppressed because it is too large Load Diff
+540 -1
View File
@@ -1,12 +1,23 @@
#include "config.h"
#include <stdexcept>
#include "AL/al.h"
#include "AL/efx.h"
#include "alc/effects/base.h"
#include "aloptional.h"
#include "effects.h"
#include "effects/base.h"
#ifdef ALSOFT_EAX
#include <cassert>
#include "alnumeric.h"
#include "al/eax_exception.h"
#include "al/eax_utils.h"
#endif // ALSOFT_EAX
namespace {
@@ -245,3 +256,531 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Vmorpher);
const EffectProps VmorpherEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
using EaxVocalMorpherEffectDirtyFlagsValue = std::uint_least8_t;
struct EaxVocalMorpherEffectDirtyFlags
{
using EaxIsBitFieldStruct = bool;
EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeA : 1;
EaxVocalMorpherEffectDirtyFlagsValue lPhonemeACoarseTuning : 1;
EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeB : 1;
EaxVocalMorpherEffectDirtyFlagsValue lPhonemeBCoarseTuning : 1;
EaxVocalMorpherEffectDirtyFlagsValue ulWaveform : 1;
EaxVocalMorpherEffectDirtyFlagsValue flRate : 1;
}; // EaxPitchShifterEffectDirtyFlags
class EaxVocalMorpherEffect final :
public EaxEffect
{
public:
EaxVocalMorpherEffect();
void dispatch(const EaxEaxCall& eax_call) override;
// [[nodiscard]]
bool apply_deferred() override;
private:
EAXVOCALMORPHERPROPERTIES eax_{};
EAXVOCALMORPHERPROPERTIES eax_d_{};
EaxVocalMorpherEffectDirtyFlags eax_dirty_flags_{};
void set_eax_defaults();
void set_efx_phoneme_a();
void set_efx_phoneme_a_coarse_tuning();
void set_efx_phoneme_b();
void set_efx_phoneme_b_coarse_tuning();
void set_efx_waveform();
void set_efx_rate();
void set_efx_defaults();
void get(const EaxEaxCall& eax_call);
void validate_phoneme_a(unsigned long ulPhonemeA);
void validate_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning);
void validate_phoneme_b(unsigned long ulPhonemeB);
void validate_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning);
void validate_waveform(unsigned long ulWaveform);
void validate_rate(float flRate);
void validate_all(const EAXVOCALMORPHERPROPERTIES& all);
void defer_phoneme_a(unsigned long ulPhonemeA);
void defer_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning);
void defer_phoneme_b(unsigned long ulPhonemeB);
void defer_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning);
void defer_waveform(unsigned long ulWaveform);
void defer_rate(float flRate);
void defer_all(const EAXVOCALMORPHERPROPERTIES& all);
void defer_phoneme_a(const EaxEaxCall& eax_call);
void defer_phoneme_a_coarse_tuning(const EaxEaxCall& eax_call);
void defer_phoneme_b(const EaxEaxCall& eax_call);
void defer_phoneme_b_coarse_tuning(const EaxEaxCall& eax_call);
void defer_waveform(const EaxEaxCall& eax_call);
void defer_rate(const EaxEaxCall& eax_call);
void defer_all(const EaxEaxCall& eax_call);
void set(const EaxEaxCall& eax_call);
}; // EaxVocalMorpherEffect
class EaxVocalMorpherEffectException :
public EaxException
{
public:
explicit EaxVocalMorpherEffectException(
const char* message)
:
EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
{
}
}; // EaxVocalMorpherEffectException
EaxVocalMorpherEffect::EaxVocalMorpherEffect()
: EaxEffect{AL_EFFECT_VOCAL_MORPHER}
{
set_eax_defaults();
set_efx_defaults();
}
void EaxVocalMorpherEffect::dispatch(const EaxEaxCall& eax_call)
{
eax_call.is_get() ? get(eax_call) : set(eax_call);
}
void EaxVocalMorpherEffect::set_eax_defaults()
{
eax_.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
eax_.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
eax_.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
eax_.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
eax_.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
eax_.flRate = EAXVOCALMORPHER_DEFAULTRATE;
eax_d_ = eax_;
}
void EaxVocalMorpherEffect::set_efx_phoneme_a()
{
const auto phoneme_a = clamp(
static_cast<ALint>(eax_.ulPhonemeA),
AL_VOCAL_MORPHER_MIN_PHONEMEA,
AL_VOCAL_MORPHER_MAX_PHONEMEA);
const auto efx_phoneme_a = PhenomeFromEnum(phoneme_a);
assert(efx_phoneme_a.has_value());
al_effect_props_.Vmorpher.PhonemeA = *efx_phoneme_a;
}
void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning()
{
const auto phoneme_a_coarse_tuning = clamp(
static_cast<ALint>(eax_.lPhonemeACoarseTuning),
AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING,
AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING);
al_effect_props_.Vmorpher.PhonemeACoarseTuning = phoneme_a_coarse_tuning;
}
void EaxVocalMorpherEffect::set_efx_phoneme_b()
{
const auto phoneme_b = clamp(
static_cast<ALint>(eax_.ulPhonemeB),
AL_VOCAL_MORPHER_MIN_PHONEMEB,
AL_VOCAL_MORPHER_MAX_PHONEMEB);
const auto efx_phoneme_b = PhenomeFromEnum(phoneme_b);
assert(efx_phoneme_b.has_value());
al_effect_props_.Vmorpher.PhonemeB = *efx_phoneme_b;
}
void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning()
{
const auto phoneme_b_coarse_tuning = clamp(
static_cast<ALint>(eax_.lPhonemeBCoarseTuning),
AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING,
AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING);
al_effect_props_.Vmorpher.PhonemeBCoarseTuning = phoneme_b_coarse_tuning;
}
void EaxVocalMorpherEffect::set_efx_waveform()
{
const auto waveform = clamp(
static_cast<ALint>(eax_.ulWaveform),
AL_VOCAL_MORPHER_MIN_WAVEFORM,
AL_VOCAL_MORPHER_MAX_WAVEFORM);
const auto wfx_waveform = WaveformFromEmum(waveform);
assert(wfx_waveform.has_value());
al_effect_props_.Vmorpher.Waveform = *wfx_waveform;
}
void EaxVocalMorpherEffect::set_efx_rate()
{
const auto rate = clamp(
eax_.flRate,
AL_VOCAL_MORPHER_MIN_RATE,
AL_VOCAL_MORPHER_MAX_RATE);
al_effect_props_.Vmorpher.Rate = rate;
}
void EaxVocalMorpherEffect::set_efx_defaults()
{
set_efx_phoneme_a();
set_efx_phoneme_a_coarse_tuning();
set_efx_phoneme_b();
set_efx_phoneme_b_coarse_tuning();
set_efx_waveform();
set_efx_rate();
}
void EaxVocalMorpherEffect::get(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXVOCALMORPHER_NONE:
break;
case EAXVOCALMORPHER_ALLPARAMETERS:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_);
break;
case EAXVOCALMORPHER_PHONEMEA:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeA);
break;
case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeACoarseTuning);
break;
case EAXVOCALMORPHER_PHONEMEB:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeB);
break;
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeBCoarseTuning);
break;
case EAXVOCALMORPHER_WAVEFORM:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulWaveform);
break;
case EAXVOCALMORPHER_RATE:
eax_call.set_value<EaxVocalMorpherEffectException>(eax_.flRate);
break;
default:
throw EaxVocalMorpherEffectException{"Unsupported property id."};
}
}
void EaxVocalMorpherEffect::validate_phoneme_a(
unsigned long ulPhonemeA)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme A",
ulPhonemeA,
EAXVOCALMORPHER_MINPHONEMEA,
EAXVOCALMORPHER_MAXPHONEMEA);
}
void EaxVocalMorpherEffect::validate_phoneme_a_coarse_tuning(
long lPhonemeACoarseTuning)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme A Coarse Tuning",
lPhonemeACoarseTuning,
EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
}
void EaxVocalMorpherEffect::validate_phoneme_b(
unsigned long ulPhonemeB)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme B",
ulPhonemeB,
EAXVOCALMORPHER_MINPHONEMEB,
EAXVOCALMORPHER_MAXPHONEMEB);
}
void EaxVocalMorpherEffect::validate_phoneme_b_coarse_tuning(
long lPhonemeBCoarseTuning)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Phoneme B Coarse Tuning",
lPhonemeBCoarseTuning,
EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
}
void EaxVocalMorpherEffect::validate_waveform(
unsigned long ulWaveform)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Waveform",
ulWaveform,
EAXVOCALMORPHER_MINWAVEFORM,
EAXVOCALMORPHER_MAXWAVEFORM);
}
void EaxVocalMorpherEffect::validate_rate(
float flRate)
{
eax_validate_range<EaxVocalMorpherEffectException>(
"Rate",
flRate,
EAXVOCALMORPHER_MINRATE,
EAXVOCALMORPHER_MAXRATE);
}
void EaxVocalMorpherEffect::validate_all(
const EAXVOCALMORPHERPROPERTIES& all)
{
validate_phoneme_a(all.ulPhonemeA);
validate_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning);
validate_phoneme_b(all.ulPhonemeB);
validate_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning);
validate_waveform(all.ulWaveform);
validate_rate(all.flRate);
}
void EaxVocalMorpherEffect::defer_phoneme_a(
unsigned long ulPhonemeA)
{
eax_d_.ulPhonemeA = ulPhonemeA;
eax_dirty_flags_.ulPhonemeA = (eax_.ulPhonemeA != eax_d_.ulPhonemeA);
}
void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning(
long lPhonemeACoarseTuning)
{
eax_d_.lPhonemeACoarseTuning = lPhonemeACoarseTuning;
eax_dirty_flags_.lPhonemeACoarseTuning = (eax_.lPhonemeACoarseTuning != eax_d_.lPhonemeACoarseTuning);
}
void EaxVocalMorpherEffect::defer_phoneme_b(
unsigned long ulPhonemeB)
{
eax_d_.ulPhonemeB = ulPhonemeB;
eax_dirty_flags_.ulPhonemeB = (eax_.ulPhonemeB != eax_d_.ulPhonemeB);
}
void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning(
long lPhonemeBCoarseTuning)
{
eax_d_.lPhonemeBCoarseTuning = lPhonemeBCoarseTuning;
eax_dirty_flags_.lPhonemeBCoarseTuning = (eax_.lPhonemeBCoarseTuning != eax_d_.lPhonemeBCoarseTuning);
}
void EaxVocalMorpherEffect::defer_waveform(
unsigned long ulWaveform)
{
eax_d_.ulWaveform = ulWaveform;
eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
}
void EaxVocalMorpherEffect::defer_rate(
float flRate)
{
eax_d_.flRate = flRate;
eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate);
}
void EaxVocalMorpherEffect::defer_all(
const EAXVOCALMORPHERPROPERTIES& all)
{
defer_phoneme_a(all.ulPhonemeA);
defer_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning);
defer_phoneme_b(all.ulPhonemeB);
defer_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning);
defer_waveform(all.ulWaveform);
defer_rate(all.flRate);
}
void EaxVocalMorpherEffect::defer_phoneme_a(
const EaxEaxCall& eax_call)
{
const auto& phoneme_a = eax_call.get_value<EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeA)>();
validate_phoneme_a(phoneme_a);
defer_phoneme_a(phoneme_a);
}
void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning(
const EaxEaxCall& eax_call)
{
const auto& phoneme_a_coarse_tuning = eax_call.get_value<
EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeACoarseTuning)
>();
validate_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning);
defer_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning);
}
void EaxVocalMorpherEffect::defer_phoneme_b(
const EaxEaxCall& eax_call)
{
const auto& phoneme_b = eax_call.get_value<
EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeB)
>();
validate_phoneme_b(phoneme_b);
defer_phoneme_b(phoneme_b);
}
void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning(
const EaxEaxCall& eax_call)
{
const auto& phoneme_b_coarse_tuning = eax_call.get_value<
EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeBCoarseTuning)
>();
validate_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning);
defer_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning);
}
void EaxVocalMorpherEffect::defer_waveform(
const EaxEaxCall& eax_call)
{
const auto& waveform = eax_call.get_value<
EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::ulWaveform)
>();
validate_waveform(waveform);
defer_waveform(waveform);
}
void EaxVocalMorpherEffect::defer_rate(
const EaxEaxCall& eax_call)
{
const auto& rate = eax_call.get_value<
EaxVocalMorpherEffectException,
const decltype(EAXVOCALMORPHERPROPERTIES::flRate)
>();
validate_rate(rate);
defer_rate(rate);
}
void EaxVocalMorpherEffect::defer_all(
const EaxEaxCall& eax_call)
{
const auto& all = eax_call.get_value<
EaxVocalMorpherEffectException,
const EAXVOCALMORPHERPROPERTIES
>();
validate_all(all);
defer_all(all);
}
// [[nodiscard]]
bool EaxVocalMorpherEffect::apply_deferred()
{
if (eax_dirty_flags_ == EaxVocalMorpherEffectDirtyFlags{})
{
return false;
}
eax_ = eax_d_;
if (eax_dirty_flags_.ulPhonemeA)
{
set_efx_phoneme_a();
}
if (eax_dirty_flags_.lPhonemeACoarseTuning)
{
set_efx_phoneme_a_coarse_tuning();
}
if (eax_dirty_flags_.ulPhonemeB)
{
set_efx_phoneme_b();
}
if (eax_dirty_flags_.lPhonemeBCoarseTuning)
{
set_efx_phoneme_b_coarse_tuning();
}
if (eax_dirty_flags_.ulWaveform)
{
set_efx_waveform();
}
if (eax_dirty_flags_.flRate)
{
set_efx_rate();
}
eax_dirty_flags_ = EaxVocalMorpherEffectDirtyFlags{};
return true;
}
void EaxVocalMorpherEffect::set(const EaxEaxCall& eax_call)
{
switch(eax_call.get_property_id())
{
case EAXVOCALMORPHER_NONE:
break;
case EAXVOCALMORPHER_ALLPARAMETERS:
defer_all(eax_call);
break;
case EAXVOCALMORPHER_PHONEMEA:
defer_phoneme_a(eax_call);
break;
case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
defer_phoneme_a_coarse_tuning(eax_call);
break;
case EAXVOCALMORPHER_PHONEMEB:
defer_phoneme_b(eax_call);
break;
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
defer_phoneme_b_coarse_tuning(eax_call);
break;
case EAXVOCALMORPHER_WAVEFORM:
defer_waveform(eax_call);
break;
case EAXVOCALMORPHER_RATE:
defer_rate(eax_call);
break;
default:
throw EaxVocalMorpherEffectException{"Unsupported property id."};
}
}
} // namespace
EaxEffectUPtr eax_create_eax_vocal_morpher_effect()
{
return std::make_unique<EaxVocalMorpherEffect>();
}
#endif // ALSOFT_EAX