mirror of
https://github.com/love2d/megasource.git
synced 2026-08-19 12:14:41 +02:00
Update OpenAL-Soft to 1.22.0
This commit is contained in:
@@ -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
@@ -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,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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user