First Commit
This commit is contained in:
1563
externals/openal-soft/al/auxeffectslot.cpp
vendored
Normal file
1563
externals/openal-soft/al/auxeffectslot.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
368
externals/openal-soft/al/auxeffectslot.h
vendored
Normal file
368
externals/openal-soft/al/auxeffectslot.h
vendored
Normal file
@@ -0,0 +1,368 @@
|
||||
#ifndef AL_AUXEFFECTSLOT_H
|
||||
#define AL_AUXEFFECTSLOT_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/device.h"
|
||||
#include "alc/effects/base.h"
|
||||
#include "almalloc.h"
|
||||
#include "atomic.h"
|
||||
#include "core/effectslot.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <memory>
|
||||
#include "eax/call.h"
|
||||
#include "eax/effect.h"
|
||||
#include "eax/exception.h"
|
||||
#include "eax/fx_slot_index.h"
|
||||
#include "eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
struct ALbuffer;
|
||||
struct ALeffect;
|
||||
struct WetBuffer;
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
class EaxFxSlotException : public EaxException {
|
||||
public:
|
||||
explicit EaxFxSlotException(const char* message)
|
||||
: EaxException{"EAX_FX_SLOT", message}
|
||||
{}
|
||||
};
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
enum class SlotState : ALenum {
|
||||
Initial = AL_INITIAL,
|
||||
Playing = AL_PLAYING,
|
||||
Stopped = AL_STOPPED,
|
||||
};
|
||||
|
||||
struct ALeffectslot {
|
||||
float Gain{1.0f};
|
||||
bool AuxSendAuto{true};
|
||||
ALeffectslot *Target{nullptr};
|
||||
ALbuffer *Buffer{nullptr};
|
||||
|
||||
struct {
|
||||
EffectSlotType Type{EffectSlotType::None};
|
||||
EffectProps Props{};
|
||||
|
||||
al::intrusive_ptr<EffectState> State;
|
||||
} Effect;
|
||||
|
||||
bool mPropsDirty{true};
|
||||
|
||||
SlotState mState{SlotState::Initial};
|
||||
|
||||
RefCount ref{0u};
|
||||
|
||||
EffectSlot *mSlot{nullptr};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{};
|
||||
|
||||
ALeffectslot(ALCcontext *context);
|
||||
ALeffectslot(const ALeffectslot&) = delete;
|
||||
ALeffectslot& operator=(const ALeffectslot&) = delete;
|
||||
~ALeffectslot();
|
||||
|
||||
ALenum initEffect(ALenum effectType, const EffectProps &effectProps, ALCcontext *context);
|
||||
void updateProps(ALCcontext *context);
|
||||
|
||||
/* This can be new'd for the context's default effect slot. */
|
||||
DEF_NEWDEL(ALeffectslot)
|
||||
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
public:
|
||||
void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
|
||||
|
||||
EaxFxSlotIndexValue eax_get_index() const noexcept { return eax_fx_slot_index_; }
|
||||
const EAX50FXSLOTPROPERTIES& eax_get_eax_fx_slot() const noexcept
|
||||
{ return eax_; }
|
||||
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax_dispatch(const EaxCall& call)
|
||||
{ return call.is_get() ? eax_get(call) : eax_set(call); }
|
||||
|
||||
void eax_commit();
|
||||
|
||||
private:
|
||||
static constexpr auto eax_load_effect_dirty_bit = EaxDirtyFlags{1} << 0;
|
||||
static constexpr auto eax_volume_dirty_bit = EaxDirtyFlags{1} << 1;
|
||||
static constexpr auto eax_lock_dirty_bit = EaxDirtyFlags{1} << 2;
|
||||
static constexpr auto eax_flags_dirty_bit = EaxDirtyFlags{1} << 3;
|
||||
static constexpr auto eax_occlusion_dirty_bit = EaxDirtyFlags{1} << 4;
|
||||
static constexpr auto eax_occlusion_lf_ratio_dirty_bit = EaxDirtyFlags{1} << 5;
|
||||
|
||||
using Exception = EaxFxSlotException;
|
||||
|
||||
using Eax4Props = EAX40FXSLOTPROPERTIES;
|
||||
|
||||
struct Eax4State {
|
||||
Eax4Props i; // Immediate.
|
||||
};
|
||||
|
||||
using Eax5Props = EAX50FXSLOTPROPERTIES;
|
||||
|
||||
struct Eax5State {
|
||||
Eax5Props i; // Immediate.
|
||||
};
|
||||
|
||||
struct EaxRangeValidator {
|
||||
template<typename TValue>
|
||||
void operator()(
|
||||
const char* name,
|
||||
const TValue& value,
|
||||
const TValue& min_value,
|
||||
const TValue& max_value) const
|
||||
{
|
||||
eax_validate_range<Exception>(name, value, min_value, max_value);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4GuidLoadEffectValidator {
|
||||
void operator()(const GUID& guidLoadEffect) const
|
||||
{
|
||||
if (guidLoadEffect != EAX_NULL_GUID &&
|
||||
guidLoadEffect != EAX_REVERB_EFFECT &&
|
||||
guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT &&
|
||||
guidLoadEffect != EAX_AUTOWAH_EFFECT &&
|
||||
guidLoadEffect != EAX_CHORUS_EFFECT &&
|
||||
guidLoadEffect != EAX_DISTORTION_EFFECT &&
|
||||
guidLoadEffect != EAX_ECHO_EFFECT &&
|
||||
guidLoadEffect != EAX_EQUALIZER_EFFECT &&
|
||||
guidLoadEffect != EAX_FLANGER_EFFECT &&
|
||||
guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT &&
|
||||
guidLoadEffect != EAX_VOCALMORPHER_EFFECT &&
|
||||
guidLoadEffect != EAX_PITCHSHIFTER_EFFECT &&
|
||||
guidLoadEffect != EAX_RINGMODULATOR_EFFECT)
|
||||
{
|
||||
eax_fail_unknown_effect_id();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4VolumeValidator {
|
||||
void operator()(long lVolume) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Volume",
|
||||
lVolume,
|
||||
EAXFXSLOT_MINVOLUME,
|
||||
EAXFXSLOT_MAXVOLUME);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4LockValidator {
|
||||
void operator()(long lLock) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Lock",
|
||||
lLock,
|
||||
EAXFXSLOT_MINLOCK,
|
||||
EAXFXSLOT_MAXLOCK);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4FlagsValidator {
|
||||
void operator()(unsigned long ulFlags) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Flags",
|
||||
ulFlags,
|
||||
0UL,
|
||||
~EAX40FXSLOTFLAGS_RESERVED);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4AllValidator {
|
||||
void operator()(const EAX40FXSLOTPROPERTIES& all) const
|
||||
{
|
||||
Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
|
||||
Eax4VolumeValidator{}(all.lVolume);
|
||||
Eax4LockValidator{}(all.lLock);
|
||||
Eax4FlagsValidator{}(all.ulFlags);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5OcclusionValidator {
|
||||
void operator()(long lOcclusion) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Occlusion",
|
||||
lOcclusion,
|
||||
EAXFXSLOT_MINOCCLUSION,
|
||||
EAXFXSLOT_MAXOCCLUSION);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5OcclusionLfRatioValidator {
|
||||
void operator()(float flOcclusionLFRatio) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Occlusion LF Ratio",
|
||||
flOcclusionLFRatio,
|
||||
EAXFXSLOT_MINOCCLUSIONLFRATIO,
|
||||
EAXFXSLOT_MAXOCCLUSIONLFRATIO);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5FlagsValidator {
|
||||
void operator()(unsigned long ulFlags) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Flags",
|
||||
ulFlags,
|
||||
0UL,
|
||||
~EAX50FXSLOTFLAGS_RESERVED);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5AllValidator {
|
||||
void operator()(const EAX50FXSLOTPROPERTIES& all) const
|
||||
{
|
||||
Eax4AllValidator{}(static_cast<const EAX40FXSLOTPROPERTIES&>(all));
|
||||
Eax5OcclusionValidator{}(all.lOcclusion);
|
||||
Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
|
||||
}
|
||||
};
|
||||
|
||||
ALCcontext* eax_al_context_{};
|
||||
EaxFxSlotIndexValue eax_fx_slot_index_{};
|
||||
int eax_version_{}; // Current EAX version.
|
||||
EaxDirtyFlags eax_df_{}; // Dirty flags for the current EAX version.
|
||||
EaxEffectUPtr eax_effect_{};
|
||||
Eax5State eax123_{}; // EAX1/EAX2/EAX3 state.
|
||||
Eax4State eax4_{}; // EAX4 state.
|
||||
Eax5State eax5_{}; // EAX5 state.
|
||||
Eax5Props eax_{}; // Current EAX state.
|
||||
|
||||
[[noreturn]] static void eax_fail(const char* message);
|
||||
[[noreturn]] static void eax_fail_unknown_effect_id();
|
||||
[[noreturn]] static void eax_fail_unknown_property_id();
|
||||
[[noreturn]] static void eax_fail_unknown_version();
|
||||
|
||||
// Gets a new value from EAX call,
|
||||
// validates it,
|
||||
// sets a dirty flag only if the new value differs form the old one,
|
||||
// and assigns the new value.
|
||||
template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
|
||||
static void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags)
|
||||
{
|
||||
const auto& src = call.get_value<Exception, const TProperties>();
|
||||
TValidator{}(src);
|
||||
dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
|
||||
dst = src;
|
||||
}
|
||||
|
||||
// Gets a new value from EAX call,
|
||||
// validates it,
|
||||
// sets a dirty flag without comparing the values,
|
||||
// and assigns the new value.
|
||||
template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
|
||||
static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
|
||||
EaxDirtyFlags& dirty_flags)
|
||||
{
|
||||
const auto& src = call.get_value<Exception, const TProperties>();
|
||||
TValidator{}(src);
|
||||
dirty_flags |= TDirtyBit;
|
||||
dst = src;
|
||||
}
|
||||
|
||||
constexpr bool eax4_fx_slot_is_legacy() const noexcept
|
||||
{ return eax_fx_slot_index_ < 2; }
|
||||
|
||||
void eax4_fx_slot_ensure_unlocked() const;
|
||||
|
||||
static ALenum eax_get_efx_effect_type(const GUID& guid);
|
||||
const GUID& eax_get_eax_default_effect_guid() const noexcept;
|
||||
long eax_get_eax_default_lock() const noexcept;
|
||||
|
||||
void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
|
||||
void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
|
||||
void eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept;
|
||||
void eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept;
|
||||
void eax_fx_slot_set_current_defaults();
|
||||
void eax_fx_slot_set_defaults();
|
||||
|
||||
void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props) const;
|
||||
void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props) const;
|
||||
void eax_fx_slot_get(const EaxCall& call) const;
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax_get(const EaxCall& call);
|
||||
|
||||
void eax_fx_slot_load_effect(int version, ALenum altype);
|
||||
void eax_fx_slot_set_volume();
|
||||
void eax_fx_slot_set_environment_flag();
|
||||
void eax_fx_slot_set_flags();
|
||||
|
||||
void eax4_fx_slot_set_all(const EaxCall& call);
|
||||
void eax5_fx_slot_set_all(const EaxCall& call);
|
||||
|
||||
bool eax_fx_slot_should_update_sources() const noexcept;
|
||||
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax4_fx_slot_set(const EaxCall& call);
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax5_fx_slot_set(const EaxCall& call);
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax_fx_slot_set(const EaxCall& call);
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax_set(const EaxCall& call);
|
||||
|
||||
template<
|
||||
EaxDirtyFlags TDirtyBit,
|
||||
typename TMemberResult,
|
||||
typename TProps,
|
||||
typename TState>
|
||||
void eax_fx_slot_commit_property(TState& state, EaxDirtyFlags& dst_df,
|
||||
TMemberResult TProps::*member) noexcept
|
||||
{
|
||||
auto& src_i = state.i;
|
||||
auto& dst_i = eax_;
|
||||
|
||||
if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
|
||||
{
|
||||
dst_df |= TDirtyBit;
|
||||
dst_i.*member = src_i.*member;
|
||||
}
|
||||
}
|
||||
|
||||
void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
|
||||
void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
|
||||
|
||||
// `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
|
||||
void eax_set_efx_slot_effect(EaxEffect &effect);
|
||||
|
||||
// `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
|
||||
void eax_set_efx_slot_send_auto(bool is_send_auto);
|
||||
|
||||
// `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
|
||||
void eax_set_efx_slot_gain(ALfloat gain);
|
||||
|
||||
public:
|
||||
class EaxDeleter {
|
||||
public:
|
||||
void operator()(ALeffectslot *effect_slot);
|
||||
};
|
||||
#endif // ALSOFT_EAX
|
||||
};
|
||||
|
||||
void UpdateAllEffectSlotProps(ALCcontext *context);
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
|
||||
|
||||
EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
|
||||
void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
#endif
|
||||
1692
externals/openal-soft/al/buffer.cpp
vendored
Normal file
1692
externals/openal-soft/al/buffer.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
externals/openal-soft/al/buffer.h
vendored
Normal file
58
externals/openal-soft/al/buffer.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef AL_BUFFER_H
|
||||
#define AL_BUFFER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "albyte.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "almalloc.h"
|
||||
#include "atomic.h"
|
||||
#include "core/buffer_storage.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "eax/x_ram.h"
|
||||
|
||||
enum class EaxStorage : uint8_t {
|
||||
Automatic,
|
||||
Accessible,
|
||||
Hardware
|
||||
};
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
struct ALbuffer : public BufferStorage {
|
||||
ALbitfieldSOFT Access{0u};
|
||||
|
||||
al::vector<al::byte,16> mDataStorage;
|
||||
|
||||
ALuint OriginalSize{0};
|
||||
|
||||
ALuint UnpackAlign{0};
|
||||
ALuint PackAlign{0};
|
||||
ALuint UnpackAmbiOrder{1};
|
||||
|
||||
ALbitfieldSOFT MappedAccess{0u};
|
||||
ALsizei MappedOffset{0};
|
||||
ALsizei MappedSize{0};
|
||||
|
||||
ALuint mLoopStart{0u};
|
||||
ALuint mLoopEnd{0u};
|
||||
|
||||
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
|
||||
RefCount ref{0u};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{0};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
EaxStorage eax_x_ram_mode{EaxStorage::Automatic};
|
||||
bool eax_x_ram_is_hardware{};
|
||||
#endif // ALSOFT_EAX
|
||||
};
|
||||
|
||||
#endif
|
||||
1621
externals/openal-soft/al/eax/api.cpp
vendored
Normal file
1621
externals/openal-soft/al/eax/api.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1493
externals/openal-soft/al/eax/api.h
vendored
Normal file
1493
externals/openal-soft/al/eax/api.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
219
externals/openal-soft/al/eax/call.cpp
vendored
Normal file
219
externals/openal-soft/al/eax/call.cpp
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
#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}, mVersion{0}, mPropertySetId{EaxCallPropertySetId::none}
|
||||
, 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
externals/openal-soft/al/eax/call.h
vendored
Normal file
97
externals/openal-soft/al/eax/call.h
vendored
Normal 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);
|
||||
|
||||
bool is_get() const noexcept { return mCallType == EaxCallType::get; }
|
||||
bool is_deferred() const noexcept { return mIsDeferred; }
|
||||
int get_version() const noexcept { return mVersion; }
|
||||
EaxCallPropertySetId get_property_set_id() const noexcept { return mPropertySetId; }
|
||||
ALuint get_property_id() const noexcept { return mPropertyId; }
|
||||
ALuint get_property_al_name() const noexcept { return mPropertySourceId; }
|
||||
EaxFxSlotIndex get_fx_slot_index() const noexcept { return mFxSlotIndex; }
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
TValue& get_value() const
|
||||
{
|
||||
if(mPropertyBufferSize < sizeof(TValue))
|
||||
fail_too_small();
|
||||
|
||||
return *static_cast<TValue*>(mPropertyBuffer);
|
||||
}
|
||||
|
||||
template<typename TValue>
|
||||
al::span<TValue> get_values(size_t max_count) const
|
||||
{
|
||||
if(max_count == 0 || mPropertyBufferSize < sizeof(TValue))
|
||||
fail_too_small();
|
||||
|
||||
const auto count = minz(mPropertyBufferSize / sizeof(TValue), max_count);
|
||||
return al::as_span(static_cast<TValue*>(mPropertyBuffer), count);
|
||||
}
|
||||
|
||||
template<typename TValue>
|
||||
al::span<TValue> get_values() const
|
||||
{
|
||||
return get_values<TValue>(~size_t{});
|
||||
}
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
void set_value(const TValue& value) const
|
||||
{
|
||||
get_value<TException, TValue>() = value;
|
||||
}
|
||||
|
||||
private:
|
||||
const EaxCallType mCallType;
|
||||
int mVersion;
|
||||
EaxFxSlotIndex mFxSlotIndex;
|
||||
EaxCallPropertySetId mPropertySetId;
|
||||
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
|
||||
418
externals/openal-soft/al/eax/effect.h
vendored
Normal file
418
externals/openal-soft/al/eax/effect.h
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
#ifndef EAX_EFFECT_INCLUDED
|
||||
#define EAX_EFFECT_INCLUDED
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "alnumeric.h"
|
||||
#include "AL/al.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
|
||||
|
||||
/* TODO: Use std::variant (C++17). */
|
||||
enum class EaxEffectType {
|
||||
None, Reverb, Chorus, Autowah, Compressor, Distortion, Echo, Equalizer, Flanger,
|
||||
FrequencyShifter, Modulator, PitchShifter, VocalMorpher
|
||||
};
|
||||
struct EaxEffectProps {
|
||||
EaxEffectType mType;
|
||||
union {
|
||||
EAXREVERBPROPERTIES mReverb;
|
||||
EAXCHORUSPROPERTIES mChorus;
|
||||
EAXAUTOWAHPROPERTIES mAutowah;
|
||||
EAXAGCCOMPRESSORPROPERTIES mCompressor;
|
||||
EAXDISTORTIONPROPERTIES mDistortion;
|
||||
EAXECHOPROPERTIES mEcho;
|
||||
EAXEQUALIZERPROPERTIES mEqualizer;
|
||||
EAXFLANGERPROPERTIES mFlanger;
|
||||
EAXFREQUENCYSHIFTERPROPERTIES mFrequencyShifter;
|
||||
EAXRINGMODULATORPROPERTIES mModulator;
|
||||
EAXPITCHSHIFTERPROPERTIES mPitchShifter;
|
||||
EAXVOCALMORPHERPROPERTIES mVocalMorpher;
|
||||
};
|
||||
};
|
||||
|
||||
constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
|
||||
{
|
||||
switch(props.mType)
|
||||
{
|
||||
case EaxEffectType::None: break;
|
||||
case EaxEffectType::Reverb: return AL_EFFECT_EAXREVERB;
|
||||
case EaxEffectType::Chorus: return AL_EFFECT_CHORUS;
|
||||
case EaxEffectType::Autowah: return AL_EFFECT_AUTOWAH;
|
||||
case EaxEffectType::Compressor: return AL_EFFECT_COMPRESSOR;
|
||||
case EaxEffectType::Distortion: return AL_EFFECT_DISTORTION;
|
||||
case EaxEffectType::Echo: return AL_EFFECT_ECHO;
|
||||
case EaxEffectType::Equalizer: return AL_EFFECT_EQUALIZER;
|
||||
case EaxEffectType::Flanger: return AL_EFFECT_FLANGER;
|
||||
case EaxEffectType::FrequencyShifter: return AL_EFFECT_FREQUENCY_SHIFTER;
|
||||
case EaxEffectType::Modulator: return AL_EFFECT_RING_MODULATOR;
|
||||
case EaxEffectType::PitchShifter: return AL_EFFECT_PITCH_SHIFTER;
|
||||
case EaxEffectType::VocalMorpher: return AL_EFFECT_VOCAL_MORPHER;
|
||||
}
|
||||
return AL_EFFECT_NULL;
|
||||
}
|
||||
|
||||
struct EaxReverbCommitter {
|
||||
struct Exception;
|
||||
|
||||
EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
|
||||
: 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);
|
||||
bool commit(const EaxEffectProps &props);
|
||||
|
||||
static void SetDefaults(EAX_REVERBPROPERTIES &props);
|
||||
static void SetDefaults(EAX20LISTENERPROPERTIES &props);
|
||||
static void SetDefaults(EAXREVERBPROPERTIES &props);
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
|
||||
static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
|
||||
static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
|
||||
static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
|
||||
static void Get(const EaxCall &call, const EaxEffectProps &props);
|
||||
|
||||
static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EaxEffectProps &props);
|
||||
|
||||
static void translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
|
||||
static void translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept;
|
||||
static void translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EaxCommitter {
|
||||
struct Exception;
|
||||
|
||||
EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
|
||||
: 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()); }
|
||||
|
||||
bool commit(const EaxEffectProps &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EaxEffectProps &props);
|
||||
static void Set(const EaxCall &call, EaxEffectProps &props);
|
||||
};
|
||||
|
||||
struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
|
||||
using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
|
||||
using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
|
||||
using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
|
||||
using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
|
||||
using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
|
||||
using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
|
||||
using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
|
||||
using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
|
||||
using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
|
||||
using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
|
||||
using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
|
||||
};
|
||||
struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
|
||||
using EaxCommitter<EaxNullCommitter>::EaxCommitter;
|
||||
};
|
||||
|
||||
|
||||
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_{};
|
||||
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
void call_set_defaults(Args&& ...args)
|
||||
{ return T::SetDefaults(std::forward<Args>(args)...); }
|
||||
|
||||
void call_set_defaults(const ALenum altype, EaxEffectProps &props)
|
||||
{
|
||||
if(altype == AL_EFFECT_EAXREVERB)
|
||||
return call_set_defaults<EaxReverbCommitter>(props);
|
||||
if(altype == AL_EFFECT_CHORUS)
|
||||
return call_set_defaults<EaxChorusCommitter>(props);
|
||||
if(altype == AL_EFFECT_AUTOWAH)
|
||||
return call_set_defaults<EaxAutowahCommitter>(props);
|
||||
if(altype == AL_EFFECT_COMPRESSOR)
|
||||
return call_set_defaults<EaxCompressorCommitter>(props);
|
||||
if(altype == AL_EFFECT_DISTORTION)
|
||||
return call_set_defaults<EaxDistortionCommitter>(props);
|
||||
if(altype == AL_EFFECT_ECHO)
|
||||
return call_set_defaults<EaxEchoCommitter>(props);
|
||||
if(altype == AL_EFFECT_EQUALIZER)
|
||||
return call_set_defaults<EaxEqualizerCommitter>(props);
|
||||
if(altype == AL_EFFECT_FLANGER)
|
||||
return call_set_defaults<EaxFlangerCommitter>(props);
|
||||
if(altype == AL_EFFECT_FREQUENCY_SHIFTER)
|
||||
return call_set_defaults<EaxFrequencyShifterCommitter>(props);
|
||||
if(altype == AL_EFFECT_RING_MODULATOR)
|
||||
return call_set_defaults<EaxModulatorCommitter>(props);
|
||||
if(altype == AL_EFFECT_PITCH_SHIFTER)
|
||||
return call_set_defaults<EaxPitchShifterCommitter>(props);
|
||||
if(altype == AL_EFFECT_VOCAL_MORPHER)
|
||||
return call_set_defaults<EaxVocalMorpherCommitter>(props);
|
||||
return call_set_defaults<EaxNullCommitter>(props);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void init()
|
||||
{
|
||||
call_set_defaults<EaxReverbCommitter>(state1_.d);
|
||||
state1_.i = state1_.d;
|
||||
call_set_defaults<EaxReverbCommitter>(state2_.d);
|
||||
state2_.i = state2_.d;
|
||||
call_set_defaults<EaxReverbCommitter>(state3_.d);
|
||||
state3_.i = state3_.d;
|
||||
call_set_defaults<T>(state4_.d);
|
||||
state4_.i = state4_.d;
|
||||
call_set_defaults<T>(state5_.d);
|
||||
state5_.i = state5_.d;
|
||||
}
|
||||
|
||||
void set_defaults(int eax_version, ALenum altype)
|
||||
{
|
||||
switch(eax_version)
|
||||
{
|
||||
case 1: call_set_defaults<EaxReverbCommitter>(state1_.d); break;
|
||||
case 2: call_set_defaults<EaxReverbCommitter>(state2_.d); break;
|
||||
case 3: call_set_defaults<EaxReverbCommitter>(state3_.d); break;
|
||||
case 4: call_set_defaults(altype, state4_.d); break;
|
||||
case 5: call_set_defaults(altype, state5_.d); break;
|
||||
}
|
||||
changed_ = true;
|
||||
}
|
||||
|
||||
|
||||
#define EAXCALL(T, Callable, ...) \
|
||||
if(T == EaxEffectType::Reverb) \
|
||||
return Callable<EaxReverbCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Chorus) \
|
||||
return Callable<EaxChorusCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Autowah) \
|
||||
return Callable<EaxAutowahCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Compressor) \
|
||||
return Callable<EaxCompressorCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Distortion) \
|
||||
return Callable<EaxDistortionCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Echo) \
|
||||
return Callable<EaxEchoCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Equalizer) \
|
||||
return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Flanger) \
|
||||
return Callable<EaxFlangerCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::FrequencyShifter) \
|
||||
return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::Modulator) \
|
||||
return Callable<EaxModulatorCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::PitchShifter) \
|
||||
return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \
|
||||
if(T == EaxEffectType::VocalMorpher) \
|
||||
return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \
|
||||
return Callable<EaxNullCommitter>(__VA_ARGS__)
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
static void call_set(Args&& ...args)
|
||||
{ return T::Set(std::forward<Args>(args)...); }
|
||||
|
||||
static void call_set(const EaxCall &call, EaxEffectProps &props)
|
||||
{ EAXCALL(props.mType, call_set, call, props); }
|
||||
|
||||
void set(const EaxCall &call)
|
||||
{
|
||||
switch(call.get_version())
|
||||
{
|
||||
case 1: call_set<EaxReverbCommitter>(call, state1_.d); break;
|
||||
case 2: call_set<EaxReverbCommitter>(call, state2_.d); break;
|
||||
case 3: call_set<EaxReverbCommitter>(call, state3_.d); break;
|
||||
case 4: call_set(call, state4_.d); break;
|
||||
case 5: call_set(call, state5_.d); break;
|
||||
}
|
||||
changed_ = true;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
static void call_get(Args&& ...args)
|
||||
{ return T::Get(std::forward<Args>(args)...); }
|
||||
|
||||
static void call_get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{ EAXCALL(props.mType, call_get, call, props); }
|
||||
|
||||
void get(const EaxCall &call)
|
||||
{
|
||||
switch(call.get_version())
|
||||
{
|
||||
case 1: call_get<EaxReverbCommitter>(call, state1_.d); break;
|
||||
case 2: call_get<EaxReverbCommitter>(call, state2_.d); break;
|
||||
case 3: call_get<EaxReverbCommitter>(call, state3_.d); break;
|
||||
case 4: call_get(call, state4_.d); break;
|
||||
case 5: call_get(call, state5_.d); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
bool call_commit(Args&& ...args)
|
||||
{ return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); }
|
||||
|
||||
bool call_commit(const EaxEffectProps &props)
|
||||
{ EAXCALL(props.mType, call_commit, 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 |= call_commit<EaxReverbCommitter>(state1_.d);
|
||||
break;
|
||||
case 2:
|
||||
state2_.i = state2_.d;
|
||||
ret |= call_commit<EaxReverbCommitter>(state2_.d);
|
||||
break;
|
||||
case 3:
|
||||
state3_.i = state3_.d;
|
||||
ret |= call_commit<EaxReverbCommitter>(state3_.d);
|
||||
break;
|
||||
case 4:
|
||||
state4_.i = state4_.d;
|
||||
ret |= call_commit(state4_.d);
|
||||
break;
|
||||
case 5:
|
||||
state5_.i = state5_.d;
|
||||
ret |= call_commit(state5_.d);
|
||||
break;
|
||||
}
|
||||
al_effect_type_ = EnumFromEaxEffectType(props_);
|
||||
return ret;
|
||||
}
|
||||
#undef EAXCALL
|
||||
}; // EaxEffect
|
||||
|
||||
using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
|
||||
|
||||
#endif // !EAX_EFFECT_INCLUDED
|
||||
59
externals/openal-soft/al/eax/exception.cpp
vendored
Normal file
59
externals/openal-soft/al/eax/exception.cpp
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "exception.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
|
||||
EaxException::EaxException(const char *context, const char *message)
|
||||
: std::runtime_error{make_message(context, message)}
|
||||
{
|
||||
}
|
||||
EaxException::~EaxException() = default;
|
||||
|
||||
|
||||
std::string EaxException::make_message(const char *context, const char *message)
|
||||
{
|
||||
const auto context_size = (context ? std::string::traits_type::length(context) : 0);
|
||||
const auto has_contex = (context_size > 0);
|
||||
|
||||
const auto message_size = (message ? std::string::traits_type::length(message) : 0);
|
||||
const auto has_message = (message_size > 0);
|
||||
|
||||
if (!has_contex && !has_message)
|
||||
{
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
static constexpr char left_prefix[] = "[";
|
||||
const auto left_prefix_size = std::string::traits_type::length(left_prefix);
|
||||
|
||||
static constexpr char right_prefix[] = "] ";
|
||||
const auto right_prefix_size = std::string::traits_type::length(right_prefix);
|
||||
|
||||
const auto what_size =
|
||||
(
|
||||
has_contex ?
|
||||
left_prefix_size + context_size + right_prefix_size :
|
||||
0) +
|
||||
message_size +
|
||||
1;
|
||||
|
||||
auto what = std::string{};
|
||||
what.reserve(what_size);
|
||||
|
||||
if (has_contex)
|
||||
{
|
||||
what.append(left_prefix, left_prefix_size);
|
||||
what.append(context, context_size);
|
||||
what.append(right_prefix, right_prefix_size);
|
||||
}
|
||||
|
||||
if (has_message)
|
||||
{
|
||||
what.append(message, message_size);
|
||||
}
|
||||
|
||||
return what;
|
||||
}
|
||||
18
externals/openal-soft/al/eax/exception.h
vendored
Normal file
18
externals/openal-soft/al/eax/exception.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef EAX_EXCEPTION_INCLUDED
|
||||
#define EAX_EXCEPTION_INCLUDED
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
|
||||
class EaxException : public std::runtime_error {
|
||||
static std::string make_message(const char *context, const char *message);
|
||||
|
||||
public:
|
||||
EaxException(const char *context, const char *message);
|
||||
~EaxException() override;
|
||||
}; // EaxException
|
||||
|
||||
|
||||
#endif // !EAX_EXCEPTION_INCLUDED
|
||||
71
externals/openal-soft/al/eax/fx_slot_index.cpp
vendored
Normal file
71
externals/openal-soft/al/eax/fx_slot_index.cpp
vendored
Normal 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};
|
||||
}
|
||||
41
externals/openal-soft/al/eax/fx_slot_index.h
vendored
Normal file
41
externals/openal-soft/al/eax/fx_slot_index.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef EAX_FX_SLOT_INDEX_INCLUDED
|
||||
#define EAX_FX_SLOT_INDEX_INCLUDED
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "aloptional.h"
|
||||
#include "api.h"
|
||||
|
||||
|
||||
using EaxFxSlotIndexValue = std::size_t;
|
||||
|
||||
class EaxFxSlotIndex : public al::optional<EaxFxSlotIndexValue>
|
||||
{
|
||||
public:
|
||||
using al::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
externals/openal-soft/al/eax/fx_slots.cpp
vendored
Normal file
75
externals/openal-soft/al/eax/fx_slots.cpp
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
49
externals/openal-soft/al/eax/fx_slots.h
vendored
Normal file
49
externals/openal-soft/al/eax/fx_slots.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
#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();
|
||||
}
|
||||
|
||||
|
||||
const ALeffectslot& get(
|
||||
EaxFxSlotIndex index) const;
|
||||
|
||||
ALeffectslot& get(
|
||||
EaxFxSlotIndex index);
|
||||
|
||||
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
|
||||
21
externals/openal-soft/al/eax/globals.cpp
vendored
Normal file
21
externals/openal-soft/al/eax/globals.cpp
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
bool eax_g_is_enabled = true;
|
||||
|
||||
|
||||
const char eax1_ext_name[] = "EAX";
|
||||
const char eax2_ext_name[] = "EAX2.0";
|
||||
const char eax3_ext_name[] = "EAX3.0";
|
||||
const char eax4_ext_name[] = "EAX4.0";
|
||||
const char eax5_ext_name[] = "EAX5.0";
|
||||
|
||||
const char eax_x_ram_ext_name[] = "EAX-RAM";
|
||||
|
||||
const char eax_eax_set_func_name[] = "EAXSet";
|
||||
const char eax_eax_get_func_name[] = "EAXGet";
|
||||
|
||||
const char eax_eax_set_buffer_mode_func_name[] = "EAXSetBufferMode";
|
||||
const char eax_eax_get_buffer_mode_func_name[] = "EAXGetBufferMode";
|
||||
22
externals/openal-soft/al/eax/globals.h
vendored
Normal file
22
externals/openal-soft/al/eax/globals.h
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef EAX_GLOBALS_INCLUDED
|
||||
#define EAX_GLOBALS_INCLUDED
|
||||
|
||||
|
||||
extern bool eax_g_is_enabled;
|
||||
|
||||
|
||||
extern const char eax1_ext_name[];
|
||||
extern const char eax2_ext_name[];
|
||||
extern const char eax3_ext_name[];
|
||||
extern const char eax4_ext_name[];
|
||||
extern const char eax5_ext_name[];
|
||||
|
||||
extern const char eax_x_ram_ext_name[];
|
||||
|
||||
extern const char eax_eax_set_func_name[];
|
||||
extern const char eax_eax_get_func_name[];
|
||||
|
||||
extern const char eax_eax_set_buffer_mode_func_name[];
|
||||
extern const char eax_eax_get_buffer_mode_func_name[];
|
||||
|
||||
#endif // !EAX_GLOBALS_INCLUDED
|
||||
26
externals/openal-soft/al/eax/utils.cpp
vendored
Normal file
26
externals/openal-soft/al/eax/utils.cpp
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
|
||||
void eax_log_exception(const char *message) noexcept
|
||||
{
|
||||
const auto exception_ptr = std::current_exception();
|
||||
assert(exception_ptr);
|
||||
|
||||
try {
|
||||
std::rethrow_exception(exception_ptr);
|
||||
}
|
||||
catch(const std::exception& ex) {
|
||||
const auto ex_message = ex.what();
|
||||
ERR("%s %s\n", message ? message : "", ex_message);
|
||||
}
|
||||
catch(...) {
|
||||
ERR("%s %s\n", message ? message : "", "Generic exception.");
|
||||
}
|
||||
}
|
||||
95
externals/openal-soft/al/eax/utils.h
vendored
Normal file
95
externals/openal-soft/al/eax/utils.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef EAX_UTILS_INCLUDED
|
||||
#define EAX_UTILS_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
using EaxDirtyFlags = unsigned int;
|
||||
|
||||
struct EaxAlLowPassParam {
|
||||
float gain;
|
||||
float gain_hf;
|
||||
};
|
||||
|
||||
void eax_log_exception(const char *message) noexcept;
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
void eax_validate_range(
|
||||
const char* value_name,
|
||||
const TValue& value,
|
||||
const TValue& min_value,
|
||||
const TValue& max_value)
|
||||
{
|
||||
if (value >= min_value && value <= max_value)
|
||||
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
|
||||
38
externals/openal-soft/al/eax/x_ram.h
vendored
Normal file
38
externals/openal-soft/al/eax/x_ram.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#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";
|
||||
|
||||
|
||||
ALboolean AL_APIENTRY EAXSetBufferMode(
|
||||
ALsizei n,
|
||||
const ALuint* buffers,
|
||||
ALint value);
|
||||
|
||||
ALenum AL_APIENTRY EAXGetBufferMode(
|
||||
ALuint buffer,
|
||||
ALint* pReserved);
|
||||
|
||||
|
||||
#endif // !EAX_X_RAM_INCLUDED
|
||||
766
externals/openal-soft/al/effect.cpp
vendored
Normal file
766
externals/openal-soft/al/effect.cpp
vendored
Normal file
@@ -0,0 +1,766 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "effect.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
#include "AL/efx-presets.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "albit.h"
|
||||
#include "alc/context.h"
|
||||
#include "alc/device.h"
|
||||
#include "alc/effects/base.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alstring.h"
|
||||
#include "core/except.h"
|
||||
#include "core/logging.h"
|
||||
#include "opthelpers.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
|
||||
#include "eax/exception.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
const EffectList gEffectList[16]{
|
||||
{ "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
|
||||
{ "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
|
||||
{ "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
|
||||
{ "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
|
||||
{ "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
|
||||
{ "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
|
||||
{ "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
|
||||
{ "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
|
||||
{ "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
|
||||
{ "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
|
||||
{ "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
|
||||
{ "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
|
||||
{ "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER },
|
||||
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
|
||||
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
|
||||
{ "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_REVERB_SOFT },
|
||||
};
|
||||
|
||||
bool DisabledEffects[MAX_EFFECTS];
|
||||
|
||||
|
||||
effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
|
||||
{
|
||||
std::va_list args;
|
||||
va_start(args, msg);
|
||||
setMessage(msg, args);
|
||||
va_end(args);
|
||||
}
|
||||
effect_exception::~effect_exception() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
struct EffectPropsItem {
|
||||
ALenum Type;
|
||||
const EffectProps &DefaultProps;
|
||||
const EffectVtable &Vtable;
|
||||
};
|
||||
constexpr EffectPropsItem EffectPropsList[] = {
|
||||
{ AL_EFFECT_NULL, NullEffectProps, NullEffectVtable },
|
||||
{ AL_EFFECT_EAXREVERB, ReverbEffectProps, ReverbEffectVtable },
|
||||
{ AL_EFFECT_REVERB, StdReverbEffectProps, StdReverbEffectVtable },
|
||||
{ AL_EFFECT_AUTOWAH, AutowahEffectProps, AutowahEffectVtable },
|
||||
{ AL_EFFECT_CHORUS, ChorusEffectProps, ChorusEffectVtable },
|
||||
{ AL_EFFECT_COMPRESSOR, CompressorEffectProps, CompressorEffectVtable },
|
||||
{ AL_EFFECT_DISTORTION, DistortionEffectProps, DistortionEffectVtable },
|
||||
{ AL_EFFECT_ECHO, EchoEffectProps, EchoEffectVtable },
|
||||
{ AL_EFFECT_EQUALIZER, EqualizerEffectProps, EqualizerEffectVtable },
|
||||
{ AL_EFFECT_FLANGER, FlangerEffectProps, FlangerEffectVtable },
|
||||
{ AL_EFFECT_FREQUENCY_SHIFTER, FshifterEffectProps, FshifterEffectVtable },
|
||||
{ AL_EFFECT_RING_MODULATOR, ModulatorEffectProps, ModulatorEffectVtable },
|
||||
{ AL_EFFECT_PITCH_SHIFTER, PshifterEffectProps, PshifterEffectVtable },
|
||||
{ AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable },
|
||||
{ AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable },
|
||||
{ AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable },
|
||||
{ AL_EFFECT_CONVOLUTION_REVERB_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable },
|
||||
};
|
||||
|
||||
|
||||
void ALeffect_setParami(ALeffect *effect, ALenum param, int value)
|
||||
{ effect->vtab->setParami(&effect->Props, param, value); }
|
||||
void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values)
|
||||
{ effect->vtab->setParamiv(&effect->Props, param, values); }
|
||||
void ALeffect_setParamf(ALeffect *effect, ALenum param, float value)
|
||||
{ effect->vtab->setParamf(&effect->Props, param, value); }
|
||||
void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values)
|
||||
{ effect->vtab->setParamfv(&effect->Props, param, values); }
|
||||
|
||||
void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value)
|
||||
{ effect->vtab->getParami(&effect->Props, param, value); }
|
||||
void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values)
|
||||
{ effect->vtab->getParamiv(&effect->Props, param, values); }
|
||||
void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value)
|
||||
{ effect->vtab->getParamf(&effect->Props, param, value); }
|
||||
void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values)
|
||||
{ effect->vtab->getParamfv(&effect->Props, param, values); }
|
||||
|
||||
|
||||
const EffectPropsItem *getEffectPropsItemByType(ALenum type)
|
||||
{
|
||||
auto iter = std::find_if(std::begin(EffectPropsList), std::end(EffectPropsList),
|
||||
[type](const EffectPropsItem &item) noexcept -> bool
|
||||
{ return item.Type == type; });
|
||||
return (iter != std::end(EffectPropsList)) ? al::to_address(iter) : nullptr;
|
||||
}
|
||||
|
||||
void InitEffectParams(ALeffect *effect, ALenum type)
|
||||
{
|
||||
const EffectPropsItem *item{getEffectPropsItemByType(type)};
|
||||
if(item)
|
||||
{
|
||||
effect->Props = item->DefaultProps;
|
||||
effect->vtab = &item->Vtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
effect->Props = EffectProps{};
|
||||
effect->vtab = &NullEffectVtable;
|
||||
}
|
||||
effect->type = type;
|
||||
}
|
||||
|
||||
bool EnsureEffects(ALCdevice *device, size_t needed)
|
||||
{
|
||||
size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
|
||||
[](size_t cur, const EffectSubList &sublist) noexcept -> size_t
|
||||
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
|
||||
|
||||
while(needed > count)
|
||||
{
|
||||
if(device->EffectList.size() >= 1<<25) UNLIKELY
|
||||
return false;
|
||||
|
||||
device->EffectList.emplace_back();
|
||||
auto sublist = device->EffectList.end() - 1;
|
||||
sublist->FreeMask = ~0_u64;
|
||||
sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
|
||||
if(!sublist->Effects) UNLIKELY
|
||||
{
|
||||
device->EffectList.pop_back();
|
||||
return false;
|
||||
}
|
||||
count += 64;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ALeffect *AllocEffect(ALCdevice *device)
|
||||
{
|
||||
auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
|
||||
[](const EffectSubList &entry) noexcept -> bool
|
||||
{ return entry.FreeMask != 0; });
|
||||
auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
|
||||
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
|
||||
ASSUME(slidx < 64);
|
||||
|
||||
ALeffect *effect{al::construct_at(sublist->Effects + slidx)};
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
|
||||
/* Add 1 to avoid effect ID 0. */
|
||||
effect->id = ((lidx<<6) | slidx) + 1;
|
||||
|
||||
sublist->FreeMask &= ~(1_u64 << slidx);
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
void FreeEffect(ALCdevice *device, ALeffect *effect)
|
||||
{
|
||||
const ALuint id{effect->id - 1};
|
||||
const size_t lidx{id >> 6};
|
||||
const ALuint slidx{id & 0x3f};
|
||||
|
||||
al::destroy_at(effect);
|
||||
|
||||
device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
|
||||
}
|
||||
|
||||
inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
|
||||
{
|
||||
const size_t lidx{(id-1) >> 6};
|
||||
const ALuint slidx{(id-1) & 0x3f};
|
||||
|
||||
if(lidx >= device->EffectList.size()) UNLIKELY
|
||||
return nullptr;
|
||||
EffectSubList &sublist = device->EffectList[lidx];
|
||||
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
|
||||
return nullptr;
|
||||
return sublist.Effects + slidx;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(n < 0) UNLIKELY
|
||||
context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
|
||||
if(n <= 0) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
if(!EnsureEffects(device, static_cast<ALuint>(n)))
|
||||
{
|
||||
context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n == 1) LIKELY
|
||||
{
|
||||
/* Special handling for the easy and normal case. */
|
||||
ALeffect *effect{AllocEffect(device)};
|
||||
effects[0] = effect->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Store the allocated buffer IDs in a separate local list, to avoid
|
||||
* modifying the user storage in case of failure.
|
||||
*/
|
||||
al::vector<ALuint> ids;
|
||||
ids.reserve(static_cast<ALuint>(n));
|
||||
do {
|
||||
ALeffect *effect{AllocEffect(device)};
|
||||
ids.emplace_back(effect->id);
|
||||
} while(--n);
|
||||
std::copy(ids.cbegin(), ids.cend(), effects);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(n < 0) UNLIKELY
|
||||
context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
|
||||
if(n <= 0) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
/* First try to find any effects that are invalid. */
|
||||
auto validate_effect = [device](const ALuint eid) -> bool
|
||||
{ return !eid || LookupEffect(device, eid) != nullptr; };
|
||||
|
||||
const ALuint *effects_end = effects + n;
|
||||
auto inveffect = std::find_if_not(effects, effects_end, validate_effect);
|
||||
if(inveffect != effects_end) UNLIKELY
|
||||
{
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All good. Delete non-0 effect IDs. */
|
||||
auto delete_effect = [device](ALuint eid) -> void
|
||||
{
|
||||
ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
|
||||
if(effect) FreeEffect(device, effect);
|
||||
};
|
||||
std::for_each(effects, effects_end, delete_effect);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(context) LIKELY
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
if(!effect || LookupEffect(device, effect))
|
||||
return AL_TRUE;
|
||||
}
|
||||
return AL_FALSE;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else if(param == AL_EFFECT_TYPE)
|
||||
{
|
||||
bool isOk{value == AL_EFFECT_NULL};
|
||||
if(!isOk)
|
||||
{
|
||||
for(const EffectList &effectitem : gEffectList)
|
||||
{
|
||||
if(value == effectitem.val && !DisabledEffects[effectitem.type])
|
||||
{
|
||||
isOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isOk)
|
||||
InitEffectParams(aleffect, value);
|
||||
else
|
||||
context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
|
||||
}
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParami(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_EFFECT_TYPE:
|
||||
alEffecti(effect, param, values[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParamiv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParamf(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParamfv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else if(param == AL_EFFECT_TYPE)
|
||||
*value = aleffect->type;
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParami(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_EFFECT_TYPE:
|
||||
alGetEffecti(effect, param, values);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamiv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamf(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamfv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
void InitEffect(ALeffect *effect)
|
||||
{
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
}
|
||||
|
||||
EffectSubList::~EffectSubList()
|
||||
{
|
||||
uint64_t usemask{~FreeMask};
|
||||
while(usemask)
|
||||
{
|
||||
const int idx{al::countr_zero(usemask)};
|
||||
al::destroy_at(Effects+idx);
|
||||
usemask &= ~(1_u64 << idx);
|
||||
}
|
||||
FreeMask = ~usemask;
|
||||
al_free(Effects);
|
||||
Effects = nullptr;
|
||||
}
|
||||
|
||||
|
||||
#define DECL(x) { #x, EFX_REVERB_PRESET_##x }
|
||||
static const struct {
|
||||
const char name[32];
|
||||
EFXEAXREVERBPROPERTIES props;
|
||||
} reverblist[] = {
|
||||
DECL(GENERIC),
|
||||
DECL(PADDEDCELL),
|
||||
DECL(ROOM),
|
||||
DECL(BATHROOM),
|
||||
DECL(LIVINGROOM),
|
||||
DECL(STONEROOM),
|
||||
DECL(AUDITORIUM),
|
||||
DECL(CONCERTHALL),
|
||||
DECL(CAVE),
|
||||
DECL(ARENA),
|
||||
DECL(HANGAR),
|
||||
DECL(CARPETEDHALLWAY),
|
||||
DECL(HALLWAY),
|
||||
DECL(STONECORRIDOR),
|
||||
DECL(ALLEY),
|
||||
DECL(FOREST),
|
||||
DECL(CITY),
|
||||
DECL(MOUNTAINS),
|
||||
DECL(QUARRY),
|
||||
DECL(PLAIN),
|
||||
DECL(PARKINGLOT),
|
||||
DECL(SEWERPIPE),
|
||||
DECL(UNDERWATER),
|
||||
DECL(DRUGGED),
|
||||
DECL(DIZZY),
|
||||
DECL(PSYCHOTIC),
|
||||
|
||||
DECL(CASTLE_SMALLROOM),
|
||||
DECL(CASTLE_SHORTPASSAGE),
|
||||
DECL(CASTLE_MEDIUMROOM),
|
||||
DECL(CASTLE_LARGEROOM),
|
||||
DECL(CASTLE_LONGPASSAGE),
|
||||
DECL(CASTLE_HALL),
|
||||
DECL(CASTLE_CUPBOARD),
|
||||
DECL(CASTLE_COURTYARD),
|
||||
DECL(CASTLE_ALCOVE),
|
||||
|
||||
DECL(FACTORY_SMALLROOM),
|
||||
DECL(FACTORY_SHORTPASSAGE),
|
||||
DECL(FACTORY_MEDIUMROOM),
|
||||
DECL(FACTORY_LARGEROOM),
|
||||
DECL(FACTORY_LONGPASSAGE),
|
||||
DECL(FACTORY_HALL),
|
||||
DECL(FACTORY_CUPBOARD),
|
||||
DECL(FACTORY_COURTYARD),
|
||||
DECL(FACTORY_ALCOVE),
|
||||
|
||||
DECL(ICEPALACE_SMALLROOM),
|
||||
DECL(ICEPALACE_SHORTPASSAGE),
|
||||
DECL(ICEPALACE_MEDIUMROOM),
|
||||
DECL(ICEPALACE_LARGEROOM),
|
||||
DECL(ICEPALACE_LONGPASSAGE),
|
||||
DECL(ICEPALACE_HALL),
|
||||
DECL(ICEPALACE_CUPBOARD),
|
||||
DECL(ICEPALACE_COURTYARD),
|
||||
DECL(ICEPALACE_ALCOVE),
|
||||
|
||||
DECL(SPACESTATION_SMALLROOM),
|
||||
DECL(SPACESTATION_SHORTPASSAGE),
|
||||
DECL(SPACESTATION_MEDIUMROOM),
|
||||
DECL(SPACESTATION_LARGEROOM),
|
||||
DECL(SPACESTATION_LONGPASSAGE),
|
||||
DECL(SPACESTATION_HALL),
|
||||
DECL(SPACESTATION_CUPBOARD),
|
||||
DECL(SPACESTATION_ALCOVE),
|
||||
|
||||
DECL(WOODEN_SMALLROOM),
|
||||
DECL(WOODEN_SHORTPASSAGE),
|
||||
DECL(WOODEN_MEDIUMROOM),
|
||||
DECL(WOODEN_LARGEROOM),
|
||||
DECL(WOODEN_LONGPASSAGE),
|
||||
DECL(WOODEN_HALL),
|
||||
DECL(WOODEN_CUPBOARD),
|
||||
DECL(WOODEN_COURTYARD),
|
||||
DECL(WOODEN_ALCOVE),
|
||||
|
||||
DECL(SPORT_EMPTYSTADIUM),
|
||||
DECL(SPORT_SQUASHCOURT),
|
||||
DECL(SPORT_SMALLSWIMMINGPOOL),
|
||||
DECL(SPORT_LARGESWIMMINGPOOL),
|
||||
DECL(SPORT_GYMNASIUM),
|
||||
DECL(SPORT_FULLSTADIUM),
|
||||
DECL(SPORT_STADIUMTANNOY),
|
||||
|
||||
DECL(PREFAB_WORKSHOP),
|
||||
DECL(PREFAB_SCHOOLROOM),
|
||||
DECL(PREFAB_PRACTISEROOM),
|
||||
DECL(PREFAB_OUTHOUSE),
|
||||
DECL(PREFAB_CARAVAN),
|
||||
|
||||
DECL(DOME_TOMB),
|
||||
DECL(PIPE_SMALL),
|
||||
DECL(DOME_SAINTPAULS),
|
||||
DECL(PIPE_LONGTHIN),
|
||||
DECL(PIPE_LARGE),
|
||||
DECL(PIPE_RESONANT),
|
||||
|
||||
DECL(OUTDOORS_BACKYARD),
|
||||
DECL(OUTDOORS_ROLLINGPLAINS),
|
||||
DECL(OUTDOORS_DEEPCANYON),
|
||||
DECL(OUTDOORS_CREEK),
|
||||
DECL(OUTDOORS_VALLEY),
|
||||
|
||||
DECL(MOOD_HEAVEN),
|
||||
DECL(MOOD_HELL),
|
||||
DECL(MOOD_MEMORY),
|
||||
|
||||
DECL(DRIVING_COMMENTATOR),
|
||||
DECL(DRIVING_PITGARAGE),
|
||||
DECL(DRIVING_INCAR_RACER),
|
||||
DECL(DRIVING_INCAR_SPORTS),
|
||||
DECL(DRIVING_INCAR_LUXURY),
|
||||
DECL(DRIVING_FULLGRANDSTAND),
|
||||
DECL(DRIVING_EMPTYGRANDSTAND),
|
||||
DECL(DRIVING_TUNNEL),
|
||||
|
||||
DECL(CITY_STREETS),
|
||||
DECL(CITY_SUBWAY),
|
||||
DECL(CITY_MUSEUM),
|
||||
DECL(CITY_LIBRARY),
|
||||
DECL(CITY_UNDERPASS),
|
||||
DECL(CITY_ABANDONED),
|
||||
|
||||
DECL(DUSTYROOM),
|
||||
DECL(CHAPEL),
|
||||
DECL(SMALLWATERROOM),
|
||||
};
|
||||
#undef DECL
|
||||
|
||||
void LoadReverbPreset(const char *name, ALeffect *effect)
|
||||
{
|
||||
if(al::strcasecmp(name, "NONE") == 0)
|
||||
{
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
TRACE("Loading reverb '%s'\n", "NONE");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!DisabledEffects[EAXREVERB_EFFECT])
|
||||
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
|
||||
else if(!DisabledEffects[REVERB_EFFECT])
|
||||
InitEffectParams(effect, AL_EFFECT_REVERB);
|
||||
else
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
for(const auto &reverbitem : reverblist)
|
||||
{
|
||||
const EFXEAXREVERBPROPERTIES *props;
|
||||
|
||||
if(al::strcasecmp(name, reverbitem.name) != 0)
|
||||
continue;
|
||||
|
||||
TRACE("Loading reverb '%s'\n", reverbitem.name);
|
||||
props = &reverbitem.props;
|
||||
effect->Props.Reverb.Density = props->flDensity;
|
||||
effect->Props.Reverb.Diffusion = props->flDiffusion;
|
||||
effect->Props.Reverb.Gain = props->flGain;
|
||||
effect->Props.Reverb.GainHF = props->flGainHF;
|
||||
effect->Props.Reverb.GainLF = props->flGainLF;
|
||||
effect->Props.Reverb.DecayTime = props->flDecayTime;
|
||||
effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
|
||||
effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
|
||||
effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
|
||||
effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
|
||||
effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
|
||||
effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
|
||||
effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
|
||||
effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
|
||||
effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
|
||||
effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
|
||||
effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
|
||||
effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
|
||||
effect->Props.Reverb.EchoTime = props->flEchoTime;
|
||||
effect->Props.Reverb.EchoDepth = props->flEchoDepth;
|
||||
effect->Props.Reverb.ModulationTime = props->flModulationTime;
|
||||
effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
|
||||
effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
|
||||
effect->Props.Reverb.HFReference = props->flHFReference;
|
||||
effect->Props.Reverb.LFReference = props->flLFReference;
|
||||
effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
|
||||
effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
WARN("Reverb preset '%s' not found\n", name);
|
||||
}
|
||||
|
||||
bool IsValidEffectType(ALenum type) noexcept
|
||||
{
|
||||
if(type == AL_EFFECT_NULL)
|
||||
return true;
|
||||
|
||||
for(const auto &effect_item : gEffectList)
|
||||
{
|
||||
if(type == effect_item.val && !DisabledEffects[effect_item.type])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
62
externals/openal-soft/al/effect.h
vendored
Normal file
62
externals/openal-soft/al/effect.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef AL_EFFECT_H
|
||||
#define AL_EFFECT_H
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "al/effects/effects.h"
|
||||
#include "alc/effects/base.h"
|
||||
|
||||
|
||||
enum {
|
||||
EAXREVERB_EFFECT = 0,
|
||||
REVERB_EFFECT,
|
||||
AUTOWAH_EFFECT,
|
||||
CHORUS_EFFECT,
|
||||
COMPRESSOR_EFFECT,
|
||||
DISTORTION_EFFECT,
|
||||
ECHO_EFFECT,
|
||||
EQUALIZER_EFFECT,
|
||||
FLANGER_EFFECT,
|
||||
FSHIFTER_EFFECT,
|
||||
MODULATOR_EFFECT,
|
||||
PSHIFTER_EFFECT,
|
||||
VMORPHER_EFFECT,
|
||||
DEDICATED_EFFECT,
|
||||
CONVOLUTION_EFFECT,
|
||||
|
||||
MAX_EFFECTS
|
||||
};
|
||||
extern bool DisabledEffects[MAX_EFFECTS];
|
||||
|
||||
extern float ReverbBoost;
|
||||
|
||||
struct EffectList {
|
||||
const char name[16];
|
||||
int type;
|
||||
ALenum val;
|
||||
};
|
||||
extern const EffectList gEffectList[16];
|
||||
|
||||
|
||||
struct ALeffect {
|
||||
// Effect type (AL_EFFECT_NULL, ...)
|
||||
ALenum type{AL_EFFECT_NULL};
|
||||
|
||||
EffectProps Props{};
|
||||
|
||||
const EffectVtable *vtab{nullptr};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{0u};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
};
|
||||
|
||||
void InitEffect(ALeffect *effect);
|
||||
|
||||
void LoadReverbPreset(const char *name, ALeffect *effect);
|
||||
|
||||
bool IsValidEffectType(ALenum type) noexcept;
|
||||
|
||||
#endif
|
||||
252
externals/openal-soft/al/effects/autowah.cpp
vendored
Normal file
252
externals/openal-soft/al/effects/autowah.cpp
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "AL/efx.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)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_AUTOWAH_ATTACK_TIME:
|
||||
if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Autowah attack time out of range"};
|
||||
props->Autowah.AttackTime = val;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_RELEASE_TIME:
|
||||
if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Autowah release time out of range"};
|
||||
props->Autowah.ReleaseTime = val;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_RESONANCE:
|
||||
if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Autowah resonance out of range"};
|
||||
props->Autowah.Resonance = val;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_PEAK_GAIN:
|
||||
if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Autowah peak gain out of range"};
|
||||
props->Autowah.PeakGain = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Autowah_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Autowah_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Autowah_setParami(EffectProps*, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
|
||||
void Autowah_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
void Autowah_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_AUTOWAH_ATTACK_TIME:
|
||||
*val = props->Autowah.AttackTime;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_RELEASE_TIME:
|
||||
*val = props->Autowah.ReleaseTime;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_RESONANCE:
|
||||
*val = props->Autowah.Resonance;
|
||||
break;
|
||||
|
||||
case AL_AUTOWAH_PEAK_GAIN:
|
||||
*val = props->Autowah.PeakGain;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
|
||||
}
|
||||
|
||||
}
|
||||
void Autowah_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Autowah_getParamf(props, param, vals); }
|
||||
|
||||
void Autowah_getParami(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
|
||||
void Autowah_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
|
||||
props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
|
||||
props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
|
||||
props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Autowah);
|
||||
|
||||
const EffectProps AutowahEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using AutowahCommitter = EaxCommitter<EaxAutowahCommitter>;
|
||||
|
||||
struct AttackTimeValidator {
|
||||
void operator()(float flAttackTime) const
|
||||
{
|
||||
eax_validate_range<AutowahCommitter::Exception>(
|
||||
"Attack Time",
|
||||
flAttackTime,
|
||||
EAXAUTOWAH_MINATTACKTIME,
|
||||
EAXAUTOWAH_MAXATTACKTIME);
|
||||
}
|
||||
}; // AttackTimeValidator
|
||||
|
||||
struct ReleaseTimeValidator {
|
||||
void operator()(float flReleaseTime) const
|
||||
{
|
||||
eax_validate_range<AutowahCommitter::Exception>(
|
||||
"Release Time",
|
||||
flReleaseTime,
|
||||
EAXAUTOWAH_MINRELEASETIME,
|
||||
EAXAUTOWAH_MAXRELEASETIME);
|
||||
}
|
||||
}; // ReleaseTimeValidator
|
||||
|
||||
struct ResonanceValidator {
|
||||
void operator()(long lResonance) const
|
||||
{
|
||||
eax_validate_range<AutowahCommitter::Exception>(
|
||||
"Resonance",
|
||||
lResonance,
|
||||
EAXAUTOWAH_MINRESONANCE,
|
||||
EAXAUTOWAH_MAXRESONANCE);
|
||||
}
|
||||
}; // ResonanceValidator
|
||||
|
||||
struct PeakLevelValidator {
|
||||
void operator()(long lPeakLevel) const
|
||||
{
|
||||
eax_validate_range<AutowahCommitter::Exception>(
|
||||
"Peak Level",
|
||||
lPeakLevel,
|
||||
EAXAUTOWAH_MINPEAKLEVEL,
|
||||
EAXAUTOWAH_MAXPEAKLEVEL);
|
||||
}
|
||||
}; // PeakLevelValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXAUTOWAHPROPERTIES& all) const
|
||||
{
|
||||
AttackTimeValidator{}(all.flAttackTime);
|
||||
ReleaseTimeValidator{}(all.flReleaseTime);
|
||||
ResonanceValidator{}(all.lResonance);
|
||||
PeakLevelValidator{}(all.lPeakLevel);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct AutowahCommitter::Exception : public EaxException
|
||||
{
|
||||
explicit Exception(const char *message) : EaxException{"EAX_AUTOWAH_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void AutowahCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AutowahCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mAutowah.flAttackTime == props.mAutowah.flAttackTime
|
||||
&& mEaxProps.mAutowah.flReleaseTime == props.mAutowah.flReleaseTime
|
||||
&& mEaxProps.mAutowah.lResonance == props.mAutowah.lResonance
|
||||
&& mEaxProps.mAutowah.lPeakLevel == props.mAutowah.lPeakLevel)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Autowah.AttackTime = props.mAutowah.flAttackTime;
|
||||
mAlProps.Autowah.ReleaseTime = props.mAutowah.flReleaseTime;
|
||||
mAlProps.Autowah.Resonance = level_mb_to_gain(static_cast<float>(props.mAutowah.lResonance));
|
||||
mAlProps.Autowah.PeakGain = level_mb_to_gain(static_cast<float>(props.mAutowah.lPeakLevel));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Autowah;
|
||||
props.mAutowah.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
|
||||
props.mAutowah.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
|
||||
props.mAutowah.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
|
||||
props.mAutowah.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXAUTOWAH_NONE: break;
|
||||
case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props.mAutowah); break;
|
||||
case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.mAutowah.flAttackTime); break;
|
||||
case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.mAutowah.flReleaseTime); break;
|
||||
case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.mAutowah.lResonance); break;
|
||||
case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(props.mAutowah.lPeakLevel); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXAUTOWAH_NONE: break;
|
||||
case EAXAUTOWAH_ALLPARAMETERS: defer<AllValidator>(call, props.mAutowah); break;
|
||||
case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.mAutowah.flAttackTime); break;
|
||||
case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.mAutowah.flReleaseTime); break;
|
||||
case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.mAutowah.lResonance); break;
|
||||
case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(call, props.mAutowah.lPeakLevel); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
724
externals/openal-soft/al/effects/chorus.cpp
vendored
Normal file
724
externals/openal-soft/al/effects/chorus.cpp
vendored
Normal file
@@ -0,0 +1,724 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "aloptional.h"
|
||||
#include "core/logging.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static_assert(ChorusMaxDelay >= AL_CHORUS_MAX_DELAY, "Chorus max delay too small");
|
||||
static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too small");
|
||||
|
||||
static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
|
||||
static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
|
||||
|
||||
inline al::optional<ChorusWaveform> WaveformFromEnum(ALenum type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid;
|
||||
case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle;
|
||||
}
|
||||
return al::nullopt;
|
||||
}
|
||||
inline ALenum EnumFromWaveform(ChorusWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
|
||||
case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
|
||||
}
|
||||
throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Chorus_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEnum(val))
|
||||
props->Chorus.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
|
||||
break;
|
||||
|
||||
case AL_CHORUS_PHASE:
|
||||
if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
|
||||
props->Chorus.Phase = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Chorus_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Chorus_setParami(props, param, vals[0]); }
|
||||
void Chorus_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_RATE:
|
||||
if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
|
||||
props->Chorus.Rate = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DEPTH:
|
||||
if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
|
||||
props->Chorus.Depth = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_FEEDBACK:
|
||||
if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
|
||||
props->Chorus.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DELAY:
|
||||
if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
|
||||
props->Chorus.Delay = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Chorus_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Chorus_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM:
|
||||
*val = EnumFromWaveform(props->Chorus.Waveform);
|
||||
break;
|
||||
|
||||
case AL_CHORUS_PHASE:
|
||||
*val = props->Chorus.Phase;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Chorus_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Chorus_getParami(props, param, vals); }
|
||||
void Chorus_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_RATE:
|
||||
*val = props->Chorus.Rate;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DEPTH:
|
||||
*val = props->Chorus.Depth;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_FEEDBACK:
|
||||
*val = props->Chorus.Feedback;
|
||||
break;
|
||||
|
||||
case AL_CHORUS_DELAY:
|
||||
*val = props->Chorus.Delay;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Chorus_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Chorus_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultChorusProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Chorus.Waveform = *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM);
|
||||
props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
|
||||
props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
|
||||
props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
|
||||
props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
|
||||
props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
void Flanger_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEnum(val))
|
||||
props->Chorus.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
|
||||
break;
|
||||
|
||||
case AL_FLANGER_PHASE:
|
||||
if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
|
||||
props->Chorus.Phase = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Flanger_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Flanger_setParami(props, param, vals[0]); }
|
||||
void Flanger_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_RATE:
|
||||
if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
|
||||
props->Chorus.Rate = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DEPTH:
|
||||
if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
|
||||
props->Chorus.Depth = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_FEEDBACK:
|
||||
if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
|
||||
props->Chorus.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DELAY:
|
||||
if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
|
||||
props->Chorus.Delay = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Flanger_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Flanger_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM:
|
||||
*val = EnumFromWaveform(props->Chorus.Waveform);
|
||||
break;
|
||||
|
||||
case AL_FLANGER_PHASE:
|
||||
*val = props->Chorus.Phase;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Flanger_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Flanger_getParami(props, param, vals); }
|
||||
void Flanger_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_RATE:
|
||||
*val = props->Chorus.Rate;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DEPTH:
|
||||
*val = props->Chorus.Depth;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_FEEDBACK:
|
||||
*val = props->Chorus.Feedback;
|
||||
break;
|
||||
|
||||
case AL_FLANGER_DELAY:
|
||||
*val = props->Chorus.Delay;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Flanger_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Flanger_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultFlangerProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Chorus.Waveform = *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM);
|
||||
props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
|
||||
props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
|
||||
props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
|
||||
props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
|
||||
props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Chorus);
|
||||
|
||||
const EffectProps ChorusEffectProps{genDefaultChorusProps()};
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Flanger);
|
||||
|
||||
const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
|
||||
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
struct EaxChorusTraits {
|
||||
using Props = EAXCHORUSPROPERTIES;
|
||||
using Committer = EaxChorusCommitter;
|
||||
static constexpr auto Field = &EaxEffectProps::mChorus;
|
||||
|
||||
static constexpr auto eax_effect_type() { return EaxEffectType::Chorus; }
|
||||
static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; }
|
||||
|
||||
static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; }
|
||||
static constexpr auto eax_allparameters_param_id() { return EAXCHORUS_ALLPARAMETERS; }
|
||||
static constexpr auto eax_waveform_param_id() { return EAXCHORUS_WAVEFORM; }
|
||||
static constexpr auto eax_phase_param_id() { return EAXCHORUS_PHASE; }
|
||||
static constexpr auto eax_rate_param_id() { return EAXCHORUS_RATE; }
|
||||
static constexpr auto eax_depth_param_id() { return EAXCHORUS_DEPTH; }
|
||||
static constexpr auto eax_feedback_param_id() { return EAXCHORUS_FEEDBACK; }
|
||||
static constexpr auto eax_delay_param_id() { return EAXCHORUS_DELAY; }
|
||||
|
||||
static constexpr auto eax_min_waveform() { return EAXCHORUS_MINWAVEFORM; }
|
||||
static constexpr auto eax_min_phase() { return EAXCHORUS_MINPHASE; }
|
||||
static constexpr auto eax_min_rate() { return EAXCHORUS_MINRATE; }
|
||||
static constexpr auto eax_min_depth() { return EAXCHORUS_MINDEPTH; }
|
||||
static constexpr auto eax_min_feedback() { return EAXCHORUS_MINFEEDBACK; }
|
||||
static constexpr auto eax_min_delay() { return EAXCHORUS_MINDELAY; }
|
||||
|
||||
static constexpr auto eax_max_waveform() { return EAXCHORUS_MAXWAVEFORM; }
|
||||
static constexpr auto eax_max_phase() { return EAXCHORUS_MAXPHASE; }
|
||||
static constexpr auto eax_max_rate() { return EAXCHORUS_MAXRATE; }
|
||||
static constexpr auto eax_max_depth() { return EAXCHORUS_MAXDEPTH; }
|
||||
static constexpr auto eax_max_feedback() { return EAXCHORUS_MAXFEEDBACK; }
|
||||
static constexpr auto eax_max_delay() { return EAXCHORUS_MAXDELAY; }
|
||||
|
||||
static constexpr auto eax_default_waveform() { return EAXCHORUS_DEFAULTWAVEFORM; }
|
||||
static constexpr auto eax_default_phase() { return EAXCHORUS_DEFAULTPHASE; }
|
||||
static constexpr auto eax_default_rate() { return EAXCHORUS_DEFAULTRATE; }
|
||||
static constexpr auto eax_default_depth() { return EAXCHORUS_DEFAULTDEPTH; }
|
||||
static constexpr auto eax_default_feedback() { return EAXCHORUS_DEFAULTFEEDBACK; }
|
||||
static constexpr auto eax_default_delay() { return EAXCHORUS_DEFAULTDELAY; }
|
||||
|
||||
static constexpr auto efx_min_waveform() { return AL_CHORUS_MIN_WAVEFORM; }
|
||||
static constexpr auto efx_min_phase() { return AL_CHORUS_MIN_PHASE; }
|
||||
static constexpr auto efx_min_rate() { return AL_CHORUS_MIN_RATE; }
|
||||
static constexpr auto efx_min_depth() { return AL_CHORUS_MIN_DEPTH; }
|
||||
static constexpr auto efx_min_feedback() { return AL_CHORUS_MIN_FEEDBACK; }
|
||||
static constexpr auto efx_min_delay() { return AL_CHORUS_MIN_DELAY; }
|
||||
|
||||
static constexpr auto efx_max_waveform() { return AL_CHORUS_MAX_WAVEFORM; }
|
||||
static constexpr auto efx_max_phase() { return AL_CHORUS_MAX_PHASE; }
|
||||
static constexpr auto efx_max_rate() { return AL_CHORUS_MAX_RATE; }
|
||||
static constexpr auto efx_max_depth() { return AL_CHORUS_MAX_DEPTH; }
|
||||
static constexpr auto efx_max_feedback() { return AL_CHORUS_MAX_FEEDBACK; }
|
||||
static constexpr auto efx_max_delay() { return AL_CHORUS_MAX_DELAY; }
|
||||
|
||||
static constexpr auto efx_default_waveform() { return AL_CHORUS_DEFAULT_WAVEFORM; }
|
||||
static constexpr auto efx_default_phase() { return AL_CHORUS_DEFAULT_PHASE; }
|
||||
static constexpr auto efx_default_rate() { return AL_CHORUS_DEFAULT_RATE; }
|
||||
static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; }
|
||||
static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; }
|
||||
static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; }
|
||||
|
||||
static ChorusWaveform eax_waveform(unsigned long type)
|
||||
{
|
||||
if(type == EAX_CHORUS_SINUSOID) return ChorusWaveform::Sinusoid;
|
||||
if(type == EAX_CHORUS_TRIANGLE) return ChorusWaveform::Triangle;
|
||||
return ChorusWaveform::Sinusoid;
|
||||
}
|
||||
}; // EaxChorusTraits
|
||||
|
||||
struct EaxFlangerTraits {
|
||||
using Props = EAXFLANGERPROPERTIES;
|
||||
using Committer = EaxFlangerCommitter;
|
||||
static constexpr auto Field = &EaxEffectProps::mFlanger;
|
||||
|
||||
static constexpr auto eax_effect_type() { return EaxEffectType::Flanger; }
|
||||
static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; }
|
||||
|
||||
static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; }
|
||||
static constexpr auto eax_allparameters_param_id() { return EAXFLANGER_ALLPARAMETERS; }
|
||||
static constexpr auto eax_waveform_param_id() { return EAXFLANGER_WAVEFORM; }
|
||||
static constexpr auto eax_phase_param_id() { return EAXFLANGER_PHASE; }
|
||||
static constexpr auto eax_rate_param_id() { return EAXFLANGER_RATE; }
|
||||
static constexpr auto eax_depth_param_id() { return EAXFLANGER_DEPTH; }
|
||||
static constexpr auto eax_feedback_param_id() { return EAXFLANGER_FEEDBACK; }
|
||||
static constexpr auto eax_delay_param_id() { return EAXFLANGER_DELAY; }
|
||||
|
||||
static constexpr auto eax_min_waveform() { return EAXFLANGER_MINWAVEFORM; }
|
||||
static constexpr auto eax_min_phase() { return EAXFLANGER_MINPHASE; }
|
||||
static constexpr auto eax_min_rate() { return EAXFLANGER_MINRATE; }
|
||||
static constexpr auto eax_min_depth() { return EAXFLANGER_MINDEPTH; }
|
||||
static constexpr auto eax_min_feedback() { return EAXFLANGER_MINFEEDBACK; }
|
||||
static constexpr auto eax_min_delay() { return EAXFLANGER_MINDELAY; }
|
||||
|
||||
static constexpr auto eax_max_waveform() { return EAXFLANGER_MAXWAVEFORM; }
|
||||
static constexpr auto eax_max_phase() { return EAXFLANGER_MAXPHASE; }
|
||||
static constexpr auto eax_max_rate() { return EAXFLANGER_MAXRATE; }
|
||||
static constexpr auto eax_max_depth() { return EAXFLANGER_MAXDEPTH; }
|
||||
static constexpr auto eax_max_feedback() { return EAXFLANGER_MAXFEEDBACK; }
|
||||
static constexpr auto eax_max_delay() { return EAXFLANGER_MAXDELAY; }
|
||||
|
||||
static constexpr auto eax_default_waveform() { return EAXFLANGER_DEFAULTWAVEFORM; }
|
||||
static constexpr auto eax_default_phase() { return EAXFLANGER_DEFAULTPHASE; }
|
||||
static constexpr auto eax_default_rate() { return EAXFLANGER_DEFAULTRATE; }
|
||||
static constexpr auto eax_default_depth() { return EAXFLANGER_DEFAULTDEPTH; }
|
||||
static constexpr auto eax_default_feedback() { return EAXFLANGER_DEFAULTFEEDBACK; }
|
||||
static constexpr auto eax_default_delay() { return EAXFLANGER_DEFAULTDELAY; }
|
||||
|
||||
static constexpr auto efx_min_waveform() { return AL_FLANGER_MIN_WAVEFORM; }
|
||||
static constexpr auto efx_min_phase() { return AL_FLANGER_MIN_PHASE; }
|
||||
static constexpr auto efx_min_rate() { return AL_FLANGER_MIN_RATE; }
|
||||
static constexpr auto efx_min_depth() { return AL_FLANGER_MIN_DEPTH; }
|
||||
static constexpr auto efx_min_feedback() { return AL_FLANGER_MIN_FEEDBACK; }
|
||||
static constexpr auto efx_min_delay() { return AL_FLANGER_MIN_DELAY; }
|
||||
|
||||
static constexpr auto efx_max_waveform() { return AL_FLANGER_MAX_WAVEFORM; }
|
||||
static constexpr auto efx_max_phase() { return AL_FLANGER_MAX_PHASE; }
|
||||
static constexpr auto efx_max_rate() { return AL_FLANGER_MAX_RATE; }
|
||||
static constexpr auto efx_max_depth() { return AL_FLANGER_MAX_DEPTH; }
|
||||
static constexpr auto efx_max_feedback() { return AL_FLANGER_MAX_FEEDBACK; }
|
||||
static constexpr auto efx_max_delay() { return AL_FLANGER_MAX_DELAY; }
|
||||
|
||||
static constexpr auto efx_default_waveform() { return AL_FLANGER_DEFAULT_WAVEFORM; }
|
||||
static constexpr auto efx_default_phase() { return AL_FLANGER_DEFAULT_PHASE; }
|
||||
static constexpr auto efx_default_rate() { return AL_FLANGER_DEFAULT_RATE; }
|
||||
static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; }
|
||||
static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; }
|
||||
static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; }
|
||||
|
||||
static ChorusWaveform eax_waveform(unsigned long type)
|
||||
{
|
||||
if(type == EAX_FLANGER_SINUSOID) return ChorusWaveform::Sinusoid;
|
||||
if(type == EAX_FLANGER_TRIANGLE) return ChorusWaveform::Triangle;
|
||||
return ChorusWaveform::Sinusoid;
|
||||
}
|
||||
}; // EaxFlangerTraits
|
||||
|
||||
template<typename TTraits>
|
||||
struct ChorusFlangerEffect {
|
||||
using Traits = TTraits;
|
||||
using Committer = typename Traits::Committer;
|
||||
using Exception = typename Committer::Exception;
|
||||
|
||||
static constexpr auto Field = Traits::Field;
|
||||
|
||||
struct WaveformValidator {
|
||||
void operator()(unsigned long ulWaveform) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Waveform",
|
||||
ulWaveform,
|
||||
Traits::eax_min_waveform(),
|
||||
Traits::eax_max_waveform());
|
||||
}
|
||||
}; // WaveformValidator
|
||||
|
||||
struct PhaseValidator {
|
||||
void operator()(long lPhase) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Phase",
|
||||
lPhase,
|
||||
Traits::eax_min_phase(),
|
||||
Traits::eax_max_phase());
|
||||
}
|
||||
}; // PhaseValidator
|
||||
|
||||
struct RateValidator {
|
||||
void operator()(float flRate) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Rate",
|
||||
flRate,
|
||||
Traits::eax_min_rate(),
|
||||
Traits::eax_max_rate());
|
||||
}
|
||||
}; // RateValidator
|
||||
|
||||
struct DepthValidator {
|
||||
void operator()(float flDepth) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Depth",
|
||||
flDepth,
|
||||
Traits::eax_min_depth(),
|
||||
Traits::eax_max_depth());
|
||||
}
|
||||
}; // DepthValidator
|
||||
|
||||
struct FeedbackValidator {
|
||||
void operator()(float flFeedback) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Feedback",
|
||||
flFeedback,
|
||||
Traits::eax_min_feedback(),
|
||||
Traits::eax_max_feedback());
|
||||
}
|
||||
}; // FeedbackValidator
|
||||
|
||||
struct DelayValidator {
|
||||
void operator()(float flDelay) const
|
||||
{
|
||||
eax_validate_range<Exception>(
|
||||
"Delay",
|
||||
flDelay,
|
||||
Traits::eax_min_delay(),
|
||||
Traits::eax_max_delay());
|
||||
}
|
||||
}; // DelayValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const typename Traits::Props& all) const
|
||||
{
|
||||
WaveformValidator{}(all.ulWaveform);
|
||||
PhaseValidator{}(all.lPhase);
|
||||
RateValidator{}(all.flRate);
|
||||
DepthValidator{}(all.flDepth);
|
||||
FeedbackValidator{}(all.flFeedback);
|
||||
DelayValidator{}(all.flDelay);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
public:
|
||||
static void SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
auto&& all = props.*Field;
|
||||
props.mType = Traits::eax_effect_type();
|
||||
all.ulWaveform = Traits::eax_default_waveform();
|
||||
all.lPhase = Traits::eax_default_phase();
|
||||
all.flRate = Traits::eax_default_rate();
|
||||
all.flDepth = Traits::eax_default_depth();
|
||||
all.flFeedback = Traits::eax_default_feedback();
|
||||
all.flDelay = Traits::eax_default_delay();
|
||||
}
|
||||
|
||||
|
||||
static void Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
auto&& all = props.*Field;
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case Traits::eax_none_param_id():
|
||||
break;
|
||||
|
||||
case Traits::eax_allparameters_param_id():
|
||||
call.template set_value<Exception>(all);
|
||||
break;
|
||||
|
||||
case Traits::eax_waveform_param_id():
|
||||
call.template set_value<Exception>(all.ulWaveform);
|
||||
break;
|
||||
|
||||
case Traits::eax_phase_param_id():
|
||||
call.template set_value<Exception>(all.lPhase);
|
||||
break;
|
||||
|
||||
case Traits::eax_rate_param_id():
|
||||
call.template set_value<Exception>(all.flRate);
|
||||
break;
|
||||
|
||||
case Traits::eax_depth_param_id():
|
||||
call.template set_value<Exception>(all.flDepth);
|
||||
break;
|
||||
|
||||
case Traits::eax_feedback_param_id():
|
||||
call.template set_value<Exception>(all.flFeedback);
|
||||
break;
|
||||
|
||||
case Traits::eax_delay_param_id():
|
||||
call.template set_value<Exception>(all.flDelay);
|
||||
break;
|
||||
|
||||
default:
|
||||
Committer::fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
static void Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
auto&& all = props.*Field;
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case Traits::eax_none_param_id():
|
||||
break;
|
||||
|
||||
case Traits::eax_allparameters_param_id():
|
||||
Committer::template defer<AllValidator>(call, all);
|
||||
break;
|
||||
|
||||
case Traits::eax_waveform_param_id():
|
||||
Committer::template defer<WaveformValidator>(call, all.ulWaveform);
|
||||
break;
|
||||
|
||||
case Traits::eax_phase_param_id():
|
||||
Committer::template defer<PhaseValidator>(call, all.lPhase);
|
||||
break;
|
||||
|
||||
case Traits::eax_rate_param_id():
|
||||
Committer::template defer<RateValidator>(call, all.flRate);
|
||||
break;
|
||||
|
||||
case Traits::eax_depth_param_id():
|
||||
Committer::template defer<DepthValidator>(call, all.flDepth);
|
||||
break;
|
||||
|
||||
case Traits::eax_feedback_param_id():
|
||||
Committer::template defer<FeedbackValidator>(call, all.flFeedback);
|
||||
break;
|
||||
|
||||
case Traits::eax_delay_param_id():
|
||||
Committer::template defer<DelayValidator>(call, all.flDelay);
|
||||
break;
|
||||
|
||||
default:
|
||||
Committer::fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
static bool Commit(const EaxEffectProps &props, EaxEffectProps &props_, EffectProps &al_props_)
|
||||
{
|
||||
if(props.mType == props_.mType)
|
||||
{
|
||||
auto&& src = props_.*Field;
|
||||
auto&& dst = props.*Field;
|
||||
if(dst.ulWaveform == src.ulWaveform && dst.lPhase == src.lPhase
|
||||
&& dst.flRate == src.flRate && dst.flDepth == src.flDepth
|
||||
&& dst.flFeedback == src.flFeedback && dst.flDelay == src.flDelay)
|
||||
return false;
|
||||
}
|
||||
|
||||
props_ = props;
|
||||
auto&& dst = props.*Field;
|
||||
|
||||
al_props_.Chorus.Waveform = Traits::eax_waveform(dst.ulWaveform);
|
||||
al_props_.Chorus.Phase = static_cast<int>(dst.lPhase);
|
||||
al_props_.Chorus.Rate = dst.flRate;
|
||||
al_props_.Chorus.Depth = dst.flDepth;
|
||||
al_props_.Chorus.Feedback = dst.flFeedback;
|
||||
al_props_.Chorus.Delay = dst.flDelay;
|
||||
|
||||
return true;
|
||||
}
|
||||
}; // EaxChorusFlangerEffect
|
||||
|
||||
|
||||
using ChorusCommitter = EaxCommitter<EaxChorusCommitter>;
|
||||
using FlangerCommitter = EaxCommitter<EaxFlangerCommitter>;
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct ChorusCommitter::Exception : public EaxException
|
||||
{
|
||||
explicit Exception(const char *message) : EaxException{"EAX_CHORUS_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void ChorusCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool ChorusCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
return Committer::Commit(props, mEaxProps, mAlProps);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::SetDefaults(props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::Get(call, props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::Set(call, props);
|
||||
}
|
||||
|
||||
template<>
|
||||
struct FlangerCommitter::Exception : public EaxException
|
||||
{
|
||||
explicit Exception(const char *message) : EaxException{"EAX_FLANGER_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void FlangerCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FlangerCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
return Committer::Commit(props, mEaxProps, mAlProps);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::SetDefaults(props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::Get(call, props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::Set(call, props);
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
162
externals/openal-soft/al/effects/compressor.cpp
vendored
Normal file
162
externals/openal-soft/al/effects/compressor.cpp
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.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 Compressor_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_COMPRESSOR_ONOFF:
|
||||
if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Compressor state out of range"};
|
||||
props->Compressor.OnOff = (val != AL_FALSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Compressor_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Compressor_setParami(props, param, vals[0]); }
|
||||
void Compressor_setParamf(EffectProps*, ALenum param, float)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
|
||||
void Compressor_setParamfv(EffectProps*, ALenum param, const float*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
void Compressor_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_COMPRESSOR_ONOFF:
|
||||
*val = props->Compressor.OnOff;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Compressor_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Compressor_getParami(props, param, vals); }
|
||||
void Compressor_getParamf(const EffectProps*, ALenum param, float*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
|
||||
void Compressor_getParamfv(const EffectProps*, ALenum param, float*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Compressor);
|
||||
|
||||
const EffectProps CompressorEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using CompressorCommitter = EaxCommitter<EaxCompressorCommitter>;
|
||||
|
||||
struct OnOffValidator {
|
||||
void operator()(unsigned long ulOnOff) const
|
||||
{
|
||||
eax_validate_range<CompressorCommitter::Exception>(
|
||||
"On-Off",
|
||||
ulOnOff,
|
||||
EAXAGCCOMPRESSOR_MINONOFF,
|
||||
EAXAGCCOMPRESSOR_MAXONOFF);
|
||||
}
|
||||
}; // OnOffValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXAGCCOMPRESSORPROPERTIES& all) const
|
||||
{
|
||||
OnOffValidator{}(all.ulOnOff);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct CompressorCommitter::Exception : public EaxException
|
||||
{
|
||||
explicit Exception(const char *message) : EaxException{"EAX_CHORUS_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void CompressorCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool CompressorCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& props.mCompressor.ulOnOff == mEaxProps.mCompressor.ulOnOff)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Compressor.OnOff = (props.mCompressor.ulOnOff != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Compressor;
|
||||
props.mCompressor.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF;
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXAGCCOMPRESSOR_NONE: break;
|
||||
case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value<Exception>(props.mCompressor); break;
|
||||
case EAXAGCCOMPRESSOR_ONOFF: call.set_value<Exception>(props.mCompressor.ulOnOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXAGCCOMPRESSOR_NONE: break;
|
||||
case EAXAGCCOMPRESSOR_ALLPARAMETERS: defer<AllValidator>(call, props.mCompressor); break;
|
||||
case EAXAGCCOMPRESSOR_ONOFF: defer<OnOffValidator>(call, props.mCompressor.ulOnOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
93
externals/openal-soft/al/effects/convolution.cpp
vendored
Normal file
93
externals/openal-soft/al/effects/convolution.cpp
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "alc/inprogext.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "effects.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void Convolution_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Convolution_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Convolution_setParami(props, param, vals[0]);
|
||||
}
|
||||
}
|
||||
void Convolution_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Convolution_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Convolution_setParamf(props, param, vals[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void Convolution_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Convolution_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Convolution_getParami(props, param, vals);
|
||||
}
|
||||
}
|
||||
void Convolution_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Convolution_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Convolution_getParamf(props, param, vals);
|
||||
}
|
||||
}
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Convolution);
|
||||
|
||||
const EffectProps ConvolutionEffectProps{genDefaultProps()};
|
||||
72
externals/openal-soft/al/effects/dedicated.cpp
vendored
Normal file
72
externals/openal-soft/al/effects/dedicated.cpp
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "effects.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void Dedicated_setParami(EffectProps*, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void Dedicated_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Dedicated_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN:
|
||||
if(!(val >= 0.0f && std::isfinite(val)))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Dedicated gain out of range"};
|
||||
props->Dedicated.Gain = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Dedicated_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Dedicated_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Dedicated_getParami(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void Dedicated_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Dedicated_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN:
|
||||
*val = props->Dedicated.Gain;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Dedicated_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Dedicated_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Dedicated.Gain = 1.0f;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Dedicated);
|
||||
|
||||
const EffectProps DedicatedEffectProps{genDefaultProps()};
|
||||
271
externals/openal-soft/al/effects/distortion.cpp
vendored
Normal file
271
externals/openal-soft/al/effects/distortion.cpp
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.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 Distortion_setParami(EffectProps*, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
|
||||
void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Distortion_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DISTORTION_EDGE:
|
||||
if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
|
||||
props->Distortion.Edge = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_GAIN:
|
||||
if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
|
||||
props->Distortion.Gain = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_LOWPASS_CUTOFF:
|
||||
if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
|
||||
props->Distortion.LowpassCutoff = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQCENTER:
|
||||
if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
|
||||
props->Distortion.EQCenter = val;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQBANDWIDTH:
|
||||
if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
|
||||
props->Distortion.EQBandwidth = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Distortion_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Distortion_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Distortion_getParami(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
|
||||
void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Distortion_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DISTORTION_EDGE:
|
||||
*val = props->Distortion.Edge;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_GAIN:
|
||||
*val = props->Distortion.Gain;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_LOWPASS_CUTOFF:
|
||||
*val = props->Distortion.LowpassCutoff;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQCENTER:
|
||||
*val = props->Distortion.EQCenter;
|
||||
break;
|
||||
|
||||
case AL_DISTORTION_EQBANDWIDTH:
|
||||
*val = props->Distortion.EQBandwidth;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Distortion_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Distortion_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
|
||||
props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
|
||||
props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
|
||||
props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
|
||||
props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Distortion);
|
||||
|
||||
const EffectProps DistortionEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using DistortionCommitter = EaxCommitter<EaxDistortionCommitter>;
|
||||
|
||||
struct EdgeValidator {
|
||||
void operator()(float flEdge) const
|
||||
{
|
||||
eax_validate_range<DistortionCommitter::Exception>(
|
||||
"Edge",
|
||||
flEdge,
|
||||
EAXDISTORTION_MINEDGE,
|
||||
EAXDISTORTION_MAXEDGE);
|
||||
}
|
||||
}; // EdgeValidator
|
||||
|
||||
struct GainValidator {
|
||||
void operator()(long lGain) const
|
||||
{
|
||||
eax_validate_range<DistortionCommitter::Exception>(
|
||||
"Gain",
|
||||
lGain,
|
||||
EAXDISTORTION_MINGAIN,
|
||||
EAXDISTORTION_MAXGAIN);
|
||||
}
|
||||
}; // GainValidator
|
||||
|
||||
struct LowPassCutOffValidator {
|
||||
void operator()(float flLowPassCutOff) const
|
||||
{
|
||||
eax_validate_range<DistortionCommitter::Exception>(
|
||||
"Low-pass Cut-off",
|
||||
flLowPassCutOff,
|
||||
EAXDISTORTION_MINLOWPASSCUTOFF,
|
||||
EAXDISTORTION_MAXLOWPASSCUTOFF);
|
||||
}
|
||||
}; // LowPassCutOffValidator
|
||||
|
||||
struct EqCenterValidator {
|
||||
void operator()(float flEQCenter) const
|
||||
{
|
||||
eax_validate_range<DistortionCommitter::Exception>(
|
||||
"EQ Center",
|
||||
flEQCenter,
|
||||
EAXDISTORTION_MINEQCENTER,
|
||||
EAXDISTORTION_MAXEQCENTER);
|
||||
}
|
||||
}; // EqCenterValidator
|
||||
|
||||
struct EqBandwidthValidator {
|
||||
void operator()(float flEQBandwidth) const
|
||||
{
|
||||
eax_validate_range<DistortionCommitter::Exception>(
|
||||
"EQ Bandwidth",
|
||||
flEQBandwidth,
|
||||
EAXDISTORTION_MINEQBANDWIDTH,
|
||||
EAXDISTORTION_MAXEQBANDWIDTH);
|
||||
}
|
||||
}; // EqBandwidthValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXDISTORTIONPROPERTIES& all) const
|
||||
{
|
||||
EdgeValidator{}(all.flEdge);
|
||||
GainValidator{}(all.lGain);
|
||||
LowPassCutOffValidator{}(all.flLowPassCutOff);
|
||||
EqCenterValidator{}(all.flEQCenter);
|
||||
EqBandwidthValidator{}(all.flEQBandwidth);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct DistortionCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char *message) : EaxException{"EAX_DISTORTION_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void DistortionCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool DistortionCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType && mEaxProps.mDistortion.flEdge == props.mDistortion.flEdge
|
||||
&& mEaxProps.mDistortion.lGain == props.mDistortion.lGain
|
||||
&& mEaxProps.mDistortion.flLowPassCutOff == props.mDistortion.flLowPassCutOff
|
||||
&& mEaxProps.mDistortion.flEQCenter == props.mDistortion.flEQCenter
|
||||
&& mEaxProps.mDistortion.flEQBandwidth == props.mDistortion.flEQBandwidth)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Distortion.Edge = props.mDistortion.flEdge;
|
||||
mAlProps.Distortion.Gain = level_mb_to_gain(static_cast<float>(props.mDistortion.lGain));
|
||||
mAlProps.Distortion.LowpassCutoff = props.mDistortion.flLowPassCutOff;
|
||||
mAlProps.Distortion.EQCenter = props.mDistortion.flEQCenter;
|
||||
mAlProps.Distortion.EQBandwidth = props.mDistortion.flEdge;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Distortion;
|
||||
props.mDistortion.flEdge = EAXDISTORTION_DEFAULTEDGE;
|
||||
props.mDistortion.lGain = EAXDISTORTION_DEFAULTGAIN;
|
||||
props.mDistortion.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
|
||||
props.mDistortion.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
|
||||
props.mDistortion.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXDISTORTION_NONE: break;
|
||||
case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props.mDistortion); break;
|
||||
case EAXDISTORTION_EDGE: call.set_value<Exception>(props.mDistortion.flEdge); break;
|
||||
case EAXDISTORTION_GAIN: call.set_value<Exception>(props.mDistortion.lGain); break;
|
||||
case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.mDistortion.flLowPassCutOff); break;
|
||||
case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.mDistortion.flEQCenter); break;
|
||||
case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.mDistortion.flEQBandwidth); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXDISTORTION_NONE: break;
|
||||
case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props.mDistortion); break;
|
||||
case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.mDistortion.flEdge); break;
|
||||
case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.mDistortion.lGain); break;
|
||||
case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.mDistortion.flLowPassCutOff); break;
|
||||
case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.mDistortion.flEQCenter); break;
|
||||
case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.mDistortion.flEQBandwidth); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
268
externals/openal-soft/al/effects/echo.cpp
vendored
Normal file
268
externals/openal-soft/al/effects/echo.cpp
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.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 {
|
||||
|
||||
static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
|
||||
static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
|
||||
|
||||
void Echo_setParami(EffectProps*, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
|
||||
void Echo_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
|
||||
void Echo_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_ECHO_DELAY:
|
||||
if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
|
||||
props->Echo.Delay = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_LRDELAY:
|
||||
if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
|
||||
props->Echo.LRDelay = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_DAMPING:
|
||||
if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
|
||||
props->Echo.Damping = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_FEEDBACK:
|
||||
if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
|
||||
props->Echo.Feedback = val;
|
||||
break;
|
||||
|
||||
case AL_ECHO_SPREAD:
|
||||
if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
|
||||
props->Echo.Spread = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Echo_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Echo_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Echo_getParami(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
|
||||
void Echo_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
|
||||
void Echo_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_ECHO_DELAY:
|
||||
*val = props->Echo.Delay;
|
||||
break;
|
||||
|
||||
case AL_ECHO_LRDELAY:
|
||||
*val = props->Echo.LRDelay;
|
||||
break;
|
||||
|
||||
case AL_ECHO_DAMPING:
|
||||
*val = props->Echo.Damping;
|
||||
break;
|
||||
|
||||
case AL_ECHO_FEEDBACK:
|
||||
*val = props->Echo.Feedback;
|
||||
break;
|
||||
|
||||
case AL_ECHO_SPREAD:
|
||||
*val = props->Echo.Spread;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Echo_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Echo_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
|
||||
props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
|
||||
props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
|
||||
props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
|
||||
props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Echo);
|
||||
|
||||
const EffectProps EchoEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using EchoCommitter = EaxCommitter<EaxEchoCommitter>;
|
||||
|
||||
struct DelayValidator {
|
||||
void operator()(float flDelay) const
|
||||
{
|
||||
eax_validate_range<EchoCommitter::Exception>(
|
||||
"Delay",
|
||||
flDelay,
|
||||
EAXECHO_MINDELAY,
|
||||
EAXECHO_MAXDELAY);
|
||||
}
|
||||
}; // DelayValidator
|
||||
|
||||
struct LrDelayValidator {
|
||||
void operator()(float flLRDelay) const
|
||||
{
|
||||
eax_validate_range<EchoCommitter::Exception>(
|
||||
"LR Delay",
|
||||
flLRDelay,
|
||||
EAXECHO_MINLRDELAY,
|
||||
EAXECHO_MAXLRDELAY);
|
||||
}
|
||||
}; // LrDelayValidator
|
||||
|
||||
struct DampingValidator {
|
||||
void operator()(float flDamping) const
|
||||
{
|
||||
eax_validate_range<EchoCommitter::Exception>(
|
||||
"Damping",
|
||||
flDamping,
|
||||
EAXECHO_MINDAMPING,
|
||||
EAXECHO_MAXDAMPING);
|
||||
}
|
||||
}; // DampingValidator
|
||||
|
||||
struct FeedbackValidator {
|
||||
void operator()(float flFeedback) const
|
||||
{
|
||||
eax_validate_range<EchoCommitter::Exception>(
|
||||
"Feedback",
|
||||
flFeedback,
|
||||
EAXECHO_MINFEEDBACK,
|
||||
EAXECHO_MAXFEEDBACK);
|
||||
}
|
||||
}; // FeedbackValidator
|
||||
|
||||
struct SpreadValidator {
|
||||
void operator()(float flSpread) const
|
||||
{
|
||||
eax_validate_range<EchoCommitter::Exception>(
|
||||
"Spread",
|
||||
flSpread,
|
||||
EAXECHO_MINSPREAD,
|
||||
EAXECHO_MAXSPREAD);
|
||||
}
|
||||
}; // SpreadValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXECHOPROPERTIES& all) const
|
||||
{
|
||||
DelayValidator{}(all.flDelay);
|
||||
LrDelayValidator{}(all.flLRDelay);
|
||||
DampingValidator{}(all.flDamping);
|
||||
FeedbackValidator{}(all.flFeedback);
|
||||
SpreadValidator{}(all.flSpread);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct EchoCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char* message) : EaxException{"EAX_ECHO_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void EchoCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool EchoCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType && mEaxProps.mEcho.flDelay == props.mEcho.flDelay
|
||||
&& mEaxProps.mEcho.flLRDelay == props.mEcho.flLRDelay
|
||||
&& mEaxProps.mEcho.flDamping == props.mEcho.flDamping
|
||||
&& mEaxProps.mEcho.flFeedback == props.mEcho.flFeedback
|
||||
&& mEaxProps.mEcho.flSpread == props.mEcho.flSpread)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Echo.Delay = props.mEcho.flDelay;
|
||||
mAlProps.Echo.LRDelay = props.mEcho.flLRDelay;
|
||||
mAlProps.Echo.Damping = props.mEcho.flDamping;
|
||||
mAlProps.Echo.Feedback = props.mEcho.flFeedback;
|
||||
mAlProps.Echo.Spread = props.mEcho.flSpread;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Echo;
|
||||
props.mEcho.flDelay = EAXECHO_DEFAULTDELAY;
|
||||
props.mEcho.flLRDelay = EAXECHO_DEFAULTLRDELAY;
|
||||
props.mEcho.flDamping = EAXECHO_DEFAULTDAMPING;
|
||||
props.mEcho.flFeedback = EAXECHO_DEFAULTFEEDBACK;
|
||||
props.mEcho.flSpread = EAXECHO_DEFAULTSPREAD;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXECHO_NONE: break;
|
||||
case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props.mEcho); break;
|
||||
case EAXECHO_DELAY: call.set_value<Exception>(props.mEcho.flDelay); break;
|
||||
case EAXECHO_LRDELAY: call.set_value<Exception>(props.mEcho.flLRDelay); break;
|
||||
case EAXECHO_DAMPING: call.set_value<Exception>(props.mEcho.flDamping); break;
|
||||
case EAXECHO_FEEDBACK: call.set_value<Exception>(props.mEcho.flFeedback); break;
|
||||
case EAXECHO_SPREAD: call.set_value<Exception>(props.mEcho.flSpread); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXECHO_NONE: break;
|
||||
case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props.mEcho); break;
|
||||
case EAXECHO_DELAY: defer<DelayValidator>(call, props.mEcho.flDelay); break;
|
||||
case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.mEcho.flLRDelay); break;
|
||||
case EAXECHO_DAMPING: defer<DampingValidator>(call, props.mEcho.flDamping); break;
|
||||
case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.mEcho.flFeedback); break;
|
||||
case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.mEcho.flSpread); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
9
externals/openal-soft/al/effects/effects.cpp
vendored
Normal file
9
externals/openal-soft/al/effects/effects.cpp
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
|
||||
#include <cassert>
|
||||
#include "AL/efx.h"
|
||||
#include "effects.h"
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
88
externals/openal-soft/al/effects/effects.h
vendored
Normal file
88
externals/openal-soft/al/effects/effects.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef AL_EFFECTS_EFFECTS_H
|
||||
#define AL_EFFECTS_EFFECTS_H
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "core/except.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "al/eax/effect.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
union EffectProps;
|
||||
|
||||
|
||||
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, ...);
|
||||
~effect_exception() override;
|
||||
|
||||
ALenum errorCode() const noexcept { return mErrorCode; }
|
||||
};
|
||||
|
||||
|
||||
struct EffectVtable {
|
||||
void (*const setParami)(EffectProps *props, ALenum param, int val);
|
||||
void (*const setParamiv)(EffectProps *props, ALenum param, const int *vals);
|
||||
void (*const setParamf)(EffectProps *props, ALenum param, float val);
|
||||
void (*const setParamfv)(EffectProps *props, ALenum param, const float *vals);
|
||||
|
||||
void (*const getParami)(const EffectProps *props, ALenum param, int *val);
|
||||
void (*const getParamiv)(const EffectProps *props, ALenum param, int *vals);
|
||||
void (*const getParamf)(const EffectProps *props, ALenum param, float *val);
|
||||
void (*const getParamfv)(const EffectProps *props, ALenum param, float *vals);
|
||||
};
|
||||
|
||||
#define DEFINE_ALEFFECT_VTABLE(T) \
|
||||
const EffectVtable T##EffectVtable = { \
|
||||
T##_setParami, T##_setParamiv, \
|
||||
T##_setParamf, T##_setParamfv, \
|
||||
T##_getParami, T##_getParamiv, \
|
||||
T##_getParamf, T##_getParamfv, \
|
||||
}
|
||||
|
||||
|
||||
/* Default properties for the given effect types. */
|
||||
extern const EffectProps NullEffectProps;
|
||||
extern const EffectProps ReverbEffectProps;
|
||||
extern const EffectProps StdReverbEffectProps;
|
||||
extern const EffectProps AutowahEffectProps;
|
||||
extern const EffectProps ChorusEffectProps;
|
||||
extern const EffectProps CompressorEffectProps;
|
||||
extern const EffectProps DistortionEffectProps;
|
||||
extern const EffectProps EchoEffectProps;
|
||||
extern const EffectProps EqualizerEffectProps;
|
||||
extern const EffectProps FlangerEffectProps;
|
||||
extern const EffectProps FshifterEffectProps;
|
||||
extern const EffectProps ModulatorEffectProps;
|
||||
extern const EffectProps PshifterEffectProps;
|
||||
extern const EffectProps VmorpherEffectProps;
|
||||
extern const EffectProps DedicatedEffectProps;
|
||||
extern const EffectProps ConvolutionEffectProps;
|
||||
|
||||
/* Vtables to get/set properties for the given effect types. */
|
||||
extern const EffectVtable NullEffectVtable;
|
||||
extern const EffectVtable ReverbEffectVtable;
|
||||
extern const EffectVtable StdReverbEffectVtable;
|
||||
extern const EffectVtable AutowahEffectVtable;
|
||||
extern const EffectVtable ChorusEffectVtable;
|
||||
extern const EffectVtable CompressorEffectVtable;
|
||||
extern const EffectVtable DistortionEffectVtable;
|
||||
extern const EffectVtable EchoEffectVtable;
|
||||
extern const EffectVtable EqualizerEffectVtable;
|
||||
extern const EffectVtable FlangerEffectVtable;
|
||||
extern const EffectVtable FshifterEffectVtable;
|
||||
extern const EffectVtable ModulatorEffectVtable;
|
||||
extern const EffectVtable PshifterEffectVtable;
|
||||
extern const EffectVtable VmorpherEffectVtable;
|
||||
extern const EffectVtable DedicatedEffectVtable;
|
||||
extern const EffectVtable ConvolutionEffectVtable;
|
||||
|
||||
#endif /* AL_EFFECTS_EFFECTS_H */
|
||||
411
externals/openal-soft/al/effects/equalizer.cpp
vendored
Normal file
411
externals/openal-soft/al/effects/equalizer.cpp
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.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 Equalizer_setParami(EffectProps*, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
|
||||
void Equalizer_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Equalizer_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_EQUALIZER_LOW_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band gain out of range"};
|
||||
props->Equalizer.LowGain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_LOW_CUTOFF:
|
||||
if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band cutoff out of range"};
|
||||
props->Equalizer.LowCutoff = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band gain out of range"};
|
||||
props->Equalizer.Mid1Gain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_CENTER:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band center out of range"};
|
||||
props->Equalizer.Mid1Center = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_WIDTH:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band width out of range"};
|
||||
props->Equalizer.Mid1Width = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band gain out of range"};
|
||||
props->Equalizer.Mid2Gain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_CENTER:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band center out of range"};
|
||||
props->Equalizer.Mid2Center = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_WIDTH:
|
||||
if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band width out of range"};
|
||||
props->Equalizer.Mid2Width = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_GAIN:
|
||||
if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band gain out of range"};
|
||||
props->Equalizer.HighGain = val;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_CUTOFF:
|
||||
if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band cutoff out of range"};
|
||||
props->Equalizer.HighCutoff = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Equalizer_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Equalizer_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Equalizer_getParami(const EffectProps*, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
|
||||
void Equalizer_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Equalizer_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_EQUALIZER_LOW_GAIN:
|
||||
*val = props->Equalizer.LowGain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_LOW_CUTOFF:
|
||||
*val = props->Equalizer.LowCutoff;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_GAIN:
|
||||
*val = props->Equalizer.Mid1Gain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_CENTER:
|
||||
*val = props->Equalizer.Mid1Center;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID1_WIDTH:
|
||||
*val = props->Equalizer.Mid1Width;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_GAIN:
|
||||
*val = props->Equalizer.Mid2Gain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_CENTER:
|
||||
*val = props->Equalizer.Mid2Center;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_MID2_WIDTH:
|
||||
*val = props->Equalizer.Mid2Width;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_GAIN:
|
||||
*val = props->Equalizer.HighGain;
|
||||
break;
|
||||
|
||||
case AL_EQUALIZER_HIGH_CUTOFF:
|
||||
*val = props->Equalizer.HighCutoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Equalizer_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Equalizer_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
|
||||
props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
|
||||
props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
|
||||
props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
|
||||
props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
|
||||
props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
|
||||
props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
|
||||
props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
|
||||
props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
|
||||
props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Equalizer);
|
||||
|
||||
const EffectProps EqualizerEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using EqualizerCommitter = EaxCommitter<EaxEqualizerCommitter>;
|
||||
|
||||
struct LowGainValidator {
|
||||
void operator()(long lLowGain) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Low Gain",
|
||||
lLowGain,
|
||||
EAXEQUALIZER_MINLOWGAIN,
|
||||
EAXEQUALIZER_MAXLOWGAIN);
|
||||
}
|
||||
}; // LowGainValidator
|
||||
|
||||
struct LowCutOffValidator {
|
||||
void operator()(float flLowCutOff) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Low Cutoff",
|
||||
flLowCutOff,
|
||||
EAXEQUALIZER_MINLOWCUTOFF,
|
||||
EAXEQUALIZER_MAXLOWCUTOFF);
|
||||
}
|
||||
}; // LowCutOffValidator
|
||||
|
||||
struct Mid1GainValidator {
|
||||
void operator()(long lMid1Gain) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid1 Gain",
|
||||
lMid1Gain,
|
||||
EAXEQUALIZER_MINMID1GAIN,
|
||||
EAXEQUALIZER_MAXMID1GAIN);
|
||||
}
|
||||
}; // Mid1GainValidator
|
||||
|
||||
struct Mid1CenterValidator {
|
||||
void operator()(float flMid1Center) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid1 Center",
|
||||
flMid1Center,
|
||||
EAXEQUALIZER_MINMID1CENTER,
|
||||
EAXEQUALIZER_MAXMID1CENTER);
|
||||
}
|
||||
}; // Mid1CenterValidator
|
||||
|
||||
struct Mid1WidthValidator {
|
||||
void operator()(float flMid1Width) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid1 Width",
|
||||
flMid1Width,
|
||||
EAXEQUALIZER_MINMID1WIDTH,
|
||||
EAXEQUALIZER_MAXMID1WIDTH);
|
||||
}
|
||||
}; // Mid1WidthValidator
|
||||
|
||||
struct Mid2GainValidator {
|
||||
void operator()(long lMid2Gain) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid2 Gain",
|
||||
lMid2Gain,
|
||||
EAXEQUALIZER_MINMID2GAIN,
|
||||
EAXEQUALIZER_MAXMID2GAIN);
|
||||
}
|
||||
}; // Mid2GainValidator
|
||||
|
||||
struct Mid2CenterValidator {
|
||||
void operator()(float flMid2Center) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid2 Center",
|
||||
flMid2Center,
|
||||
EAXEQUALIZER_MINMID2CENTER,
|
||||
EAXEQUALIZER_MAXMID2CENTER);
|
||||
}
|
||||
}; // Mid2CenterValidator
|
||||
|
||||
struct Mid2WidthValidator {
|
||||
void operator()(float flMid2Width) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"Mid2 Width",
|
||||
flMid2Width,
|
||||
EAXEQUALIZER_MINMID2WIDTH,
|
||||
EAXEQUALIZER_MAXMID2WIDTH);
|
||||
}
|
||||
}; // Mid2WidthValidator
|
||||
|
||||
struct HighGainValidator {
|
||||
void operator()(long lHighGain) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"High Gain",
|
||||
lHighGain,
|
||||
EAXEQUALIZER_MINHIGHGAIN,
|
||||
EAXEQUALIZER_MAXHIGHGAIN);
|
||||
}
|
||||
}; // HighGainValidator
|
||||
|
||||
struct HighCutOffValidator {
|
||||
void operator()(float flHighCutOff) const
|
||||
{
|
||||
eax_validate_range<EqualizerCommitter::Exception>(
|
||||
"High Cutoff",
|
||||
flHighCutOff,
|
||||
EAXEQUALIZER_MINHIGHCUTOFF,
|
||||
EAXEQUALIZER_MAXHIGHCUTOFF);
|
||||
}
|
||||
}; // HighCutOffValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXEQUALIZERPROPERTIES& all) const
|
||||
{
|
||||
LowGainValidator{}(all.lLowGain);
|
||||
LowCutOffValidator{}(all.flLowCutOff);
|
||||
Mid1GainValidator{}(all.lMid1Gain);
|
||||
Mid1CenterValidator{}(all.flMid1Center);
|
||||
Mid1WidthValidator{}(all.flMid1Width);
|
||||
Mid2GainValidator{}(all.lMid2Gain);
|
||||
Mid2CenterValidator{}(all.flMid2Center);
|
||||
Mid2WidthValidator{}(all.flMid2Width);
|
||||
HighGainValidator{}(all.lHighGain);
|
||||
HighCutOffValidator{}(all.flHighCutOff);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct EqualizerCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char* message) : EaxException{"EAX_EQUALIZER_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void EqualizerCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool EqualizerCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType && mEaxProps.mEqualizer.lLowGain == props.mEqualizer.lLowGain
|
||||
&& mEaxProps.mEqualizer.flLowCutOff == props.mEqualizer.flLowCutOff
|
||||
&& mEaxProps.mEqualizer.lMid1Gain == props.mEqualizer.lMid1Gain
|
||||
&& mEaxProps.mEqualizer.flMid1Center == props.mEqualizer.flMid1Center
|
||||
&& mEaxProps.mEqualizer.flMid1Width == props.mEqualizer.flMid1Width
|
||||
&& mEaxProps.mEqualizer.lMid2Gain == props.mEqualizer.lMid2Gain
|
||||
&& mEaxProps.mEqualizer.flMid2Center == props.mEqualizer.flMid2Center
|
||||
&& mEaxProps.mEqualizer.flMid2Width == props.mEqualizer.flMid2Width
|
||||
&& mEaxProps.mEqualizer.lHighGain == props.mEqualizer.lHighGain
|
||||
&& mEaxProps.mEqualizer.flHighCutOff == props.mEqualizer.flHighCutOff)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Equalizer.LowGain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lLowGain));
|
||||
mAlProps.Equalizer.LowCutoff = props.mEqualizer.flLowCutOff;
|
||||
mAlProps.Equalizer.Mid1Gain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lMid1Gain));
|
||||
mAlProps.Equalizer.Mid1Center = props.mEqualizer.flMid1Center;
|
||||
mAlProps.Equalizer.Mid1Width = props.mEqualizer.flMid1Width;
|
||||
mAlProps.Equalizer.Mid2Gain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lMid2Gain));
|
||||
mAlProps.Equalizer.Mid2Center = props.mEqualizer.flMid2Center;
|
||||
mAlProps.Equalizer.Mid2Width = props.mEqualizer.flMid2Width;
|
||||
mAlProps.Equalizer.HighGain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lHighGain));
|
||||
mAlProps.Equalizer.HighCutoff = props.mEqualizer.flHighCutOff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Equalizer;
|
||||
props.mEqualizer.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN;
|
||||
props.mEqualizer.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF;
|
||||
props.mEqualizer.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN;
|
||||
props.mEqualizer.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER;
|
||||
props.mEqualizer.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH;
|
||||
props.mEqualizer.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN;
|
||||
props.mEqualizer.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER;
|
||||
props.mEqualizer.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH;
|
||||
props.mEqualizer.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN;
|
||||
props.mEqualizer.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXEQUALIZER_NONE: break;
|
||||
case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props.mEqualizer); break;
|
||||
case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.mEqualizer.lLowGain); break;
|
||||
case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.mEqualizer.flLowCutOff); break;
|
||||
case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.mEqualizer.lMid1Gain); break;
|
||||
case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.mEqualizer.flMid1Center); break;
|
||||
case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.mEqualizer.flMid1Width); break;
|
||||
case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.mEqualizer.lMid2Gain); break;
|
||||
case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.mEqualizer.flMid2Center); break;
|
||||
case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.mEqualizer.flMid2Width); break;
|
||||
case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.mEqualizer.lHighGain); break;
|
||||
case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.mEqualizer.flHighCutOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXEQUALIZER_NONE: break;
|
||||
case EAXEQUALIZER_ALLPARAMETERS: defer<AllValidator>(call, props.mEqualizer); break;
|
||||
case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.mEqualizer.lLowGain); break;
|
||||
case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.mEqualizer.flLowCutOff); break;
|
||||
case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.mEqualizer.lMid1Gain); break;
|
||||
case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.mEqualizer.flMid1Center); break;
|
||||
case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.mEqualizer.flMid1Width); break;
|
||||
case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.mEqualizer.lMid2Gain); break;
|
||||
case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.mEqualizer.flMid2Center); break;
|
||||
case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.mEqualizer.flMid2Width); break;
|
||||
case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.mEqualizer.lHighGain); break;
|
||||
case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(call, props.mEqualizer.flHighCutOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
264
externals/openal-soft/al/effects/fshifter.cpp
vendored
Normal file
264
externals/openal-soft/al/effects/fshifter.cpp
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "aloptional.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
al::optional<FShifterDirection> DirectionFromEmum(ALenum value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: return FShifterDirection::Down;
|
||||
case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return FShifterDirection::Up;
|
||||
case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return FShifterDirection::Off;
|
||||
}
|
||||
return al::nullopt;
|
||||
}
|
||||
ALenum EnumFromDirection(FShifterDirection dir)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case FShifterDirection::Down: return AL_FREQUENCY_SHIFTER_DIRECTION_DOWN;
|
||||
case FShifterDirection::Up: return AL_FREQUENCY_SHIFTER_DIRECTION_UP;
|
||||
case FShifterDirection::Off: return AL_FREQUENCY_SHIFTER_DIRECTION_OFF;
|
||||
}
|
||||
throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
|
||||
}
|
||||
|
||||
void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_FREQUENCY:
|
||||
if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
|
||||
props->Fshifter.Frequency = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Fshifter_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Fshifter_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Fshifter_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
|
||||
if(auto diropt = DirectionFromEmum(val))
|
||||
props->Fshifter.LeftDirection = *diropt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE,
|
||||
"Unsupported frequency shifter left direction: 0x%04x", val};
|
||||
break;
|
||||
|
||||
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
|
||||
if(auto diropt = DirectionFromEmum(val))
|
||||
props->Fshifter.RightDirection = *diropt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE,
|
||||
"Unsupported frequency shifter right direction: 0x%04x", val};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM,
|
||||
"Invalid frequency shifter integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Fshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Fshifter_setParami(props, param, vals[0]); }
|
||||
|
||||
void Fshifter_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
|
||||
*val = EnumFromDirection(props->Fshifter.LeftDirection);
|
||||
break;
|
||||
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
|
||||
*val = EnumFromDirection(props->Fshifter.RightDirection);
|
||||
break;
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM,
|
||||
"Invalid frequency shifter integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Fshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Fshifter_getParami(props, param, vals); }
|
||||
|
||||
void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_FREQUENCY:
|
||||
*val = props->Fshifter.Frequency;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Fshifter_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Fshifter_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
|
||||
props.Fshifter.LeftDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
|
||||
props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Fshifter);
|
||||
|
||||
const EffectProps FshifterEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using FrequencyShifterCommitter = EaxCommitter<EaxFrequencyShifterCommitter>;
|
||||
|
||||
struct FrequencyValidator {
|
||||
void operator()(float flFrequency) const
|
||||
{
|
||||
eax_validate_range<FrequencyShifterCommitter::Exception>(
|
||||
"Frequency",
|
||||
flFrequency,
|
||||
EAXFREQUENCYSHIFTER_MINFREQUENCY,
|
||||
EAXFREQUENCYSHIFTER_MAXFREQUENCY);
|
||||
}
|
||||
}; // FrequencyValidator
|
||||
|
||||
struct LeftDirectionValidator {
|
||||
void operator()(unsigned long ulLeftDirection) const
|
||||
{
|
||||
eax_validate_range<FrequencyShifterCommitter::Exception>(
|
||||
"Left Direction",
|
||||
ulLeftDirection,
|
||||
EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
|
||||
EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
|
||||
}
|
||||
}; // LeftDirectionValidator
|
||||
|
||||
struct RightDirectionValidator {
|
||||
void operator()(unsigned long ulRightDirection) const
|
||||
{
|
||||
eax_validate_range<FrequencyShifterCommitter::Exception>(
|
||||
"Right Direction",
|
||||
ulRightDirection,
|
||||
EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
|
||||
EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
|
||||
}
|
||||
}; // RightDirectionValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXFREQUENCYSHIFTERPROPERTIES& all) const
|
||||
{
|
||||
FrequencyValidator{}(all.flFrequency);
|
||||
LeftDirectionValidator{}(all.ulLeftDirection);
|
||||
RightDirectionValidator{}(all.ulRightDirection);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct FrequencyShifterCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char *message) : EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void FrequencyShifterCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FrequencyShifterCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mFrequencyShifter.flFrequency == props.mFrequencyShifter.flFrequency
|
||||
&& mEaxProps.mFrequencyShifter.ulLeftDirection == props.mFrequencyShifter.ulLeftDirection
|
||||
&& mEaxProps.mFrequencyShifter.ulRightDirection == props.mFrequencyShifter.ulRightDirection)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
auto get_direction = [](unsigned long dir) noexcept
|
||||
{
|
||||
if(dir == EAX_FREQUENCYSHIFTER_DOWN)
|
||||
return FShifterDirection::Down;
|
||||
if(dir == EAX_FREQUENCYSHIFTER_UP)
|
||||
return FShifterDirection::Up;
|
||||
return FShifterDirection::Off;
|
||||
};
|
||||
|
||||
mAlProps.Fshifter.Frequency = props.mFrequencyShifter.flFrequency;
|
||||
mAlProps.Fshifter.LeftDirection = get_direction(props.mFrequencyShifter.ulLeftDirection);
|
||||
mAlProps.Fshifter.RightDirection = get_direction(props.mFrequencyShifter.ulRightDirection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::FrequencyShifter;
|
||||
props.mFrequencyShifter.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
|
||||
props.mFrequencyShifter.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
|
||||
props.mFrequencyShifter.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXFREQUENCYSHIFTER_NONE: break;
|
||||
case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mFrequencyShifter); break;
|
||||
case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.mFrequencyShifter.flFrequency); break;
|
||||
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.mFrequencyShifter.ulLeftDirection); break;
|
||||
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.mFrequencyShifter.ulRightDirection); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXFREQUENCYSHIFTER_NONE: break;
|
||||
case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mFrequencyShifter); break;
|
||||
case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.mFrequencyShifter.flFrequency); break;
|
||||
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.mFrequencyShifter.ulLeftDirection); break;
|
||||
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(call, props.mFrequencyShifter.ulRightDirection); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
272
externals/openal-soft/al/effects/modulator.cpp
vendored
Normal file
272
externals/openal-soft/al/effects/modulator.cpp
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "aloptional.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case AL_RING_MODULATOR_SINUSOID: return ModulatorWaveform::Sinusoid;
|
||||
case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth;
|
||||
case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square;
|
||||
}
|
||||
return al::nullopt;
|
||||
}
|
||||
ALenum EnumFromWaveform(ModulatorWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
|
||||
case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
|
||||
case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
|
||||
}
|
||||
throw std::runtime_error{"Invalid modulator waveform: " +
|
||||
std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Modulator_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
|
||||
props->Modulator.Frequency = val;
|
||||
break;
|
||||
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
|
||||
props->Modulator.HighPassCutoff = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Modulator_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Modulator_setParamf(props, param, vals[0]); }
|
||||
void Modulator_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
Modulator_setParamf(props, param, static_cast<float>(val));
|
||||
break;
|
||||
|
||||
case AL_RING_MODULATOR_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEmum(val))
|
||||
props->Modulator.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Modulator_setParami(props, param, vals[0]); }
|
||||
|
||||
void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
*val = static_cast<int>(props->Modulator.Frequency);
|
||||
break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
*val = static_cast<int>(props->Modulator.HighPassCutoff);
|
||||
break;
|
||||
case AL_RING_MODULATOR_WAVEFORM:
|
||||
*val = EnumFromWaveform(props->Modulator.Waveform);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Modulator_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Modulator_getParami(props, param, vals); }
|
||||
void Modulator_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY:
|
||||
*val = props->Modulator.Frequency;
|
||||
break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
|
||||
*val = props->Modulator.HighPassCutoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Modulator_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
|
||||
props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
|
||||
props.Modulator.Waveform = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM);
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Modulator);
|
||||
|
||||
const EffectProps ModulatorEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>;
|
||||
|
||||
struct FrequencyValidator {
|
||||
void operator()(float flFrequency) const
|
||||
{
|
||||
eax_validate_range<ModulatorCommitter::Exception>(
|
||||
"Frequency",
|
||||
flFrequency,
|
||||
EAXRINGMODULATOR_MINFREQUENCY,
|
||||
EAXRINGMODULATOR_MAXFREQUENCY);
|
||||
}
|
||||
}; // FrequencyValidator
|
||||
|
||||
struct HighPassCutOffValidator {
|
||||
void operator()(float flHighPassCutOff) const
|
||||
{
|
||||
eax_validate_range<ModulatorCommitter::Exception>(
|
||||
"High-Pass Cutoff",
|
||||
flHighPassCutOff,
|
||||
EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
|
||||
EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
|
||||
}
|
||||
}; // HighPassCutOffValidator
|
||||
|
||||
struct WaveformValidator {
|
||||
void operator()(unsigned long ulWaveform) const
|
||||
{
|
||||
eax_validate_range<ModulatorCommitter::Exception>(
|
||||
"Waveform",
|
||||
ulWaveform,
|
||||
EAXRINGMODULATOR_MINWAVEFORM,
|
||||
EAXRINGMODULATOR_MAXWAVEFORM);
|
||||
}
|
||||
}; // WaveformValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXRINGMODULATORPROPERTIES& all) const
|
||||
{
|
||||
FrequencyValidator{}(all.flFrequency);
|
||||
HighPassCutOffValidator{}(all.flHighPassCutOff);
|
||||
WaveformValidator{}(all.ulWaveform);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct ModulatorCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void ModulatorCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool ModulatorCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mModulator.flFrequency == props.mModulator.flFrequency
|
||||
&& mEaxProps.mModulator.flHighPassCutOff == props.mModulator.flHighPassCutOff
|
||||
&& mEaxProps.mModulator.ulWaveform == props.mModulator.ulWaveform)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
auto get_waveform = [](unsigned long form)
|
||||
{
|
||||
if(form == EAX_RINGMODULATOR_SINUSOID)
|
||||
return ModulatorWaveform::Sinusoid;
|
||||
if(form == EAX_RINGMODULATOR_SAWTOOTH)
|
||||
return ModulatorWaveform::Sawtooth;
|
||||
if(form == EAX_RINGMODULATOR_SQUARE)
|
||||
return ModulatorWaveform::Square;
|
||||
return ModulatorWaveform::Sinusoid;
|
||||
};
|
||||
|
||||
mAlProps.Modulator.Frequency = props.mModulator.flFrequency;
|
||||
mAlProps.Modulator.HighPassCutoff = props.mModulator.flHighPassCutOff;
|
||||
mAlProps.Modulator.Waveform = get_waveform(props.mModulator.ulWaveform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Modulator;
|
||||
props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
|
||||
props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
|
||||
props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXRINGMODULATOR_NONE: break;
|
||||
case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props.mModulator); break;
|
||||
case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.mModulator.flFrequency); break;
|
||||
case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.mModulator.flHighPassCutOff); break;
|
||||
case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.mModulator.ulWaveform); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch (call.get_property_id())
|
||||
{
|
||||
case EAXRINGMODULATOR_NONE: break;
|
||||
case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props.mModulator); break;
|
||||
case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.mModulator.flFrequency); break;
|
||||
case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.mModulator.flHighPassCutOff); break;
|
||||
case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.mModulator.ulWaveform); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
149
externals/openal-soft/al/effects/null.cpp
vendored
Normal file
149
externals/openal-soft/al/effects/null.cpp
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "al/eax/exception.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Null_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Null_setParami(props, param, vals[0]);
|
||||
}
|
||||
}
|
||||
void Null_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Null_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Null_setParamf(props, param, vals[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void Null_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Null_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Null_getParami(props, param, vals);
|
||||
}
|
||||
}
|
||||
void Null_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Null_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
Null_getParamf(props, param, vals);
|
||||
}
|
||||
}
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Null);
|
||||
|
||||
const EffectProps NullEffectProps{genDefaultProps()};
|
||||
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using NullCommitter = EaxCommitter<EaxNullCommitter>;
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct NullCommitter::Exception : public EaxException
|
||||
{
|
||||
explicit Exception(const char *message) : EaxException{"EAX_NULL_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void NullCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool NullCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
const bool ret{props.mType != mEaxProps.mType};
|
||||
mEaxProps = props;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props = EaxEffectProps{};
|
||||
props.mType = EaxEffectType::None;
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::Get(const EaxCall &call, const EaxEffectProps&)
|
||||
{
|
||||
if(call.get_property_id() != 0)
|
||||
fail_unknown_property_id();
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::Set(const EaxCall &call, EaxEffectProps&)
|
||||
{
|
||||
if(call.get_property_id() != 0)
|
||||
fail_unknown_property_id();
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
191
externals/openal-soft/al/effects/pshifter.cpp
vendored
Normal file
191
externals/openal-soft/al/effects/pshifter.cpp
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.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 Pshifter_setParamf(EffectProps*, ALenum param, float)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
|
||||
void Pshifter_setParamfv(EffectProps*, ALenum param, const float*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
void Pshifter_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_PITCH_SHIFTER_COARSE_TUNE:
|
||||
if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Pitch shifter coarse tune out of range"};
|
||||
props->Pshifter.CoarseTune = val;
|
||||
break;
|
||||
|
||||
case AL_PITCH_SHIFTER_FINE_TUNE:
|
||||
if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Pitch shifter fine tune out of range"};
|
||||
props->Pshifter.FineTune = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Pshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Pshifter_setParami(props, param, vals[0]); }
|
||||
|
||||
void Pshifter_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_PITCH_SHIFTER_COARSE_TUNE:
|
||||
*val = props->Pshifter.CoarseTune;
|
||||
break;
|
||||
case AL_PITCH_SHIFTER_FINE_TUNE:
|
||||
*val = props->Pshifter.FineTune;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Pshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
|
||||
{ Pshifter_getParami(props, param, vals); }
|
||||
|
||||
void Pshifter_getParamf(const EffectProps*, ALenum param, float*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
|
||||
void Pshifter_getParamfv(const EffectProps*, ALenum param, float*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
|
||||
props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Pshifter);
|
||||
|
||||
const EffectProps PshifterEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using PitchShifterCommitter = EaxCommitter<EaxPitchShifterCommitter>;
|
||||
|
||||
struct CoarseTuneValidator {
|
||||
void operator()(long lCoarseTune) const
|
||||
{
|
||||
eax_validate_range<PitchShifterCommitter::Exception>(
|
||||
"Coarse Tune",
|
||||
lCoarseTune,
|
||||
EAXPITCHSHIFTER_MINCOARSETUNE,
|
||||
EAXPITCHSHIFTER_MAXCOARSETUNE);
|
||||
}
|
||||
}; // CoarseTuneValidator
|
||||
|
||||
struct FineTuneValidator {
|
||||
void operator()(long lFineTune) const
|
||||
{
|
||||
eax_validate_range<PitchShifterCommitter::Exception>(
|
||||
"Fine Tune",
|
||||
lFineTune,
|
||||
EAXPITCHSHIFTER_MINFINETUNE,
|
||||
EAXPITCHSHIFTER_MAXFINETUNE);
|
||||
}
|
||||
}; // FineTuneValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXPITCHSHIFTERPROPERTIES& all) const
|
||||
{
|
||||
CoarseTuneValidator{}(all.lCoarseTune);
|
||||
FineTuneValidator{}(all.lFineTune);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct PitchShifterCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char *message) : EaxException{"EAX_PITCH_SHIFTER_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void PitchShifterCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool PitchShifterCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mPitchShifter.lCoarseTune == props.mPitchShifter.lCoarseTune
|
||||
&& mEaxProps.mPitchShifter.lFineTune == props.mPitchShifter.lFineTune)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Pshifter.CoarseTune = static_cast<int>(mEaxProps.mPitchShifter.lCoarseTune);
|
||||
mAlProps.Pshifter.FineTune = static_cast<int>(mEaxProps.mPitchShifter.lFineTune);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::PitchShifter;
|
||||
props.mPitchShifter.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE;
|
||||
props.mPitchShifter.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE;
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXPITCHSHIFTER_NONE: break;
|
||||
case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mPitchShifter); break;
|
||||
case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.mPitchShifter.lCoarseTune); break;
|
||||
case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.mPitchShifter.lFineTune); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXPITCHSHIFTER_NONE: break;
|
||||
case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mPitchShifter); break;
|
||||
case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.mPitchShifter.lCoarseTune); break;
|
||||
case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.mPitchShifter.lFineTune); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
1499
externals/openal-soft/al/effects/reverb.cpp
vendored
Normal file
1499
externals/openal-soft/al/effects/reverb.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
520
externals/openal-soft/al/effects/vmorpher.cpp
vendored
Normal file
520
externals/openal-soft/al/effects/vmorpher.cpp
vendored
Normal file
@@ -0,0 +1,520 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "aloptional.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
|
||||
{
|
||||
#define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
|
||||
return VMorpherPhenome::x
|
||||
switch(val)
|
||||
{
|
||||
HANDLE_PHENOME(A);
|
||||
HANDLE_PHENOME(E);
|
||||
HANDLE_PHENOME(I);
|
||||
HANDLE_PHENOME(O);
|
||||
HANDLE_PHENOME(U);
|
||||
HANDLE_PHENOME(AA);
|
||||
HANDLE_PHENOME(AE);
|
||||
HANDLE_PHENOME(AH);
|
||||
HANDLE_PHENOME(AO);
|
||||
HANDLE_PHENOME(EH);
|
||||
HANDLE_PHENOME(ER);
|
||||
HANDLE_PHENOME(IH);
|
||||
HANDLE_PHENOME(IY);
|
||||
HANDLE_PHENOME(UH);
|
||||
HANDLE_PHENOME(UW);
|
||||
HANDLE_PHENOME(B);
|
||||
HANDLE_PHENOME(D);
|
||||
HANDLE_PHENOME(F);
|
||||
HANDLE_PHENOME(G);
|
||||
HANDLE_PHENOME(J);
|
||||
HANDLE_PHENOME(K);
|
||||
HANDLE_PHENOME(L);
|
||||
HANDLE_PHENOME(M);
|
||||
HANDLE_PHENOME(N);
|
||||
HANDLE_PHENOME(P);
|
||||
HANDLE_PHENOME(R);
|
||||
HANDLE_PHENOME(S);
|
||||
HANDLE_PHENOME(T);
|
||||
HANDLE_PHENOME(V);
|
||||
HANDLE_PHENOME(Z);
|
||||
}
|
||||
return al::nullopt;
|
||||
#undef HANDLE_PHENOME
|
||||
}
|
||||
ALenum EnumFromPhenome(VMorpherPhenome phenome)
|
||||
{
|
||||
#define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
|
||||
switch(phenome)
|
||||
{
|
||||
HANDLE_PHENOME(A);
|
||||
HANDLE_PHENOME(E);
|
||||
HANDLE_PHENOME(I);
|
||||
HANDLE_PHENOME(O);
|
||||
HANDLE_PHENOME(U);
|
||||
HANDLE_PHENOME(AA);
|
||||
HANDLE_PHENOME(AE);
|
||||
HANDLE_PHENOME(AH);
|
||||
HANDLE_PHENOME(AO);
|
||||
HANDLE_PHENOME(EH);
|
||||
HANDLE_PHENOME(ER);
|
||||
HANDLE_PHENOME(IH);
|
||||
HANDLE_PHENOME(IY);
|
||||
HANDLE_PHENOME(UH);
|
||||
HANDLE_PHENOME(UW);
|
||||
HANDLE_PHENOME(B);
|
||||
HANDLE_PHENOME(D);
|
||||
HANDLE_PHENOME(F);
|
||||
HANDLE_PHENOME(G);
|
||||
HANDLE_PHENOME(J);
|
||||
HANDLE_PHENOME(K);
|
||||
HANDLE_PHENOME(L);
|
||||
HANDLE_PHENOME(M);
|
||||
HANDLE_PHENOME(N);
|
||||
HANDLE_PHENOME(P);
|
||||
HANDLE_PHENOME(R);
|
||||
HANDLE_PHENOME(S);
|
||||
HANDLE_PHENOME(T);
|
||||
HANDLE_PHENOME(V);
|
||||
HANDLE_PHENOME(Z);
|
||||
}
|
||||
throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
|
||||
#undef HANDLE_PHENOME
|
||||
}
|
||||
|
||||
al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return VMorpherWaveform::Sinusoid;
|
||||
case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle;
|
||||
case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth;
|
||||
}
|
||||
return al::nullopt;
|
||||
}
|
||||
ALenum EnumFromWaveform(VMorpherWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
|
||||
case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
|
||||
case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
|
||||
}
|
||||
throw std::runtime_error{"Invalid vocal morpher waveform: " +
|
||||
std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_PHONEMEA:
|
||||
if(auto phenomeopt = PhenomeFromEnum(val))
|
||||
props->Vmorpher.PhonemeA = *phenomeopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
|
||||
if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
|
||||
props->Vmorpher.PhonemeACoarseTuning = val;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEB:
|
||||
if(auto phenomeopt = PhenomeFromEnum(val))
|
||||
props->Vmorpher.PhonemeB = *phenomeopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
|
||||
if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
|
||||
props->Vmorpher.PhonemeBCoarseTuning = val;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEmum(val))
|
||||
props->Vmorpher.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_RATE:
|
||||
if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
|
||||
props->Vmorpher.Rate = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Vmorpher_setParamf(props, param, vals[0]); }
|
||||
|
||||
void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_PHONEMEA:
|
||||
*val = EnumFromPhenome(props->Vmorpher.PhonemeA);
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
|
||||
*val = props->Vmorpher.PhonemeACoarseTuning;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEB:
|
||||
*val = EnumFromPhenome(props->Vmorpher.PhonemeB);
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
|
||||
*val = props->Vmorpher.PhonemeBCoarseTuning;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_WAVEFORM:
|
||||
*val = EnumFromWaveform(props->Vmorpher.Waveform);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_RATE:
|
||||
*val = props->Vmorpher.Rate;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Vmorpher_getParamf(props, param, vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
|
||||
props.Vmorpher.PhonemeA = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
|
||||
props.Vmorpher.PhonemeB = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
|
||||
props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
|
||||
props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
|
||||
props.Vmorpher.Waveform = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Vmorpher);
|
||||
|
||||
const EffectProps VmorpherEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
|
||||
|
||||
struct PhonemeAValidator {
|
||||
void operator()(unsigned long ulPhonemeA) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Phoneme A",
|
||||
ulPhonemeA,
|
||||
EAXVOCALMORPHER_MINPHONEMEA,
|
||||
EAXVOCALMORPHER_MAXPHONEMEA);
|
||||
}
|
||||
}; // PhonemeAValidator
|
||||
|
||||
struct PhonemeACoarseTuningValidator {
|
||||
void operator()(long lPhonemeACoarseTuning) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Phoneme A Coarse Tuning",
|
||||
lPhonemeACoarseTuning,
|
||||
EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
|
||||
EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
|
||||
}
|
||||
}; // PhonemeACoarseTuningValidator
|
||||
|
||||
struct PhonemeBValidator {
|
||||
void operator()(unsigned long ulPhonemeB) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Phoneme B",
|
||||
ulPhonemeB,
|
||||
EAXVOCALMORPHER_MINPHONEMEB,
|
||||
EAXVOCALMORPHER_MAXPHONEMEB);
|
||||
}
|
||||
}; // PhonemeBValidator
|
||||
|
||||
struct PhonemeBCoarseTuningValidator {
|
||||
void operator()(long lPhonemeBCoarseTuning) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Phoneme B Coarse Tuning",
|
||||
lPhonemeBCoarseTuning,
|
||||
EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
|
||||
EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
|
||||
}
|
||||
}; // PhonemeBCoarseTuningValidator
|
||||
|
||||
struct WaveformValidator {
|
||||
void operator()(unsigned long ulWaveform) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Waveform",
|
||||
ulWaveform,
|
||||
EAXVOCALMORPHER_MINWAVEFORM,
|
||||
EAXVOCALMORPHER_MAXWAVEFORM);
|
||||
}
|
||||
}; // WaveformValidator
|
||||
|
||||
struct RateValidator {
|
||||
void operator()(float flRate) const
|
||||
{
|
||||
eax_validate_range<VocalMorpherCommitter::Exception>(
|
||||
"Rate",
|
||||
flRate,
|
||||
EAXVOCALMORPHER_MINRATE,
|
||||
EAXVOCALMORPHER_MAXRATE);
|
||||
}
|
||||
}; // RateValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
|
||||
{
|
||||
PhonemeAValidator{}(all.ulPhonemeA);
|
||||
PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
|
||||
PhonemeBValidator{}(all.ulPhonemeB);
|
||||
PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
|
||||
WaveformValidator{}(all.ulWaveform);
|
||||
RateValidator{}(all.flRate);
|
||||
}
|
||||
}; // AllValidator
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct VocalMorpherCommitter::Exception : public EaxException {
|
||||
explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
[[noreturn]] void VocalMorpherCommitter::fail(const char *message)
|
||||
{
|
||||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mVocalMorpher.ulPhonemeA == props.mVocalMorpher.ulPhonemeA
|
||||
&& mEaxProps.mVocalMorpher.lPhonemeACoarseTuning == props.mVocalMorpher.lPhonemeACoarseTuning
|
||||
&& mEaxProps.mVocalMorpher.ulPhonemeB == props.mVocalMorpher.ulPhonemeB
|
||||
&& mEaxProps.mVocalMorpher.lPhonemeBCoarseTuning == props.mVocalMorpher.lPhonemeBCoarseTuning
|
||||
&& mEaxProps.mVocalMorpher.ulWaveform == props.mVocalMorpher.ulWaveform
|
||||
&& mEaxProps.mVocalMorpher.flRate == props.mVocalMorpher.flRate)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
auto get_phoneme = [](unsigned long phoneme) noexcept
|
||||
{
|
||||
#define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
|
||||
switch(phoneme)
|
||||
{
|
||||
HANDLE_PHENOME(A);
|
||||
HANDLE_PHENOME(E);
|
||||
HANDLE_PHENOME(I);
|
||||
HANDLE_PHENOME(O);
|
||||
HANDLE_PHENOME(U);
|
||||
HANDLE_PHENOME(AA);
|
||||
HANDLE_PHENOME(AE);
|
||||
HANDLE_PHENOME(AH);
|
||||
HANDLE_PHENOME(AO);
|
||||
HANDLE_PHENOME(EH);
|
||||
HANDLE_PHENOME(ER);
|
||||
HANDLE_PHENOME(IH);
|
||||
HANDLE_PHENOME(IY);
|
||||
HANDLE_PHENOME(UH);
|
||||
HANDLE_PHENOME(UW);
|
||||
HANDLE_PHENOME(B);
|
||||
HANDLE_PHENOME(D);
|
||||
HANDLE_PHENOME(F);
|
||||
HANDLE_PHENOME(G);
|
||||
HANDLE_PHENOME(J);
|
||||
HANDLE_PHENOME(K);
|
||||
HANDLE_PHENOME(L);
|
||||
HANDLE_PHENOME(M);
|
||||
HANDLE_PHENOME(N);
|
||||
HANDLE_PHENOME(P);
|
||||
HANDLE_PHENOME(R);
|
||||
HANDLE_PHENOME(S);
|
||||
HANDLE_PHENOME(T);
|
||||
HANDLE_PHENOME(V);
|
||||
HANDLE_PHENOME(Z);
|
||||
}
|
||||
return VMorpherPhenome::A;
|
||||
#undef HANDLE_PHENOME
|
||||
};
|
||||
auto get_waveform = [](unsigned long form) noexcept
|
||||
{
|
||||
if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid;
|
||||
if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle;
|
||||
if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth;
|
||||
return VMorpherWaveform::Sinusoid;
|
||||
};
|
||||
|
||||
mAlProps.Vmorpher.PhonemeA = get_phoneme(props.mVocalMorpher.ulPhonemeA);
|
||||
mAlProps.Vmorpher.PhonemeACoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeACoarseTuning);
|
||||
mAlProps.Vmorpher.PhonemeB = get_phoneme(props.mVocalMorpher.ulPhonemeB);
|
||||
mAlProps.Vmorpher.PhonemeBCoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeBCoarseTuning);
|
||||
mAlProps.Vmorpher.Waveform = get_waveform(props.mVocalMorpher.ulWaveform);
|
||||
mAlProps.Vmorpher.Rate = props.mVocalMorpher.flRate;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::VocalMorpher;
|
||||
props.mVocalMorpher.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
|
||||
props.mVocalMorpher.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
|
||||
props.mVocalMorpher.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
|
||||
props.mVocalMorpher.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
|
||||
props.mVocalMorpher.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
|
||||
props.mVocalMorpher.flRate = EAXVOCALMORPHER_DEFAULTRATE;
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXVOCALMORPHER_NONE:
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_ALLPARAMETERS:
|
||||
call.set_value<Exception>(props.mVocalMorpher);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEA:
|
||||
call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
|
||||
call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEB:
|
||||
call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
|
||||
call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_WAVEFORM:
|
||||
call.set_value<Exception>(props.mVocalMorpher.ulWaveform);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_RATE:
|
||||
call.set_value<Exception>(props.mVocalMorpher.flRate);
|
||||
break;
|
||||
|
||||
default:
|
||||
fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
{
|
||||
switch(call.get_property_id())
|
||||
{
|
||||
case EAXVOCALMORPHER_NONE:
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_ALLPARAMETERS:
|
||||
defer<AllValidator>(call, props.mVocalMorpher);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEA:
|
||||
defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
|
||||
defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEB:
|
||||
defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
|
||||
defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_WAVEFORM:
|
||||
defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform);
|
||||
break;
|
||||
|
||||
case EAXVOCALMORPHER_RATE:
|
||||
defer<RateValidator>(call, props.mVocalMorpher.flRate);
|
||||
break;
|
||||
|
||||
default:
|
||||
fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
106
externals/openal-soft/al/error.cpp
vendored
Normal file
106
externals/openal-soft/al/error.cpp
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2000 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "almalloc.h"
|
||||
#include "core/except.h"
|
||||
#include "core/logging.h"
|
||||
#include "opthelpers.h"
|
||||
#include "vector.h"
|
||||
|
||||
|
||||
bool TrapALError{false};
|
||||
|
||||
void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
|
||||
{
|
||||
auto message = al::vector<char>(256);
|
||||
|
||||
va_list args, args2;
|
||||
va_start(args, msg);
|
||||
va_copy(args2, args);
|
||||
int msglen{std::vsnprintf(message.data(), message.size(), msg, args)};
|
||||
if(msglen >= 0 && static_cast<size_t>(msglen) >= message.size())
|
||||
{
|
||||
message.resize(static_cast<size_t>(msglen) + 1u);
|
||||
msglen = std::vsnprintf(message.data(), message.size(), msg, args2);
|
||||
}
|
||||
va_end(args2);
|
||||
va_end(args);
|
||||
|
||||
if(msglen >= 0) msg = message.data();
|
||||
else msg = "<internal error constructing message>";
|
||||
|
||||
WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
|
||||
decltype(std::declval<void*>()){this}, errorCode, msg);
|
||||
if(TrapALError)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/* DebugBreak will cause an exception if there is no debugger */
|
||||
if(IsDebuggerPresent())
|
||||
DebugBreak();
|
||||
#elif defined(SIGTRAP)
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
}
|
||||
|
||||
ALenum curerr{AL_NO_ERROR};
|
||||
mLastError.compare_exchange_strong(curerr, errorCode);
|
||||
}
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetError(void)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY
|
||||
{
|
||||
static constexpr ALenum deferror{AL_INVALID_OPERATION};
|
||||
WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
|
||||
if(TrapALError)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if(IsDebuggerPresent())
|
||||
DebugBreak();
|
||||
#elif defined(SIGTRAP)
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
}
|
||||
return deferror;
|
||||
}
|
||||
|
||||
return context->mLastError.exchange(AL_NO_ERROR);
|
||||
}
|
||||
END_API_FUNC
|
||||
215
externals/openal-soft/al/event.cpp
vendored
Normal file
215
externals/openal-soft/al/event.cpp
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "event.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "albyte.h"
|
||||
#include "alc/context.h"
|
||||
#include "alc/effects/base.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "almalloc.h"
|
||||
#include "core/async_event.h"
|
||||
#include "core/except.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/voice_change.h"
|
||||
#include "opthelpers.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "threads.h"
|
||||
|
||||
|
||||
static int EventThread(ALCcontext *context)
|
||||
{
|
||||
RingBuffer *ring{context->mAsyncEvents.get()};
|
||||
bool quitnow{false};
|
||||
while(!quitnow)
|
||||
{
|
||||
auto evt_data = ring->getReadVector().first;
|
||||
if(evt_data.len == 0)
|
||||
{
|
||||
context->mEventSem.wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mEventCbLock};
|
||||
do {
|
||||
auto *evt_ptr = reinterpret_cast<AsyncEvent*>(evt_data.buf);
|
||||
evt_data.buf += sizeof(AsyncEvent);
|
||||
evt_data.len -= 1;
|
||||
|
||||
AsyncEvent evt{*evt_ptr};
|
||||
al::destroy_at(evt_ptr);
|
||||
ring->readAdvance(1);
|
||||
|
||||
quitnow = evt.EnumType == AsyncEvent::KillThread;
|
||||
if(quitnow) UNLIKELY break;
|
||||
|
||||
if(evt.EnumType == AsyncEvent::ReleaseEffectState)
|
||||
{
|
||||
al::intrusive_ptr<EffectState>{evt.u.mEffectState};
|
||||
continue;
|
||||
}
|
||||
|
||||
auto enabledevts = context->mEnabledEvts.load(std::memory_order_acquire);
|
||||
if(!context->mEventCb || !enabledevts.test(evt.EnumType))
|
||||
continue;
|
||||
|
||||
if(evt.EnumType == AsyncEvent::SourceStateChange)
|
||||
{
|
||||
ALuint state{};
|
||||
std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)};
|
||||
msg += " state has changed to ";
|
||||
switch(evt.u.srcstate.state)
|
||||
{
|
||||
case AsyncEvent::SrcState::Reset:
|
||||
msg += "AL_INITIAL";
|
||||
state = AL_INITIAL;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Stop:
|
||||
msg += "AL_STOPPED";
|
||||
state = AL_STOPPED;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Play:
|
||||
msg += "AL_PLAYING";
|
||||
state = AL_PLAYING;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Pause:
|
||||
msg += "AL_PAUSED";
|
||||
state = AL_PAUSED;
|
||||
break;
|
||||
}
|
||||
context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id,
|
||||
state, static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam);
|
||||
}
|
||||
else if(evt.EnumType == AsyncEvent::BufferCompleted)
|
||||
{
|
||||
std::string msg{std::to_string(evt.u.bufcomp.count)};
|
||||
if(evt.u.bufcomp.count == 1) msg += " buffer completed";
|
||||
else msg += " buffers completed";
|
||||
context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id,
|
||||
evt.u.bufcomp.count, static_cast<ALsizei>(msg.length()), msg.c_str(),
|
||||
context->mEventParam);
|
||||
}
|
||||
else if(evt.EnumType == AsyncEvent::Disconnected)
|
||||
{
|
||||
context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0,
|
||||
static_cast<ALsizei>(strlen(evt.u.disconnect.msg)), evt.u.disconnect.msg,
|
||||
context->mEventParam);
|
||||
}
|
||||
} while(evt_data.len != 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StartEventThrd(ALCcontext *ctx)
|
||||
{
|
||||
try {
|
||||
ctx->mEventThread = std::thread{EventThread, ctx};
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
ERR("Failed to start event thread: %s\n", e.what());
|
||||
}
|
||||
catch(...) {
|
||||
ERR("Failed to start event thread! Expect problems.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StopEventThrd(ALCcontext *ctx)
|
||||
{
|
||||
RingBuffer *ring{ctx->mAsyncEvents.get()};
|
||||
auto evt_data = ring->getWriteVector().first;
|
||||
if(evt_data.len == 0)
|
||||
{
|
||||
do {
|
||||
std::this_thread::yield();
|
||||
evt_data = ring->getWriteVector().first;
|
||||
} while(evt_data.len == 0);
|
||||
}
|
||||
al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread);
|
||||
ring->writeAdvance(1);
|
||||
|
||||
ctx->mEventSem.post();
|
||||
if(ctx->mEventThread.joinable())
|
||||
ctx->mEventThread.join();
|
||||
}
|
||||
|
||||
AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(count < 0) context->setError(AL_INVALID_VALUE, "Controlling %d events", count);
|
||||
if(count <= 0) return;
|
||||
if(!types) return context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
|
||||
ContextBase::AsyncEventBitset flags{};
|
||||
const ALenum *types_end = types+count;
|
||||
auto bad_type = std::find_if_not(types, types_end,
|
||||
[&flags](ALenum type) noexcept -> bool
|
||||
{
|
||||
if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
|
||||
flags.set(AsyncEvent::BufferCompleted);
|
||||
else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
|
||||
flags.set(AsyncEvent::SourceStateChange);
|
||||
else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT)
|
||||
flags.set(AsyncEvent::Disconnected);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
);
|
||||
if(bad_type != types_end)
|
||||
return context->setError(AL_INVALID_ENUM, "Invalid event type 0x%04x", *bad_type);
|
||||
|
||||
if(enable)
|
||||
{
|
||||
auto enabledevts = context->mEnabledEvts.load(std::memory_order_relaxed);
|
||||
while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire) == 0)
|
||||
{
|
||||
/* enabledevts is (re-)filled with the current value on failure, so
|
||||
* just try again.
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto enabledevts = context->mEnabledEvts.load(std::memory_order_relaxed);
|
||||
while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire) == 0)
|
||||
{
|
||||
}
|
||||
/* Wait to ensure the event handler sees the changed flags before
|
||||
* returning.
|
||||
*/
|
||||
std::lock_guard<std::mutex> _{context->mEventCbLock};
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
std::lock_guard<std::mutex> __{context->mEventCbLock};
|
||||
context->mEventCb = callback;
|
||||
context->mEventParam = userParam;
|
||||
}
|
||||
END_API_FUNC
|
||||
9
externals/openal-soft/al/event.h
vendored
Normal file
9
externals/openal-soft/al/event.h
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef AL_EVENT_H
|
||||
#define AL_EVENT_H
|
||||
|
||||
struct ALCcontext;
|
||||
|
||||
void StartEventThrd(ALCcontext *ctx);
|
||||
void StopEventThrd(ALCcontext *ctx);
|
||||
|
||||
#endif
|
||||
82
externals/openal-soft/al/extension.cpp
vendored
Normal file
82
externals/openal-soft/al/extension.cpp
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "alstring.h"
|
||||
#include "core/except.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return AL_FALSE;
|
||||
|
||||
if(!extName) UNLIKELY
|
||||
{
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
size_t len{strlen(extName)};
|
||||
const char *ptr{context->mExtensionList};
|
||||
while(ptr && *ptr)
|
||||
{
|
||||
if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
|
||||
return AL_TRUE;
|
||||
|
||||
if((ptr=strchr(ptr, ' ')) != nullptr)
|
||||
{
|
||||
do {
|
||||
++ptr;
|
||||
} while(isspace(*ptr));
|
||||
}
|
||||
}
|
||||
|
||||
return AL_FALSE;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(!funcName) return nullptr;
|
||||
return alcGetProcAddress(nullptr, funcName);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(!enumName) return static_cast<ALenum>(0);
|
||||
return alcGetEnumValue(nullptr, enumName);
|
||||
}
|
||||
END_API_FUNC
|
||||
722
externals/openal-soft/al/filter.cpp
vendored
Normal file
722
externals/openal-soft/al/filter.cpp
vendored
Normal file
@@ -0,0 +1,722 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "albit.h"
|
||||
#include "alc/context.h"
|
||||
#include "alc/device.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "core/except.h"
|
||||
#include "opthelpers.h"
|
||||
#include "vector.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class filter_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
|
||||
filter_exception(ALenum code, const char *msg, ...);
|
||||
~filter_exception() override;
|
||||
|
||||
ALenum errorCode() const noexcept { return mErrorCode; }
|
||||
};
|
||||
|
||||
filter_exception::filter_exception(ALenum code, const char* msg, ...) : mErrorCode{code}
|
||||
{
|
||||
std::va_list args;
|
||||
va_start(args, msg);
|
||||
setMessage(msg, args);
|
||||
va_end(args);
|
||||
}
|
||||
filter_exception::~filter_exception() = default;
|
||||
|
||||
|
||||
#define DEFINE_ALFILTER_VTABLE(T) \
|
||||
const ALfilter::Vtable T##_vtable = { \
|
||||
T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \
|
||||
T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \
|
||||
}
|
||||
|
||||
void ALlowpass_setParami(ALfilter*, ALenum param, int)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
|
||||
void ALlowpass_setParamiv(ALfilter*, ALenum param, const int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_LOWPASS_GAIN:
|
||||
if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
|
||||
throw filter_exception{AL_INVALID_VALUE, "Low-pass gain %f out of range", val};
|
||||
filter->Gain = val;
|
||||
break;
|
||||
|
||||
case AL_LOWPASS_GAINHF:
|
||||
if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
|
||||
throw filter_exception{AL_INVALID_VALUE, "Low-pass gainhf %f out of range", val};
|
||||
filter->GainHF = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALlowpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
|
||||
{ ALlowpass_setParamf(filter, param, vals[0]); }
|
||||
|
||||
void ALlowpass_getParami(const ALfilter*, ALenum param, int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
|
||||
void ALlowpass_getParamiv(const ALfilter*, ALenum param, int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_LOWPASS_GAIN:
|
||||
*val = filter->Gain;
|
||||
break;
|
||||
|
||||
case AL_LOWPASS_GAINHF:
|
||||
*val = filter->GainHF;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALlowpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
|
||||
{ ALlowpass_getParamf(filter, param, vals); }
|
||||
|
||||
DEFINE_ALFILTER_VTABLE(ALlowpass);
|
||||
|
||||
|
||||
void ALhighpass_setParami(ALfilter*, ALenum param, int)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
|
||||
void ALhighpass_setParamiv(ALfilter*, ALenum param, const int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_HIGHPASS_GAIN:
|
||||
if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
|
||||
throw filter_exception{AL_INVALID_VALUE, "High-pass gain %f out of range", val};
|
||||
filter->Gain = val;
|
||||
break;
|
||||
|
||||
case AL_HIGHPASS_GAINLF:
|
||||
if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
|
||||
throw filter_exception{AL_INVALID_VALUE, "High-pass gainlf %f out of range", val};
|
||||
filter->GainLF = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALhighpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
|
||||
{ ALhighpass_setParamf(filter, param, vals[0]); }
|
||||
|
||||
void ALhighpass_getParami(const ALfilter*, ALenum param, int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
|
||||
void ALhighpass_getParamiv(const ALfilter*, ALenum param, int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_HIGHPASS_GAIN:
|
||||
*val = filter->Gain;
|
||||
break;
|
||||
|
||||
case AL_HIGHPASS_GAINLF:
|
||||
*val = filter->GainLF;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALhighpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
|
||||
{ ALhighpass_getParamf(filter, param, vals); }
|
||||
|
||||
DEFINE_ALFILTER_VTABLE(ALhighpass);
|
||||
|
||||
|
||||
void ALbandpass_setParami(ALfilter*, ALenum param, int)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
|
||||
void ALbandpass_setParamiv(ALfilter*, ALenum param, const int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_BANDPASS_GAIN:
|
||||
if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
|
||||
throw filter_exception{AL_INVALID_VALUE, "Band-pass gain %f out of range", val};
|
||||
filter->Gain = val;
|
||||
break;
|
||||
|
||||
case AL_BANDPASS_GAINHF:
|
||||
if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
|
||||
throw filter_exception{AL_INVALID_VALUE, "Band-pass gainhf %f out of range", val};
|
||||
filter->GainHF = val;
|
||||
break;
|
||||
|
||||
case AL_BANDPASS_GAINLF:
|
||||
if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
|
||||
throw filter_exception{AL_INVALID_VALUE, "Band-pass gainlf %f out of range", val};
|
||||
filter->GainLF = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALbandpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
|
||||
{ ALbandpass_setParamf(filter, param, vals[0]); }
|
||||
|
||||
void ALbandpass_getParami(const ALfilter*, ALenum param, int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
|
||||
void ALbandpass_getParamiv(const ALfilter*, ALenum param, int*)
|
||||
{
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_BANDPASS_GAIN:
|
||||
*val = filter->Gain;
|
||||
break;
|
||||
|
||||
case AL_BANDPASS_GAINHF:
|
||||
*val = filter->GainHF;
|
||||
break;
|
||||
|
||||
case AL_BANDPASS_GAINLF:
|
||||
*val = filter->GainLF;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ALbandpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
|
||||
{ ALbandpass_getParamf(filter, param, vals); }
|
||||
|
||||
DEFINE_ALFILTER_VTABLE(ALbandpass);
|
||||
|
||||
|
||||
void ALnullfilter_setParami(ALfilter*, ALenum param, int)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_setParamiv(ALfilter*, ALenum param, const int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_setParamf(ALfilter*, ALenum param, float)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_setParamfv(ALfilter*, ALenum param, const float*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
|
||||
void ALnullfilter_getParami(const ALfilter*, ALenum param, int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_getParamiv(const ALfilter*, ALenum param, int*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_getParamf(const ALfilter*, ALenum param, float*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
void ALnullfilter_getParamfv(const ALfilter*, ALenum param, float*)
|
||||
{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
|
||||
|
||||
DEFINE_ALFILTER_VTABLE(ALnullfilter);
|
||||
|
||||
|
||||
void InitFilterParams(ALfilter *filter, ALenum type)
|
||||
{
|
||||
if(type == AL_FILTER_LOWPASS)
|
||||
{
|
||||
filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
|
||||
filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
|
||||
filter->HFReference = LOWPASSFREQREF;
|
||||
filter->GainLF = 1.0f;
|
||||
filter->LFReference = HIGHPASSFREQREF;
|
||||
filter->vtab = &ALlowpass_vtable;
|
||||
}
|
||||
else if(type == AL_FILTER_HIGHPASS)
|
||||
{
|
||||
filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
|
||||
filter->GainHF = 1.0f;
|
||||
filter->HFReference = LOWPASSFREQREF;
|
||||
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
|
||||
filter->LFReference = HIGHPASSFREQREF;
|
||||
filter->vtab = &ALhighpass_vtable;
|
||||
}
|
||||
else if(type == AL_FILTER_BANDPASS)
|
||||
{
|
||||
filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
|
||||
filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
|
||||
filter->HFReference = LOWPASSFREQREF;
|
||||
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
|
||||
filter->LFReference = HIGHPASSFREQREF;
|
||||
filter->vtab = &ALbandpass_vtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
filter->Gain = 1.0f;
|
||||
filter->GainHF = 1.0f;
|
||||
filter->HFReference = LOWPASSFREQREF;
|
||||
filter->GainLF = 1.0f;
|
||||
filter->LFReference = HIGHPASSFREQREF;
|
||||
filter->vtab = &ALnullfilter_vtable;
|
||||
}
|
||||
filter->type = type;
|
||||
}
|
||||
|
||||
bool EnsureFilters(ALCdevice *device, size_t needed)
|
||||
{
|
||||
size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0},
|
||||
[](size_t cur, const FilterSubList &sublist) noexcept -> size_t
|
||||
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
|
||||
|
||||
while(needed > count)
|
||||
{
|
||||
if(device->FilterList.size() >= 1<<25) UNLIKELY
|
||||
return false;
|
||||
|
||||
device->FilterList.emplace_back();
|
||||
auto sublist = device->FilterList.end() - 1;
|
||||
sublist->FreeMask = ~0_u64;
|
||||
sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64));
|
||||
if(!sublist->Filters) UNLIKELY
|
||||
{
|
||||
device->FilterList.pop_back();
|
||||
return false;
|
||||
}
|
||||
count += 64;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ALfilter *AllocFilter(ALCdevice *device)
|
||||
{
|
||||
auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
|
||||
[](const FilterSubList &entry) noexcept -> bool
|
||||
{ return entry.FreeMask != 0; });
|
||||
auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist));
|
||||
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
|
||||
ASSUME(slidx < 64);
|
||||
|
||||
ALfilter *filter{al::construct_at(sublist->Filters + slidx)};
|
||||
InitFilterParams(filter, AL_FILTER_NULL);
|
||||
|
||||
/* Add 1 to avoid filter ID 0. */
|
||||
filter->id = ((lidx<<6) | slidx) + 1;
|
||||
|
||||
sublist->FreeMask &= ~(1_u64 << slidx);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
void FreeFilter(ALCdevice *device, ALfilter *filter)
|
||||
{
|
||||
const ALuint id{filter->id - 1};
|
||||
const size_t lidx{id >> 6};
|
||||
const ALuint slidx{id & 0x3f};
|
||||
|
||||
al::destroy_at(filter);
|
||||
|
||||
device->FilterList[lidx].FreeMask |= 1_u64 << slidx;
|
||||
}
|
||||
|
||||
|
||||
inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
|
||||
{
|
||||
const size_t lidx{(id-1) >> 6};
|
||||
const ALuint slidx{(id-1) & 0x3f};
|
||||
|
||||
if(lidx >= device->FilterList.size()) UNLIKELY
|
||||
return nullptr;
|
||||
FilterSubList &sublist = device->FilterList[lidx];
|
||||
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
|
||||
return nullptr;
|
||||
return sublist.Filters + slidx;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(n < 0) UNLIKELY
|
||||
context->setError(AL_INVALID_VALUE, "Generating %d filters", n);
|
||||
if(n <= 0) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
if(!EnsureFilters(device, static_cast<ALuint>(n)))
|
||||
{
|
||||
context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d filter%s", n, (n==1)?"":"s");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n == 1) LIKELY
|
||||
{
|
||||
/* Special handling for the easy and normal case. */
|
||||
ALfilter *filter{AllocFilter(device)};
|
||||
if(filter) filters[0] = filter->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Store the allocated buffer IDs in a separate local list, to avoid
|
||||
* modifying the user storage in case of failure.
|
||||
*/
|
||||
al::vector<ALuint> ids;
|
||||
ids.reserve(static_cast<ALuint>(n));
|
||||
do {
|
||||
ALfilter *filter{AllocFilter(device)};
|
||||
ids.emplace_back(filter->id);
|
||||
} while(--n);
|
||||
std::copy(ids.begin(), ids.end(), filters);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(n < 0) UNLIKELY
|
||||
context->setError(AL_INVALID_VALUE, "Deleting %d filters", n);
|
||||
if(n <= 0) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
/* First try to find any filters that are invalid. */
|
||||
auto validate_filter = [device](const ALuint fid) -> bool
|
||||
{ return !fid || LookupFilter(device, fid) != nullptr; };
|
||||
|
||||
const ALuint *filters_end = filters + n;
|
||||
auto invflt = std::find_if_not(filters, filters_end, validate_filter);
|
||||
if(invflt != filters_end) UNLIKELY
|
||||
{
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", *invflt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All good. Delete non-0 filter IDs. */
|
||||
auto delete_filter = [device](const ALuint fid) -> void
|
||||
{
|
||||
ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr};
|
||||
if(filter) FreeFilter(device, filter);
|
||||
};
|
||||
std::for_each(filters, filters_end, delete_filter);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(context) LIKELY
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
if(!filter || LookupFilter(device, filter))
|
||||
return AL_TRUE;
|
||||
}
|
||||
return AL_FALSE;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else
|
||||
{
|
||||
if(param == AL_FILTER_TYPE)
|
||||
{
|
||||
if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS
|
||||
|| value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
|
||||
InitFilterParams(alfilt, value);
|
||||
else
|
||||
context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
|
||||
}
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->setParami(param, value);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FILTER_TYPE:
|
||||
alFilteri(filter, param, values[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->setParamiv(param, values);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->setParamf(param, value);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->setParamfv(param, values);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
const ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else
|
||||
{
|
||||
if(param == AL_FILTER_TYPE)
|
||||
*value = alfilt->type;
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->getParami(param, value);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FILTER_TYPE:
|
||||
alGetFilteri(filter, param, values);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
const ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->getParamiv(param, values);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
const ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->getParamf(param, value);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->FilterLock};
|
||||
|
||||
const ALfilter *alfilt{LookupFilter(device, filter)};
|
||||
if(!alfilt) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
|
||||
else try
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
alfilt->getParamfv(param, values);
|
||||
}
|
||||
catch(filter_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
FilterSubList::~FilterSubList()
|
||||
{
|
||||
uint64_t usemask{~FreeMask};
|
||||
while(usemask)
|
||||
{
|
||||
const int idx{al::countr_zero(usemask)};
|
||||
al::destroy_at(Filters+idx);
|
||||
usemask &= ~(1_u64 << idx);
|
||||
}
|
||||
FreeMask = ~usemask;
|
||||
al_free(Filters);
|
||||
Filters = nullptr;
|
||||
}
|
||||
52
externals/openal-soft/al/filter.h
vendored
Normal file
52
externals/openal-soft/al/filter.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef AL_FILTER_H
|
||||
#define AL_FILTER_H
|
||||
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
#define LOWPASSFREQREF 5000.0f
|
||||
#define HIGHPASSFREQREF 250.0f
|
||||
|
||||
|
||||
struct ALfilter {
|
||||
ALenum type{AL_FILTER_NULL};
|
||||
|
||||
float Gain{1.0f};
|
||||
float GainHF{1.0f};
|
||||
float HFReference{LOWPASSFREQREF};
|
||||
float GainLF{1.0f};
|
||||
float LFReference{HIGHPASSFREQREF};
|
||||
|
||||
struct Vtable {
|
||||
void (*const setParami )(ALfilter *filter, ALenum param, int val);
|
||||
void (*const setParamiv)(ALfilter *filter, ALenum param, const int *vals);
|
||||
void (*const setParamf )(ALfilter *filter, ALenum param, float val);
|
||||
void (*const setParamfv)(ALfilter *filter, ALenum param, const float *vals);
|
||||
|
||||
void (*const getParami )(const ALfilter *filter, ALenum param, int *val);
|
||||
void (*const getParamiv)(const ALfilter *filter, ALenum param, int *vals);
|
||||
void (*const getParamf )(const ALfilter *filter, ALenum param, float *val);
|
||||
void (*const getParamfv)(const ALfilter *filter, ALenum param, float *vals);
|
||||
};
|
||||
const Vtable *vtab{nullptr};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{0};
|
||||
|
||||
void setParami(ALenum param, int value) { vtab->setParami(this, param, value); }
|
||||
void setParamiv(ALenum param, const int *values) { vtab->setParamiv(this, param, values); }
|
||||
void setParamf(ALenum param, float value) { vtab->setParamf(this, param, value); }
|
||||
void setParamfv(ALenum param, const float *values) { vtab->setParamfv(this, param, values); }
|
||||
void getParami(ALenum param, int *value) const { vtab->getParami(this, param, value); }
|
||||
void getParamiv(ALenum param, int *values) const { vtab->getParamiv(this, param, values); }
|
||||
void getParamf(ALenum param, float *value) const { vtab->getParamf(this, param, value); }
|
||||
void getParamfv(ALenum param, float *values) const { vtab->getParamfv(this, param, values); }
|
||||
|
||||
DISABLE_ALLOC()
|
||||
};
|
||||
|
||||
#endif
|
||||
444
externals/openal-soft/al/listener.cpp
vendored
Normal file
444
externals/openal-soft/al/listener.cpp
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2000 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "listener.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "almalloc.h"
|
||||
#include "atomic.h"
|
||||
#include "core/except.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
inline void UpdateProps(ALCcontext *context)
|
||||
{
|
||||
if(!context->mDeferUpdates)
|
||||
{
|
||||
UpdateContextProps(context);
|
||||
return;
|
||||
}
|
||||
context->mPropsDirty = true;
|
||||
}
|
||||
|
||||
inline void CommitAndUpdateProps(ALCcontext *context)
|
||||
{
|
||||
if(!context->mDeferUpdates)
|
||||
{
|
||||
#ifdef ALSOFT_EAX
|
||||
if(context->eaxNeedsCommit())
|
||||
{
|
||||
context->mPropsDirty = true;
|
||||
context->applyAllUpdates();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
UpdateContextProps(context);
|
||||
return;
|
||||
}
|
||||
context->mPropsDirty = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
if(!(value >= 0.0f && std::isfinite(value)))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener gain out of range");
|
||||
listener.Gain = value;
|
||||
UpdateProps(context.get());
|
||||
break;
|
||||
|
||||
case AL_METERS_PER_UNIT:
|
||||
if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener meters per unit out of range");
|
||||
listener.mMetersPerUnit = value;
|
||||
UpdateProps(context.get());
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener float property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener position out of range");
|
||||
listener.Position[0] = value1;
|
||||
listener.Position[1] = value2;
|
||||
listener.Position[2] = value3;
|
||||
CommitAndUpdateProps(context.get());
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener velocity out of range");
|
||||
listener.Velocity[0] = value1;
|
||||
listener.Velocity[1] = value2;
|
||||
listener.Velocity[2] = value3;
|
||||
CommitAndUpdateProps(context.get());
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
case AL_METERS_PER_UNIT:
|
||||
alListenerf(param, values[0]);
|
||||
return;
|
||||
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alListener3f(param, values[0], values[1], values[2]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values) UNLIKELY
|
||||
return context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
|
||||
std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener orientation out of range");
|
||||
/* AT then UP */
|
||||
listener.OrientAt[0] = values[0];
|
||||
listener.OrientAt[1] = values[1];
|
||||
listener.OrientAt[2] = values[2];
|
||||
listener.OrientUp[0] = values[3];
|
||||
listener.OrientUp[1] = values[4];
|
||||
listener.OrientUp[2] = values[5];
|
||||
CommitAndUpdateProps(context.get());
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alListeneri(ALenum param, ALint /*value*/)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener integer property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alListener3f(param, static_cast<ALfloat>(value1), static_cast<ALfloat>(value2),
|
||||
static_cast<ALfloat>(value3));
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
ALfloat fvals[6];
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alListener3f(param, static_cast<ALfloat>(values[0]), static_cast<ALfloat>(values[1]),
|
||||
static_cast<ALfloat>(values[2]));
|
||||
return;
|
||||
|
||||
case AL_ORIENTATION:
|
||||
fvals[0] = static_cast<ALfloat>(values[0]);
|
||||
fvals[1] = static_cast<ALfloat>(values[1]);
|
||||
fvals[2] = static_cast<ALfloat>(values[2]);
|
||||
fvals[3] = static_cast<ALfloat>(values[3]);
|
||||
fvals[4] = static_cast<ALfloat>(values[4]);
|
||||
fvals[5] = static_cast<ALfloat>(values[5]);
|
||||
alListenerfv(param, fvals);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!values) UNLIKELY
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!value)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
*value = listener.Gain;
|
||||
break;
|
||||
|
||||
case AL_METERS_PER_UNIT:
|
||||
*value = listener.mMetersPerUnit;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener float property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!value1 || !value2 || !value3)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
*value1 = listener.Position[0];
|
||||
*value2 = listener.Position[1];
|
||||
*value3 = listener.Position[2];
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
*value1 = listener.Velocity[0];
|
||||
*value2 = listener.Velocity[1];
|
||||
*value3 = listener.Velocity[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
case AL_METERS_PER_UNIT:
|
||||
alGetListenerf(param, values);
|
||||
return;
|
||||
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alGetListener3f(param, values+0, values+1, values+2);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
// AT then UP
|
||||
values[0] = listener.OrientAt[0];
|
||||
values[1] = listener.OrientAt[1];
|
||||
values[2] = listener.OrientAt[2];
|
||||
values[3] = listener.OrientUp[0];
|
||||
values[4] = listener.OrientUp[1];
|
||||
values[5] = listener.OrientUp[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!value)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener integer property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!value1 || !value2 || !value3)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
*value1 = static_cast<ALint>(listener.Position[0]);
|
||||
*value2 = static_cast<ALint>(listener.Position[1]);
|
||||
*value3 = static_cast<ALint>(listener.Position[2]);
|
||||
break;
|
||||
|
||||
case AL_VELOCITY:
|
||||
*value1 = static_cast<ALint>(listener.Velocity[0]);
|
||||
*value2 = static_cast<ALint>(listener.Velocity[1]);
|
||||
*value3 = static_cast<ALint>(listener.Velocity[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
|
||||
START_API_FUNC
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alGetListener3i(param, values+0, values+1, values+2);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
// AT then UP
|
||||
values[0] = static_cast<ALint>(listener.OrientAt[0]);
|
||||
values[1] = static_cast<ALint>(listener.OrientAt[1]);
|
||||
values[2] = static_cast<ALint>(listener.OrientAt[2]);
|
||||
values[3] = static_cast<ALint>(listener.OrientUp[0]);
|
||||
values[4] = static_cast<ALint>(listener.OrientUp[1]);
|
||||
values[5] = static_cast<ALint>(listener.OrientUp[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property");
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
24
externals/openal-soft/al/listener.h
vendored
Normal file
24
externals/openal-soft/al/listener.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef AL_LISTENER_H
|
||||
#define AL_LISTENER_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
struct ALlistener {
|
||||
std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
|
||||
std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
|
||||
std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
|
||||
std::array<float,3> OrientUp{{0.0f, 1.0f, 0.0f}};
|
||||
float Gain{1.0f};
|
||||
float mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
};
|
||||
|
||||
#endif
|
||||
5345
externals/openal-soft/al/source.cpp
vendored
Normal file
5345
externals/openal-soft/al/source.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1044
externals/openal-soft/al/source.h
vendored
Normal file
1044
externals/openal-soft/al/source.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
963
externals/openal-soft/al/state.cpp
vendored
Normal file
963
externals/openal-soft/al/state.cpp
vendored
Normal file
@@ -0,0 +1,963 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2000 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "alc/alu.h"
|
||||
#include "alc/context.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "alnumeric.h"
|
||||
#include "aloptional.h"
|
||||
#include "atomic.h"
|
||||
#include "core/context.h"
|
||||
#include "core/except.h"
|
||||
#include "core/mixer/defs.h"
|
||||
#include "core/voice.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "opthelpers.h"
|
||||
#include "strutils.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alc/device.h"
|
||||
|
||||
#include "eax/globals.h"
|
||||
#include "eax/x_ram.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr ALchar alVendor[] = "OpenAL Community";
|
||||
constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
|
||||
constexpr ALchar alRenderer[] = "OpenAL Soft";
|
||||
|
||||
// Error Messages
|
||||
constexpr ALchar alNoError[] = "No Error";
|
||||
constexpr ALchar alErrInvalidName[] = "Invalid Name";
|
||||
constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
|
||||
constexpr ALchar alErrInvalidValue[] = "Invalid Value";
|
||||
constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
|
||||
constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
|
||||
|
||||
/* Resampler strings */
|
||||
template<Resampler rtype> struct ResamplerName { };
|
||||
template<> struct ResamplerName<Resampler::Point>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
|
||||
template<> struct ResamplerName<Resampler::Linear>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "Linear"; } };
|
||||
template<> struct ResamplerName<Resampler::Cubic>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "Cubic"; } };
|
||||
template<> struct ResamplerName<Resampler::FastBSinc12>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
|
||||
template<> struct ResamplerName<Resampler::BSinc12>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
|
||||
template<> struct ResamplerName<Resampler::FastBSinc24>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
|
||||
template<> struct ResamplerName<Resampler::BSinc24>
|
||||
{ static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
|
||||
|
||||
const ALchar *GetResamplerName(const Resampler rtype)
|
||||
{
|
||||
#define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
|
||||
switch(rtype)
|
||||
{
|
||||
HANDLE_RESAMPLER(Resampler::Point);
|
||||
HANDLE_RESAMPLER(Resampler::Linear);
|
||||
HANDLE_RESAMPLER(Resampler::Cubic);
|
||||
HANDLE_RESAMPLER(Resampler::FastBSinc12);
|
||||
HANDLE_RESAMPLER(Resampler::BSinc12);
|
||||
HANDLE_RESAMPLER(Resampler::FastBSinc24);
|
||||
HANDLE_RESAMPLER(Resampler::BSinc24);
|
||||
}
|
||||
#undef HANDLE_RESAMPLER
|
||||
/* Should never get here. */
|
||||
throw std::runtime_error{"Unexpected resampler index"};
|
||||
}
|
||||
|
||||
al::optional<DistanceModel> DistanceModelFromALenum(ALenum model)
|
||||
{
|
||||
switch(model)
|
||||
{
|
||||
case AL_NONE: return DistanceModel::Disable;
|
||||
case AL_INVERSE_DISTANCE: return DistanceModel::Inverse;
|
||||
case AL_INVERSE_DISTANCE_CLAMPED: return DistanceModel::InverseClamped;
|
||||
case AL_LINEAR_DISTANCE: return DistanceModel::Linear;
|
||||
case AL_LINEAR_DISTANCE_CLAMPED: return DistanceModel::LinearClamped;
|
||||
case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent;
|
||||
case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped;
|
||||
}
|
||||
return al::nullopt;
|
||||
}
|
||||
ALenum ALenumFromDistanceModel(DistanceModel model)
|
||||
{
|
||||
switch(model)
|
||||
{
|
||||
case DistanceModel::Disable: return AL_NONE;
|
||||
case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
|
||||
case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
|
||||
case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
|
||||
case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
|
||||
case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
|
||||
case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
|
||||
}
|
||||
throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* WARNING: Non-standard export! Not part of any extension, or exposed in the
|
||||
* alcFunctions list.
|
||||
*/
|
||||
AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
|
||||
START_API_FUNC
|
||||
{
|
||||
static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
|
||||
if(spoof) return spoof->c_str();
|
||||
return ALSOFT_VERSION;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
#define DO_UPDATEPROPS() do { \
|
||||
if(!context->mDeferUpdates) \
|
||||
UpdateContextProps(context.get()); \
|
||||
else \
|
||||
context->mPropsDirty = true; \
|
||||
} while(0)
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alEnable(ALenum capability)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
switch(capability)
|
||||
{
|
||||
case AL_SOURCE_DISTANCE_MODEL:
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mSourceDistanceModel = true;
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
break;
|
||||
|
||||
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
|
||||
context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDisable(ALenum capability)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
switch(capability)
|
||||
{
|
||||
case AL_SOURCE_DISTANCE_MODEL:
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mSourceDistanceModel = false;
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
break;
|
||||
|
||||
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
|
||||
context->mStopVoicesOnDisconnect = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return AL_FALSE;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALboolean value{AL_FALSE};
|
||||
switch(capability)
|
||||
{
|
||||
case AL_SOURCE_DISTANCE_MODEL:
|
||||
value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
|
||||
break;
|
||||
|
||||
case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
|
||||
value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return AL_FALSE;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALboolean value{AL_FALSE};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
if(context->mDopplerFactor != 0.0f)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
if(context->mDopplerVelocity != 0.0f)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_DISTANCE_MODEL:
|
||||
if(context->mDistanceModel == DistanceModel::Default)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_SPEED_OF_SOUND:
|
||||
if(context->mSpeedOfSound != 0.0f)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
if(context->mDeferUpdates)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
if(GainMixMax/context->mGainBoost != 0.0f)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
/* Always non-0. */
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return 0.0;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALdouble value{0.0};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
value = context->mDopplerFactor;
|
||||
break;
|
||||
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
value = context->mDopplerVelocity;
|
||||
break;
|
||||
|
||||
case AL_DISTANCE_MODEL:
|
||||
value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel));
|
||||
break;
|
||||
|
||||
case AL_SPEED_OF_SOUND:
|
||||
value = context->mSpeedOfSound;
|
||||
break;
|
||||
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
if(context->mDeferUpdates)
|
||||
value = static_cast<ALdouble>(AL_TRUE);
|
||||
break;
|
||||
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
value = ALdouble{GainMixMax}/context->mGainBoost;
|
||||
break;
|
||||
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
value = static_cast<ALdouble>(Resampler::Max) + 1.0;
|
||||
break;
|
||||
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
value = static_cast<ALdouble>(ResamplerDefault);
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return 0.0f;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALfloat value{0.0f};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
value = context->mDopplerFactor;
|
||||
break;
|
||||
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
value = context->mDopplerVelocity;
|
||||
break;
|
||||
|
||||
case AL_DISTANCE_MODEL:
|
||||
value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel));
|
||||
break;
|
||||
|
||||
case AL_SPEED_OF_SOUND:
|
||||
value = context->mSpeedOfSound;
|
||||
break;
|
||||
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
if(context->mDeferUpdates)
|
||||
value = static_cast<ALfloat>(AL_TRUE);
|
||||
break;
|
||||
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
value = GainMixMax/context->mGainBoost;
|
||||
break;
|
||||
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
value = static_cast<ALfloat>(Resampler::Max) + 1.0f;
|
||||
break;
|
||||
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
value = static_cast<ALfloat>(ResamplerDefault);
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return 0;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALint value{0};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
value = static_cast<ALint>(context->mDopplerFactor);
|
||||
break;
|
||||
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
value = static_cast<ALint>(context->mDopplerVelocity);
|
||||
break;
|
||||
|
||||
case AL_DISTANCE_MODEL:
|
||||
value = ALenumFromDistanceModel(context->mDistanceModel);
|
||||
break;
|
||||
|
||||
case AL_SPEED_OF_SOUND:
|
||||
value = static_cast<ALint>(context->mSpeedOfSound);
|
||||
break;
|
||||
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
if(context->mDeferUpdates)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
value = static_cast<ALint>(GainMixMax/context->mGainBoost);
|
||||
break;
|
||||
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
value = static_cast<int>(Resampler::Max) + 1;
|
||||
break;
|
||||
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
value = static_cast<int>(ResamplerDefault);
|
||||
break;
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
|
||||
#define EAX_ERROR "[alGetInteger] EAX not enabled."
|
||||
|
||||
case AL_EAX_RAM_SIZE:
|
||||
if (eax_g_is_enabled)
|
||||
{
|
||||
value = eax_x_ram_max_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->setError(AL_INVALID_VALUE, EAX_ERROR);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AL_EAX_RAM_FREE:
|
||||
if (eax_g_is_enabled)
|
||||
{
|
||||
auto device = context->mALDevice.get();
|
||||
std::lock_guard<std::mutex> device_lock{device->BufferLock};
|
||||
|
||||
value = static_cast<ALint>(device->eax_x_ram_free_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->setError(AL_INVALID_VALUE, EAX_ERROR);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#undef EAX_ERROR
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return 0_i64;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
ALint64SOFT value{0};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
value = static_cast<ALint64SOFT>(context->mDopplerFactor);
|
||||
break;
|
||||
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
value = static_cast<ALint64SOFT>(context->mDopplerVelocity);
|
||||
break;
|
||||
|
||||
case AL_DISTANCE_MODEL:
|
||||
value = ALenumFromDistanceModel(context->mDistanceModel);
|
||||
break;
|
||||
|
||||
case AL_SPEED_OF_SOUND:
|
||||
value = static_cast<ALint64SOFT>(context->mSpeedOfSound);
|
||||
break;
|
||||
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
if(context->mDeferUpdates)
|
||||
value = AL_TRUE;
|
||||
break;
|
||||
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost);
|
||||
break;
|
||||
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
value = static_cast<ALint64SOFT>(Resampler::Max) + 1;
|
||||
break;
|
||||
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
value = static_cast<ALint64SOFT>(ResamplerDefault);
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return nullptr;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
void *value{nullptr};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_EVENT_CALLBACK_FUNCTION_SOFT:
|
||||
value = reinterpret_cast<void*>(context->mEventCb);
|
||||
break;
|
||||
|
||||
case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
|
||||
value = context->mEventParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
case AL_DISTANCE_MODEL:
|
||||
case AL_SPEED_OF_SOUND:
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
values[0] = alGetBoolean(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
case AL_DISTANCE_MODEL:
|
||||
case AL_SPEED_OF_SOUND:
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
values[0] = alGetDouble(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
case AL_DISTANCE_MODEL:
|
||||
case AL_SPEED_OF_SOUND:
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
values[0] = alGetFloat(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
case AL_DISTANCE_MODEL:
|
||||
case AL_SPEED_OF_SOUND:
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
values[0] = alGetInteger(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_DOPPLER_FACTOR:
|
||||
case AL_DOPPLER_VELOCITY:
|
||||
case AL_DISTANCE_MODEL:
|
||||
case AL_SPEED_OF_SOUND:
|
||||
case AL_DEFERRED_UPDATES_SOFT:
|
||||
case AL_GAIN_LIMIT_SOFT:
|
||||
case AL_NUM_RESAMPLERS_SOFT:
|
||||
case AL_DEFAULT_RESAMPLER_SOFT:
|
||||
values[0] = alGetInteger64SOFT(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
{
|
||||
switch(pname)
|
||||
{
|
||||
case AL_EVENT_CALLBACK_FUNCTION_SOFT:
|
||||
case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
|
||||
values[0] = alGetPointerSOFT(pname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!values)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(pname)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return nullptr;
|
||||
|
||||
const ALchar *value{nullptr};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_VENDOR:
|
||||
value = alVendor;
|
||||
break;
|
||||
|
||||
case AL_VERSION:
|
||||
value = alVersion;
|
||||
break;
|
||||
|
||||
case AL_RENDERER:
|
||||
value = alRenderer;
|
||||
break;
|
||||
|
||||
case AL_EXTENSIONS:
|
||||
value = context->mExtensionList;
|
||||
break;
|
||||
|
||||
case AL_NO_ERROR:
|
||||
value = alNoError;
|
||||
break;
|
||||
|
||||
case AL_INVALID_NAME:
|
||||
value = alErrInvalidName;
|
||||
break;
|
||||
|
||||
case AL_INVALID_ENUM:
|
||||
value = alErrInvalidEnum;
|
||||
break;
|
||||
|
||||
case AL_INVALID_VALUE:
|
||||
value = alErrInvalidValue;
|
||||
break;
|
||||
|
||||
case AL_INVALID_OPERATION:
|
||||
value = alErrInvalidOp;
|
||||
break;
|
||||
|
||||
case AL_OUT_OF_MEMORY:
|
||||
value = alErrOutOfMemory;
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDopplerFactor(ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!(value >= 0.0f && std::isfinite(value)))
|
||||
context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mDopplerFactor = value;
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!(value >= 0.0f && std::isfinite(value)))
|
||||
context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mDopplerVelocity = value;
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(!(value > 0.0f && std::isfinite(value)))
|
||||
context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mSpeedOfSound = value;
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alDistanceModel(ALenum value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
if(auto model = DistanceModelFromALenum(value))
|
||||
{
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->mDistanceModel = *model;
|
||||
if(!context->mSourceDistanceModel)
|
||||
DO_UPDATEPROPS();
|
||||
}
|
||||
else
|
||||
context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alDeferUpdatesSOFT(void)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->deferUpdates();
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alProcessUpdatesSOFT(void)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
context->processUpdates();
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return nullptr;
|
||||
|
||||
const ALchar *value{nullptr};
|
||||
switch(pname)
|
||||
{
|
||||
case AL_RESAMPLER_NAME_SOFT:
|
||||
if(index < 0 || index > static_cast<ALint>(Resampler::Max))
|
||||
context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
|
||||
else
|
||||
value = GetResamplerName(static_cast<Resampler>(index));
|
||||
break;
|
||||
|
||||
default:
|
||||
context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
void UpdateContextProps(ALCcontext *context)
|
||||
{
|
||||
/* Get an unused proprty container, or allocate a new one as needed. */
|
||||
ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
|
||||
if(!props)
|
||||
props = new ContextProps{};
|
||||
else
|
||||
{
|
||||
ContextProps *next;
|
||||
do {
|
||||
next = props->next.load(std::memory_order_relaxed);
|
||||
} while(context->mFreeContextProps.compare_exchange_weak(props, next,
|
||||
std::memory_order_seq_cst, std::memory_order_acquire) == 0);
|
||||
}
|
||||
|
||||
/* Copy in current property values. */
|
||||
ALlistener &listener = context->mListener;
|
||||
props->Position = listener.Position;
|
||||
props->Velocity = listener.Velocity;
|
||||
props->OrientAt = listener.OrientAt;
|
||||
props->OrientUp = listener.OrientUp;
|
||||
props->Gain = listener.Gain;
|
||||
props->MetersPerUnit = listener.mMetersPerUnit;
|
||||
|
||||
props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
|
||||
props->DopplerFactor = context->mDopplerFactor;
|
||||
props->DopplerVelocity = context->mDopplerVelocity;
|
||||
props->SpeedOfSound = context->mSpeedOfSound;
|
||||
|
||||
props->SourceDistanceModel = context->mSourceDistanceModel;
|
||||
props->mDistanceModel = context->mDistanceModel;
|
||||
|
||||
/* Set the new container for updating internal parameters. */
|
||||
props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
|
||||
if(props)
|
||||
{
|
||||
/* If there was an unused update container, put it back in the
|
||||
* freelist.
|
||||
*/
|
||||
AtomicReplaceHead(context->mFreeContextProps, props);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user