Update OpenAL-soft to 1.23.1-bc7cb17.

This commit is contained in:
Miku AuahDark
2024-03-20 11:06:03 +08:00
parent 4a512be715
commit 73a6fc9196
294 changed files with 44342 additions and 40077 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+218
View File
@@ -0,0 +1,218 @@
#include "config.h"
#include "call.h"
#include "exception.h"
namespace {
constexpr auto deferred_flag = 0x80000000U;
class EaxCallException : public EaxException {
public:
explicit EaxCallException(const char* message)
: EaxException{"EAX_CALL", message}
{}
}; // EaxCallException
} // namespace
EaxCall::EaxCall(
EaxCallType type,
const GUID& property_set_guid,
ALuint property_id,
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size)
: mCallType{type}, mIsDeferred{(property_id & deferred_flag) != 0}
, mPropertyId{property_id & ~deferred_flag}, mPropertySourceId{property_source_id}
, mPropertyBuffer{property_buffer}, mPropertyBufferSize{property_size}
{
switch(mCallType)
{
case EaxCallType::get:
case EaxCallType::set:
break;
default:
fail("Invalid type.");
}
if (false)
{
}
else if (property_set_guid == EAXPROPERTYID_EAX40_Context)
{
mVersion = 4;
mPropertySetId = EaxCallPropertySetId::context;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_Context)
{
mVersion = 5;
mPropertySetId = EaxCallPropertySetId::context;
}
else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties)
{
mVersion = 2;
mFxSlotIndex = 0u;
mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
}
else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties)
{
mVersion = 3;
mFxSlotIndex = 0u;
mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
}
else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0)
{
mVersion = 4;
mFxSlotIndex = 0u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0)
{
mVersion = 5;
mFxSlotIndex = 0u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1)
{
mVersion = 4;
mFxSlotIndex = 1u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1)
{
mVersion = 5;
mFxSlotIndex = 1u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2)
{
mVersion = 4;
mFxSlotIndex = 2u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2)
{
mVersion = 5;
mFxSlotIndex = 2u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3)
{
mVersion = 4;
mFxSlotIndex = 3u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3)
{
mVersion = 5;
mFxSlotIndex = 3u;
mPropertySetId = EaxCallPropertySetId::fx_slot;
}
else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties)
{
mVersion = 2;
mPropertySetId = EaxCallPropertySetId::source;
}
else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties)
{
mVersion = 3;
mPropertySetId = EaxCallPropertySetId::source;
}
else if (property_set_guid == EAXPROPERTYID_EAX40_Source)
{
mVersion = 4;
mPropertySetId = EaxCallPropertySetId::source;
}
else if (property_set_guid == EAXPROPERTYID_EAX50_Source)
{
mVersion = 5;
mPropertySetId = EaxCallPropertySetId::source;
}
else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties)
{
mVersion = 1;
mFxSlotIndex = 0u;
mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
}
else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties)
{
mVersion = 1;
mPropertySetId = EaxCallPropertySetId::source;
}
else
{
fail("Unsupported property set id.");
}
switch(mPropertyId)
{
case EAXCONTEXT_LASTERROR:
case EAXCONTEXT_SPEAKERCONFIG:
case EAXCONTEXT_EAXSESSION:
case EAXFXSLOT_NONE:
case EAXFXSLOT_ALLPARAMETERS:
case EAXFXSLOT_LOADEFFECT:
case EAXFXSLOT_VOLUME:
case EAXFXSLOT_LOCK:
case EAXFXSLOT_FLAGS:
case EAXFXSLOT_OCCLUSION:
case EAXFXSLOT_OCCLUSIONLFRATIO:
// EAX allow to set "defer" flag on immediate-only properties.
// If we don't clear our flag then "applyAllUpdates" in EAX context won't be called.
mIsDeferred = false;
break;
}
if(!mIsDeferred)
{
if(mPropertySetId != EaxCallPropertySetId::fx_slot && mPropertyId != 0)
{
if(mPropertyBuffer == nullptr)
fail("Null property buffer.");
if(mPropertyBufferSize == 0)
fail("Empty property.");
}
}
if(mPropertySetId == EaxCallPropertySetId::source && mPropertySourceId == 0)
fail("Null AL source id.");
if(mPropertySetId == EaxCallPropertySetId::fx_slot)
{
if(mPropertyId < EAXFXSLOT_NONE)
mPropertySetId = EaxCallPropertySetId::fx_slot_effect;
}
}
[[noreturn]] void EaxCall::fail(const char* message)
{
throw EaxCallException{message};
}
[[noreturn]] void EaxCall::fail_too_small()
{
fail("Property buffer too small.");
}
EaxCall create_eax_call(
EaxCallType type,
const GUID* property_set_id,
ALuint property_id,
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size)
{
if(!property_set_id)
throw EaxCallException{"Null property set ID."};
return EaxCall{
type,
*property_set_id,
property_id,
property_source_id,
property_buffer,
property_size
};
}
+97
View File
@@ -0,0 +1,97 @@
#ifndef EAX_EAX_CALL_INCLUDED
#define EAX_EAX_CALL_INCLUDED
#include "AL/al.h"
#include "alnumeric.h"
#include "alspan.h"
#include "api.h"
#include "fx_slot_index.h"
enum class EaxCallType {
none,
get,
set,
}; // EaxCallType
enum class EaxCallPropertySetId {
none,
context,
fx_slot,
source,
fx_slot_effect,
}; // EaxCallPropertySetId
class EaxCall {
public:
EaxCall(
EaxCallType type,
const GUID& property_set_guid,
ALuint property_id,
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size);
[[nodiscard]] auto is_get() const noexcept -> bool { return mCallType == EaxCallType::get; }
[[nodiscard]] auto is_deferred() const noexcept -> bool { return mIsDeferred; }
[[nodiscard]] auto get_version() const noexcept -> int { return mVersion; }
[[nodiscard]] auto get_property_set_id() const noexcept -> EaxCallPropertySetId { return mPropertySetId; }
[[nodiscard]] auto get_property_id() const noexcept -> ALuint { return mPropertyId; }
[[nodiscard]] auto get_property_al_name() const noexcept -> ALuint { return mPropertySourceId; }
[[nodiscard]] auto get_fx_slot_index() const noexcept -> EaxFxSlotIndex { return mFxSlotIndex; }
template<typename TException, typename TValue>
[[nodiscard]] auto get_value() const -> TValue&
{
if(mPropertyBufferSize < sizeof(TValue))
fail_too_small();
return *static_cast<TValue*>(mPropertyBuffer);
}
template<typename TValue>
[[nodiscard]] auto get_values(size_t max_count) const -> al::span<TValue>
{
if(max_count == 0 || mPropertyBufferSize < sizeof(TValue))
fail_too_small();
const auto count = std::min(mPropertyBufferSize/sizeof(TValue), max_count);
return {static_cast<TValue*>(mPropertyBuffer), count};
}
template<typename TValue>
[[nodiscard]] auto get_values() const -> al::span<TValue>
{
return get_values<TValue>(~0_uz);
}
template<typename TException, typename TValue>
auto set_value(const TValue& value) const -> void
{
get_value<TException, TValue>() = value;
}
private:
const EaxCallType mCallType;
int mVersion{};
EaxFxSlotIndex mFxSlotIndex{};
EaxCallPropertySetId mPropertySetId{EaxCallPropertySetId::none};
bool mIsDeferred;
const ALuint mPropertyId;
const ALuint mPropertySourceId;
ALvoid*const mPropertyBuffer;
const ALuint mPropertyBufferSize;
[[noreturn]] static void fail(const char* message);
[[noreturn]] static void fail_too_small();
}; // EaxCall
EaxCall create_eax_call(
EaxCallType type,
const GUID* property_set_id,
ALuint property_id,
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size);
#endif // !EAX_EAX_CALL_INCLUDED
+457
View File
@@ -0,0 +1,457 @@
#ifndef EAX_EFFECT_INCLUDED
#define EAX_EFFECT_INCLUDED
#include <cassert>
#include <memory>
#include <variant>
#include "alnumeric.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "core/effects/base.h"
#include "call.h"
struct EaxEffectErrorMessages {
static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
static constexpr auto unknown_version() noexcept { return "Unknown version."; }
}; // EaxEffectErrorMessages
using EaxEffectProps = std::variant<std::monostate,
EAXREVERBPROPERTIES,
EAXCHORUSPROPERTIES,
EAXAUTOWAHPROPERTIES,
EAXAGCCOMPRESSORPROPERTIES,
EAXDISTORTIONPROPERTIES,
EAXECHOPROPERTIES,
EAXEQUALIZERPROPERTIES,
EAXFLANGERPROPERTIES,
EAXFREQUENCYSHIFTERPROPERTIES,
EAXRINGMODULATORPROPERTIES,
EAXPITCHSHIFTERPROPERTIES,
EAXVOCALMORPHERPROPERTIES>;
template<typename... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<typename... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
{
return std::visit(overloaded{
[](const std::monostate&) noexcept { return AL_EFFECT_NULL; },
[](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; },
[](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; },
[](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; },
[](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; },
[](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; },
[](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; },
[](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; },
[](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; },
[](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; },
[](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; },
[](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; },
[](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; }
}, props);
}
struct EaxReverbCommitter {
struct Exception;
EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
: mEaxProps{eaxprops}, mAlProps{alprops}
{ }
EaxEffectProps &mEaxProps;
EffectProps &mAlProps;
[[noreturn]] static void fail(const char* message);
[[noreturn]] static void fail_unknown_property_id()
{ fail(EaxEffectErrorMessages::unknown_property_id()); }
template<typename TValidator, typename TProperty>
static void defer(const EaxCall& call, TProperty& property)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
property = value;
}
template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
static void defer(const EaxCall& call, TProperties& properties, TProperty&)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
TDeferrer{}(properties, value);
}
template<typename TValidator, typename TProperty>
static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
if (value == property)
return;
property = value;
properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
}
bool commit(const EAX_REVERBPROPERTIES &props);
bool commit(const EAX20LISTENERPROPERTIES &props);
bool commit(const EAXREVERBPROPERTIES &props);
static void SetDefaults(EAX_REVERBPROPERTIES &props);
static void SetDefaults(EAX20LISTENERPROPERTIES &props);
static void SetDefaults(EAXREVERBPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
};
template<typename T>
struct EaxCommitter {
struct Exception;
EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
: mEaxProps{eaxprops}, mAlProps{alprops}
{ }
EaxEffectProps &mEaxProps;
EffectProps &mAlProps;
template<typename TValidator, typename TProperty>
static void defer(const EaxCall& call, TProperty& property)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
property = value;
}
[[noreturn]] static void fail(const char *message);
[[noreturn]] static void fail_unknown_property_id()
{ fail(EaxEffectErrorMessages::unknown_property_id()); }
};
struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
bool commit(const EAXAUTOWAHPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
};
struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
bool commit(const EAXCHORUSPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
};
struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
};
struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
bool commit(const EAXDISTORTIONPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
};
struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
bool commit(const EAXECHOPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
};
struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
bool commit(const EAXEQUALIZERPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
};
struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
bool commit(const EAXFLANGERPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
};
struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
};
struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
bool commit(const EAXRINGMODULATORPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
};
struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
};
struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
bool commit(const EAXVOCALMORPHERPROPERTIES &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
};
struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
using EaxCommitter<EaxNullCommitter>::EaxCommitter;
bool commit(const std::monostate &props);
static void SetDefaults(EaxEffectProps &props);
static void Get(const EaxCall &call, const std::monostate &props);
static void Set(const EaxCall &call, std::monostate &props);
};
template<typename T>
struct CommitterFromProps { };
template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
template<typename T>
using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
class EaxEffect {
public:
EaxEffect() noexcept = default;
~EaxEffect() = default;
ALenum al_effect_type_{AL_EFFECT_NULL};
EffectProps al_effect_props_{};
using Props1 = EAX_REVERBPROPERTIES;
using Props2 = EAX20LISTENERPROPERTIES;
using Props3 = EAXREVERBPROPERTIES;
using Props4 = EaxEffectProps;
struct State1 {
Props1 i; // Immediate.
Props1 d; // Deferred.
};
struct State2 {
Props2 i; // Immediate.
Props2 d; // Deferred.
};
struct State3 {
Props3 i; // Immediate.
Props3 d; // Deferred.
};
struct State4 {
Props4 i; // Immediate.
Props4 d; // Deferred.
};
int version_{};
bool changed_{};
Props4 props_{};
State1 state1_{};
State2 state2_{};
State3 state3_{};
State4 state4_{};
State4 state5_{};
static void call_set_defaults(const ALenum altype, EaxEffectProps &props)
{
switch(altype)
{
case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
case AL_EFFECT_NULL: break;
}
return EaxNullCommitter::SetDefaults(props);
}
template<typename T>
void init()
{
EaxReverbCommitter::SetDefaults(state1_.d);
state1_.i = state1_.d;
EaxReverbCommitter::SetDefaults(state2_.d);
state2_.i = state2_.d;
EaxReverbCommitter::SetDefaults(state3_.d);
state3_.i = state3_.d;
T::SetDefaults(state4_.d);
state4_.i = state4_.d;
T::SetDefaults(state5_.d);
state5_.i = state5_.d;
}
void set_defaults(int eax_version, ALenum altype)
{
switch(eax_version)
{
case 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
case 4: call_set_defaults(altype, state4_.d); break;
case 5: call_set_defaults(altype, state5_.d); break;
}
changed_ = true;
}
static void call_set(const EaxCall &call, EaxEffectProps &props)
{
return std::visit([&](auto &arg)
{ return CommitterFor<decltype(arg)>::Set(call, arg); },
props);
}
void set(const EaxCall &call)
{
switch(call.get_version())
{
case 1: EaxReverbCommitter::Set(call, state1_.d); break;
case 2: EaxReverbCommitter::Set(call, state2_.d); break;
case 3: EaxReverbCommitter::Set(call, state3_.d); break;
case 4: call_set(call, state4_.d); break;
case 5: call_set(call, state5_.d); break;
}
changed_ = true;
}
static void call_get(const EaxCall &call, const EaxEffectProps &props)
{
return std::visit([&](auto &arg)
{ return CommitterFor<decltype(arg)>::Get(call, arg); },
props);
}
void get(const EaxCall &call) const
{
switch(call.get_version())
{
case 1: EaxReverbCommitter::Get(call, state1_.d); break;
case 2: EaxReverbCommitter::Get(call, state2_.d); break;
case 3: EaxReverbCommitter::Get(call, state3_.d); break;
case 4: call_get(call, state4_.d); break;
case 5: call_get(call, state5_.d); break;
}
}
bool call_commit(const EaxEffectProps &props)
{
return std::visit([&](auto &arg)
{ return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
props);
}
bool commit(int eax_version)
{
changed_ |= version_ != eax_version;
if(!changed_) return false;
bool ret{version_ != eax_version};
version_ = eax_version;
changed_ = false;
switch(eax_version)
{
case 1:
state1_.i = state1_.d;
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
break;
case 2:
state2_.i = state2_.d;
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
break;
case 3:
state3_.i = state3_.d;
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
break;
case 4:
state4_.i = state4_.d;
ret |= call_commit(state4_.d);
break;
case 5:
state5_.i = state5_.d;
ret |= call_commit(state5_.d);
break;
}
al_effect_type_ = EnumFromEaxEffectType(props_);
return ret;
}
#undef EAXCALL
}; // EaxEffect
using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
#endif // !EAX_EFFECT_INCLUDED
+32
View File
@@ -0,0 +1,32 @@
#include "config.h"
#include "exception.h"
#include <cassert>
#include <string>
EaxException::EaxException(std::string_view context, std::string_view message)
: std::runtime_error{make_message(context, message)}
{
}
EaxException::~EaxException() = default;
std::string EaxException::make_message(std::string_view context, std::string_view message)
{
auto what = std::string{};
if(context.empty() && message.empty())
return what;
what.reserve((!context.empty() ? context.size() + 3 : 0) + message.length() + 1);
if(!context.empty())
{
what += "[";
what += context;
what += "] ";
}
what += message;
return what;
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef EAX_EXCEPTION_INCLUDED
#define EAX_EXCEPTION_INCLUDED
#include <stdexcept>
#include <string>
#include <string_view>
class EaxException : public std::runtime_error {
static std::string make_message(std::string_view context, std::string_view message);
public:
EaxException(std::string_view context, std::string_view message);
~EaxException() override;
}; // EaxException
#endif // !EAX_EXCEPTION_INCLUDED
+71
View File
@@ -0,0 +1,71 @@
#include "config.h"
#include "fx_slot_index.h"
#include "exception.h"
namespace
{
class EaxFxSlotIndexException :
public EaxException
{
public:
explicit EaxFxSlotIndexException(
const char* message)
:
EaxException{"EAX_FX_SLOT_INDEX", message}
{
}
}; // EaxFxSlotIndexException
} // namespace
void EaxFxSlotIndex::set(EaxFxSlotIndexValue index)
{
if(index >= EaxFxSlotIndexValue{EAX_MAX_FXSLOTS})
fail("Index out of range.");
emplace(index);
}
void EaxFxSlotIndex::set(const GUID &guid)
{
if (false)
{
}
else if (guid == EAX_NULL_GUID)
{
reset();
}
else if (guid == EAXPROPERTYID_EAX40_FXSlot0 || guid == EAXPROPERTYID_EAX50_FXSlot0)
{
emplace(0u);
}
else if (guid == EAXPROPERTYID_EAX40_FXSlot1 || guid == EAXPROPERTYID_EAX50_FXSlot1)
{
emplace(1u);
}
else if (guid == EAXPROPERTYID_EAX40_FXSlot2 || guid == EAXPROPERTYID_EAX50_FXSlot2)
{
emplace(2u);
}
else if (guid == EAXPROPERTYID_EAX40_FXSlot3 || guid == EAXPROPERTYID_EAX50_FXSlot3)
{
emplace(3u);
}
else
{
fail("Unsupported GUID.");
}
}
[[noreturn]]
void EaxFxSlotIndex::fail(const char* message)
{
throw EaxFxSlotIndexException{message};
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef EAX_FX_SLOT_INDEX_INCLUDED
#define EAX_FX_SLOT_INDEX_INCLUDED
#include <cstddef>
#include <optional>
#include "api.h"
using EaxFxSlotIndexValue = std::size_t;
class EaxFxSlotIndex : public std::optional<EaxFxSlotIndexValue> {
public:
using std::optional<EaxFxSlotIndexValue>::optional;
EaxFxSlotIndex& operator=(const EaxFxSlotIndexValue &value) { set(value); return *this; }
EaxFxSlotIndex& operator=(const GUID &guid) { set(guid); return *this; }
void set(EaxFxSlotIndexValue index);
void set(const GUID& guid);
private:
[[noreturn]]
static void fail(const char *message);
}; // EaxFxSlotIndex
inline bool operator==(const EaxFxSlotIndex& lhs, const EaxFxSlotIndex& rhs) noexcept
{
if(lhs.has_value() != rhs.has_value())
return false;
if(lhs.has_value())
return *lhs == *rhs;
return true;
}
inline bool operator!=(const EaxFxSlotIndex& lhs, const EaxFxSlotIndex& rhs) noexcept
{ return !(lhs == rhs); }
#endif // !EAX_FX_SLOT_INDEX_INCLUDED
+75
View File
@@ -0,0 +1,75 @@
#include "config.h"
#include "fx_slots.h"
#include <array>
#include "api.h"
#include "exception.h"
namespace
{
class EaxFxSlotsException :
public EaxException
{
public:
explicit EaxFxSlotsException(
const char* message)
:
EaxException{"EAX_FX_SLOTS", message}
{
}
}; // EaxFxSlotsException
} // namespace
void EaxFxSlots::initialize(ALCcontext& al_context)
{
initialize_fx_slots(al_context);
}
void EaxFxSlots::uninitialize() noexcept
{
for (auto& fx_slot : fx_slots_)
{
fx_slot = nullptr;
}
}
const ALeffectslot& EaxFxSlots::get(EaxFxSlotIndex index) const
{
if(!index.has_value())
fail("Empty index.");
return *fx_slots_[index.value()];
}
ALeffectslot& EaxFxSlots::get(EaxFxSlotIndex index)
{
if(!index.has_value())
fail("Empty index.");
return *fx_slots_[index.value()];
}
[[noreturn]]
void EaxFxSlots::fail(
const char* message)
{
throw EaxFxSlotsException{message};
}
void EaxFxSlots::initialize_fx_slots(ALCcontext& al_context)
{
auto fx_slot_index = EaxFxSlotIndexValue{};
for (auto& fx_slot : fx_slots_)
{
fx_slot = eax_create_al_effect_slot(al_context);
fx_slot->eax_initialize(al_context, fx_slot_index);
fx_slot_index += 1;
}
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef EAX_FX_SLOTS_INCLUDED
#define EAX_FX_SLOTS_INCLUDED
#include <array>
#include "al/auxeffectslot.h"
#include "api.h"
#include "call.h"
#include "fx_slot_index.h"
class EaxFxSlots
{
public:
void initialize(ALCcontext& al_context);
void uninitialize() noexcept;
void commit()
{
for(auto& fx_slot : fx_slots_)
fx_slot->eax_commit();
}
[[nodiscard]] auto get(EaxFxSlotIndex index) const -> const ALeffectslot&;
[[nodiscard]] auto get(EaxFxSlotIndex index) -> ALeffectslot&;
private:
using Items = std::array<EaxAlEffectSlotUPtr, EAX_MAX_FXSLOTS>;
Items fx_slots_{};
[[noreturn]]
static void fail(const char* message);
void initialize_fx_slots(ALCcontext& al_context);
}; // EaxFxSlots
#endif // !EAX_FX_SLOTS_INCLUDED
+6
View File
@@ -0,0 +1,6 @@
#ifndef EAX_GLOBALS_INCLUDED
#define EAX_GLOBALS_INCLUDED
inline bool eax_g_is_enabled{true};
#endif /* EAX_GLOBALS_INCLUDED */
+26
View File
@@ -0,0 +1,26 @@
#include "config.h"
#include "utils.h"
#include <cassert>
#include <exception>
#include "alstring.h"
#include "core/logging.h"
void eax_log_exception(std::string_view message) noexcept
{
const auto exception_ptr = std::current_exception();
assert(exception_ptr);
try {
std::rethrow_exception(exception_ptr);
}
catch(const std::exception& ex) {
ERR("%.*s %s\n", al::sizei(message), message.data(), ex.what());
}
catch(...) {
ERR("%.*s %s\n", al::sizei(message), message.data(), "Generic exception.");
}
}
+95
View File
@@ -0,0 +1,95 @@
#ifndef EAX_UTILS_INCLUDED
#define EAX_UTILS_INCLUDED
#include <algorithm>
#include <cstdint>
#include <string>
#include <string_view>
#include <type_traits>
#include "opthelpers.h"
using EaxDirtyFlags = unsigned int;
struct EaxAlLowPassParam {
float gain;
float gain_hf;
};
void eax_log_exception(std::string_view message) noexcept;
template<typename TException, typename TValue>
void eax_validate_range(std::string_view value_name, const TValue& value, const TValue& min_value,
const TValue& max_value)
{
if(value >= min_value && value <= max_value) LIKELY
return;
const auto message =
std::string{value_name} +
" out of range (value: " +
std::to_string(value) + "; min: " +
std::to_string(min_value) + "; max: " +
std::to_string(max_value) + ").";
throw TException{message.c_str()};
}
namespace detail {
template<typename T>
struct EaxIsBitFieldStruct {
private:
using yes = std::true_type;
using no = std::false_type;
template<typename U>
static auto test(int) -> decltype(std::declval<typename U::EaxIsBitFieldStruct>(), yes{});
template<typename>
static no test(...);
public:
static constexpr auto value = std::is_same<decltype(test<T>(0)), yes>::value;
};
template<typename T, typename TValue>
inline bool eax_bit_fields_are_equal(const T& lhs, const T& rhs) noexcept
{
static_assert(sizeof(T) == sizeof(TValue), "Invalid type size.");
return reinterpret_cast<const TValue&>(lhs) == reinterpret_cast<const TValue&>(rhs);
}
} // namespace detail
template<
typename T,
std::enable_if_t<detail::EaxIsBitFieldStruct<T>::value, int> = 0
>
inline bool operator==(const T& lhs, const T& rhs) noexcept
{
using Value = std::conditional_t<
sizeof(T) == 1,
std::uint8_t,
std::conditional_t<
sizeof(T) == 2,
std::uint16_t,
std::conditional_t<
sizeof(T) == 4,
std::uint32_t,
void>>>;
static_assert(!std::is_same<Value, void>::value, "Unsupported type.");
return detail::eax_bit_fields_are_equal<T, Value>(lhs, rhs);
}
template<
typename T,
std::enable_if_t<detail::EaxIsBitFieldStruct<T>::value, int> = 0
>
inline bool operator!=(const T& lhs, const T& rhs) noexcept
{
return !(lhs == rhs);
}
#endif // !EAX_UTILS_INCLUDED
+35
View File
@@ -0,0 +1,35 @@
#ifndef EAX_X_RAM_INCLUDED
#define EAX_X_RAM_INCLUDED
#include "AL/al.h"
constexpr auto eax_x_ram_min_size = ALsizei{};
constexpr auto eax_x_ram_max_size = ALsizei{64 * 1'024 * 1'024};
constexpr auto AL_EAX_RAM_SIZE = ALenum{0x202201};
constexpr auto AL_EAX_RAM_FREE = ALenum{0x202202};
constexpr auto AL_STORAGE_AUTOMATIC = ALenum{0x202203};
constexpr auto AL_STORAGE_HARDWARE = ALenum{0x202204};
constexpr auto AL_STORAGE_ACCESSIBLE = ALenum{0x202205};
constexpr auto AL_EAX_RAM_SIZE_NAME = "AL_EAX_RAM_SIZE";
constexpr auto AL_EAX_RAM_FREE_NAME = "AL_EAX_RAM_FREE";
constexpr auto AL_STORAGE_AUTOMATIC_NAME = "AL_STORAGE_AUTOMATIC";
constexpr auto AL_STORAGE_HARDWARE_NAME = "AL_STORAGE_HARDWARE";
constexpr auto AL_STORAGE_ACCESSIBLE_NAME = "AL_STORAGE_ACCESSIBLE";
/* NOLINTBEGIN(readability-inconsistent-declaration-parameter-name)
* These functions are defined using macros to forward them in a generic way to
* implementation functions, which gives the parameters generic names.
*/
ALboolean AL_APIENTRY EAXSetBufferMode(ALsizei n, const ALuint *buffers, ALint value) noexcept;
ALenum AL_APIENTRY EAXGetBufferMode(ALuint buffer, ALint *pReserved) noexcept;
/* NOLINTEND(readability-inconsistent-declaration-parameter-name) */
#endif // !EAX_X_RAM_INCLUDED