mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 00:54:54 +00:00
update openal
This commit is contained in:
parent
62f3b93ff9
commit
6721a6b021
287 changed files with 33851 additions and 27325 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,23 +1,24 @@
|
|||
#ifndef AL_AUXEFFECTSLOT_H
|
||||
#define AL_AUXEFFECTSLOT_H
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#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 "alnumeric.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "core/effectslot.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <memory>
|
||||
#include "eax/api.h"
|
||||
#include "eax/call.h"
|
||||
#include "eax/effect.h"
|
||||
#include "eax/exception.h"
|
||||
|
|
@ -26,8 +27,6 @@
|
|||
#endif // ALSOFT_EAX
|
||||
|
||||
struct ALbuffer;
|
||||
struct ALeffect;
|
||||
struct WetBuffer;
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
class EaxFxSlotException : public EaxException {
|
||||
|
|
@ -38,30 +37,30 @@ public:
|
|||
};
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
enum class SlotState : ALenum {
|
||||
Initial = AL_INITIAL,
|
||||
Playing = AL_PLAYING,
|
||||
Stopped = AL_STOPPED,
|
||||
enum class SlotState : bool {
|
||||
Initial, Playing,
|
||||
};
|
||||
|
||||
struct ALeffectslot {
|
||||
ALuint EffectId{};
|
||||
float Gain{1.0f};
|
||||
bool AuxSendAuto{true};
|
||||
ALeffectslot *Target{nullptr};
|
||||
ALbuffer *Buffer{nullptr};
|
||||
|
||||
struct {
|
||||
struct EffectData {
|
||||
EffectSlotType Type{EffectSlotType::None};
|
||||
EffectProps Props{};
|
||||
|
||||
al::intrusive_ptr<EffectState> State;
|
||||
} Effect;
|
||||
};
|
||||
EffectData Effect;
|
||||
|
||||
bool mPropsDirty{true};
|
||||
|
||||
SlotState mState{SlotState::Initial};
|
||||
|
||||
RefCount ref{0u};
|
||||
std::atomic<ALuint> ref{0u};
|
||||
|
||||
EffectSlot *mSlot{nullptr};
|
||||
|
||||
|
|
@ -73,23 +72,23 @@ struct ALeffectslot {
|
|||
ALeffectslot& operator=(const ALeffectslot&) = delete;
|
||||
~ALeffectslot();
|
||||
|
||||
ALenum initEffect(ALenum effectType, const EffectProps &effectProps, ALCcontext *context);
|
||||
void updateProps(ALCcontext *context);
|
||||
ALenum initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps,
|
||||
ALCcontext *context);
|
||||
void updateProps(ALCcontext *context) const;
|
||||
|
||||
/* This can be new'd for the context's default effect slot. */
|
||||
DEF_NEWDEL(ALeffectslot)
|
||||
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
|
||||
|
||||
|
||||
#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
|
||||
[[nodiscard]] auto eax_get_index() const noexcept -> EaxFxSlotIndexValue { return eax_fx_slot_index_; }
|
||||
[[nodiscard]] auto eax_get_eax_fx_slot() const noexcept -> const EAX50FXSLOTPROPERTIES&
|
||||
{ return eax_; }
|
||||
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax_dispatch(const EaxCall& call)
|
||||
[[nodiscard]] auto eax_dispatch(const EaxCall& call) -> bool
|
||||
{ return call.is_get() ? eax_get(call) : eax_set(call); }
|
||||
|
||||
void eax_commit();
|
||||
|
|
@ -193,6 +192,17 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
struct Eax5FlagsValidator {
|
||||
void operator()(unsigned long ulFlags) const
|
||||
{
|
||||
EaxRangeValidator{}(
|
||||
"Flags",
|
||||
ulFlags,
|
||||
0UL,
|
||||
~EAX50FXSLOTFLAGS_RESERVED);
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5OcclusionValidator {
|
||||
void operator()(long lOcclusion) const
|
||||
{
|
||||
|
|
@ -215,21 +225,13 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
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));
|
||||
Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
|
||||
Eax4VolumeValidator{}(all.lVolume);
|
||||
Eax4LockValidator{}(all.lLock);
|
||||
Eax5FlagsValidator{}(all.ulFlags);
|
||||
Eax5OcclusionValidator{}(all.lOcclusion);
|
||||
Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
|
||||
}
|
||||
|
|
@ -277,14 +279,14 @@ private:
|
|||
dst = src;
|
||||
}
|
||||
|
||||
constexpr bool eax4_fx_slot_is_legacy() const noexcept
|
||||
[[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
|
||||
{ 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;
|
||||
[[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
|
||||
[[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
|
||||
[[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
|
||||
|
||||
void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
|
||||
void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
|
||||
|
|
@ -293,8 +295,8 @@ private:
|
|||
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;
|
||||
static void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props);
|
||||
static void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props);
|
||||
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);
|
||||
|
|
@ -307,7 +309,7 @@ private:
|
|||
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;
|
||||
[[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
|
||||
|
||||
// Returns `true` if all sources should be updated, or `false` otherwise.
|
||||
bool eax4_fx_slot_set(const EaxCall& call);
|
||||
|
|
@ -365,4 +367,20 @@ EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
|
|||
void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
struct EffectSlotSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
|
||||
|
||||
EffectSlotSubList() noexcept = default;
|
||||
EffectSlotSubList(const EffectSlotSubList&) = delete;
|
||||
EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
|
||||
: FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
|
||||
~EffectSlotSubList();
|
||||
|
||||
EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
|
||||
EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,20 +1,23 @@
|
|||
#ifndef AL_BUFFER_H
|
||||
#define AL_BUFFER_H
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "albyte.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "almalloc.h"
|
||||
#include "atomic.h"
|
||||
#include "alnumeric.h"
|
||||
#include "core/buffer_storage.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "eax/x_ram.h"
|
||||
|
||||
enum class EaxStorage : uint8_t {
|
||||
Automatic,
|
||||
Accessible,
|
||||
|
|
@ -26,7 +29,7 @@ enum class EaxStorage : uint8_t {
|
|||
struct ALbuffer : public BufferStorage {
|
||||
ALbitfieldSOFT Access{0u};
|
||||
|
||||
al::vector<al::byte,16> mDataStorage;
|
||||
al::vector<std::byte,16> mDataStorage;
|
||||
|
||||
ALuint OriginalSize{0};
|
||||
|
||||
|
|
@ -42,12 +45,14 @@ struct ALbuffer : public BufferStorage {
|
|||
ALuint mLoopEnd{0u};
|
||||
|
||||
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
|
||||
RefCount ref{0u};
|
||||
std::atomic<ALuint> ref{0u};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{0};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
|
||||
|
||||
DISABLE_ALLOC
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
EaxStorage eax_x_ram_mode{EaxStorage::Automatic};
|
||||
|
|
@ -55,4 +60,19 @@ struct ALbuffer : public BufferStorage {
|
|||
#endif // ALSOFT_EAX
|
||||
};
|
||||
|
||||
struct BufferSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
gsl::owner<std::array<ALbuffer,64>*> Buffers{nullptr};
|
||||
|
||||
BufferSubList() noexcept = default;
|
||||
BufferSubList(const BufferSubList&) = delete;
|
||||
BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; }
|
||||
~BufferSubList();
|
||||
|
||||
BufferSubList& operator=(const BufferSubList&) = delete;
|
||||
BufferSubList& operator=(BufferSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
618
Engine/lib/openal-soft/al/debug.cpp
Normal file
618
Engine/lib/openal-soft/al/debug.cpp
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "alc/device.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "auxeffectslot.h"
|
||||
#include "buffer.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/voice.h"
|
||||
#include "direct_defs.h"
|
||||
#include "effect.h"
|
||||
#include "error.h"
|
||||
#include "filter.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "opthelpers.h"
|
||||
#include "source.h"
|
||||
|
||||
|
||||
/* Declared here to prevent compilers from thinking it should be inlined, which
|
||||
* GCC warns about increasing code size.
|
||||
*/
|
||||
DebugGroup::~DebugGroup() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
static_assert(DebugSeverityBase+DebugSeverityCount <= 32, "Too many debug bits");
|
||||
|
||||
template<typename T, T ...Vals>
|
||||
constexpr auto make_array_sequence(std::integer_sequence<T, Vals...>)
|
||||
{ return std::array<T,sizeof...(Vals)>{Vals...}; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
constexpr auto make_array_sequence()
|
||||
{ return make_array_sequence(std::make_integer_sequence<T,N>{}); }
|
||||
|
||||
|
||||
constexpr auto GetDebugSource(ALenum source) noexcept -> std::optional<DebugSource>
|
||||
{
|
||||
switch(source)
|
||||
{
|
||||
case AL_DEBUG_SOURCE_API_EXT: return DebugSource::API;
|
||||
case AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT: return DebugSource::System;
|
||||
case AL_DEBUG_SOURCE_THIRD_PARTY_EXT: return DebugSource::ThirdParty;
|
||||
case AL_DEBUG_SOURCE_APPLICATION_EXT: return DebugSource::Application;
|
||||
case AL_DEBUG_SOURCE_OTHER_EXT: return DebugSource::Other;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
constexpr auto GetDebugType(ALenum type) noexcept -> std::optional<DebugType>
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case AL_DEBUG_TYPE_ERROR_EXT: return DebugType::Error;
|
||||
case AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT: return DebugType::DeprecatedBehavior;
|
||||
case AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT: return DebugType::UndefinedBehavior;
|
||||
case AL_DEBUG_TYPE_PORTABILITY_EXT: return DebugType::Portability;
|
||||
case AL_DEBUG_TYPE_PERFORMANCE_EXT: return DebugType::Performance;
|
||||
case AL_DEBUG_TYPE_MARKER_EXT: return DebugType::Marker;
|
||||
case AL_DEBUG_TYPE_PUSH_GROUP_EXT: return DebugType::PushGroup;
|
||||
case AL_DEBUG_TYPE_POP_GROUP_EXT: return DebugType::PopGroup;
|
||||
case AL_DEBUG_TYPE_OTHER_EXT: return DebugType::Other;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
constexpr auto GetDebugSeverity(ALenum severity) noexcept -> std::optional<DebugSeverity>
|
||||
{
|
||||
switch(severity)
|
||||
{
|
||||
case AL_DEBUG_SEVERITY_HIGH_EXT: return DebugSeverity::High;
|
||||
case AL_DEBUG_SEVERITY_MEDIUM_EXT: return DebugSeverity::Medium;
|
||||
case AL_DEBUG_SEVERITY_LOW_EXT: return DebugSeverity::Low;
|
||||
case AL_DEBUG_SEVERITY_NOTIFICATION_EXT: return DebugSeverity::Notification;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
constexpr auto GetDebugSourceEnum(DebugSource source) -> ALenum
|
||||
{
|
||||
switch(source)
|
||||
{
|
||||
case DebugSource::API: return AL_DEBUG_SOURCE_API_EXT;
|
||||
case DebugSource::System: return AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT;
|
||||
case DebugSource::ThirdParty: return AL_DEBUG_SOURCE_THIRD_PARTY_EXT;
|
||||
case DebugSource::Application: return AL_DEBUG_SOURCE_APPLICATION_EXT;
|
||||
case DebugSource::Other: return AL_DEBUG_SOURCE_OTHER_EXT;
|
||||
}
|
||||
throw std::runtime_error{"Unexpected debug source value "+std::to_string(al::to_underlying(source))};
|
||||
}
|
||||
|
||||
constexpr auto GetDebugTypeEnum(DebugType type) -> ALenum
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case DebugType::Error: return AL_DEBUG_TYPE_ERROR_EXT;
|
||||
case DebugType::DeprecatedBehavior: return AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT;
|
||||
case DebugType::UndefinedBehavior: return AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT;
|
||||
case DebugType::Portability: return AL_DEBUG_TYPE_PORTABILITY_EXT;
|
||||
case DebugType::Performance: return AL_DEBUG_TYPE_PERFORMANCE_EXT;
|
||||
case DebugType::Marker: return AL_DEBUG_TYPE_MARKER_EXT;
|
||||
case DebugType::PushGroup: return AL_DEBUG_TYPE_PUSH_GROUP_EXT;
|
||||
case DebugType::PopGroup: return AL_DEBUG_TYPE_POP_GROUP_EXT;
|
||||
case DebugType::Other: return AL_DEBUG_TYPE_OTHER_EXT;
|
||||
}
|
||||
throw std::runtime_error{"Unexpected debug type value "+std::to_string(al::to_underlying(type))};
|
||||
}
|
||||
|
||||
constexpr auto GetDebugSeverityEnum(DebugSeverity severity) -> ALenum
|
||||
{
|
||||
switch(severity)
|
||||
{
|
||||
case DebugSeverity::High: return AL_DEBUG_SEVERITY_HIGH_EXT;
|
||||
case DebugSeverity::Medium: return AL_DEBUG_SEVERITY_MEDIUM_EXT;
|
||||
case DebugSeverity::Low: return AL_DEBUG_SEVERITY_LOW_EXT;
|
||||
case DebugSeverity::Notification: return AL_DEBUG_SEVERITY_NOTIFICATION_EXT;
|
||||
}
|
||||
throw std::runtime_error{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity))};
|
||||
}
|
||||
|
||||
|
||||
constexpr auto GetDebugSourceName(DebugSource source) noexcept -> const char*
|
||||
{
|
||||
switch(source)
|
||||
{
|
||||
case DebugSource::API: return "API";
|
||||
case DebugSource::System: return "Audio System";
|
||||
case DebugSource::ThirdParty: return "Third Party";
|
||||
case DebugSource::Application: return "Application";
|
||||
case DebugSource::Other: return "Other";
|
||||
}
|
||||
return "<invalid source>";
|
||||
}
|
||||
|
||||
constexpr auto GetDebugTypeName(DebugType type) noexcept -> const char*
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case DebugType::Error: return "Error";
|
||||
case DebugType::DeprecatedBehavior: return "Deprecated Behavior";
|
||||
case DebugType::UndefinedBehavior: return "Undefined Behavior";
|
||||
case DebugType::Portability: return "Portability";
|
||||
case DebugType::Performance: return "Performance";
|
||||
case DebugType::Marker: return "Marker";
|
||||
case DebugType::PushGroup: return "Push Group";
|
||||
case DebugType::PopGroup: return "Pop Group";
|
||||
case DebugType::Other: return "Other";
|
||||
}
|
||||
return "<invalid type>";
|
||||
}
|
||||
|
||||
constexpr auto GetDebugSeverityName(DebugSeverity severity) noexcept -> const char*
|
||||
{
|
||||
switch(severity)
|
||||
{
|
||||
case DebugSeverity::High: return "High";
|
||||
case DebugSeverity::Medium: return "Medium";
|
||||
case DebugSeverity::Low: return "Low";
|
||||
case DebugSeverity::Notification: return "Notification";
|
||||
}
|
||||
return "<invalid severity>";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void ALCcontext::sendDebugMessage(std::unique_lock<std::mutex> &debuglock, DebugSource source,
|
||||
DebugType type, ALuint id, DebugSeverity severity, std::string_view message)
|
||||
{
|
||||
if(!mDebugEnabled.load(std::memory_order_relaxed)) UNLIKELY
|
||||
return;
|
||||
|
||||
if(message.length() >= MaxDebugMessageLength) UNLIKELY
|
||||
{
|
||||
ERR("Debug message too long (%zu >= %d):\n-> %.*s\n", message.length(),
|
||||
MaxDebugMessageLength, al::sizei(message), message.data());
|
||||
return;
|
||||
}
|
||||
|
||||
DebugGroup &debug = mDebugGroups.back();
|
||||
|
||||
const uint64_t idfilter{(1_u64 << (DebugSourceBase+al::to_underlying(source)))
|
||||
| (1_u64 << (DebugTypeBase+al::to_underlying(type)))
|
||||
| (uint64_t{id} << 32)};
|
||||
auto iditer = std::lower_bound(debug.mIdFilters.cbegin(), debug.mIdFilters.cend(), idfilter);
|
||||
if(iditer != debug.mIdFilters.cend() && *iditer == idfilter)
|
||||
return;
|
||||
|
||||
const uint filter{(1u << (DebugSourceBase+al::to_underlying(source)))
|
||||
| (1u << (DebugTypeBase+al::to_underlying(type)))
|
||||
| (1u << (DebugSeverityBase+al::to_underlying(severity)))};
|
||||
auto iter = std::lower_bound(debug.mFilters.cbegin(), debug.mFilters.cend(), filter);
|
||||
if(iter != debug.mFilters.cend() && *iter == filter)
|
||||
return;
|
||||
|
||||
if(mDebugCb)
|
||||
{
|
||||
auto callback = mDebugCb;
|
||||
auto param = mDebugParam;
|
||||
debuglock.unlock();
|
||||
callback(GetDebugSourceEnum(source), GetDebugTypeEnum(type), id,
|
||||
GetDebugSeverityEnum(severity), static_cast<ALsizei>(message.length()), message.data(),
|
||||
param);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mDebugLog.size() < MaxDebugLoggedMessages)
|
||||
mDebugLog.emplace_back(source, type, id, severity, message);
|
||||
else UNLIKELY
|
||||
ERR("Debug message log overflow. Lost message:\n"
|
||||
" Source: %s\n"
|
||||
" Type: %s\n"
|
||||
" ID: %u\n"
|
||||
" Severity: %s\n"
|
||||
" Message: \"%.*s\"\n",
|
||||
GetDebugSourceName(source), GetDebugTypeName(type), id,
|
||||
GetDebugSeverityName(severity), al::sizei(message), message.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT2(void, alDebugMessageCallback,EXT, ALDEBUGPROCEXT,callback, void*,userParam)
|
||||
FORCE_ALIGN void AL_APIENTRY alDebugMessageCallbackDirectEXT(ALCcontext *context,
|
||||
ALDEBUGPROCEXT callback, void *userParam) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
|
||||
context->mDebugCb = callback;
|
||||
context->mDebugParam = userParam;
|
||||
}
|
||||
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT6(void, alDebugMessageInsert,EXT, ALenum,source, ALenum,type, ALuint,id, ALenum,severity, ALsizei,length, const ALchar*,message)
|
||||
FORCE_ALIGN void AL_APIENTRY alDebugMessageInsertDirectEXT(ALCcontext *context, ALenum source,
|
||||
ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) noexcept
|
||||
try {
|
||||
if(!context->mContextFlags.test(ContextFlags::DebugBit))
|
||||
return;
|
||||
|
||||
if(!message)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Null message pointer"};
|
||||
|
||||
auto msgview = (length < 0) ? std::string_view{message}
|
||||
: std::string_view{message, static_cast<uint>(length)};
|
||||
if(msgview.size() >= MaxDebugMessageLength)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Debug message too long (%zu >= %d)",
|
||||
msgview.size(), MaxDebugMessageLength};
|
||||
|
||||
auto dsource = GetDebugSource(source);
|
||||
if(!dsource)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug source 0x%04x", source};
|
||||
if(*dsource != DebugSource::ThirdParty && *dsource != DebugSource::Application)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Debug source 0x%04x not allowed", source};
|
||||
|
||||
auto dtype = GetDebugType(type);
|
||||
if(!dtype)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug type 0x%04x", type};
|
||||
|
||||
auto dseverity = GetDebugSeverity(severity);
|
||||
if(!dseverity)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug severity 0x%04x", severity};
|
||||
|
||||
context->debugMessage(*dsource, *dtype, id, *dseverity, msgview);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT6(void, alDebugMessageControl,EXT, ALenum,source, ALenum,type, ALenum,severity, ALsizei,count, const ALuint*,ids, ALboolean,enable)
|
||||
FORCE_ALIGN void AL_APIENTRY alDebugMessageControlDirectEXT(ALCcontext *context, ALenum source,
|
||||
ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) noexcept
|
||||
try {
|
||||
if(count > 0)
|
||||
{
|
||||
if(!ids)
|
||||
throw al::context_error{AL_INVALID_VALUE, "IDs is null with non-0 count"};
|
||||
if(source == AL_DONT_CARE_EXT)
|
||||
throw al::context_error{AL_INVALID_OPERATION,
|
||||
"Debug source cannot be AL_DONT_CARE_EXT with IDs"};
|
||||
if(type == AL_DONT_CARE_EXT)
|
||||
throw al::context_error{AL_INVALID_OPERATION,
|
||||
"Debug type cannot be AL_DONT_CARE_EXT with IDs"};
|
||||
if(severity != AL_DONT_CARE_EXT)
|
||||
throw al::context_error{AL_INVALID_OPERATION,
|
||||
"Debug severity must be AL_DONT_CARE_EXT with IDs"};
|
||||
}
|
||||
|
||||
if(enable != AL_TRUE && enable != AL_FALSE)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug enable %d", enable};
|
||||
|
||||
static constexpr size_t ElemCount{DebugSourceCount + DebugTypeCount + DebugSeverityCount};
|
||||
static constexpr auto Values = make_array_sequence<uint8_t,ElemCount>();
|
||||
|
||||
auto srcIndices = al::span{Values}.subspan(DebugSourceBase,DebugSourceCount);
|
||||
if(source != AL_DONT_CARE_EXT)
|
||||
{
|
||||
auto dsource = GetDebugSource(source);
|
||||
if(!dsource)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug source 0x%04x", source};
|
||||
srcIndices = srcIndices.subspan(al::to_underlying(*dsource), 1);
|
||||
}
|
||||
|
||||
auto typeIndices = al::span{Values}.subspan(DebugTypeBase,DebugTypeCount);
|
||||
if(type != AL_DONT_CARE_EXT)
|
||||
{
|
||||
auto dtype = GetDebugType(type);
|
||||
if(!dtype)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug type 0x%04x", type};
|
||||
typeIndices = typeIndices.subspan(al::to_underlying(*dtype), 1);
|
||||
}
|
||||
|
||||
auto svrIndices = al::span{Values}.subspan(DebugSeverityBase,DebugSeverityCount);
|
||||
if(severity != AL_DONT_CARE_EXT)
|
||||
{
|
||||
auto dseverity = GetDebugSeverity(severity);
|
||||
if(!dseverity)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug severity 0x%04x", severity};
|
||||
svrIndices = svrIndices.subspan(al::to_underlying(*dseverity), 1);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
|
||||
DebugGroup &debug = context->mDebugGroups.back();
|
||||
if(count > 0)
|
||||
{
|
||||
const uint filterbase{(1u<<srcIndices[0]) | (1u<<typeIndices[0])};
|
||||
|
||||
for(const uint id : al::span{ids, static_cast<uint>(count)})
|
||||
{
|
||||
const uint64_t filter{filterbase | (uint64_t{id} << 32)};
|
||||
|
||||
auto iter = std::lower_bound(debug.mIdFilters.cbegin(), debug.mIdFilters.cend(),
|
||||
filter);
|
||||
if(!enable && (iter == debug.mIdFilters.cend() || *iter != filter))
|
||||
debug.mIdFilters.insert(iter, filter);
|
||||
else if(enable && iter != debug.mIdFilters.cend() && *iter == filter)
|
||||
debug.mIdFilters.erase(iter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto apply_filter = [enable,&debug](const uint filter)
|
||||
{
|
||||
auto iter = std::lower_bound(debug.mFilters.cbegin(), debug.mFilters.cend(), filter);
|
||||
if(!enable && (iter == debug.mFilters.cend() || *iter != filter))
|
||||
debug.mFilters.insert(iter, filter);
|
||||
else if(enable && iter != debug.mFilters.cend() && *iter == filter)
|
||||
debug.mFilters.erase(iter);
|
||||
};
|
||||
auto apply_severity = [apply_filter,svrIndices](const uint filter)
|
||||
{
|
||||
std::for_each(svrIndices.cbegin(), svrIndices.cend(),
|
||||
[apply_filter,filter](const uint idx){ apply_filter(filter | (1<<idx)); });
|
||||
};
|
||||
auto apply_type = [apply_severity,typeIndices](const uint filter)
|
||||
{
|
||||
std::for_each(typeIndices.cbegin(), typeIndices.cend(),
|
||||
[apply_severity,filter](const uint idx){ apply_severity(filter | (1<<idx)); });
|
||||
};
|
||||
std::for_each(srcIndices.cbegin(), srcIndices.cend(),
|
||||
[apply_type](const uint idx){ apply_type(1<<idx); });
|
||||
}
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT4(void, alPushDebugGroup,EXT, ALenum,source, ALuint,id, ALsizei,length, const ALchar*,message)
|
||||
FORCE_ALIGN void AL_APIENTRY alPushDebugGroupDirectEXT(ALCcontext *context, ALenum source,
|
||||
ALuint id, ALsizei length, const ALchar *message) noexcept
|
||||
try {
|
||||
if(length < 0)
|
||||
{
|
||||
size_t newlen{std::strlen(message)};
|
||||
if(newlen >= MaxDebugMessageLength)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Debug message too long (%zu >= %d)", newlen,
|
||||
MaxDebugMessageLength};
|
||||
length = static_cast<ALsizei>(newlen);
|
||||
}
|
||||
else if(length >= MaxDebugMessageLength)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Debug message too long (%d >= %d)", length,
|
||||
MaxDebugMessageLength};
|
||||
|
||||
auto dsource = GetDebugSource(source);
|
||||
if(!dsource)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid debug source 0x%04x", source};
|
||||
if(*dsource != DebugSource::ThirdParty && *dsource != DebugSource::Application)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Debug source 0x%04x not allowed", source};
|
||||
|
||||
std::unique_lock<std::mutex> debuglock{context->mDebugCbLock};
|
||||
if(context->mDebugGroups.size() >= MaxDebugGroupDepth)
|
||||
throw al::context_error{AL_STACK_OVERFLOW_EXT, "Pushing too many debug groups"};
|
||||
|
||||
context->mDebugGroups.emplace_back(*dsource, id,
|
||||
std::string_view{message, static_cast<uint>(length)});
|
||||
auto &oldback = *(context->mDebugGroups.end()-2);
|
||||
auto &newback = context->mDebugGroups.back();
|
||||
|
||||
newback.mFilters = oldback.mFilters;
|
||||
newback.mIdFilters = oldback.mIdFilters;
|
||||
|
||||
if(context->mContextFlags.test(ContextFlags::DebugBit))
|
||||
context->sendDebugMessage(debuglock, newback.mSource, DebugType::PushGroup, newback.mId,
|
||||
DebugSeverity::Notification, newback.mMessage);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT(void, alPopDebugGroup,EXT)
|
||||
FORCE_ALIGN void AL_APIENTRY alPopDebugGroupDirectEXT(ALCcontext *context) noexcept
|
||||
try {
|
||||
std::unique_lock<std::mutex> debuglock{context->mDebugCbLock};
|
||||
if(context->mDebugGroups.size() <= 1)
|
||||
throw al::context_error{AL_STACK_UNDERFLOW_EXT,
|
||||
"Attempting to pop the default debug group"};
|
||||
|
||||
DebugGroup &debug = context->mDebugGroups.back();
|
||||
const auto source = debug.mSource;
|
||||
const auto id = debug.mId;
|
||||
std::string message{std::move(debug.mMessage)};
|
||||
|
||||
context->mDebugGroups.pop_back();
|
||||
if(context->mContextFlags.test(ContextFlags::DebugBit))
|
||||
context->sendDebugMessage(debuglock, source, DebugType::PopGroup, id,
|
||||
DebugSeverity::Notification, message);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT8(ALuint, alGetDebugMessageLog,EXT, ALuint,count, ALsizei,logBufSize, ALenum*,sources, ALenum*,types, ALuint*,ids, ALenum*,severities, ALsizei*,lengths, ALchar*,logBuf)
|
||||
FORCE_ALIGN ALuint AL_APIENTRY alGetDebugMessageLogDirectEXT(ALCcontext *context, ALuint count,
|
||||
ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities,
|
||||
ALsizei *lengths, ALchar *logBuf) noexcept
|
||||
try {
|
||||
if(logBufSize < 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Negative debug log buffer size"};
|
||||
|
||||
auto sourcesOut = al::span{sources, sources ? count : 0u};
|
||||
auto typesOut = al::span{types, types ? count : 0u};
|
||||
auto idsOut = al::span{ids, ids ? count : 0u};
|
||||
auto severitiesOut = al::span{severities, severities ? count : 0u};
|
||||
auto lengthsOut = al::span{lengths, lengths ? count : 0u};
|
||||
auto logOut = al::span{logBuf, logBuf ? static_cast<ALuint>(logBufSize) : 0u};
|
||||
|
||||
std::lock_guard<std::mutex> debuglock{context->mDebugCbLock};
|
||||
for(ALuint i{0};i < count;++i)
|
||||
{
|
||||
if(context->mDebugLog.empty())
|
||||
return i;
|
||||
|
||||
auto &entry = context->mDebugLog.front();
|
||||
const size_t tocopy{entry.mMessage.size() + 1};
|
||||
if(logOut.data() != nullptr)
|
||||
{
|
||||
if(logOut.size() < tocopy)
|
||||
return i;
|
||||
auto oiter = std::copy(entry.mMessage.cbegin(), entry.mMessage.cend(), logOut.begin());
|
||||
*oiter = '\0';
|
||||
logOut = {oiter+1, logOut.end()};
|
||||
}
|
||||
|
||||
if(!sourcesOut.empty())
|
||||
{
|
||||
sourcesOut.front() = GetDebugSourceEnum(entry.mSource);
|
||||
sourcesOut = sourcesOut.subspan<1>();
|
||||
}
|
||||
if(!typesOut.empty())
|
||||
{
|
||||
typesOut.front() = GetDebugTypeEnum(entry.mType);
|
||||
typesOut = typesOut.subspan<1>();
|
||||
}
|
||||
if(!idsOut.empty())
|
||||
{
|
||||
idsOut.front() = entry.mId;
|
||||
idsOut = idsOut.subspan<1>();
|
||||
}
|
||||
if(!severitiesOut.empty())
|
||||
{
|
||||
severitiesOut.front() = GetDebugSeverityEnum(entry.mSeverity);
|
||||
severitiesOut = severitiesOut.subspan<1>();
|
||||
}
|
||||
if(!lengthsOut.empty())
|
||||
{
|
||||
lengthsOut.front() = static_cast<ALsizei>(tocopy);
|
||||
lengthsOut = lengthsOut.subspan<1>();
|
||||
}
|
||||
|
||||
context->mDebugLog.pop_front();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
return 0;
|
||||
}
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT4(void, alObjectLabel,EXT, ALenum,identifier, ALuint,name, ALsizei,length, const ALchar*,label)
|
||||
FORCE_ALIGN void AL_APIENTRY alObjectLabelDirectEXT(ALCcontext *context, ALenum identifier,
|
||||
ALuint name, ALsizei length, const ALchar *label) noexcept
|
||||
try {
|
||||
if(!label && length != 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Null label pointer"};
|
||||
|
||||
auto objname = (length < 0) ? std::string_view{label}
|
||||
: std::string_view{label, static_cast<uint>(length)};
|
||||
if(objname.size() >= MaxObjectLabelLength)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Object label length too long (%zu >= %d)",
|
||||
objname.size(), MaxObjectLabelLength};
|
||||
|
||||
switch(identifier)
|
||||
{
|
||||
case AL_SOURCE_EXT: ALsource::SetName(context, name, objname); return;
|
||||
case AL_BUFFER: ALbuffer::SetName(context, name, objname); return;
|
||||
case AL_FILTER_EXT: ALfilter::SetName(context, name, objname); return;
|
||||
case AL_EFFECT_EXT: ALeffect::SetName(context, name, objname); return;
|
||||
case AL_AUXILIARY_EFFECT_SLOT_EXT: ALeffectslot::SetName(context, name, objname); return;
|
||||
}
|
||||
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid name identifier 0x%04x", identifier};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
FORCE_ALIGN DECL_FUNCEXT5(void, alGetObjectLabel,EXT, ALenum,identifier, ALuint,name, ALsizei,bufSize, ALsizei*,length, ALchar*,label)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetObjectLabelDirectEXT(ALCcontext *context, ALenum identifier,
|
||||
ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) noexcept
|
||||
try {
|
||||
if(bufSize < 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Negative label bufSize"};
|
||||
|
||||
if(!label && !length)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Null length and label"};
|
||||
if(label && bufSize == 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Zero label bufSize"};
|
||||
|
||||
const auto labelOut = al::span{label, label ? static_cast<ALuint>(bufSize) : 0u};
|
||||
auto copy_name = [name,length,labelOut](std::unordered_map<ALuint,std::string> &names)
|
||||
{
|
||||
std::string_view objname;
|
||||
|
||||
auto iter = names.find(name);
|
||||
if(iter != names.end())
|
||||
objname = iter->second;
|
||||
|
||||
if(labelOut.empty())
|
||||
*length = static_cast<ALsizei>(objname.size());
|
||||
else
|
||||
{
|
||||
const size_t tocopy{std::min(objname.size(), labelOut.size()-1)};
|
||||
auto oiter = std::copy_n(objname.cbegin(), tocopy, labelOut.begin());
|
||||
*oiter = '\0';
|
||||
if(length)
|
||||
*length = static_cast<ALsizei>(tocopy);
|
||||
}
|
||||
};
|
||||
|
||||
if(identifier == AL_SOURCE_EXT)
|
||||
{
|
||||
std::lock_guard srclock{context->mSourceLock};
|
||||
copy_name(context->mSourceNames);
|
||||
}
|
||||
else if(identifier == AL_BUFFER)
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard buflock{device->BufferLock};
|
||||
copy_name(device->mBufferNames);
|
||||
}
|
||||
else if(identifier == AL_FILTER_EXT)
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard filterlock{device->FilterLock};
|
||||
copy_name(device->mFilterNames);
|
||||
}
|
||||
else if(identifier == AL_EFFECT_EXT)
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard effectlock{device->EffectLock};
|
||||
copy_name(device->mEffectNames);
|
||||
}
|
||||
else if(identifier == AL_AUXILIARY_EFFECT_SLOT_EXT)
|
||||
{
|
||||
std::lock_guard slotlock{context->mEffectSlotLock};
|
||||
copy_name(context->mEffectSlotNames);
|
||||
}
|
||||
else
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid name identifier 0x%04x", identifier};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
70
Engine/lib/openal-soft/al/debug.h
Normal file
70
Engine/lib/openal-soft/al/debug.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef AL_DEBUG_H
|
||||
#define AL_DEBUG_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
|
||||
/* Somewhat arbitrary. Avoid letting it get out of control if the app enables
|
||||
* logging but never reads it.
|
||||
*/
|
||||
inline constexpr std::uint8_t MaxDebugLoggedMessages{64};
|
||||
inline constexpr std::uint16_t MaxDebugMessageLength{1024};
|
||||
inline constexpr std::uint8_t MaxDebugGroupDepth{64};
|
||||
inline constexpr std::uint16_t MaxObjectLabelLength{1024};
|
||||
|
||||
|
||||
inline constexpr uint DebugSourceBase{0};
|
||||
enum class DebugSource : std::uint8_t {
|
||||
API = 0,
|
||||
System,
|
||||
ThirdParty,
|
||||
Application,
|
||||
Other,
|
||||
};
|
||||
inline constexpr uint DebugSourceCount{5};
|
||||
|
||||
inline constexpr uint DebugTypeBase{DebugSourceBase + DebugSourceCount};
|
||||
enum class DebugType : std::uint8_t {
|
||||
Error = 0,
|
||||
DeprecatedBehavior,
|
||||
UndefinedBehavior,
|
||||
Portability,
|
||||
Performance,
|
||||
Marker,
|
||||
PushGroup,
|
||||
PopGroup,
|
||||
Other,
|
||||
};
|
||||
inline constexpr uint DebugTypeCount{9};
|
||||
|
||||
inline constexpr uint DebugSeverityBase{DebugTypeBase + DebugTypeCount};
|
||||
enum class DebugSeverity : std::uint8_t {
|
||||
High = 0,
|
||||
Medium,
|
||||
Low,
|
||||
Notification,
|
||||
};
|
||||
inline constexpr uint DebugSeverityCount{4};
|
||||
|
||||
struct DebugGroup {
|
||||
const uint mId;
|
||||
const DebugSource mSource;
|
||||
std::string mMessage;
|
||||
std::vector<uint> mFilters;
|
||||
std::vector<std::uint64_t> mIdFilters;
|
||||
|
||||
template<typename T>
|
||||
DebugGroup(DebugSource source, uint id, T&& message)
|
||||
: mId{id}, mSource{source}, mMessage{std::forward<T>(message)}
|
||||
{ }
|
||||
DebugGroup(const DebugGroup&) = default;
|
||||
DebugGroup(DebugGroup&&) = default;
|
||||
~DebugGroup();
|
||||
};
|
||||
|
||||
#endif /* AL_DEBUG_H */
|
||||
127
Engine/lib/openal-soft/al/direct_defs.h
Normal file
127
Engine/lib/openal-soft/al/direct_defs.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef AL_DIRECT_DEFS_H
|
||||
#define AL_DIRECT_DEFS_H
|
||||
|
||||
namespace detail_ {
|
||||
|
||||
template<typename T>
|
||||
constexpr T DefaultVal() noexcept { return T{}; }
|
||||
|
||||
template<>
|
||||
constexpr void DefaultVal() noexcept { }
|
||||
|
||||
} // namespace detail_
|
||||
|
||||
#define DECL_FUNC(R, Name) \
|
||||
auto AL_APIENTRY Name() noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get()); \
|
||||
}
|
||||
|
||||
#define DECL_FUNC1(R, Name, T1,n1) \
|
||||
auto AL_APIENTRY Name(T1 n1) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get(), n1); \
|
||||
}
|
||||
|
||||
#define DECL_FUNC2(R, Name, T1,n1, T2,n2) \
|
||||
auto AL_APIENTRY Name(T1 n1, T2 n2) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get(), n1, n2); \
|
||||
}
|
||||
|
||||
#define DECL_FUNC3(R, Name, T1,n1, T2,n2, T3,n3) \
|
||||
auto AL_APIENTRY Name(T1 n1, T2 n2, T3 n3) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get(), n1, n2, n3); \
|
||||
}
|
||||
|
||||
#define DECL_FUNC4(R, Name, T1,n1, T2,n2, T3,n3, T4,n4) \
|
||||
auto AL_APIENTRY Name(T1 n1, T2 n2, T3 n3, T4 n4) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get(), n1, n2, n3, n4); \
|
||||
}
|
||||
|
||||
#define DECL_FUNC5(R, Name, T1,n1, T2,n2, T3,n3, T4,n4, T5,n5) \
|
||||
auto AL_APIENTRY Name(T1 n1, T2 n2, T3 n3, T4 n4, T5 n5) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct(context.get(), n1, n2, n3, n4, n5); \
|
||||
}
|
||||
|
||||
|
||||
#define DECL_FUNCEXT(R, Name,Ext) \
|
||||
auto AL_APIENTRY Name##Ext() noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get()); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT1(R, Name,Ext, T1,n1) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT2(R, Name,Ext, T1,n1, T2,n2) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT3(R, Name,Ext, T1,n1, T2,n2, T3,n3) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2, T3 n3) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2, n3); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT4(R, Name,Ext, T1,n1, T2,n2, T3,n3, T4,n4) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2, T3 n3, T4 n4) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2, n3, n4); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT5(R, Name,Ext, T1,n1, T2,n2, T3,n3, T4,n4, T5,n5) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2, T3 n3, T4 n4, T5 n5) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2, n3, n4, n5); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT6(R, Name,Ext, T1,n1, T2,n2, T3,n3, T4,n4, T5,n5, T6,n6) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2, T3 n3, T4 n4, T5 n5, T6 n6) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2, n3, n4, n5, n6); \
|
||||
}
|
||||
|
||||
#define DECL_FUNCEXT8(R, Name,Ext, T1,n1, T2,n2, T3,n3, T4,n4, T5,n5, T6,n6, T7,n7, T8,n8) \
|
||||
auto AL_APIENTRY Name##Ext(T1 n1, T2 n2, T3 n3, T4 n4, T5 n5, T6 n6, T7 n7, T8 n8) noexcept -> R \
|
||||
{ \
|
||||
auto context = GetContextRef(); \
|
||||
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
|
||||
return Name##Direct##Ext(context.get(), n1, n2, n3, n4, n5, n6, n7, n8); \
|
||||
}
|
||||
|
||||
#endif /* AL_DIRECT_DEFS_H */
|
||||
|
|
@ -10,34 +10,39 @@
|
|||
//
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cfloat>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#ifdef _WIN32
|
||||
#include <guiddef.h>
|
||||
#endif
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
|
||||
#ifndef GUID_DEFINED
|
||||
#define GUID_DEFINED
|
||||
typedef struct _GUID {
|
||||
#ifndef _WIN32
|
||||
using GUID = struct _GUID { /* NOLINT(*-reserved-identifier) */
|
||||
std::uint32_t Data1;
|
||||
std::uint16_t Data2;
|
||||
std::uint16_t Data3;
|
||||
std::uint8_t Data4[8];
|
||||
} GUID;
|
||||
std::array<std::uint8_t,8> Data4;
|
||||
};
|
||||
|
||||
#ifndef _SYS_GUID_OPERATOR_EQ_
|
||||
#define _SYS_GUID_OPERATOR_EQ_
|
||||
inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept
|
||||
{ return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; }
|
||||
|
||||
inline bool operator!=(const GUID& lhs, const GUID& rhs) noexcept
|
||||
{ return !(lhs == rhs); }
|
||||
#endif // _SYS_GUID_OPERATOR_EQ_
|
||||
#endif // GUID_DEFINED
|
||||
#endif // _WIN32
|
||||
|
||||
#define DECL_EQOP(T, ...) \
|
||||
[[nodiscard]] auto get_members() const noexcept { return std::forward_as_tuple(__VA_ARGS__); } \
|
||||
[[nodiscard]] friend bool operator==(const T &lhs, const T &rhs) noexcept \
|
||||
{ return lhs.get_members() == rhs.get_members(); } \
|
||||
[[nodiscard]] friend bool operator!=(const T &lhs, const T &rhs) noexcept \
|
||||
{ return !(lhs == rhs); }
|
||||
|
||||
extern const GUID DSPROPSETID_EAX_ReverbProperties;
|
||||
|
||||
|
|
@ -276,11 +281,15 @@ struct EAXVECTOR {
|
|||
float x;
|
||||
float y;
|
||||
float z;
|
||||
[[nodiscard]]
|
||||
auto get_members() const noexcept { return std::forward_as_tuple(x, y, z); }
|
||||
}; // EAXVECTOR
|
||||
|
||||
[[nodiscard]]
|
||||
inline bool operator==(const EAXVECTOR& lhs, const EAXVECTOR& rhs) noexcept
|
||||
{ return std::memcmp(&lhs, &rhs, sizeof(EAXVECTOR)) == 0; }
|
||||
{ return lhs.get_members() == rhs.get_members(); }
|
||||
|
||||
[[nodiscard]]
|
||||
inline bool operator!=(const EAXVECTOR& lhs, const EAXVECTOR& rhs) noexcept
|
||||
{ return !(lhs == rhs); }
|
||||
|
||||
|
|
@ -361,6 +370,7 @@ constexpr auto EAXCONTEXT_MINMACROFXFACTOR = 0.0F;
|
|||
constexpr auto EAXCONTEXT_MAXMACROFXFACTOR = 1.0F;
|
||||
constexpr auto EAXCONTEXT_DEFAULTMACROFXFACTOR = 0.0F;
|
||||
|
||||
constexpr auto EAXCONTEXT_DEFAULTLASTERROR = EAX_OK;
|
||||
|
||||
extern const GUID EAXPROPERTYID_EAX40_FXSlot0;
|
||||
extern const GUID EAXPROPERTYID_EAX50_FXSlot0;
|
||||
|
|
@ -613,7 +623,7 @@ struct EAX30SOURCEPROPERTIES {
|
|||
float flOcclusionLFRatio; // occlusion low-frequency level re. main control
|
||||
float flOcclusionRoomRatio; // relative occlusion control for room effect
|
||||
float flOcclusionDirectRatio; // relative occlusion control for direct path
|
||||
long lExclusion; // main exlusion control (attenuation at high frequencies)
|
||||
long lExclusion; // main exclusion control (attenuation at high frequencies)
|
||||
float flExclusionLFRatio; // exclusion low-frequency level re. main control
|
||||
long lOutsideVolumeHF; // outside sound cone level at high frequencies
|
||||
float flDopplerFactor; // like DS3D flDopplerFactor but per source
|
||||
|
|
@ -653,11 +663,11 @@ struct EAXSPEAKERLEVELPROPERTIES {
|
|||
}; // EAXSPEAKERLEVELPROPERTIES
|
||||
|
||||
struct EAX40ACTIVEFXSLOTS {
|
||||
GUID guidActiveFXSlots[EAX40_MAX_ACTIVE_FXSLOTS];
|
||||
std::array<GUID,EAX40_MAX_ACTIVE_FXSLOTS> guidActiveFXSlots;
|
||||
}; // EAX40ACTIVEFXSLOTS
|
||||
|
||||
struct EAX50ACTIVEFXSLOTS {
|
||||
GUID guidActiveFXSlots[EAX50_MAX_ACTIVE_FXSLOTS];
|
||||
std::array<GUID,EAX50_MAX_ACTIVE_FXSLOTS> guidActiveFXSlots;
|
||||
}; // EAX50ACTIVEFXSLOTS
|
||||
|
||||
// Use this structure for EAXSOURCE_OBSTRUCTIONPARAMETERS property.
|
||||
|
|
@ -836,6 +846,11 @@ struct EAXREVERBPROPERTIES {
|
|||
float flLFReference; // reference low frequency
|
||||
float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
|
||||
unsigned long ulFlags; // modifies the behavior of properties
|
||||
DECL_EQOP(EAXREVERBPROPERTIES, ulEnvironment, flEnvironmentSize, flEnvironmentDiffusion, lRoom,
|
||||
lRoomHF, lRoomLF, flDecayTime, flDecayHFRatio, flDecayLFRatio, lReflections,
|
||||
flReflectionsDelay, vReflectionsPan, lReverb, flReverbDelay, vReverbPan, flEchoTime,
|
||||
flEchoDepth, flModulationTime, flModulationDepth, flAirAbsorptionHF, flHFReference,
|
||||
flLFReference, flRoomRolloffFactor, ulFlags)
|
||||
}; // EAXREVERBPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -965,6 +980,7 @@ enum EAXAGCCOMPRESSOR_PROPERTY : unsigned int {
|
|||
|
||||
struct EAXAGCCOMPRESSORPROPERTIES {
|
||||
unsigned long ulOnOff; // Switch Compressor on or off
|
||||
DECL_EQOP(EAXAGCCOMPRESSORPROPERTIES, ulOnOff)
|
||||
}; // EAXAGCCOMPRESSORPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -991,6 +1007,7 @@ struct EAXAUTOWAHPROPERTIES {
|
|||
float flReleaseTime; // Release time (seconds)
|
||||
long lResonance; // Resonance (mB)
|
||||
long lPeakLevel; // Peak level (mB)
|
||||
DECL_EQOP(EAXAUTOWAHPROPERTIES, flAttackTime, flReleaseTime, lResonance, lPeakLevel)
|
||||
}; // EAXAUTOWAHPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1038,6 +1055,7 @@ struct EAXCHORUSPROPERTIES {
|
|||
float flDepth; // Depth (0 to 1)
|
||||
float flFeedback; // Feedback (-1 to 1)
|
||||
float flDelay; // Delay (seconds)
|
||||
DECL_EQOP(EAXCHORUSPROPERTIES, ulWaveform, lPhase, flRate, flDepth, flFeedback, flDelay)
|
||||
}; // EAXCHORUSPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1086,6 +1104,7 @@ struct EAXDISTORTIONPROPERTIES {
|
|||
float flLowPassCutOff; // Controls the cut-off of the filter pre-distortion (Hz)
|
||||
float flEQCenter; // Controls the center frequency of the EQ post-distortion (Hz)
|
||||
float flEQBandwidth; // Controls the bandwidth of the EQ post-distortion (Hz)
|
||||
DECL_EQOP(EAXDISTORTIONPROPERTIES, flEdge, lGain, flLowPassCutOff, flEQCenter, flEQBandwidth)
|
||||
}; // EAXDISTORTIONPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1130,6 +1149,7 @@ struct EAXECHOPROPERTIES {
|
|||
float flDamping; // Controls a low-pass filter that dampens the echoes (0 to 1)
|
||||
float flFeedback; // Controls the duration of echo repetition (0 to 1)
|
||||
float flSpread; // Controls the left-right spread of the echoes
|
||||
DECL_EQOP(EAXECHOPROPERTIES, flDelay, flLRDelay, flDamping, flFeedback, flSpread)
|
||||
}; // EAXECHOPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1184,6 +1204,8 @@ struct EAXEQUALIZERPROPERTIES {
|
|||
float flMid2Width; // (octaves)
|
||||
long lHighGain; // (mB)
|
||||
float flHighCutOff; // (Hz)
|
||||
DECL_EQOP(EAXEQUALIZERPROPERTIES, lLowGain, flLowCutOff, lMid1Gain, flMid1Center, flMid1Width,
|
||||
lMid2Gain, flMid2Center, flMid2Width, lHighGain, flHighCutOff)
|
||||
}; // EAXEQUALIZERPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1255,6 +1277,7 @@ struct EAXFLANGERPROPERTIES {
|
|||
float flDepth; // Depth (0 to 1)
|
||||
float flFeedback; // Feedback (0 to 1)
|
||||
float flDelay; // Delay (seconds)
|
||||
DECL_EQOP(EAXFLANGERPROPERTIES, ulWaveform, lPhase, flRate, flDepth, flFeedback, flDelay)
|
||||
}; // EAXFLANGERPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1305,6 +1328,7 @@ struct EAXFREQUENCYSHIFTERPROPERTIES {
|
|||
float flFrequency; // (Hz)
|
||||
unsigned long ulLeftDirection; // see enum above
|
||||
unsigned long ulRightDirection; // see enum above
|
||||
DECL_EQOP(EAXFREQUENCYSHIFTERPROPERTIES, flFrequency, ulLeftDirection, ulRightDirection)
|
||||
}; // EAXFREQUENCYSHIFTERPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1383,6 +1407,8 @@ struct EAXVOCALMORPHERPROPERTIES {
|
|||
long lPhonemeBCoarseTuning; // (semitones)
|
||||
unsigned long ulWaveform; // Waveform selector - see enum above
|
||||
float flRate; // (Hz)
|
||||
DECL_EQOP(EAXVOCALMORPHERPROPERTIES, ulPhonemeA, lPhonemeACoarseTuning, ulPhonemeB,
|
||||
lPhonemeBCoarseTuning, ulWaveform, flRate)
|
||||
}; // EAXVOCALMORPHERPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1425,6 +1451,7 @@ enum EAXPITCHSHIFTER_PROPERTY : unsigned int {
|
|||
struct EAXPITCHSHIFTERPROPERTIES {
|
||||
long lCoarseTune; // Amount of pitch shift (semitones)
|
||||
long lFineTune; // Amount of pitch shift (cents)
|
||||
DECL_EQOP(EAXPITCHSHIFTERPROPERTIES, lCoarseTune, lFineTune)
|
||||
}; // EAXPITCHSHIFTERPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1460,6 +1487,7 @@ struct EAXRINGMODULATORPROPERTIES {
|
|||
float flFrequency; // Frequency of modulation (Hz)
|
||||
float flHighPassCutOff; // Cut-off frequency of high-pass filter (Hz)
|
||||
unsigned long ulWaveform; // Waveform selector - see enum above
|
||||
DECL_EQOP(EAXRINGMODULATORPROPERTIES, flFrequency, flHighPassCutOff, ulWaveform)
|
||||
}; // EAXRINGMODULATORPROPERTIES
|
||||
|
||||
|
||||
|
|
@ -1490,4 +1518,5 @@ using LPEAXGET = ALenum(AL_APIENTRY*)(
|
|||
ALvoid* property_buffer,
|
||||
ALuint property_size);
|
||||
|
||||
#undef DECL_EQOP
|
||||
#endif // !EAX_API_INCLUDED
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ EaxCall::EaxCall(
|
|||
ALuint property_source_id,
|
||||
ALvoid* property_buffer,
|
||||
ALuint property_size)
|
||||
: mCallType{type}, mVersion{0}, mPropertySetId{EaxCallPropertySetId::none}
|
||||
, mIsDeferred{(property_id & deferred_flag) != 0}
|
||||
: mCallType{type}, mIsDeferred{(property_id & deferred_flag) != 0}
|
||||
, mPropertyId{property_id & ~deferred_flag}, mPropertySourceId{property_source_id}
|
||||
, mPropertyBuffer{property_buffer}, mPropertyBufferSize{property_size}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,16 +31,16 @@ public:
|
|||
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; }
|
||||
[[nodiscard]] auto is_get() const noexcept -> bool { return mCallType == EaxCallType::get; }
|
||||
[[nodiscard]] auto is_deferred() const noexcept -> bool { return mIsDeferred; }
|
||||
[[nodiscard]] auto get_version() const noexcept -> int { return mVersion; }
|
||||
[[nodiscard]] auto get_property_set_id() const noexcept -> EaxCallPropertySetId { return mPropertySetId; }
|
||||
[[nodiscard]] auto get_property_id() const noexcept -> ALuint { return mPropertyId; }
|
||||
[[nodiscard]] auto get_property_al_name() const noexcept -> ALuint { return mPropertySourceId; }
|
||||
[[nodiscard]] auto get_fx_slot_index() const noexcept -> EaxFxSlotIndex { return mFxSlotIndex; }
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
TValue& get_value() const
|
||||
[[nodiscard]] auto get_value() const -> TValue&
|
||||
{
|
||||
if(mPropertyBufferSize < sizeof(TValue))
|
||||
fail_too_small();
|
||||
|
|
@ -49,32 +49,32 @@ public:
|
|||
}
|
||||
|
||||
template<typename TValue>
|
||||
al::span<TValue> get_values(size_t max_count) const
|
||||
[[nodiscard]] auto get_values(size_t max_count) const -> al::span<TValue>
|
||||
{
|
||||
if(max_count == 0 || mPropertyBufferSize < sizeof(TValue))
|
||||
fail_too_small();
|
||||
|
||||
const auto count = minz(mPropertyBufferSize / sizeof(TValue), max_count);
|
||||
return al::as_span(static_cast<TValue*>(mPropertyBuffer), count);
|
||||
const auto count = std::min(mPropertyBufferSize/sizeof(TValue), max_count);
|
||||
return {static_cast<TValue*>(mPropertyBuffer), count};
|
||||
}
|
||||
|
||||
template<typename TValue>
|
||||
al::span<TValue> get_values() const
|
||||
[[nodiscard]] auto get_values() const -> al::span<TValue>
|
||||
{
|
||||
return get_values<TValue>(~size_t{});
|
||||
return get_values<TValue>(~0_uz);
|
||||
}
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
void set_value(const TValue& value) const
|
||||
auto set_value(const TValue& value) const -> void
|
||||
{
|
||||
get_value<TException, TValue>() = value;
|
||||
}
|
||||
|
||||
private:
|
||||
const EaxCallType mCallType;
|
||||
int mVersion;
|
||||
EaxFxSlotIndex mFxSlotIndex;
|
||||
EaxCallPropertySetId mPropertySetId;
|
||||
int mVersion{};
|
||||
EaxFxSlotIndex mFxSlotIndex{};
|
||||
EaxCallPropertySetId mPropertySetId{EaxCallPropertySetId::none};
|
||||
bool mIsDeferred;
|
||||
|
||||
const ALuint mPropertyId;
|
||||
|
|
|
|||
|
|
@ -4,60 +4,56 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
|
||||
#include "alnumeric.h"
|
||||
#include "AL/al.h"
|
||||
#include "AL/alext.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "call.h"
|
||||
|
||||
struct EaxEffectErrorMessages
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
using EaxEffectProps = std::variant<std::monostate,
|
||||
EAXREVERBPROPERTIES,
|
||||
EAXCHORUSPROPERTIES,
|
||||
EAXAUTOWAHPROPERTIES,
|
||||
EAXAGCCOMPRESSORPROPERTIES,
|
||||
EAXDISTORTIONPROPERTIES,
|
||||
EAXECHOPROPERTIES,
|
||||
EAXEQUALIZERPROPERTIES,
|
||||
EAXFLANGERPROPERTIES,
|
||||
EAXFREQUENCYSHIFTERPROPERTIES,
|
||||
EAXRINGMODULATORPROPERTIES,
|
||||
EAXPITCHSHIFTERPROPERTIES,
|
||||
EAXVOCALMORPHERPROPERTIES>;
|
||||
|
||||
template<typename... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
|
||||
template<typename... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
|
||||
{
|
||||
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;
|
||||
return std::visit(overloaded{
|
||||
[](const std::monostate&) noexcept { return AL_EFFECT_NULL; },
|
||||
[](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; },
|
||||
[](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; },
|
||||
[](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; },
|
||||
[](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; },
|
||||
[](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; },
|
||||
[](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; },
|
||||
[](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; },
|
||||
[](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; },
|
||||
[](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; },
|
||||
[](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; },
|
||||
[](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; },
|
||||
[](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; }
|
||||
}, props);
|
||||
}
|
||||
|
||||
struct EaxReverbCommitter {
|
||||
|
|
@ -105,7 +101,6 @@ struct EaxReverbCommitter {
|
|||
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);
|
||||
|
|
@ -115,16 +110,13 @@ struct EaxReverbCommitter {
|
|||
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;
|
||||
static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
|
||||
static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -149,51 +141,137 @@ struct EaxCommitter {
|
|||
[[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;
|
||||
|
||||
bool commit(const EAXAUTOWAHPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
|
||||
};
|
||||
struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
|
||||
using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXCHORUSPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
|
||||
};
|
||||
struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
|
||||
using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
|
||||
};
|
||||
struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
|
||||
using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXDISTORTIONPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
|
||||
};
|
||||
struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
|
||||
using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXECHOPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
|
||||
};
|
||||
struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
|
||||
using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXEQUALIZERPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
|
||||
};
|
||||
struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
|
||||
using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXFLANGERPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
|
||||
};
|
||||
struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
|
||||
using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
|
||||
};
|
||||
struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
|
||||
using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXRINGMODULATORPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
|
||||
};
|
||||
struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
|
||||
using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
|
||||
};
|
||||
struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
|
||||
using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const EAXVOCALMORPHERPROPERTIES &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
|
||||
static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
|
||||
};
|
||||
struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
|
||||
using EaxCommitter<EaxNullCommitter>::EaxCommitter;
|
||||
|
||||
bool commit(const std::monostate &props);
|
||||
|
||||
static void SetDefaults(EaxEffectProps &props);
|
||||
static void Get(const EaxCall &call, const std::monostate &props);
|
||||
static void Set(const EaxCall &call, std::monostate &props);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct CommitterFromProps { };
|
||||
|
||||
template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
|
||||
template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
|
||||
template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
|
||||
template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
|
||||
template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
|
||||
template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
|
||||
template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
|
||||
template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
|
||||
template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
|
||||
template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
|
||||
template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
|
||||
template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
|
||||
template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
|
||||
|
||||
template<typename T>
|
||||
using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
|
||||
|
||||
|
||||
class EaxEffect {
|
||||
public:
|
||||
|
|
@ -238,51 +316,39 @@ public:
|
|||
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)
|
||||
static 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);
|
||||
switch(altype)
|
||||
{
|
||||
case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
|
||||
case AL_EFFECT_NULL: break;
|
||||
}
|
||||
return EaxNullCommitter::SetDefaults(props);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void init()
|
||||
{
|
||||
call_set_defaults<EaxReverbCommitter>(state1_.d);
|
||||
EaxReverbCommitter::SetDefaults(state1_.d);
|
||||
state1_.i = state1_.d;
|
||||
call_set_defaults<EaxReverbCommitter>(state2_.d);
|
||||
EaxReverbCommitter::SetDefaults(state2_.d);
|
||||
state2_.i = state2_.d;
|
||||
call_set_defaults<EaxReverbCommitter>(state3_.d);
|
||||
EaxReverbCommitter::SetDefaults(state3_.d);
|
||||
state3_.i = state3_.d;
|
||||
call_set_defaults<T>(state4_.d);
|
||||
T::SetDefaults(state4_.d);
|
||||
state4_.i = state4_.d;
|
||||
call_set_defaults<T>(state5_.d);
|
||||
T::SetDefaults(state5_.d);
|
||||
state5_.i = state5_.d;
|
||||
}
|
||||
|
||||
|
|
@ -290,9 +356,9 @@ public:
|
|||
{
|
||||
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 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
|
||||
case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
|
||||
case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
|
||||
case 4: call_set_defaults(altype, state4_.d); break;
|
||||
case 5: call_set_defaults(altype, state5_.d); break;
|
||||
}
|
||||
|
|
@ -300,47 +366,20 @@ public:
|
|||
}
|
||||
|
||||
|
||||
#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); }
|
||||
{
|
||||
return std::visit([&](auto &arg)
|
||||
{ return CommitterFor<decltype(arg)>::Set(call, arg); },
|
||||
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 1: EaxReverbCommitter::Set(call, state1_.d); break;
|
||||
case 2: EaxReverbCommitter::Set(call, state2_.d); break;
|
||||
case 3: EaxReverbCommitter::Set(call, state3_.d); break;
|
||||
case 4: call_set(call, state4_.d); break;
|
||||
case 5: call_set(call, state5_.d); break;
|
||||
}
|
||||
|
|
@ -348,32 +387,32 @@ public:
|
|||
}
|
||||
|
||||
|
||||
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); }
|
||||
{
|
||||
return std::visit([&](auto &arg)
|
||||
{ return CommitterFor<decltype(arg)>::Get(call, arg); },
|
||||
props);
|
||||
}
|
||||
|
||||
void get(const EaxCall &call)
|
||||
void get(const EaxCall &call) const
|
||||
{
|
||||
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 1: EaxReverbCommitter::Get(call, state1_.d); break;
|
||||
case 2: EaxReverbCommitter::Get(call, state2_.d); break;
|
||||
case 3: EaxReverbCommitter::Get(call, state3_.d); break;
|
||||
case 4: call_get(call, state4_.d); break;
|
||||
case 5: call_get(call, state5_.d); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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); }
|
||||
{
|
||||
return std::visit([&](auto &arg)
|
||||
{ return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
|
||||
props);
|
||||
}
|
||||
|
||||
bool commit(int eax_version)
|
||||
{
|
||||
|
|
@ -388,15 +427,15 @@ public:
|
|||
{
|
||||
case 1:
|
||||
state1_.i = state1_.d;
|
||||
ret |= call_commit<EaxReverbCommitter>(state1_.d);
|
||||
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
|
||||
break;
|
||||
case 2:
|
||||
state2_.i = state2_.d;
|
||||
ret |= call_commit<EaxReverbCommitter>(state2_.d);
|
||||
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
|
||||
break;
|
||||
case 3:
|
||||
state3_.i = state3_.d;
|
||||
ret |= call_commit<EaxReverbCommitter>(state3_.d);
|
||||
ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
|
||||
break;
|
||||
case 4:
|
||||
state4_.i = state4_.d;
|
||||
|
|
|
|||
|
|
@ -6,54 +6,27 @@
|
|||
#include <string>
|
||||
|
||||
|
||||
EaxException::EaxException(const char *context, const char *message)
|
||||
EaxException::EaxException(std::string_view context, std::string_view message)
|
||||
: std::runtime_error{make_message(context, message)}
|
||||
{
|
||||
}
|
||||
EaxException::~EaxException() = default;
|
||||
|
||||
|
||||
std::string EaxException::make_message(const char *context, const char *message)
|
||||
std::string EaxException::make_message(std::string_view context, std::string_view 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(context.empty() && message.empty())
|
||||
return what;
|
||||
|
||||
if (has_contex)
|
||||
what.reserve((!context.empty() ? context.size() + 3 : 0) + message.length() + 1);
|
||||
if(!context.empty())
|
||||
{
|
||||
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);
|
||||
what += "[";
|
||||
what += context;
|
||||
what += "] ";
|
||||
}
|
||||
what += message;
|
||||
|
||||
return what;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
#ifndef EAX_EXCEPTION_INCLUDED
|
||||
#define EAX_EXCEPTION_INCLUDED
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
class EaxException : public std::runtime_error {
|
||||
static std::string make_message(const char *context, const char *message);
|
||||
static std::string make_message(std::string_view context, std::string_view message);
|
||||
|
||||
public:
|
||||
EaxException(const char *context, const char *message);
|
||||
EaxException() = delete;
|
||||
EaxException(const EaxException&) = default;
|
||||
EaxException(EaxException&&) = default;
|
||||
EaxException(std::string_view context, std::string_view message);
|
||||
~EaxException() override;
|
||||
}; // EaxException
|
||||
|
||||
auto operator=(const EaxException&) -> EaxException& = default;
|
||||
auto operator=(EaxException&&) -> EaxException& = default;
|
||||
};
|
||||
|
||||
#endif // !EAX_EXCEPTION_INCLUDED
|
||||
#endif /* EAX_EXCEPTION_INCLUDED */
|
||||
|
|
|
|||
|
|
@ -3,17 +3,16 @@
|
|||
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
#include "aloptional.h"
|
||||
#include "api.h"
|
||||
|
||||
|
||||
using EaxFxSlotIndexValue = std::size_t;
|
||||
|
||||
class EaxFxSlotIndex : public al::optional<EaxFxSlotIndexValue>
|
||||
{
|
||||
class EaxFxSlotIndex : public std::optional<EaxFxSlotIndexValue> {
|
||||
public:
|
||||
using al::optional<EaxFxSlotIndexValue>::optional;
|
||||
using std::optional<EaxFxSlotIndexValue>::optional;
|
||||
|
||||
EaxFxSlotIndex& operator=(const EaxFxSlotIndexValue &value) { set(value); return *this; }
|
||||
EaxFxSlotIndex& operator=(const GUID &guid) { set(guid); return *this; }
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@
|
|||
|
||||
#include "al/auxeffectslot.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "call.h"
|
||||
#include "fx_slot_index.h"
|
||||
|
||||
|
||||
class EaxFxSlots
|
||||
{
|
||||
class EaxFxSlots {
|
||||
public:
|
||||
void initialize(ALCcontext& al_context);
|
||||
|
||||
|
|
@ -25,11 +22,9 @@ public:
|
|||
}
|
||||
|
||||
|
||||
const ALeffectslot& get(
|
||||
EaxFxSlotIndex index) const;
|
||||
[[nodiscard]] auto get(EaxFxSlotIndex index) const -> const ALeffectslot&;
|
||||
|
||||
ALeffectslot& get(
|
||||
EaxFxSlotIndex index);
|
||||
[[nodiscard]] auto get(EaxFxSlotIndex index) -> ALeffectslot&;
|
||||
|
||||
private:
|
||||
using Items = std::array<EaxAlEffectSlotUPtr, EAX_MAX_FXSLOTS>;
|
||||
|
|
@ -39,8 +34,7 @@ private:
|
|||
|
||||
|
||||
[[noreturn]]
|
||||
static void fail(
|
||||
const char* message);
|
||||
static void fail(const char* message);
|
||||
|
||||
void initialize_fx_slots(ALCcontext& al_context);
|
||||
}; // EaxFxSlots
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
#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";
|
||||
|
|
@ -1,22 +1,6 @@
|
|||
#ifndef EAX_GLOBALS_INCLUDED
|
||||
#define EAX_GLOBALS_INCLUDED
|
||||
|
||||
inline bool eax_g_is_enabled{true};
|
||||
|
||||
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
|
||||
#endif /* EAX_GLOBALS_INCLUDED */
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
#include <cassert>
|
||||
#include <exception>
|
||||
|
||||
#include "alstring.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
|
||||
void eax_log_exception(const char *message) noexcept
|
||||
void eax_log_exception(std::string_view message) noexcept
|
||||
{
|
||||
const auto exception_ptr = std::current_exception();
|
||||
assert(exception_ptr);
|
||||
|
|
@ -17,10 +18,9 @@ void eax_log_exception(const char *message) noexcept
|
|||
std::rethrow_exception(exception_ptr);
|
||||
}
|
||||
catch(const std::exception& ex) {
|
||||
const auto ex_message = ex.what();
|
||||
ERR("%s %s\n", message ? message : "", ex_message);
|
||||
ERR("%.*s %s\n", al::sizei(message), message.data(), ex.what());
|
||||
}
|
||||
catch(...) {
|
||||
ERR("%s %s\n", message ? message : "", "Generic exception.");
|
||||
ERR("%.*s %s\n", al::sizei(message), message.data(), "Generic exception.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@
|
|||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "opthelpers.h"
|
||||
|
||||
using EaxDirtyFlags = unsigned int;
|
||||
|
||||
struct EaxAlLowPassParam {
|
||||
|
|
@ -13,16 +16,13 @@ struct EaxAlLowPassParam {
|
|||
float gain_hf;
|
||||
};
|
||||
|
||||
void eax_log_exception(const char *message) noexcept;
|
||||
void eax_log_exception(std::string_view message) noexcept;
|
||||
|
||||
template<typename TException, typename TValue>
|
||||
void eax_validate_range(
|
||||
const char* value_name,
|
||||
const TValue& value,
|
||||
const TValue& min_value,
|
||||
void eax_validate_range(std::string_view value_name, const TValue& value, const TValue& min_value,
|
||||
const TValue& max_value)
|
||||
{
|
||||
if (value >= min_value && value <= max_value)
|
||||
if(value >= min_value && value <= max_value) LIKELY
|
||||
return;
|
||||
|
||||
const auto message =
|
||||
|
|
|
|||
|
|
@ -24,15 +24,7 @@ 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);
|
||||
|
||||
ALboolean AL_APIENTRY EAXSetBufferMode(ALsizei n, const ALuint *buffers, ALint value) noexcept;
|
||||
ALenum AL_APIENTRY EAXGetBufferMode(ALuint buffer, ALint *pReserved) noexcept;
|
||||
|
||||
#endif // !EAX_X_RAM_INCLUDED
|
||||
|
|
|
|||
|
|
@ -28,9 +28,13 @@
|
|||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
|
@ -38,26 +42,23 @@
|
|||
#include "AL/efx-presets.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "al/effects/effects.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 "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "core/except.h"
|
||||
#include "core/logging.h"
|
||||
#include "direct_defs.h"
|
||||
#include "error.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "opthelpers.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
|
||||
#include "eax/exception.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
const EffectList gEffectList[16]{
|
||||
const std::array<EffectList,16> gEffectList{{
|
||||
{ "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
|
||||
{ "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
|
||||
{ "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
|
||||
|
|
@ -73,95 +74,74 @@ const EffectList gEffectList[16]{
|
|||
{ "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 },
|
||||
};
|
||||
{ "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_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 },
|
||||
};
|
||||
using SubListAllocator = al::allocator<std::array<ALeffect,64>>;
|
||||
|
||||
|
||||
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)
|
||||
constexpr auto GetDefaultProps(ALenum type) noexcept -> const EffectProps&
|
||||
{
|
||||
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;
|
||||
switch(type)
|
||||
{
|
||||
case AL_EFFECT_NULL: return NullEffectProps;
|
||||
case AL_EFFECT_EAXREVERB: return ReverbEffectProps;
|
||||
case AL_EFFECT_REVERB: return StdReverbEffectProps;
|
||||
case AL_EFFECT_AUTOWAH: return AutowahEffectProps;
|
||||
case AL_EFFECT_CHORUS: return ChorusEffectProps;
|
||||
case AL_EFFECT_COMPRESSOR: return CompressorEffectProps;
|
||||
case AL_EFFECT_DISTORTION: return DistortionEffectProps;
|
||||
case AL_EFFECT_ECHO: return EchoEffectProps;
|
||||
case AL_EFFECT_EQUALIZER: return EqualizerEffectProps;
|
||||
case AL_EFFECT_FLANGER: return FlangerEffectProps;
|
||||
case AL_EFFECT_FREQUENCY_SHIFTER: return FshifterEffectProps;
|
||||
case AL_EFFECT_RING_MODULATOR: return ModulatorEffectProps;
|
||||
case AL_EFFECT_PITCH_SHIFTER: return PshifterEffectProps;
|
||||
case AL_EFFECT_VOCAL_MORPHER: return VmorpherEffectProps;
|
||||
case AL_EFFECT_DEDICATED_DIALOGUE: return DedicatedDialogEffectProps;
|
||||
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: return DedicatedLfeEffectProps;
|
||||
case AL_EFFECT_CONVOLUTION_SOFT: return ConvolutionEffectProps;
|
||||
}
|
||||
return NullEffectProps;
|
||||
}
|
||||
|
||||
void InitEffectParams(ALeffect *effect, ALenum type)
|
||||
void InitEffectParams(ALeffect *effect, ALenum type) noexcept
|
||||
{
|
||||
const EffectPropsItem *item{getEffectPropsItemByType(type)};
|
||||
if(item)
|
||||
switch(type)
|
||||
{
|
||||
effect->Props = item->DefaultProps;
|
||||
effect->vtab = &item->Vtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
effect->Props = EffectProps{};
|
||||
effect->vtab = &NullEffectVtable;
|
||||
case AL_EFFECT_NULL: effect->PropsVariant.emplace<NullEffectHandler>(); break;
|
||||
case AL_EFFECT_EAXREVERB: effect->PropsVariant.emplace<ReverbEffectHandler>(); break;
|
||||
case AL_EFFECT_REVERB: effect->PropsVariant.emplace<StdReverbEffectHandler>(); break;
|
||||
case AL_EFFECT_AUTOWAH: effect->PropsVariant.emplace<AutowahEffectHandler>(); break;
|
||||
case AL_EFFECT_CHORUS: effect->PropsVariant.emplace<ChorusEffectHandler>(); break;
|
||||
case AL_EFFECT_COMPRESSOR: effect->PropsVariant.emplace<CompressorEffectHandler>(); break;
|
||||
case AL_EFFECT_DISTORTION: effect->PropsVariant.emplace<DistortionEffectHandler>(); break;
|
||||
case AL_EFFECT_ECHO: effect->PropsVariant.emplace<EchoEffectHandler>(); break;
|
||||
case AL_EFFECT_EQUALIZER: effect->PropsVariant.emplace<EqualizerEffectHandler>(); break;
|
||||
case AL_EFFECT_FLANGER: effect->PropsVariant.emplace<ChorusEffectHandler>(); break;
|
||||
case AL_EFFECT_FREQUENCY_SHIFTER: effect->PropsVariant.emplace<FshifterEffectHandler>(); break;
|
||||
case AL_EFFECT_RING_MODULATOR: effect->PropsVariant.emplace<ModulatorEffectHandler>(); break;
|
||||
case AL_EFFECT_PITCH_SHIFTER: effect->PropsVariant.emplace<PshifterEffectHandler>(); break;
|
||||
case AL_EFFECT_VOCAL_MORPHER: effect->PropsVariant.emplace<VmorpherEffectHandler>(); break;
|
||||
case AL_EFFECT_DEDICATED_DIALOGUE:
|
||||
effect->PropsVariant.emplace<DedicatedDialogEffectHandler>();
|
||||
break;
|
||||
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
|
||||
effect->PropsVariant.emplace<DedicatedLfeEffectHandler>();
|
||||
break;
|
||||
case AL_EFFECT_CONVOLUTION_SOFT:
|
||||
effect->PropsVariant.emplace<ConvolutionEffectHandler>();
|
||||
break;
|
||||
}
|
||||
effect->Props = GetDefaultProps(type);
|
||||
effect->type = type;
|
||||
}
|
||||
|
||||
bool EnsureEffects(ALCdevice *device, size_t needed)
|
||||
{
|
||||
size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
|
||||
auto EnsureEffects(ALCdevice *device, size_t needed) noexcept -> bool
|
||||
try {
|
||||
size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), 0_uz,
|
||||
[](size_t cur, const EffectSubList &sublist) noexcept -> size_t
|
||||
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
|
||||
|
||||
|
|
@ -170,21 +150,19 @@ bool EnsureEffects(ALCdevice *device, size_t needed)
|
|||
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;
|
||||
EffectSubList sublist{};
|
||||
sublist.FreeMask = ~0_u64;
|
||||
sublist.Effects = SubListAllocator{}.allocate(1);
|
||||
device->EffectList.emplace_back(std::move(sublist));
|
||||
count += std::tuple_size_v<SubListAllocator::value_type>;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch(...) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ALeffect *AllocEffect(ALCdevice *device)
|
||||
ALeffect *AllocEffect(ALCdevice *device) noexcept
|
||||
{
|
||||
auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
|
||||
[](const EffectSubList &entry) noexcept -> bool
|
||||
|
|
@ -193,7 +171,7 @@ ALeffect *AllocEffect(ALCdevice *device)
|
|||
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
|
||||
ASSUME(slidx < 64);
|
||||
|
||||
ALeffect *effect{al::construct_at(sublist->Effects + slidx)};
|
||||
ALeffect *effect{al::construct_at(al::to_address(sublist->Effects->begin() + slidx))};
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
|
||||
/* Add 1 to avoid effect ID 0. */
|
||||
|
|
@ -206,16 +184,18 @@ ALeffect *AllocEffect(ALCdevice *device)
|
|||
|
||||
void FreeEffect(ALCdevice *device, ALeffect *effect)
|
||||
{
|
||||
device->mEffectNames.erase(effect->id);
|
||||
|
||||
const ALuint id{effect->id - 1};
|
||||
const size_t lidx{id >> 6};
|
||||
const ALuint slidx{id & 0x3f};
|
||||
|
||||
al::destroy_at(effect);
|
||||
std::destroy_at(effect);
|
||||
|
||||
device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
|
||||
}
|
||||
|
||||
inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
|
||||
inline auto LookupEffect(ALCdevice *device, ALuint id) noexcept -> ALeffect*
|
||||
{
|
||||
const size_t lidx{(id-1) >> 6};
|
||||
const ALuint slidx{(id-1) & 0x3f};
|
||||
|
|
@ -225,320 +205,294 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
|
|||
EffectSubList &sublist = device->EffectList[lidx];
|
||||
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
|
||||
return nullptr;
|
||||
return sublist.Effects + slidx;
|
||||
return al::to_address(sublist.Effects->begin() + 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);
|
||||
AL_API DECL_FUNC2(void, alGenEffects, ALsizei,n, ALuint*,effects)
|
||||
FORCE_ALIGN void AL_APIENTRY alGenEffectsDirect(ALCcontext *context, ALsizei n, ALuint *effects) noexcept
|
||||
try {
|
||||
if(n < 0)
|
||||
throw al::context_error{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;
|
||||
}
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
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);
|
||||
}
|
||||
const al::span eids{effects, static_cast<ALuint>(n)};
|
||||
if(!EnsureEffects(device, eids.size()))
|
||||
throw al::context_error{AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n,
|
||||
(n == 1) ? "" : "s"};
|
||||
|
||||
std::generate(eids.begin(), eids.end(), [device]{ return AllocEffect(device)->id; });
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
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);
|
||||
AL_API DECL_FUNC2(void, alDeleteEffects, ALsizei,n, const ALuint*,effects)
|
||||
FORCE_ALIGN void AL_APIENTRY alDeleteEffectsDirect(ALCcontext *context, ALsizei n,
|
||||
const ALuint *effects) noexcept
|
||||
try {
|
||||
if(n < 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Deleting %d effects", n};
|
||||
if(n <= 0) UNLIKELY return;
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{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;
|
||||
}
|
||||
const al::span eids{effects, static_cast<ALuint>(n)};
|
||||
auto inveffect = std::find_if_not(eids.begin(), eids.end(), validate_effect);
|
||||
if(inveffect != eids.end())
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", *inveffect};
|
||||
|
||||
/* 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);
|
||||
if(ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr})
|
||||
FreeEffect(device, effect);
|
||||
};
|
||||
std::for_each(effects, effects_end, delete_effect);
|
||||
std::for_each(eids.begin(), eids.end(), delete_effect);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
|
||||
START_API_FUNC
|
||||
AL_API DECL_FUNC1(ALboolean, alIsEffect, ALuint,effect)
|
||||
FORCE_ALIGN ALboolean AL_APIENTRY alIsEffectDirect(ALCcontext *context, ALuint effect) noexcept
|
||||
{
|
||||
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;
|
||||
}
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> effectlock{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;
|
||||
|
||||
AL_API DECL_FUNC3(void, alEffecti, ALuint,effect, ALenum,param, ALint,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALint value) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{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)
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
switch(param)
|
||||
{
|
||||
bool isOk{value == AL_EFFECT_NULL};
|
||||
if(!isOk)
|
||||
case AL_EFFECT_TYPE:
|
||||
if(value != AL_EFFECT_NULL)
|
||||
{
|
||||
for(const EffectList &effectitem : gEffectList)
|
||||
{
|
||||
if(value == effectitem.val && !DisabledEffects[effectitem.type])
|
||||
{
|
||||
isOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto check_effect = [value](const EffectList &item) -> bool
|
||||
{ return value == item.val && !DisabledEffects.test(item.type); };
|
||||
if(!std::any_of(gEffectList.cbegin(), gEffectList.cend(), check_effect))
|
||||
throw al::context_error{AL_INVALID_VALUE, "Effect type 0x%04x not supported",
|
||||
value};
|
||||
}
|
||||
|
||||
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]);
|
||||
InitEffectParams(aleffect, value);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,value](auto &arg)
|
||||
{
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.SetParami(std::get<PropType>(aleffect->Props), param, value);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC3(void, alEffectiv, ALuint,effect, ALenum,param, const ALint*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
const ALint *values) noexcept
|
||||
try {
|
||||
switch(param)
|
||||
{
|
||||
case AL_EFFECT_TYPE:
|
||||
alEffectiDirect(context, effect, param, *values);
|
||||
return;
|
||||
}
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,values](auto &arg)
|
||||
{
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.SetParamiv(std::get<PropType>(aleffect->Props), param, values);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC3(void, alEffectf, ALuint,effect, ALenum,param, ALfloat,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALfloat value) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,value](auto &arg)
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParamiv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.SetParamf(std::get<PropType>(aleffect->Props), param, value);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& 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;
|
||||
|
||||
AL_API DECL_FUNC3(void, alEffectfv, ALuint,effect, ALenum,param, const ALfloat*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
const ALfloat *values) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,values](auto &arg)
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_setParamf(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.SetParamfv(std::get<PropType>(aleffect->Props), param, values);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
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());
|
||||
}
|
||||
catch(al::context_error& 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;
|
||||
|
||||
AL_API DECL_FUNC3(void, alGetEffecti, ALuint,effect, ALenum,param, ALint*,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALint *value) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{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)
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case 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;
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,value](auto &arg)
|
||||
{
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.GetParami(std::get<PropType>(aleffect->Props), param, value);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC3(void, alGetEffectiv, ALuint,effect, ALenum,param, ALint*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALint *values) noexcept
|
||||
try {
|
||||
switch(param)
|
||||
{
|
||||
case AL_EFFECT_TYPE:
|
||||
alGetEffectiDirect(context, effect, param, values);
|
||||
return;
|
||||
}
|
||||
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,values](auto &arg)
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamiv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.GetParamiv(std::get<PropType>(aleffect->Props), param, values);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& 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;
|
||||
|
||||
AL_API DECL_FUNC3(void, alGetEffectf, ALuint,effect, ALenum,param, ALfloat*,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALfloat *value) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,value](auto &arg)
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamf(aleffect, param, value);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.GetParamf(std::get<PropType>(aleffect->Props), param, value);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& 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;
|
||||
|
||||
AL_API DECL_FUNC3(void, alGetEffectfv, ALuint,effect, ALenum,param, ALfloat*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param,
|
||||
ALfloat *values) noexcept
|
||||
try {
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> _{device->EffectLock};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
const ALeffect *aleffect{LookupEffect(device, effect)};
|
||||
if(!aleffect) UNLIKELY
|
||||
context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
|
||||
else try
|
||||
if(!aleffect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", effect};
|
||||
|
||||
/* Call the appropriate handler */
|
||||
std::visit([aleffect,param,values](auto &arg)
|
||||
{
|
||||
/* Call the appropriate handler */
|
||||
ALeffect_getParamfv(aleffect, param, values);
|
||||
}
|
||||
catch(effect_exception &e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
|
||||
using PropType = typename Type::prop_type;
|
||||
return arg.GetParamfv(std::get<PropType>(aleffect->Props), param, values);
|
||||
}, aleffect->PropsVariant);
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
|
||||
void InitEffect(ALeffect *effect)
|
||||
|
|
@ -546,26 +500,43 @@ void InitEffect(ALeffect *effect)
|
|||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
}
|
||||
|
||||
void ALeffect::SetName(ALCcontext* context, ALuint id, std::string_view name)
|
||||
{
|
||||
ALCdevice *device{context->mALDevice.get()};
|
||||
std::lock_guard<std::mutex> effectlock{device->EffectLock};
|
||||
|
||||
auto effect = LookupEffect(device, id);
|
||||
if(!effect)
|
||||
throw al::context_error{AL_INVALID_NAME, "Invalid effect ID %u", id};
|
||||
|
||||
device->mEffectNames.insert_or_assign(id, name);
|
||||
}
|
||||
|
||||
|
||||
EffectSubList::~EffectSubList()
|
||||
{
|
||||
if(!Effects)
|
||||
return;
|
||||
|
||||
uint64_t usemask{~FreeMask};
|
||||
while(usemask)
|
||||
{
|
||||
const int idx{al::countr_zero(usemask)};
|
||||
al::destroy_at(Effects+idx);
|
||||
std::destroy_at(al::to_address(Effects->begin()+idx));
|
||||
usemask &= ~(1_u64 << idx);
|
||||
}
|
||||
FreeMask = ~usemask;
|
||||
al_free(Effects);
|
||||
SubListAllocator{}.deallocate(Effects, 1);
|
||||
Effects = nullptr;
|
||||
}
|
||||
|
||||
|
||||
#define DECL(x) { #x, EFX_REVERB_PRESET_##x }
|
||||
static const struct {
|
||||
const char name[32];
|
||||
struct EffectPreset {
|
||||
const char name[32]; /* NOLINT(*-avoid-c-arrays) */
|
||||
EFXEAXREVERBPROPERTIES props;
|
||||
} reverblist[] = {
|
||||
};
|
||||
#define DECL(x) EffectPreset{#x, EFX_REVERB_PRESET_##x}
|
||||
static constexpr std::array reverblist{
|
||||
DECL(GENERIC),
|
||||
DECL(PADDEDCELL),
|
||||
DECL(ROOM),
|
||||
|
|
@ -695,61 +666,62 @@ static const struct {
|
|||
};
|
||||
#undef DECL
|
||||
|
||||
void LoadReverbPreset(const char *name, ALeffect *effect)
|
||||
void LoadReverbPreset(const std::string_view name, ALeffect *effect)
|
||||
{
|
||||
if(al::strcasecmp(name, "NONE") == 0)
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
if(al::case_compare(name, "NONE"sv) == 0)
|
||||
{
|
||||
InitEffectParams(effect, AL_EFFECT_NULL);
|
||||
TRACE("Loading reverb '%s'\n", "NONE");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!DisabledEffects[EAXREVERB_EFFECT])
|
||||
if(!DisabledEffects.test(EAXREVERB_EFFECT))
|
||||
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
|
||||
else if(!DisabledEffects[REVERB_EFFECT])
|
||||
else if(!DisabledEffects.test(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)
|
||||
if(al::case_compare(name, std::data(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;
|
||||
TRACE("Loading reverb '%s'\n", std::data(reverbitem.name));
|
||||
const auto &props = reverbitem.props;
|
||||
auto &dst = std::get<ReverbProps>(effect->Props);
|
||||
dst.Density = props.flDensity;
|
||||
dst.Diffusion = props.flDiffusion;
|
||||
dst.Gain = props.flGain;
|
||||
dst.GainHF = props.flGainHF;
|
||||
dst.GainLF = props.flGainLF;
|
||||
dst.DecayTime = props.flDecayTime;
|
||||
dst.DecayHFRatio = props.flDecayHFRatio;
|
||||
dst.DecayLFRatio = props.flDecayLFRatio;
|
||||
dst.ReflectionsGain = props.flReflectionsGain;
|
||||
dst.ReflectionsDelay = props.flReflectionsDelay;
|
||||
dst.ReflectionsPan[0] = props.flReflectionsPan[0];
|
||||
dst.ReflectionsPan[1] = props.flReflectionsPan[1];
|
||||
dst.ReflectionsPan[2] = props.flReflectionsPan[2];
|
||||
dst.LateReverbGain = props.flLateReverbGain;
|
||||
dst.LateReverbDelay = props.flLateReverbDelay;
|
||||
dst.LateReverbPan[0] = props.flLateReverbPan[0];
|
||||
dst.LateReverbPan[1] = props.flLateReverbPan[1];
|
||||
dst.LateReverbPan[2] = props.flLateReverbPan[2];
|
||||
dst.EchoTime = props.flEchoTime;
|
||||
dst.EchoDepth = props.flEchoDepth;
|
||||
dst.ModulationTime = props.flModulationTime;
|
||||
dst.ModulationDepth = props.flModulationDepth;
|
||||
dst.AirAbsorptionGainHF = props.flAirAbsorptionGainHF;
|
||||
dst.HFReference = props.flHFReference;
|
||||
dst.LFReference = props.flLFReference;
|
||||
dst.RoomRolloffFactor = props.flRoomRolloffFactor;
|
||||
dst.DecayHFLimit = props.iDecayHFLimit ? AL_TRUE : AL_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
WARN("Reverb preset '%s' not found\n", name);
|
||||
WARN("Reverb preset '%.*s' not found\n", al::sizei(name), name.data());
|
||||
}
|
||||
|
||||
bool IsValidEffectType(ALenum type) noexcept
|
||||
|
|
@ -757,10 +729,7 @@ 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;
|
||||
auto check_effect = [type](const EffectList &item) noexcept -> bool
|
||||
{ return type == item.val && !DisabledEffects.test(item.type); };
|
||||
return std::any_of(gEffectList.cbegin(), gEffectList.cend(), check_effect);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
#ifndef AL_EFFECT_H
|
||||
#define AL_EFFECT_H
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "al/effects/effects.h"
|
||||
#include "alc/effects/base.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "effects/effects.h"
|
||||
|
||||
|
||||
enum {
|
||||
|
|
@ -27,36 +36,55 @@ enum {
|
|||
|
||||
MAX_EFFECTS
|
||||
};
|
||||
extern bool DisabledEffects[MAX_EFFECTS];
|
||||
|
||||
extern float ReverbBoost;
|
||||
inline std::bitset<MAX_EFFECTS> DisabledEffects;
|
||||
|
||||
struct EffectList {
|
||||
const char name[16];
|
||||
int type;
|
||||
const char name[16]; /* NOLINT(*-avoid-c-arrays) */
|
||||
ALuint type;
|
||||
ALenum val;
|
||||
};
|
||||
extern const EffectList gEffectList[16];
|
||||
extern const std::array<EffectList,16> gEffectList;
|
||||
|
||||
using EffectHandlerVariant = std::variant<NullEffectHandler,ReverbEffectHandler,
|
||||
StdReverbEffectHandler,AutowahEffectHandler,ChorusEffectHandler,CompressorEffectHandler,
|
||||
DistortionEffectHandler,EchoEffectHandler,EqualizerEffectHandler,FlangerEffectHandler,
|
||||
FshifterEffectHandler,ModulatorEffectHandler,PshifterEffectHandler,VmorpherEffectHandler,
|
||||
DedicatedDialogEffectHandler,DedicatedLfeEffectHandler,ConvolutionEffectHandler>;
|
||||
|
||||
struct ALeffect {
|
||||
// Effect type (AL_EFFECT_NULL, ...)
|
||||
ALenum type{AL_EFFECT_NULL};
|
||||
|
||||
EffectHandlerVariant PropsVariant;
|
||||
EffectProps Props{};
|
||||
|
||||
const EffectVtable *vtab{nullptr};
|
||||
|
||||
/* Self ID */
|
||||
ALuint id{0u};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
|
||||
|
||||
DISABLE_ALLOC
|
||||
};
|
||||
|
||||
void InitEffect(ALeffect *effect);
|
||||
|
||||
void LoadReverbPreset(const char *name, ALeffect *effect);
|
||||
void LoadReverbPreset(const std::string_view name, ALeffect *effect);
|
||||
|
||||
bool IsValidEffectType(ALenum type) noexcept;
|
||||
|
||||
struct EffectSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
gsl::owner<std::array<ALeffect,64>*> Effects{nullptr}; /* 64 */
|
||||
|
||||
EffectSubList() noexcept = default;
|
||||
EffectSubList(const EffectSubList&) = delete;
|
||||
EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; }
|
||||
~EffectSubList();
|
||||
|
||||
EffectSubList& operator=(const EffectSubList&) = delete;
|
||||
EffectSubList& operator=(EffectSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -20,100 +21,87 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Autowah_setParamf(EffectProps *props, ALenum param, float val)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
AutowahProps props{};
|
||||
props.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
|
||||
props.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
|
||||
props.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
|
||||
props.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps AutowahEffectProps{genDefaultProps()};
|
||||
|
||||
void AutowahEffectHandler::SetParami(AutowahProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
|
||||
void AutowahEffectHandler::SetParamiv(AutowahProps&, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
void AutowahEffectHandler::SetParamf(AutowahProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 AutowahEffectHandler::SetParamfv(AutowahProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Autowah_setParami(EffectProps*, ALenum param, int)
|
||||
void AutowahEffectHandler::GetParami(const AutowahProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
|
||||
void Autowah_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void AutowahEffectHandler::GetParamiv(const AutowahProps&, ALenum param, 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)
|
||||
void AutowahEffectHandler::GetParamf(const AutowahProps &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;
|
||||
case AL_AUTOWAH_ATTACK_TIME: *val = props.AttackTime; break;
|
||||
case AL_AUTOWAH_RELEASE_TIME: *val = props.ReleaseTime; break;
|
||||
case AL_AUTOWAH_RESONANCE: *val = props.Resonance; break;
|
||||
case AL_AUTOWAH_PEAK_GAIN: *val = props.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()};
|
||||
void AutowahEffectHandler::GetParamfv(const AutowahProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
|
@ -189,62 +177,62 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AutowahCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxAutowahCommitter::commit(const EAXAUTOWAHPROPERTIES &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)
|
||||
if(auto *cur = std::get_if<EAXAUTOWAHPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
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));
|
||||
mAlProps = [&]{
|
||||
AutowahProps ret{};
|
||||
ret.AttackTime = props.flAttackTime;
|
||||
ret.ReleaseTime = props.flReleaseTime;
|
||||
ret.Resonance = level_mb_to_gain(static_cast<float>(props.lResonance));
|
||||
ret.PeakGain = level_mb_to_gain(static_cast<float>(props.lPeakLevel));
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxAutowahCommitter::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;
|
||||
static constexpr EAXAUTOWAHPROPERTIES defprops{[]
|
||||
{
|
||||
EAXAUTOWAHPROPERTIES ret{};
|
||||
ret.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
|
||||
ret.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
|
||||
ret.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
|
||||
ret.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxAutowahCommitter::Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &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;
|
||||
case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.flAttackTime); break;
|
||||
case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.flReleaseTime); break;
|
||||
case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.lResonance); break;
|
||||
case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(props.lPeakLevel); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxAutowahCommitter::Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &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;
|
||||
case EAXAUTOWAH_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.flAttackTime); break;
|
||||
case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.flReleaseTime); break;
|
||||
case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.lResonance); break;
|
||||
case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(call, props.lPeakLevel); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <optional>
|
||||
#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/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -27,16 +25,16 @@ static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too sm
|
|||
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)
|
||||
constexpr std::optional<ChorusWaveform> WaveformFromEnum(ALenum type) noexcept
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid;
|
||||
case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle;
|
||||
}
|
||||
return al::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
inline ALenum EnumFromWaveform(ChorusWaveform type)
|
||||
constexpr ALenum EnumFromWaveform(ChorusWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
@ -46,13 +44,41 @@ inline ALenum EnumFromWaveform(ChorusWaveform type)
|
|||
throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Chorus_setParami(EffectProps *props, ALenum param, int val)
|
||||
constexpr EffectProps genDefaultChorusProps() noexcept
|
||||
{
|
||||
ChorusProps props{};
|
||||
props.Waveform = WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM).value();
|
||||
props.Phase = AL_CHORUS_DEFAULT_PHASE;
|
||||
props.Rate = AL_CHORUS_DEFAULT_RATE;
|
||||
props.Depth = AL_CHORUS_DEFAULT_DEPTH;
|
||||
props.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
|
||||
props.Delay = AL_CHORUS_DEFAULT_DELAY;
|
||||
return props;
|
||||
}
|
||||
|
||||
constexpr EffectProps genDefaultFlangerProps() noexcept
|
||||
{
|
||||
ChorusProps props{};
|
||||
props.Waveform = WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM).value();
|
||||
props.Phase = AL_FLANGER_DEFAULT_PHASE;
|
||||
props.Rate = AL_FLANGER_DEFAULT_RATE;
|
||||
props.Depth = AL_FLANGER_DEFAULT_DEPTH;
|
||||
props.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
|
||||
props.Delay = AL_FLANGER_DEFAULT_DELAY;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps ChorusEffectProps{genDefaultChorusProps()};
|
||||
|
||||
void ChorusEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_CHORUS_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEnum(val))
|
||||
props->Chorus.Waveform = *formopt;
|
||||
props.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -60,115 +86,89 @@ void Chorus_setParami(EffectProps *props, ALenum param, int val)
|
|||
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;
|
||||
props.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)
|
||||
void ChorusEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
void ChorusEffectHandler::SetParamf(ChorusProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 ChorusEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
void ChorusEffectHandler::GetParami(const ChorusProps &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;
|
||||
case AL_CHORUS_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
|
||||
case AL_CHORUS_PHASE: *val = props.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)
|
||||
void ChorusEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
void ChorusEffectHandler::GetParamf(const ChorusProps &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;
|
||||
case AL_CHORUS_RATE: *val = props.Rate; break;
|
||||
case AL_CHORUS_DEPTH: *val = props.Depth; break;
|
||||
case AL_CHORUS_FEEDBACK: *val = props.Feedback; break;
|
||||
case AL_CHORUS_DELAY: *val = props.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 ChorusEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
|
||||
void Flanger_setParami(EffectProps *props, ALenum param, int val)
|
||||
const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
|
||||
|
||||
void FlangerEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FLANGER_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEnum(val))
|
||||
props->Chorus.Waveform = *formopt;
|
||||
props.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -176,127 +176,87 @@ void Flanger_setParami(EffectProps *props, ALenum param, int val)
|
|||
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;
|
||||
props.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)
|
||||
void FlangerEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
void FlangerEffectHandler::SetParamf(ChorusProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 FlangerEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
void FlangerEffectHandler::GetParami(const ChorusProps &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;
|
||||
case AL_FLANGER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
|
||||
case AL_FLANGER_PHASE: *val = props.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)
|
||||
void FlangerEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
void FlangerEffectHandler::GetParamf(const ChorusProps &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;
|
||||
case AL_FLANGER_RATE: *val = props.Rate; break;
|
||||
case AL_FLANGER_DEPTH: *val = props.Depth; break;
|
||||
case AL_FLANGER_FEEDBACK: *val = props.Feedback; break;
|
||||
case AL_FLANGER_DELAY: *val = props.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()};
|
||||
void FlangerEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
||||
struct EaxChorusTraits {
|
||||
using Props = EAXCHORUSPROPERTIES;
|
||||
using EaxProps = 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; }
|
||||
|
|
@ -359,11 +319,9 @@ struct EaxChorusTraits {
|
|||
}; // EaxChorusTraits
|
||||
|
||||
struct EaxFlangerTraits {
|
||||
using Props = EAXFLANGERPROPERTIES;
|
||||
using EaxProps = 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; }
|
||||
|
|
@ -428,11 +386,10 @@ struct EaxFlangerTraits {
|
|||
template<typename TTraits>
|
||||
struct ChorusFlangerEffect {
|
||||
using Traits = TTraits;
|
||||
using EaxProps = typename Traits::EaxProps;
|
||||
using Committer = typename Traits::Committer;
|
||||
using Exception = typename Committer::Exception;
|
||||
|
||||
static constexpr auto Field = Traits::Field;
|
||||
|
||||
struct WaveformValidator {
|
||||
void operator()(unsigned long ulWaveform) const
|
||||
{
|
||||
|
|
@ -500,7 +457,7 @@ struct ChorusFlangerEffect {
|
|||
}; // DelayValidator
|
||||
|
||||
struct AllValidator {
|
||||
void operator()(const typename Traits::Props& all) const
|
||||
void operator()(const EaxProps& all) const
|
||||
{
|
||||
WaveformValidator{}(all.ulWaveform);
|
||||
PhaseValidator{}(all.lPhase);
|
||||
|
|
@ -514,8 +471,7 @@ struct ChorusFlangerEffect {
|
|||
public:
|
||||
static void SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
auto&& all = props.*Field;
|
||||
props.mType = Traits::eax_effect_type();
|
||||
auto&& all = props.emplace<EaxProps>();
|
||||
all.ulWaveform = Traits::eax_default_waveform();
|
||||
all.lPhase = Traits::eax_default_phase();
|
||||
all.flRate = Traits::eax_default_rate();
|
||||
|
|
@ -525,109 +481,83 @@ public:
|
|||
}
|
||||
|
||||
|
||||
static void Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
static void Get(const EaxCall &call, const EaxProps &all)
|
||||
{
|
||||
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)
|
||||
static void Set(const EaxCall &call, EaxProps &all)
|
||||
{
|
||||
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_)
|
||||
static bool Commit(const EaxProps &props, EaxEffectProps &props_, ChorusProps &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;
|
||||
}
|
||||
if(auto *cur = std::get_if<EaxProps>(&props_); cur && *cur == props)
|
||||
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;
|
||||
al_props_.Waveform = Traits::eax_waveform(props.ulWaveform);
|
||||
al_props_.Phase = static_cast<int>(props.lPhase);
|
||||
al_props_.Rate = props.flRate;
|
||||
al_props_.Depth = props.flDepth;
|
||||
al_props_.Feedback = props.flFeedback;
|
||||
al_props_.Delay = props.flDelay;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -652,29 +582,25 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool ChorusCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxChorusCommitter::commit(const EAXCHORUSPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
return Committer::Commit(props, mEaxProps, mAlProps);
|
||||
return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxChorusCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::SetDefaults(props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxChorusCommitter::Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::Get(call, props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChorusCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxChorusCommitter::Set(const EaxCall &call, EAXCHORUSPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
|
||||
Committer::Set(call, props);
|
||||
|
|
@ -693,29 +619,25 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FlangerCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxFlangerCommitter::commit(const EAXFLANGERPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
return Committer::Commit(props, mEaxProps, mAlProps);
|
||||
return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxFlangerCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::SetDefaults(props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxFlangerCommitter::Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::Get(call, props);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FlangerCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxFlangerCommitter::Set(const EaxCall &call, EAXFLANGERPROPERTIES &props)
|
||||
{
|
||||
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
|
||||
Committer::Set(call, props);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -16,14 +17,25 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Compressor_setParami(EffectProps *props, ALenum param, int val)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
CompressorProps props{};
|
||||
props.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps CompressorEffectProps{genDefaultProps()};
|
||||
|
||||
void CompressorEffectHandler::SetParami(CompressorProps &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);
|
||||
props.OnOff = (val != AL_FALSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -31,51 +43,36 @@ void Compressor_setParami(EffectProps *props, ALenum param, int val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Compressor_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Compressor_setParami(props, param, vals[0]); }
|
||||
void Compressor_setParamf(EffectProps*, ALenum param, float)
|
||||
void CompressorEffectHandler::SetParamiv(CompressorProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
void CompressorEffectHandler::SetParamf(CompressorProps&, ALenum param, float)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
|
||||
void Compressor_setParamfv(EffectProps*, ALenum param, const float*)
|
||||
void CompressorEffectHandler::SetParamfv(CompressorProps&, 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)
|
||||
void CompressorEffectHandler::GetParami(const CompressorProps &props, ALenum param, int *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_COMPRESSOR_ONOFF:
|
||||
*val = props->Compressor.OnOff;
|
||||
break;
|
||||
|
||||
case AL_COMPRESSOR_ONOFF: *val = props.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*)
|
||||
void CompressorEffectHandler::GetParamiv(const CompressorProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
void CompressorEffectHandler::GetParamf(const CompressorProps&, ALenum param, float*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
|
||||
void Compressor_getParamfv(const EffectProps*, ALenum param, float*)
|
||||
void CompressorEffectHandler::GetParamfv(const CompressorProps&, 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 {
|
||||
|
|
@ -115,46 +112,40 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool CompressorCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxCompressorCommitter::commit(const EAXAGCCOMPRESSORPROPERTIES &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& props.mCompressor.ulOnOff == mEaxProps.mCompressor.ulOnOff)
|
||||
if(auto *cur = std::get_if<EAXAGCCOMPRESSORPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
mAlProps = CompressorProps{props.ulOnOff != 0};
|
||||
|
||||
mAlProps.Compressor.OnOff = (props.mCompressor.ulOnOff != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxCompressorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Compressor;
|
||||
props.mCompressor.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF;
|
||||
props = EAXAGCCOMPRESSORPROPERTIES{EAXAGCCOMPRESSOR_DEFAULTONOFF};
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxCompressorCommitter::Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &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;
|
||||
case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXAGCCOMPRESSOR_ONOFF: call.set_value<Exception>(props.ulOnOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxCompressorCommitter::Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &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;
|
||||
case EAXAGCCOMPRESSOR_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXAGCCOMPRESSOR_ONOFF: defer<OnOffValidator>(call, props.ulOnOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +1,117 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "alc/inprogext.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "effects.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void Convolution_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
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{};
|
||||
ConvolutionProps props{};
|
||||
props.OrientAt = {0.0f, 0.0f, -1.0f};
|
||||
props.OrientUp = {0.0f, 1.0f, 0.0f};
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Convolution);
|
||||
|
||||
const EffectProps ConvolutionEffectProps{genDefaultProps()};
|
||||
|
||||
void ConvolutionEffectHandler::SetParami(ConvolutionProps& /*props*/, ALenum param, int /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::SetParamiv(ConvolutionProps &props, ALenum param, const int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SetParami(props, param, *vals);
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::SetParamf(ConvolutionProps& /*props*/, ALenum param, float /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::SetParamfv(ConvolutionProps &props, ALenum param, const float *values)
|
||||
{
|
||||
static constexpr auto finite_checker = [](float val) -> bool { return std::isfinite(val); };
|
||||
al::span<const float> vals;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CONVOLUTION_ORIENTATION_SOFT:
|
||||
vals = {values, 6_uz};
|
||||
if(!std::all_of(vals.cbegin(), vals.cend(), finite_checker))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Property 0x%04x value out of range", param};
|
||||
|
||||
std::copy_n(vals.cbegin(), props.OrientAt.size(), props.OrientAt.begin());
|
||||
std::copy_n(vals.cbegin()+3, props.OrientUp.size(), props.OrientUp.begin());
|
||||
break;
|
||||
|
||||
default:
|
||||
SetParamf(props, param, *values);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvolutionEffectHandler::GetParami(const ConvolutionProps& /*props*/, ALenum param, int* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::GetParamiv(const ConvolutionProps &props, ALenum param, int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
GetParami(props, param, vals);
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::GetParamf(const ConvolutionProps& /*props*/, ALenum param, float* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void ConvolutionEffectHandler::GetParamfv(const ConvolutionProps &props, ALenum param, float *values)
|
||||
{
|
||||
al::span<float> vals;
|
||||
switch(param)
|
||||
{
|
||||
case AL_CONVOLUTION_ORIENTATION_SOFT:
|
||||
vals = {values, 6_uz};
|
||||
std::copy(props.OrientAt.cbegin(), props.OrientAt.cend(), vals.begin());
|
||||
std::copy(props.OrientUp.cbegin(), props.OrientUp.cend(), vals.begin()+3);
|
||||
break;
|
||||
|
||||
default:
|
||||
GetParamf(props, param, values);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,61 +12,111 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Dedicated_setParami(EffectProps*, ALenum param, int)
|
||||
constexpr EffectProps genDefaultDialogProps() noexcept
|
||||
{
|
||||
DedicatedProps props{};
|
||||
props.Target = DedicatedProps::Dialog;
|
||||
props.Gain = 1.0f;
|
||||
return props;
|
||||
}
|
||||
|
||||
constexpr EffectProps genDefaultLfeProps() noexcept
|
||||
{
|
||||
DedicatedProps props{};
|
||||
props.Target = DedicatedProps::Lfe;
|
||||
props.Gain = 1.0f;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps DedicatedDialogEffectProps{genDefaultDialogProps()};
|
||||
|
||||
void DedicatedDialogEffectHandler::SetParami(DedicatedProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void Dedicated_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void DedicatedDialogEffectHandler::SetParamiv(DedicatedProps&, 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)
|
||||
void DedicatedDialogEffectHandler::SetParamf(DedicatedProps &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;
|
||||
props.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 DedicatedDialogEffectHandler::SetParamfv(DedicatedProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Dedicated_getParami(const EffectProps*, ALenum param, int*)
|
||||
void DedicatedDialogEffectHandler::GetParami(const DedicatedProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void Dedicated_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
void DedicatedDialogEffectHandler::GetParamiv(const DedicatedProps&, 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)
|
||||
void DedicatedDialogEffectHandler::GetParamf(const DedicatedProps &props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN: *val = props.Gain; break;
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void DedicatedDialogEffectHandler::GetParamfv(const DedicatedProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
|
||||
const EffectProps DedicatedLfeEffectProps{genDefaultLfeProps()};
|
||||
|
||||
void DedicatedLfeEffectHandler::SetParami(DedicatedProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void DedicatedLfeEffectHandler::SetParamiv(DedicatedProps&, ALenum param, const int*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
void DedicatedLfeEffectHandler::SetParamf(DedicatedProps &props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN:
|
||||
*val = props->Dedicated.Gain;
|
||||
if(!(val >= 0.0f && std::isfinite(val)))
|
||||
throw effect_exception{AL_INVALID_VALUE, "Dedicated gain out of range"};
|
||||
props.Gain = val;
|
||||
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); }
|
||||
void DedicatedLfeEffectHandler::SetParamfv(DedicatedProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
void DedicatedLfeEffectHandler::GetParami(const DedicatedProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
|
||||
void DedicatedLfeEffectHandler::GetParamiv(const DedicatedProps&, ALenum param, int*)
|
||||
{
|
||||
EffectProps props{};
|
||||
props.Dedicated.Gain = 1.0f;
|
||||
return props;
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Dedicated);
|
||||
|
||||
const EffectProps DedicatedEffectProps{genDefaultProps()};
|
||||
void DedicatedLfeEffectHandler::GetParamf(const DedicatedProps &props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_DEDICATED_GAIN: *val = props.Gain; break;
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void DedicatedLfeEffectHandler::GetParamfv(const DedicatedProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -16,108 +17,93 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Distortion_setParami(EffectProps*, ALenum param, int)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
DistortionProps props{};
|
||||
props.Edge = AL_DISTORTION_DEFAULT_EDGE;
|
||||
props.Gain = AL_DISTORTION_DEFAULT_GAIN;
|
||||
props.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
|
||||
props.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
|
||||
props.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps DistortionEffectProps{genDefaultProps()};
|
||||
|
||||
void DistortionEffectHandler::SetParami(DistortionProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
|
||||
void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void DistortionEffectHandler::SetParamiv(DistortionProps&, 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)
|
||||
void DistortionEffectHandler::SetParamf(DistortionProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 DistortionEffectHandler::SetParamfv(DistortionProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Distortion_getParami(const EffectProps*, ALenum param, int*)
|
||||
void DistortionEffectHandler::GetParami(const DistortionProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
|
||||
void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
void DistortionEffectHandler::GetParamiv(const DistortionProps&, 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)
|
||||
void DistortionEffectHandler::GetParamf(const DistortionProps &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;
|
||||
case AL_DISTORTION_EDGE: *val = props.Edge; break;
|
||||
case AL_DISTORTION_GAIN: *val = props.Gain; break;
|
||||
case AL_DISTORTION_LOWPASS_CUTOFF: *val = props.LowpassCutoff; break;
|
||||
case AL_DISTORTION_EQCENTER: *val = props.EQCenter; break;
|
||||
case AL_DISTORTION_EQBANDWIDTH: *val = props.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); }
|
||||
void DistortionEffectHandler::GetParamfv(const DistortionProps &props, ALenum param, float *vals)
|
||||
{ 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 {
|
||||
|
|
@ -204,66 +190,66 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool DistortionCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxDistortionCommitter::commit(const EAXDISTORTIONPROPERTIES &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)
|
||||
if(auto *cur = std::get_if<EAXDISTORTIONPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
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;
|
||||
mAlProps = [&]{
|
||||
DistortionProps ret{};
|
||||
ret.Edge = props.flEdge;
|
||||
ret.Gain = level_mb_to_gain(static_cast<float>(props.lGain));
|
||||
ret.LowpassCutoff = props.flLowPassCutOff;
|
||||
ret.EQCenter = props.flEQCenter;
|
||||
ret.EQBandwidth = props.flEdge;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxDistortionCommitter::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;
|
||||
static constexpr EAXDISTORTIONPROPERTIES defprops{[]
|
||||
{
|
||||
EAXDISTORTIONPROPERTIES ret{};
|
||||
ret.flEdge = EAXDISTORTION_DEFAULTEDGE;
|
||||
ret.lGain = EAXDISTORTION_DEFAULTGAIN;
|
||||
ret.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
|
||||
ret.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
|
||||
ret.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxDistortionCommitter::Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &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;
|
||||
case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXDISTORTION_EDGE: call.set_value<Exception>(props.flEdge); break;
|
||||
case EAXDISTORTION_GAIN: call.set_value<Exception>(props.lGain); break;
|
||||
case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.flLowPassCutOff); break;
|
||||
case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.flEQCenter); break;
|
||||
case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.flEQBandwidth); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxDistortionCommitter::Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &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;
|
||||
case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.flEdge); break;
|
||||
case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.lGain); break;
|
||||
case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.flLowPassCutOff); break;
|
||||
case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.flEQCenter); break;
|
||||
case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.flEQBandwidth); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -19,102 +20,87 @@ 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)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EchoProps props{};
|
||||
props.Delay = AL_ECHO_DEFAULT_DELAY;
|
||||
props.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
|
||||
props.Damping = AL_ECHO_DEFAULT_DAMPING;
|
||||
props.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
|
||||
props.Spread = AL_ECHO_DEFAULT_SPREAD;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps EchoEffectProps{genDefaultProps()};
|
||||
|
||||
void EchoEffectHandler::SetParami(EchoProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
|
||||
void Echo_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void EchoEffectHandler::SetParamiv(EchoProps&, 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)
|
||||
void EchoEffectHandler::SetParamf(EchoProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 EchoEffectHandler::SetParamfv(EchoProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Echo_getParami(const EffectProps*, ALenum param, int*)
|
||||
void EchoEffectHandler::GetParami(const EchoProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
|
||||
void Echo_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
void EchoEffectHandler::GetParamiv(const EchoProps&, 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)
|
||||
void EchoEffectHandler::GetParamf(const EchoProps &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;
|
||||
case AL_ECHO_DELAY: *val = props.Delay; break;
|
||||
case AL_ECHO_LRDELAY: *val = props.LRDelay; break;
|
||||
case AL_ECHO_DAMPING: *val = props.Damping; break;
|
||||
case AL_ECHO_FEEDBACK: *val = props.Feedback; break;
|
||||
case AL_ECHO_SPREAD: *val = props.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); }
|
||||
void EchoEffectHandler::GetParamfv(const EchoProps &props, ALenum param, float *vals)
|
||||
{ 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 {
|
||||
|
|
@ -201,66 +187,66 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool EchoCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxEchoCommitter::commit(const EAXECHOPROPERTIES &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)
|
||||
if(auto *cur = std::get_if<EAXECHOPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
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;
|
||||
mAlProps = [&]{
|
||||
EchoProps ret{};
|
||||
ret.Delay = props.flDelay;
|
||||
ret.LRDelay = props.flLRDelay;
|
||||
ret.Damping = props.flDamping;
|
||||
ret.Feedback = props.flFeedback;
|
||||
ret.Spread = props.flSpread;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxEchoCommitter::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;
|
||||
static constexpr EAXECHOPROPERTIES defprops{[]
|
||||
{
|
||||
EAXECHOPROPERTIES ret{};
|
||||
ret.flDelay = EAXECHO_DEFAULTDELAY;
|
||||
ret.flLRDelay = EAXECHO_DEFAULTLRDELAY;
|
||||
ret.flDamping = EAXECHO_DEFAULTDAMPING;
|
||||
ret.flFeedback = EAXECHO_DEFAULTFEEDBACK;
|
||||
ret.flSpread = EAXECHO_DEFAULTSPREAD;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxEchoCommitter::Get(const EaxCall &call, const EAXECHOPROPERTIES &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;
|
||||
case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break;
|
||||
case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break;
|
||||
case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break;
|
||||
case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break;
|
||||
case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxEchoCommitter::Set(const EaxCall &call, EAXECHOPROPERTIES &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;
|
||||
case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break;
|
||||
case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break;
|
||||
case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break;
|
||||
case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break;
|
||||
case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.flSpread); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
#include "config.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
|
||||
#include <cassert>
|
||||
#include "AL/efx.h"
|
||||
#include "effects.h"
|
||||
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
|
|||
|
|
@ -1,52 +1,47 @@
|
|||
#ifndef AL_EFFECTS_EFFECTS_H
|
||||
#define AL_EFFECTS_EFFECTS_H
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "core/except.h"
|
||||
#include "al/error.h"
|
||||
#include "core/effects/base.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; }
|
||||
#define DECL_HANDLER(N, T) \
|
||||
struct N { \
|
||||
using prop_type = T; \
|
||||
\
|
||||
static void SetParami(prop_type &props, ALenum param, int val); \
|
||||
static void SetParamiv(prop_type &props, ALenum param, const int *vals); \
|
||||
static void SetParamf(prop_type &props, ALenum param, float val); \
|
||||
static void SetParamfv(prop_type &props, ALenum param, const float *vals);\
|
||||
static void GetParami(const prop_type &props, ALenum param, int *val); \
|
||||
static void GetParamiv(const prop_type &props, ALenum param, int *vals); \
|
||||
static void GetParamf(const prop_type &props, ALenum param, float *val); \
|
||||
static void GetParamfv(const prop_type &props, ALenum param, float *vals);\
|
||||
};
|
||||
DECL_HANDLER(NullEffectHandler, std::monostate)
|
||||
DECL_HANDLER(ReverbEffectHandler, ReverbProps)
|
||||
DECL_HANDLER(StdReverbEffectHandler, ReverbProps)
|
||||
DECL_HANDLER(AutowahEffectHandler, AutowahProps)
|
||||
DECL_HANDLER(ChorusEffectHandler, ChorusProps)
|
||||
DECL_HANDLER(CompressorEffectHandler, CompressorProps)
|
||||
DECL_HANDLER(DistortionEffectHandler, DistortionProps)
|
||||
DECL_HANDLER(EchoEffectHandler, EchoProps)
|
||||
DECL_HANDLER(EqualizerEffectHandler, EqualizerProps)
|
||||
DECL_HANDLER(FlangerEffectHandler, ChorusProps)
|
||||
DECL_HANDLER(FshifterEffectHandler, FshifterProps)
|
||||
DECL_HANDLER(ModulatorEffectHandler, ModulatorProps)
|
||||
DECL_HANDLER(PshifterEffectHandler, PshifterProps)
|
||||
DECL_HANDLER(VmorpherEffectHandler, VmorpherProps)
|
||||
DECL_HANDLER(DedicatedDialogEffectHandler, DedicatedProps)
|
||||
DECL_HANDLER(DedicatedLfeEffectHandler, DedicatedProps)
|
||||
DECL_HANDLER(ConvolutionEffectHandler, ConvolutionProps)
|
||||
#undef DECL_HANDLER
|
||||
|
||||
|
||||
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, \
|
||||
}
|
||||
using effect_exception = al::context_error;
|
||||
|
||||
|
||||
/* Default properties for the given effect types. */
|
||||
|
|
@ -64,25 +59,8 @@ extern const EffectProps FshifterEffectProps;
|
|||
extern const EffectProps ModulatorEffectProps;
|
||||
extern const EffectProps PshifterEffectProps;
|
||||
extern const EffectProps VmorpherEffectProps;
|
||||
extern const EffectProps DedicatedEffectProps;
|
||||
extern const EffectProps DedicatedDialogEffectProps;
|
||||
extern const EffectProps DedicatedLfeEffectProps;
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -16,163 +17,133 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void Equalizer_setParami(EffectProps*, ALenum param, int)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
EqualizerProps props{};
|
||||
props.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
|
||||
props.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
|
||||
props.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
|
||||
props.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
|
||||
props.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
|
||||
props.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
|
||||
props.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
|
||||
props.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
|
||||
props.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
|
||||
props.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps EqualizerEffectProps{genDefaultProps()};
|
||||
|
||||
void EqualizerEffectHandler::SetParami(EqualizerProps&, ALenum param, int)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
|
||||
void Equalizer_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void EqualizerEffectHandler::SetParamiv(EqualizerProps&, 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)
|
||||
void EqualizerEffectHandler::SetParamf(EqualizerProps &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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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;
|
||||
props.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 EqualizerEffectHandler::SetParamfv(EqualizerProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Equalizer_getParami(const EffectProps*, ALenum param, int*)
|
||||
void EqualizerEffectHandler::GetParami(const EqualizerProps&, ALenum param, int*)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
|
||||
void Equalizer_getParamiv(const EffectProps*, ALenum param, int*)
|
||||
void EqualizerEffectHandler::GetParamiv(const EqualizerProps&, 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)
|
||||
void EqualizerEffectHandler::GetParamf(const EqualizerProps &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;
|
||||
case AL_EQUALIZER_LOW_GAIN: *val = props.LowGain; break;
|
||||
case AL_EQUALIZER_LOW_CUTOFF: *val = props.LowCutoff; break;
|
||||
case AL_EQUALIZER_MID1_GAIN: *val = props.Mid1Gain; break;
|
||||
case AL_EQUALIZER_MID1_CENTER: *val = props.Mid1Center; break;
|
||||
case AL_EQUALIZER_MID1_WIDTH: *val = props.Mid1Width; break;
|
||||
case AL_EQUALIZER_MID2_GAIN: *val = props.Mid2Gain; break;
|
||||
case AL_EQUALIZER_MID2_CENTER: *val = props.Mid2Center; break;
|
||||
case AL_EQUALIZER_MID2_WIDTH: *val = props.Mid2Width; break;
|
||||
case AL_EQUALIZER_HIGH_GAIN: *val = props.HighGain; break;
|
||||
case AL_EQUALIZER_HIGH_CUTOFF: *val = props.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); }
|
||||
void EqualizerEffectHandler::GetParamfv(const EqualizerProps &props, ALenum param, float *vals)
|
||||
{ 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 {
|
||||
|
|
@ -319,91 +290,86 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool EqualizerCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxEqualizerCommitter::commit(const EAXEQUALIZERPROPERTIES &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)
|
||||
if(auto *cur = std::get_if<EAXEQUALIZERPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
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;
|
||||
mAlProps = [&]{
|
||||
EqualizerProps ret{};
|
||||
ret.LowGain = level_mb_to_gain(static_cast<float>(props.lLowGain));
|
||||
ret.LowCutoff = props.flLowCutOff;
|
||||
ret.Mid1Gain = level_mb_to_gain(static_cast<float>(props.lMid1Gain));
|
||||
ret.Mid1Center = props.flMid1Center;
|
||||
ret.Mid1Width = props.flMid1Width;
|
||||
ret.Mid2Gain = level_mb_to_gain(static_cast<float>(props.lMid2Gain));
|
||||
ret.Mid2Center = props.flMid2Center;
|
||||
ret.Mid2Width = props.flMid2Width;
|
||||
ret.HighGain = level_mb_to_gain(static_cast<float>(props.lHighGain));
|
||||
ret.HighCutoff = props.flHighCutOff;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxEqualizerCommitter::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;
|
||||
static constexpr EAXEQUALIZERPROPERTIES defprops{[]
|
||||
{
|
||||
EAXEQUALIZERPROPERTIES ret{};
|
||||
ret.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN;
|
||||
ret.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF;
|
||||
ret.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN;
|
||||
ret.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER;
|
||||
ret.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH;
|
||||
ret.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN;
|
||||
ret.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER;
|
||||
ret.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH;
|
||||
ret.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN;
|
||||
ret.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxEqualizerCommitter::Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &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;
|
||||
case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.lLowGain); break;
|
||||
case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.flLowCutOff); break;
|
||||
case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.lMid1Gain); break;
|
||||
case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.flMid1Center); break;
|
||||
case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.flMid1Width); break;
|
||||
case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.lMid2Gain); break;
|
||||
case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.flMid2Center); break;
|
||||
case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.flMid2Width); break;
|
||||
case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.lHighGain); break;
|
||||
case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.flHighCutOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxEqualizerCommitter::Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &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;
|
||||
case EAXEQUALIZER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.lLowGain); break;
|
||||
case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.flLowCutOff); break;
|
||||
case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.lMid1Gain); break;
|
||||
case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.flMid1Center); break;
|
||||
case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.flMid1Width); break;
|
||||
case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.lMid2Gain); break;
|
||||
case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.flMid2Center); break;
|
||||
case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.flMid2Width); break;
|
||||
case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.lHighGain); break;
|
||||
case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(call, props.flHighCutOff); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <optional>
|
||||
#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/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
|
||||
namespace {
|
||||
|
||||
al::optional<FShifterDirection> DirectionFromEmum(ALenum value)
|
||||
constexpr std::optional<FShifterDirection> DirectionFromEmum(ALenum value) noexcept
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
|
|
@ -28,9 +29,9 @@ al::optional<FShifterDirection> DirectionFromEmum(ALenum value)
|
|||
case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return FShifterDirection::Up;
|
||||
case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return FShifterDirection::Off;
|
||||
}
|
||||
return al::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
ALenum EnumFromDirection(FShifterDirection dir)
|
||||
constexpr ALenum EnumFromDirection(FShifterDirection dir)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
|
|
@ -41,31 +42,26 @@ ALenum EnumFromDirection(FShifterDirection dir)
|
|||
throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
|
||||
}
|
||||
|
||||
void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
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};
|
||||
}
|
||||
FshifterProps props{};
|
||||
props.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
|
||||
props.LeftDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION).value();
|
||||
props.RightDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION).value();
|
||||
return props;
|
||||
}
|
||||
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)
|
||||
} // namespace
|
||||
|
||||
const EffectProps FshifterEffectProps{genDefaultProps()};
|
||||
|
||||
void FshifterEffectHandler::SetParami(FshifterProps &props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
|
||||
if(auto diropt = DirectionFromEmum(val))
|
||||
props->Fshifter.LeftDirection = *diropt;
|
||||
props.LeftDirection = *diropt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE,
|
||||
"Unsupported frequency shifter left direction: 0x%04x", val};
|
||||
|
|
@ -73,7 +69,7 @@ void Fshifter_setParami(EffectProps *props, ALenum param, int val)
|
|||
|
||||
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
|
||||
if(auto diropt = DirectionFromEmum(val))
|
||||
props->Fshifter.RightDirection = *diropt;
|
||||
props.RightDirection = *diropt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE,
|
||||
"Unsupported frequency shifter right direction: 0x%04x", val};
|
||||
|
|
@ -84,33 +80,17 @@ void Fshifter_setParami(EffectProps *props, ALenum param, int val)
|
|||
"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 FshifterEffectHandler::SetParamiv(FshifterProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
|
||||
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)
|
||||
void FshifterEffectHandler::SetParamf(FshifterProps &props, ALenum param, float val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_FREQUENCY:
|
||||
*val = props->Fshifter.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.Frequency = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -118,23 +98,44 @@ void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Fshifter_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Fshifter_getParamf(props, param, vals); }
|
||||
void FshifterEffectHandler::SetParamfv(FshifterProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
void FshifterEffectHandler::GetParami(const FshifterProps &props, ALenum param, int *val)
|
||||
{
|
||||
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;
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
|
||||
*val = EnumFromDirection(props.LeftDirection);
|
||||
break;
|
||||
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
|
||||
*val = EnumFromDirection(props.RightDirection);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM,
|
||||
"Invalid frequency shifter integer property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void FshifterEffectHandler::GetParamiv(const FshifterProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
|
||||
} // namespace
|
||||
void FshifterEffectHandler::GetParamf(const FshifterProps &props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_FREQUENCY_SHIFTER_FREQUENCY:
|
||||
*val = props.Frequency;
|
||||
break;
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Fshifter);
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void FshifterEffectHandler::GetParamfv(const FshifterProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
const EffectProps FshifterEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
|
@ -197,13 +198,9 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FrequencyShifterCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxFrequencyShifterCommitter::commit(const EAXFREQUENCYSHIFTERPROPERTIES &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mFrequencyShifter.flFrequency == props.mFrequencyShifter.flFrequency
|
||||
&& mEaxProps.mFrequencyShifter.ulLeftDirection == props.mFrequencyShifter.ulLeftDirection
|
||||
&& mEaxProps.mFrequencyShifter.ulRightDirection == props.mFrequencyShifter.ulRightDirection)
|
||||
if(auto *cur = std::get_if<EAXFREQUENCYSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
|
@ -217,46 +214,52 @@ bool FrequencyShifterCommitter::commit(const EaxEffectProps &props)
|
|||
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);
|
||||
mAlProps = [&]{
|
||||
FshifterProps ret{};
|
||||
ret.Frequency = props.flFrequency;
|
||||
ret.LeftDirection = get_direction(props.ulLeftDirection);
|
||||
ret.RightDirection = get_direction(props.ulRightDirection);
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxFrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::FrequencyShifter;
|
||||
props.mFrequencyShifter.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
|
||||
props.mFrequencyShifter.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
|
||||
props.mFrequencyShifter.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
|
||||
static constexpr EAXFREQUENCYSHIFTERPROPERTIES defprops{[]
|
||||
{
|
||||
EAXFREQUENCYSHIFTERPROPERTIES ret{};
|
||||
ret.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
|
||||
ret.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
|
||||
ret.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxFrequencyShifterCommitter::Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &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;
|
||||
case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
|
||||
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.ulLeftDirection); break;
|
||||
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.ulRightDirection); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxFrequencyShifterCommitter::Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &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;
|
||||
case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
|
||||
case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.ulLeftDirection); break;
|
||||
case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(call, props.ulRightDirection); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <optional>
|
||||
#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/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
|
||||
namespace {
|
||||
|
||||
al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
|
||||
constexpr std::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) noexcept
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
|
|
@ -28,9 +29,9 @@ al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
|
|||
case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth;
|
||||
case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square;
|
||||
}
|
||||
return al::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
ALenum EnumFromWaveform(ModulatorWaveform type)
|
||||
constexpr ALenum EnumFromWaveform(ModulatorWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
@ -42,40 +43,31 @@ ALenum EnumFromWaveform(ModulatorWaveform type)
|
|||
std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Modulator_setParamf(EffectProps *props, ALenum param, float val)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
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};
|
||||
}
|
||||
ModulatorProps props{};
|
||||
props.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
|
||||
props.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
|
||||
props.Waveform = WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM).value();
|
||||
return props;
|
||||
}
|
||||
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)
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps ModulatorEffectProps{genDefaultProps()};
|
||||
|
||||
void ModulatorEffectHandler::SetParami(ModulatorProps &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));
|
||||
SetParamf(props, param, static_cast<float>(val));
|
||||
break;
|
||||
|
||||
case AL_RING_MODULATOR_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEmum(val))
|
||||
props->Modulator.Waveform = *formopt;
|
||||
props.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -85,62 +77,61 @@ void Modulator_setParami(EffectProps *props, ALenum param, int val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Modulator_setParami(props, param, vals[0]); }
|
||||
void ModulatorEffectHandler::SetParamiv(ModulatorProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
|
||||
void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
void ModulatorEffectHandler::SetParamf(ModulatorProps &props, ALenum param, float 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);
|
||||
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.Frequency = val;
|
||||
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;
|
||||
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.HighPassCutoff = val;
|
||||
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); }
|
||||
void ModulatorEffectHandler::SetParamfv(ModulatorProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
EffectProps genDefaultProps() noexcept
|
||||
void ModulatorEffectHandler::GetParami(const ModulatorProps &props, ALenum param, int *val)
|
||||
{
|
||||
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;
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY: *val = static_cast<int>(props.Frequency); break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = static_cast<int>(props.HighPassCutoff); break;
|
||||
case AL_RING_MODULATOR_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
|
||||
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void ModulatorEffectHandler::GetParamiv(const ModulatorProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
void ModulatorEffectHandler::GetParamf(const ModulatorProps &props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_RING_MODULATOR_FREQUENCY: *val = props.Frequency; break;
|
||||
case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = props.HighPassCutoff; break;
|
||||
|
||||
} // namespace
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
|
||||
}
|
||||
}
|
||||
void ModulatorEffectHandler::GetParamfv(const ModulatorProps &props, ALenum param, float *vals)
|
||||
{ GetParamf(props, param, vals); }
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Modulator);
|
||||
|
||||
const EffectProps ModulatorEffectProps{genDefaultProps()};
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
|
@ -203,13 +194,9 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool ModulatorCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxModulatorCommitter::commit(const EAXRINGMODULATORPROPERTIES &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mModulator.flFrequency == props.mModulator.flFrequency
|
||||
&& mEaxProps.mModulator.flHighPassCutOff == props.mModulator.flHighPassCutOff
|
||||
&& mEaxProps.mModulator.ulWaveform == props.mModulator.ulWaveform)
|
||||
if(auto *cur = std::get_if<EAXRINGMODULATORPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
|
@ -225,46 +212,52 @@ bool ModulatorCommitter::commit(const EaxEffectProps &props)
|
|||
return ModulatorWaveform::Sinusoid;
|
||||
};
|
||||
|
||||
mAlProps.Modulator.Frequency = props.mModulator.flFrequency;
|
||||
mAlProps.Modulator.HighPassCutoff = props.mModulator.flHighPassCutOff;
|
||||
mAlProps.Modulator.Waveform = get_waveform(props.mModulator.ulWaveform);
|
||||
mAlProps = [&]{
|
||||
ModulatorProps ret{};
|
||||
ret.Frequency = props.flFrequency;
|
||||
ret.HighPassCutoff = props.flHighPassCutOff;
|
||||
ret.Waveform = get_waveform(props.ulWaveform);
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxModulatorCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::Modulator;
|
||||
props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
|
||||
props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
|
||||
props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
|
||||
static constexpr EAXRINGMODULATORPROPERTIES defprops{[]
|
||||
{
|
||||
EAXRINGMODULATORPROPERTIES ret{};
|
||||
ret.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
|
||||
ret.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
|
||||
ret.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxModulatorCommitter::Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &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;
|
||||
case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
|
||||
case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.flHighPassCutOff); break;
|
||||
case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxModulatorCommitter::Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props)
|
||||
{
|
||||
switch (call.get_property_id())
|
||||
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;
|
||||
case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
|
||||
case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.flHighPassCutOff); break;
|
||||
case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,94 +8,92 @@
|
|||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
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;
|
||||
return std::monostate{};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEFINE_ALEFFECT_VTABLE(Null);
|
||||
|
||||
const EffectProps NullEffectProps{genDefaultProps()};
|
||||
|
||||
void NullEffectHandler::SetParami(std::monostate& /*props*/, ALenum param, int /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::SetParamiv(std::monostate &props, ALenum param, const int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SetParami(props, param, *vals);
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::SetParamf(std::monostate& /*props*/, ALenum param, float /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::SetParamfv(std::monostate &props, ALenum param, const float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
SetParamf(props, param, *vals);
|
||||
}
|
||||
}
|
||||
|
||||
void NullEffectHandler::GetParami(const std::monostate& /*props*/, ALenum param, int* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::GetParamiv(const std::monostate &props, ALenum param, int *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
GetParami(props, param, vals);
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::GetParamf(const std::monostate& /*props*/, ALenum param, float* /*val*/)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
|
||||
param};
|
||||
}
|
||||
}
|
||||
void NullEffectHandler::GetParamfv(const std::monostate &props, ALenum param, float *vals)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
GetParamf(props, param, vals);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
namespace {
|
||||
|
|
@ -117,30 +115,26 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool NullCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxNullCommitter::commit(const std::monostate &props)
|
||||
{
|
||||
const bool ret{props.mType != mEaxProps.mType};
|
||||
const bool ret{std::holds_alternative<std::monostate>(mEaxProps)};
|
||||
mEaxProps = props;
|
||||
mAlProps = std::monostate{};
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxNullCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props = EaxEffectProps{};
|
||||
props.mType = EaxEffectType::None;
|
||||
props = std::monostate{};
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::Get(const EaxCall &call, const EaxEffectProps&)
|
||||
void EaxNullCommitter::Get(const EaxCall &call, const std::monostate&)
|
||||
{
|
||||
if(call.get_property_id() != 0)
|
||||
fail_unknown_property_id();
|
||||
}
|
||||
|
||||
template<>
|
||||
void NullCommitter::Set(const EaxCall &call, EaxEffectProps&)
|
||||
void EaxNullCommitter::Set(const EaxCall &call, std::monostate&)
|
||||
{
|
||||
if(call.get_property_id() != 0)
|
||||
fail_unknown_property_id();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -16,28 +17,32 @@
|
|||
|
||||
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*)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
|
||||
param};
|
||||
PshifterProps props{};
|
||||
props.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
|
||||
props.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
|
||||
return props;
|
||||
}
|
||||
|
||||
void Pshifter_setParami(EffectProps *props, ALenum param, int val)
|
||||
} // namespace
|
||||
|
||||
const EffectProps PshifterEffectProps{genDefaultProps()};
|
||||
|
||||
void PshifterEffectHandler::SetParami(PshifterProps &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;
|
||||
props.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;
|
||||
props.FineTune = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -45,49 +50,40 @@ void Pshifter_setParami(EffectProps *props, ALenum param, int val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Pshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
|
||||
{ Pshifter_setParami(props, param, vals[0]); }
|
||||
void PshifterEffectHandler::SetParamiv(PshifterProps &props, ALenum param, const int *vals)
|
||||
{ SetParami(props, param, *vals); }
|
||||
|
||||
void Pshifter_getParami(const EffectProps *props, ALenum param, int *val)
|
||||
void PshifterEffectHandler::SetParamf(PshifterProps&, ALenum param, float)
|
||||
{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
|
||||
void PshifterEffectHandler::SetParamfv(PshifterProps&, ALenum param, const float*)
|
||||
{
|
||||
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
|
||||
param};
|
||||
}
|
||||
|
||||
void PshifterEffectHandler::GetParami(const PshifterProps &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;
|
||||
case AL_PITCH_SHIFTER_COARSE_TUNE: *val = props.CoarseTune; break;
|
||||
case AL_PITCH_SHIFTER_FINE_TUNE: *val = props.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 PshifterEffectHandler::GetParamiv(const PshifterProps &props, ALenum param, int *vals)
|
||||
{ GetParami(props, param, vals); }
|
||||
|
||||
void Pshifter_getParamf(const EffectProps*, ALenum param, float*)
|
||||
void PshifterEffectHandler::GetParamf(const PshifterProps&, 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*)
|
||||
void PshifterEffectHandler::GetParamfv(const PshifterProps&, 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 {
|
||||
|
|
@ -138,52 +134,48 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool PitchShifterCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxPitchShifterCommitter::commit(const EAXPITCHSHIFTERPROPERTIES &props)
|
||||
{
|
||||
if(props.mType == mEaxProps.mType
|
||||
&& mEaxProps.mPitchShifter.lCoarseTune == props.mPitchShifter.lCoarseTune
|
||||
&& mEaxProps.mPitchShifter.lFineTune == props.mPitchShifter.lFineTune)
|
||||
if(auto *cur = std::get_if<EAXPITCHSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
||||
mAlProps.Pshifter.CoarseTune = static_cast<int>(mEaxProps.mPitchShifter.lCoarseTune);
|
||||
mAlProps.Pshifter.FineTune = static_cast<int>(mEaxProps.mPitchShifter.lFineTune);
|
||||
mAlProps = [&]{
|
||||
PshifterProps ret{};
|
||||
ret.CoarseTune = static_cast<int>(props.lCoarseTune);
|
||||
ret.FineTune = static_cast<int>(props.lFineTune);
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxPitchShifterCommitter::SetDefaults(EaxEffectProps &props)
|
||||
{
|
||||
props.mType = EaxEffectType::PitchShifter;
|
||||
props.mPitchShifter.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE;
|
||||
props.mPitchShifter.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE;
|
||||
props = EAXPITCHSHIFTERPROPERTIES{EAXPITCHSHIFTER_DEFAULTCOARSETUNE,
|
||||
EAXPITCHSHIFTER_DEFAULTFINETUNE};
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxPitchShifterCommitter::Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &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;
|
||||
case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.lCoarseTune); break;
|
||||
case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.lFineTune); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxPitchShifterCommitter::Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &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;
|
||||
case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.lCoarseTune); break;
|
||||
case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.lFineTune); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,18 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/effects/base.h"
|
||||
#include "aloptional.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include <cassert>
|
||||
#include "alnumeric.h"
|
||||
#include "al/eax/effect.h"
|
||||
#include "al/eax/exception.h"
|
||||
#include "al/eax/utils.h"
|
||||
#endif // ALSOFT_EAX
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
namespace {
|
||||
|
||||
al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
|
||||
constexpr std::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) noexcept
|
||||
{
|
||||
#define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
|
||||
return VMorpherPhenome::x
|
||||
|
|
@ -57,10 +57,10 @@ al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
|
|||
HANDLE_PHENOME(V);
|
||||
HANDLE_PHENOME(Z);
|
||||
}
|
||||
return al::nullopt;
|
||||
return std::nullopt;
|
||||
#undef HANDLE_PHENOME
|
||||
}
|
||||
ALenum EnumFromPhenome(VMorpherPhenome phenome)
|
||||
constexpr ALenum EnumFromPhenome(VMorpherPhenome phenome)
|
||||
{
|
||||
#define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
|
||||
switch(phenome)
|
||||
|
|
@ -100,7 +100,7 @@ ALenum EnumFromPhenome(VMorpherPhenome phenome)
|
|||
#undef HANDLE_PHENOME
|
||||
}
|
||||
|
||||
al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
|
||||
constexpr std::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) noexcept
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
|
|
@ -108,9 +108,9 @@ al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
|
|||
case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle;
|
||||
case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth;
|
||||
}
|
||||
return al::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
ALenum EnumFromWaveform(VMorpherWaveform type)
|
||||
constexpr ALenum EnumFromWaveform(VMorpherWaveform type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
|
@ -122,13 +122,29 @@ ALenum EnumFromWaveform(VMorpherWaveform type)
|
|||
std::to_string(static_cast<int>(type))};
|
||||
}
|
||||
|
||||
void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
|
||||
constexpr EffectProps genDefaultProps() noexcept
|
||||
{
|
||||
VmorpherProps props{};
|
||||
props.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
|
||||
props.PhonemeA = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA).value();
|
||||
props.PhonemeB = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB).value();
|
||||
props.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
|
||||
props.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
|
||||
props.Waveform = WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM).value();
|
||||
return props;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const EffectProps VmorpherEffectProps{genDefaultProps()};
|
||||
|
||||
void VmorpherEffectHandler::SetParami(VmorpherProps &props, ALenum param, int val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_PHONEMEA:
|
||||
if(auto phenomeopt = PhenomeFromEnum(val))
|
||||
props->Vmorpher.PhonemeA = *phenomeopt;
|
||||
props.PhonemeA = *phenomeopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -136,12 +152,12 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
|
|||
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;
|
||||
props.PhonemeACoarseTuning = val;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_PHONEMEB:
|
||||
if(auto phenomeopt = PhenomeFromEnum(val))
|
||||
props->Vmorpher.PhonemeB = *phenomeopt;
|
||||
props.PhonemeB = *phenomeopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -149,12 +165,12 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
|
|||
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;
|
||||
props.PhonemeBCoarseTuning = val;
|
||||
break;
|
||||
|
||||
case AL_VOCAL_MORPHER_WAVEFORM:
|
||||
if(auto formopt = WaveformFromEmum(val))
|
||||
props->Vmorpher.Waveform = *formopt;
|
||||
props.Waveform = *formopt;
|
||||
else
|
||||
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
|
||||
break;
|
||||
|
|
@ -164,19 +180,19 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
|
||||
void VmorpherEffectHandler::SetParamiv(VmorpherProps&, 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)
|
||||
void VmorpherEffectHandler::SetParamf(VmorpherProps &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;
|
||||
props.Rate = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -184,49 +200,35 @@ void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
|
||||
{ Vmorpher_setParamf(props, param, vals[0]); }
|
||||
void VmorpherEffectHandler::SetParamfv(VmorpherProps &props, ALenum param, const float *vals)
|
||||
{ SetParamf(props, param, *vals); }
|
||||
|
||||
void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
|
||||
void VmorpherEffectHandler::GetParami(const VmorpherProps &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;
|
||||
case AL_VOCAL_MORPHER_PHONEMEA: *val = EnumFromPhenome(props.PhonemeA); break;
|
||||
case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: *val = props.PhonemeACoarseTuning; break;
|
||||
case AL_VOCAL_MORPHER_PHONEMEB: *val = EnumFromPhenome(props.PhonemeB); break;
|
||||
case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: *val = props.PhonemeBCoarseTuning; break;
|
||||
case AL_VOCAL_MORPHER_WAVEFORM: *val = EnumFromWaveform(props.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*)
|
||||
void VmorpherEffectHandler::GetParamiv(const VmorpherProps&, 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)
|
||||
void VmorpherEffectHandler::GetParamf(const VmorpherProps &props, ALenum param, float *val)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_VOCAL_MORPHER_RATE:
|
||||
*val = props->Vmorpher.Rate;
|
||||
*val = props.Rate;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -234,26 +236,9 @@ void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
|
|||
param};
|
||||
}
|
||||
}
|
||||
void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
|
||||
{ Vmorpher_getParamf(props, param, vals); }
|
||||
void VmorpherEffectHandler::GetParamfv(const VmorpherProps &props, ALenum param, float *vals)
|
||||
{ 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 {
|
||||
|
|
@ -352,16 +337,9 @@ template<>
|
|||
throw Exception{message};
|
||||
}
|
||||
|
||||
template<>
|
||||
bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
|
||||
bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &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)
|
||||
if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props)
|
||||
return false;
|
||||
|
||||
mEaxProps = props;
|
||||
|
|
@ -413,107 +391,65 @@ bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
|
|||
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;
|
||||
mAlProps = [&]{
|
||||
VmorpherProps ret{};
|
||||
ret.PhonemeA = get_phoneme(props.ulPhonemeA);
|
||||
ret.PhonemeACoarseTuning = static_cast<int>(props.lPhonemeACoarseTuning);
|
||||
ret.PhonemeB = get_phoneme(props.ulPhonemeB);
|
||||
ret.PhonemeBCoarseTuning = static_cast<int>(props.lPhonemeBCoarseTuning);
|
||||
ret.Waveform = get_waveform(props.ulWaveform);
|
||||
ret.Rate = props.flRate;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
|
||||
void EaxVocalMorpherCommitter::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;
|
||||
static constexpr EAXVOCALMORPHERPROPERTIES defprops{[]
|
||||
{
|
||||
EAXVOCALMORPHERPROPERTIES ret{};
|
||||
ret.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
|
||||
ret.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
|
||||
ret.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
|
||||
ret.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
|
||||
ret.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
|
||||
ret.flRate = EAXVOCALMORPHER_DEFAULTRATE;
|
||||
return ret;
|
||||
}()};
|
||||
props = defprops;
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
|
||||
void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &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();
|
||||
case EAXVOCALMORPHER_NONE: break;
|
||||
case EAXVOCALMORPHER_ALLPARAMETERS: call.set_value<Exception>(props); break;
|
||||
case EAXVOCALMORPHER_PHONEMEA: call.set_value<Exception>(props.ulPhonemeA); break;
|
||||
case EAXVOCALMORPHER_PHONEMEACOARSETUNING: call.set_value<Exception>(props.lPhonemeACoarseTuning); break;
|
||||
case EAXVOCALMORPHER_PHONEMEB: call.set_value<Exception>(props.ulPhonemeB); break;
|
||||
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: call.set_value<Exception>(props.lPhonemeBCoarseTuning); break;
|
||||
case EAXVOCALMORPHER_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
|
||||
case EAXVOCALMORPHER_RATE: call.set_value<Exception>(props.flRate); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props)
|
||||
void EaxVocalMorpherCommitter::Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &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();
|
||||
case EAXVOCALMORPHER_NONE: break;
|
||||
case EAXVOCALMORPHER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
|
||||
case EAXVOCALMORPHER_PHONEMEA: defer<PhonemeAValidator>(call, props.ulPhonemeA); break;
|
||||
case EAXVOCALMORPHER_PHONEMEACOARSETUNING: defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break;
|
||||
case EAXVOCALMORPHER_PHONEMEB: defer<PhonemeBValidator>(call, props.ulPhonemeB); break;
|
||||
case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break;
|
||||
case EAXVOCALMORPHER_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
|
||||
case EAXVOCALMORPHER_RATE: defer<RateValidator>(call, props.flRate); break;
|
||||
default: fail_unknown_property_id();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
|
@ -29,27 +31,45 @@
|
|||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "al/debug.h"
|
||||
#include "alc/alconfig.h"
|
||||
#include "alc/context.h"
|
||||
#include "almalloc.h"
|
||||
#include "core/except.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "core/logging.h"
|
||||
#include "opthelpers.h"
|
||||
#include "vector.h"
|
||||
#include "strutils.h"
|
||||
|
||||
|
||||
bool TrapALError{false};
|
||||
namespace al {
|
||||
context_error::context_error(ALenum code, const char *msg, ...) : mErrorCode{code}
|
||||
{
|
||||
/* NOLINTBEGIN(*-array-to-pointer-decay) */
|
||||
std::va_list args;
|
||||
va_start(args, msg);
|
||||
setMessage(msg, args);
|
||||
va_end(args);
|
||||
/* NOLINTEND(*-array-to-pointer-decay) */
|
||||
}
|
||||
context_error::~context_error() = default;
|
||||
} /* namespace al */
|
||||
|
||||
void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
|
||||
{
|
||||
auto message = al::vector<char>(256);
|
||||
auto message = std::vector<char>(256);
|
||||
|
||||
va_list args, args2;
|
||||
/* NOLINTBEGIN(*-array-to-pointer-decay) */
|
||||
std::va_list args, args2;
|
||||
va_start(args, msg);
|
||||
va_copy(args2, args);
|
||||
int msglen{std::vsnprintf(message.data(), message.size(), msg, args)};
|
||||
|
|
@ -60,9 +80,15 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
|
|||
}
|
||||
va_end(args2);
|
||||
va_end(args);
|
||||
/* NOLINTEND(*-array-to-pointer-decay) */
|
||||
|
||||
if(msglen >= 0) msg = message.data();
|
||||
else msg = "<internal error constructing message>";
|
||||
if(msglen >= 0)
|
||||
msg = message.data();
|
||||
else
|
||||
{
|
||||
msg = "<internal error constructing message>";
|
||||
msglen = static_cast<int>(strlen(msg));
|
||||
}
|
||||
|
||||
WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
|
||||
decltype(std::declval<void*>()){this}, errorCode, msg);
|
||||
|
|
@ -77,30 +103,55 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
|
|||
#endif
|
||||
}
|
||||
|
||||
ALenum curerr{AL_NO_ERROR};
|
||||
mLastError.compare_exchange_strong(curerr, errorCode);
|
||||
if(mLastThreadError.get() == AL_NO_ERROR)
|
||||
mLastThreadError.set(errorCode);
|
||||
|
||||
debugMessage(DebugSource::API, DebugType::Error, 0, DebugSeverity::High,
|
||||
{msg, static_cast<uint>(msglen)});
|
||||
}
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetError(void)
|
||||
START_API_FUNC
|
||||
/* Special-case alGetError since it (potentially) raises a debug signal and
|
||||
* returns a non-default value for a null context.
|
||||
*/
|
||||
AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum
|
||||
{
|
||||
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;
|
||||
}
|
||||
if(auto context = GetContextRef()) LIKELY
|
||||
return alGetErrorDirect(context.get());
|
||||
|
||||
return context->mLastError.exchange(AL_NO_ERROR);
|
||||
auto get_value = [](const char *envname, const char *optname) -> ALenum
|
||||
{
|
||||
auto optstr = al::getenv(envname);
|
||||
if(!optstr)
|
||||
optstr = ConfigValueStr({}, "game_compat", optname);
|
||||
if(optstr)
|
||||
{
|
||||
char *end{};
|
||||
auto value = std::strtoul(optstr->c_str(), &end, 0);
|
||||
if(end && *end == '\0' && value <= std::numeric_limits<ALenum>::max())
|
||||
return static_cast<ALenum>(value);
|
||||
ERR("Invalid default error value: \"%s\"", optstr->c_str());
|
||||
}
|
||||
return AL_INVALID_OPERATION;
|
||||
};
|
||||
static const ALenum deferror{get_value("__ALSOFT_DEFAULT_ERROR", "default-error")};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept
|
||||
{
|
||||
ALenum ret{context->mLastThreadError.get()};
|
||||
if(ret != AL_NO_ERROR) UNLIKELY
|
||||
context->mLastThreadError.set(AL_NO_ERROR);
|
||||
return ret;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
|
|
|||
27
Engine/lib/openal-soft/al/error.h
Normal file
27
Engine/lib/openal-soft/al/error.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef AL_ERROR_H
|
||||
#define AL_ERROR_H
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include "core/except.h"
|
||||
|
||||
namespace al {
|
||||
|
||||
class context_error final : public al::base_exception {
|
||||
ALenum mErrorCode{};
|
||||
|
||||
public:
|
||||
#ifdef __MINGW32__
|
||||
[[gnu::format(__MINGW_PRINTF_FORMAT, 3, 4)]]
|
||||
#else
|
||||
[[gnu::format(printf, 3, 4)]]
|
||||
#endif
|
||||
context_error(ALenum code, const char *msg, ...);
|
||||
~context_error() final;
|
||||
|
||||
[[nodiscard]] auto errorCode() const noexcept -> ALenum { return mErrorCode; }
|
||||
};
|
||||
|
||||
} /* namespace al */
|
||||
|
||||
#endif /* AL_ERROR_H */
|
||||
|
|
@ -3,35 +3,49 @@
|
|||
|
||||
#include "event.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <bitset>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#include "albyte.h"
|
||||
#include "alc/context.h"
|
||||
#include "alc/effects/base.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "almalloc.h"
|
||||
#include "alsem.h"
|
||||
#include "alspan.h"
|
||||
#include "core/async_event.h"
|
||||
#include "core/except.h"
|
||||
#include "core/context.h"
|
||||
#include "core/effects/base.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/voice_change.h"
|
||||
#include "debug.h"
|
||||
#include "direct_defs.h"
|
||||
#include "error.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "opthelpers.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "threads.h"
|
||||
|
||||
|
||||
static int EventThread(ALCcontext *context)
|
||||
namespace {
|
||||
|
||||
template<typename... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
|
||||
template<typename... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
int EventThread(ALCcontext *context)
|
||||
{
|
||||
RingBuffer *ring{context->mAsyncEvents.get()};
|
||||
bool quitnow{false};
|
||||
|
|
@ -44,76 +58,98 @@ static int EventThread(ALCcontext *context)
|
|||
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;
|
||||
std::lock_guard<std::mutex> eventlock{context->mEventCbLock};
|
||||
auto evt_span = al::span{std::launder(reinterpret_cast<AsyncEvent*>(evt_data.buf)),
|
||||
evt_data.len};
|
||||
for(auto &event : evt_span)
|
||||
{
|
||||
quitnow = std::holds_alternative<AsyncKillThread>(event);
|
||||
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)
|
||||
auto proc_killthread = [](AsyncKillThread&) { };
|
||||
auto proc_release = [](AsyncEffectReleaseEvent &evt)
|
||||
{
|
||||
al::intrusive_ptr<EffectState>{evt.mEffectState};
|
||||
};
|
||||
auto proc_srcstate = [context,enabledevts](AsyncSourceStateEvent &evt)
|
||||
{
|
||||
if(!context->mEventCb
|
||||
|| !enabledevts.test(al::to_underlying(AsyncEnableBits::SourceState)))
|
||||
return;
|
||||
|
||||
ALuint state{};
|
||||
std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)};
|
||||
std::string msg{"Source ID " + std::to_string(evt.mId)};
|
||||
msg += " state has changed to ";
|
||||
switch(evt.u.srcstate.state)
|
||||
switch(evt.mState)
|
||||
{
|
||||
case AsyncEvent::SrcState::Reset:
|
||||
case AsyncSrcState::Reset:
|
||||
msg += "AL_INITIAL";
|
||||
state = AL_INITIAL;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Stop:
|
||||
case AsyncSrcState::Stop:
|
||||
msg += "AL_STOPPED";
|
||||
state = AL_STOPPED;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Play:
|
||||
case AsyncSrcState::Play:
|
||||
msg += "AL_PLAYING";
|
||||
state = AL_PLAYING;
|
||||
break;
|
||||
case AsyncEvent::SrcState::Pause:
|
||||
case AsyncSrcState::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)
|
||||
context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.mId, state,
|
||||
static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam);
|
||||
};
|
||||
auto proc_buffercomp = [context,enabledevts](AsyncBufferCompleteEvent &evt)
|
||||
{
|
||||
std::string msg{std::to_string(evt.u.bufcomp.count)};
|
||||
if(evt.u.bufcomp.count == 1) msg += " buffer completed";
|
||||
if(!context->mEventCb
|
||||
|| !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted)))
|
||||
return;
|
||||
|
||||
std::string msg{std::to_string(evt.mCount)};
|
||||
if(evt.mCount == 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_BUFFER_COMPLETED_SOFT, evt.mId, evt.mCount,
|
||||
static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam);
|
||||
};
|
||||
auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt)
|
||||
{
|
||||
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);
|
||||
context->debugMessage(DebugSource::System, DebugType::Error, 0,
|
||||
DebugSeverity::High, evt.msg);
|
||||
|
||||
if(context->mEventCb
|
||||
&& enabledevts.test(al::to_underlying(AsyncEnableBits::Disconnected)))
|
||||
context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0,
|
||||
static_cast<ALsizei>(evt.msg.length()), evt.msg.c_str(),
|
||||
context->mEventParam);
|
||||
};
|
||||
|
||||
std::visit(overloaded{proc_srcstate, proc_buffercomp, proc_release, proc_disconnect,
|
||||
proc_killthread}, event);
|
||||
}
|
||||
std::destroy(evt_span.begin(), evt_span.end());
|
||||
ring->readAdvance(evt_span.size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr std::optional<AsyncEnableBits> GetEventType(ALenum etype) noexcept
|
||||
{
|
||||
switch(etype)
|
||||
{
|
||||
case AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT: return AsyncEnableBits::BufferCompleted;
|
||||
case AL_EVENT_TYPE_DISCONNECTED_SOFT: return AsyncEnableBits::Disconnected;
|
||||
case AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT: return AsyncEnableBits::SourceState;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void StartEventThrd(ALCcontext *ctx)
|
||||
{
|
||||
try {
|
||||
|
|
@ -138,7 +174,7 @@ void StopEventThrd(ALCcontext *ctx)
|
|||
evt_data = ring->getWriteVector().first;
|
||||
} while(evt_data.len == 0);
|
||||
}
|
||||
al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread);
|
||||
std::ignore = InitAsyncEvent<AsyncKillThread>(evt_data.buf);
|
||||
ring->writeAdvance(1);
|
||||
|
||||
ctx->mEventSem.post();
|
||||
|
|
@ -146,34 +182,25 @@ void StopEventThrd(ALCcontext *ctx)
|
|||
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;
|
||||
AL_API DECL_FUNCEXT3(void, alEventControl,SOFT, ALsizei,count, const ALenum*,types, ALboolean,enable)
|
||||
FORCE_ALIGN void AL_APIENTRY alEventControlDirectSOFT(ALCcontext *context, ALsizei count,
|
||||
const ALenum *types, ALboolean enable) noexcept
|
||||
try {
|
||||
if(count < 0)
|
||||
throw al::context_error{AL_INVALID_VALUE, "Controlling %d events", count};
|
||||
if(count <= 0) 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");
|
||||
if(!types)
|
||||
throw al::context_error{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);
|
||||
for(ALenum evttype : al::span{types, static_cast<uint>(count)})
|
||||
{
|
||||
auto etype = GetEventType(evttype);
|
||||
if(!etype)
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid event type 0x%04x", evttype};
|
||||
flags.set(al::to_underlying(*etype));
|
||||
}
|
||||
|
||||
if(enable)
|
||||
{
|
||||
|
|
@ -196,20 +223,18 @@ START_API_FUNC
|
|||
/* Wait to ensure the event handler sees the changed flags before
|
||||
* returning.
|
||||
*/
|
||||
std::lock_guard<std::mutex> _{context->mEventCbLock};
|
||||
std::lock_guard<std::mutex> eventlock{context->mEventCbLock};
|
||||
}
|
||||
}
|
||||
END_API_FUNC
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
|
||||
START_API_FUNC
|
||||
AL_API DECL_FUNCEXT2(void, alEventCallback,SOFT, ALEVENTPROCSOFT,callback, void*,userParam)
|
||||
FORCE_ALIGN void AL_APIENTRY alEventCallbackDirectSOFT(ALCcontext *context,
|
||||
ALEVENTPROCSOFT callback, void *userParam) noexcept
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
std::lock_guard<std::mutex> __{context->mEventCbLock};
|
||||
std::lock_guard<std::mutex> eventlock{context->mEventCbLock};
|
||||
context->mEventCb = callback;
|
||||
context->mEventParam = userParam;
|
||||
}
|
||||
END_API_FUNC
|
||||
|
|
|
|||
|
|
@ -20,63 +20,59 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "alstring.h"
|
||||
#include "core/except.h"
|
||||
#include "direct_defs.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
|
||||
START_API_FUNC
|
||||
AL_API DECL_FUNC1(ALboolean, alIsExtensionPresent, const ALchar*,extName)
|
||||
FORCE_ALIGN ALboolean AL_APIENTRY alIsExtensionPresentDirect(ALCcontext *context, const ALchar *extName) noexcept
|
||||
{
|
||||
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)
|
||||
const std::string_view tofind{extName};
|
||||
for(std::string_view ext : context->mExtensions)
|
||||
{
|
||||
if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
|
||||
if(al::case_compare(ext, tofind) == 0)
|
||||
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
|
||||
AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) noexcept
|
||||
{
|
||||
if(!funcName) return nullptr;
|
||||
return alcGetProcAddress(nullptr, funcName);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName)
|
||||
START_API_FUNC
|
||||
FORCE_ALIGN ALvoid* AL_APIENTRY alGetProcAddressDirect(ALCcontext*, const ALchar *funcName) noexcept
|
||||
{
|
||||
if(!enumName) return static_cast<ALenum>(0);
|
||||
if(!funcName) return nullptr;
|
||||
return alcGetProcAddress(nullptr, funcName);
|
||||
}
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) noexcept
|
||||
{
|
||||
if(!enumName) return ALenum{0};
|
||||
return alcGetEnumValue(nullptr, enumName);
|
||||
}
|
||||
|
||||
FORCE_ALIGN ALenum AL_APIENTRY alGetEnumValueDirect(ALCcontext*, const ALchar *enumName) noexcept
|
||||
{
|
||||
if(!enumName) return ALenum{0};
|
||||
return alcGetEnumValue(nullptr, enumName);
|
||||
}
|
||||
END_API_FUNC
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +1,40 @@
|
|||
#ifndef AL_FILTER_H
|
||||
#define AL_FILTER_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/alext.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
|
||||
#define LOWPASSFREQREF 5000.0f
|
||||
#define HIGHPASSFREQREF 250.0f
|
||||
|
||||
inline constexpr float LowPassFreqRef{5000.0f};
|
||||
inline constexpr float HighPassFreqRef{250.0f};
|
||||
|
||||
template<typename T>
|
||||
struct FilterTable {
|
||||
static void setParami(struct ALfilter*, ALenum, int);
|
||||
static void setParamiv(struct ALfilter*, ALenum, const int*);
|
||||
static void setParamf(struct ALfilter*, ALenum, float);
|
||||
static void setParamfv(struct ALfilter*, ALenum, const float*);
|
||||
|
||||
static void getParami(const struct ALfilter*, ALenum, int*);
|
||||
static void getParamiv(const struct ALfilter*, ALenum, int*);
|
||||
static void getParamf(const struct ALfilter*, ALenum, float*);
|
||||
static void getParamfv(const struct ALfilter*, ALenum, float*);
|
||||
};
|
||||
|
||||
struct NullFilterTable : public FilterTable<NullFilterTable> { };
|
||||
struct LowpassFilterTable : public FilterTable<LowpassFilterTable> { };
|
||||
struct HighpassFilterTable : public FilterTable<HighpassFilterTable> { };
|
||||
struct BandpassFilterTable : public FilterTable<BandpassFilterTable> { };
|
||||
|
||||
|
||||
struct ALfilter {
|
||||
|
|
@ -17,36 +42,35 @@ struct ALfilter {
|
|||
|
||||
float Gain{1.0f};
|
||||
float GainHF{1.0f};
|
||||
float HFReference{LOWPASSFREQREF};
|
||||
float HFReference{LowPassFreqRef};
|
||||
float GainLF{1.0f};
|
||||
float LFReference{HIGHPASSFREQREF};
|
||||
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};
|
||||
using TableTypes = std::variant<NullFilterTable,LowpassFilterTable,HighpassFilterTable,
|
||||
BandpassFilterTable>;
|
||||
TableTypes mTypeVariant;
|
||||
|
||||
/* 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); }
|
||||
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
|
||||
|
||||
DISABLE_ALLOC()
|
||||
DISABLE_ALLOC
|
||||
};
|
||||
|
||||
struct FilterSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
gsl::owner<std::array<ALfilter,64>*> Filters{nullptr};
|
||||
|
||||
FilterSubList() noexcept = default;
|
||||
FilterSubList(const FilterSubList&) = delete;
|
||||
FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; }
|
||||
~FilterSubList();
|
||||
|
||||
FilterSubList& operator=(const FilterSubList&) = delete;
|
||||
FilterSubList& operator=(FilterSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "listener.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
|
||||
|
|
@ -30,9 +31,10 @@
|
|||
#include "AL/efx.h"
|
||||
|
||||
#include "alc/context.h"
|
||||
#include "almalloc.h"
|
||||
#include "atomic.h"
|
||||
#include "core/except.h"
|
||||
#include "alc/inprogext.h"
|
||||
#include "alspan.h"
|
||||
#include "direct_defs.h"
|
||||
#include "error.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
|
|
@ -68,377 +70,333 @@ inline void CommitAndUpdateProps(ALCcontext *context)
|
|||
|
||||
} // namespace
|
||||
|
||||
AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value)
|
||||
START_API_FUNC
|
||||
{
|
||||
ContextRef context{GetContextRef()};
|
||||
if(!context) UNLIKELY return;
|
||||
|
||||
AL_API DECL_FUNC2(void, alListenerf, ALenum,param, ALfloat,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alListenerfDirect(ALCcontext *context, ALenum param, ALfloat value) noexcept
|
||||
try {
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
std::lock_guard<std::mutex> proplock{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");
|
||||
throw al::context_error{AL_INVALID_VALUE, "Listener gain out of range"};
|
||||
listener.Gain = value;
|
||||
UpdateProps(context.get());
|
||||
break;
|
||||
UpdateProps(context);
|
||||
return;
|
||||
|
||||
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");
|
||||
throw al::context_error{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");
|
||||
UpdateProps(context);
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
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;
|
||||
|
||||
AL_API DECL_FUNC4(void, alListener3f, ALenum,param, ALfloat,value1, ALfloat,value2, ALfloat,value3)
|
||||
FORCE_ALIGN void AL_APIENTRY alListener3fDirect(ALCcontext *context, ALenum param, ALfloat value1,
|
||||
ALfloat value2, ALfloat value3) noexcept
|
||||
try {
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
std::lock_guard<std::mutex> proplock{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");
|
||||
throw al::context_error{AL_INVALID_VALUE, "Listener position out of range"};
|
||||
listener.Position[0] = value1;
|
||||
listener.Position[1] = value2;
|
||||
listener.Position[2] = value3;
|
||||
CommitAndUpdateProps(context.get());
|
||||
break;
|
||||
CommitAndUpdateProps(context);
|
||||
return;
|
||||
|
||||
case AL_VELOCITY:
|
||||
if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
|
||||
return context->setError(AL_INVALID_VALUE, "Listener velocity out of range");
|
||||
throw al::context_error{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");
|
||||
CommitAndUpdateProps(context);
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
if(values)
|
||||
AL_API DECL_FUNC2(void, alListenerfv, ALenum,param, const ALfloat*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alListenerfvDirect(ALCcontext *context, ALenum param,
|
||||
const ALfloat *values) noexcept
|
||||
try {
|
||||
if(!values)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
switch(param)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
case AL_METERS_PER_UNIT:
|
||||
alListenerf(param, values[0]);
|
||||
return;
|
||||
case AL_GAIN:
|
||||
case AL_METERS_PER_UNIT:
|
||||
alListenerfDirect(context, param, *values);
|
||||
return;
|
||||
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alListener3f(param, values[0], values[1], values[2]);
|
||||
return;
|
||||
}
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
auto vals = al::span<const float,3>{values, 3_uz};
|
||||
alListener3fDirect(context, param, vals[0], vals[1], vals[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};
|
||||
std::lock_guard<std::mutex> proplock{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])))
|
||||
auto vals = al::span<const float,6>{values, 6_uz};
|
||||
if(!std::all_of(vals.cbegin(), vals.cend(), [](float f) { return std::isfinite(f); }))
|
||||
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");
|
||||
std::copy_n(vals.cbegin(), 3, listener.OrientAt.begin());
|
||||
std::copy_n(vals.cbegin()+3, 3, listener.OrientUp.begin());
|
||||
CommitAndUpdateProps(context);
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
|
||||
}
|
||||
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");
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
|
||||
START_API_FUNC
|
||||
{
|
||||
|
||||
AL_API DECL_FUNC2(void, alListeneri, ALenum,param, ALint,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alListeneriDirect(ALCcontext *context, ALenum param, ALint /*value*/) noexcept
|
||||
try {
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC4(void, alListener3i, ALenum,param, ALint,value1, ALint,value2, ALint,value3)
|
||||
FORCE_ALIGN void AL_APIENTRY alListener3iDirect(ALCcontext *context, ALenum param, ALint value1,
|
||||
ALint value2, ALint value3) noexcept
|
||||
try {
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alListener3f(param, static_cast<ALfloat>(value1), static_cast<ALfloat>(value2),
|
||||
static_cast<ALfloat>(value3));
|
||||
alListener3fDirect(context, 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> proplock{context->mPropLock};
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
AL_API DECL_FUNC2(void, alListeneriv, ALenum,param, const ALint*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alListenerivDirect(ALCcontext *context, ALenum param,
|
||||
const ALint *values) noexcept
|
||||
try {
|
||||
if(!values)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
al::span<const ALint> vals;
|
||||
switch(param)
|
||||
{
|
||||
default:
|
||||
context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property");
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
vals = {values, 3_uz};
|
||||
alListener3fDirect(context, param, static_cast<ALfloat>(vals[0]),
|
||||
static_cast<ALfloat>(vals[1]), static_cast<ALfloat>(vals[2]));
|
||||
return;
|
||||
|
||||
case AL_ORIENTATION:
|
||||
vals = {values, 6_uz};
|
||||
const std::array fvals{static_cast<ALfloat>(vals[0]), static_cast<ALfloat>(vals[1]),
|
||||
static_cast<ALfloat>(vals[2]), static_cast<ALfloat>(vals[3]),
|
||||
static_cast<ALfloat>(vals[4]), static_cast<ALfloat>(vals[5]),
|
||||
};
|
||||
alListenerfvDirect(context, param, fvals.data());
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
|
||||
param};
|
||||
}
|
||||
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");
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
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};
|
||||
AL_API DECL_FUNC2(void, alGetListenerf, ALenum,param, ALfloat*,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListenerfDirect(ALCcontext *context, ALenum param,
|
||||
ALfloat *value) noexcept
|
||||
try {
|
||||
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;
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> _{context->mPropLock};
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN: *value = listener.Gain; return;
|
||||
case AL_METERS_PER_UNIT: *value = listener.mMetersPerUnit; return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC4(void, alGetListener3f, ALenum,param, ALfloat*,value1, ALfloat*,value2, ALfloat*,value3)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListener3fDirect(ALCcontext *context, ALenum param,
|
||||
ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept
|
||||
try {
|
||||
if(!value1 || !value2 || !value3)
|
||||
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
||||
else switch(param)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
ALlistener &listener = context->mListener;
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
*value1 = listener.Position[0];
|
||||
*value2 = listener.Position[1];
|
||||
*value3 = listener.Position[2];
|
||||
break;
|
||||
return;
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
|
||||
START_API_FUNC
|
||||
{
|
||||
AL_API DECL_FUNC2(void, alGetListenerfv, ALenum,param, ALfloat*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListenerfvDirect(ALCcontext *context, ALenum param,
|
||||
ALfloat *values) noexcept
|
||||
try {
|
||||
if(!values)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case AL_GAIN:
|
||||
case AL_METERS_PER_UNIT:
|
||||
alGetListenerf(param, values);
|
||||
alGetListenerfDirect(context, param, values);
|
||||
return;
|
||||
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alGetListener3f(param, values+0, values+1, values+2);
|
||||
auto vals = al::span<ALfloat,3>{values, 3_uz};
|
||||
alGetListener3fDirect(context, param, &vals[0], &vals[1], &vals[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)
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
al::span<ALfloat,6> vals{values, 6_uz};
|
||||
// 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");
|
||||
std::copy_n(listener.OrientAt.cbegin(), 3, vals.begin());
|
||||
std::copy_n(listener.OrientUp.cbegin(), 3, vals.begin()+3);
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
|
||||
}
|
||||
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");
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
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;
|
||||
|
||||
AL_API DECL_FUNC2(void, alGetListeneri, ALenum,param, ALint*,value)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListeneriDirect(ALCcontext *context, ALenum param, ALint *value) noexcept
|
||||
try {
|
||||
if(!value) throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
|
||||
AL_API DECL_FUNC4(void, alGetListener3i, ALenum,param, ALint*,value1, ALint*,value2, ALint*,value3)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListener3iDirect(ALCcontext *context, ALenum param,
|
||||
ALint *value1, ALint *value2, ALint *value3) noexcept
|
||||
try {
|
||||
if(!value1 || !value2 || !value3)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
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)
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
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;
|
||||
return;
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
||||
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
|
||||
START_API_FUNC
|
||||
{
|
||||
AL_API DECL_FUNC2(void, alGetListeneriv, ALenum,param, ALint*,values)
|
||||
FORCE_ALIGN void AL_APIENTRY alGetListenerivDirect(ALCcontext *context, ALenum param,
|
||||
ALint *values) noexcept
|
||||
try {
|
||||
if(!values)
|
||||
throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case AL_POSITION:
|
||||
case AL_VELOCITY:
|
||||
alGetListener3i(param, values+0, values+1, values+2);
|
||||
auto vals = al::span<ALint,3>{values, 3_uz};
|
||||
alGetListener3iDirect(context, param, &vals[0], &vals[1], &vals[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)
|
||||
std::lock_guard<std::mutex> proplock{context->mPropLock};
|
||||
|
||||
static constexpr auto f2i = [](const float val) noexcept { return static_cast<ALint>(val); };
|
||||
switch(param)
|
||||
{
|
||||
case AL_ORIENTATION:
|
||||
auto vals = al::span<ALint,6>{values, 6_uz};
|
||||
// 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");
|
||||
std::transform(listener.OrientAt.cbegin(), listener.OrientAt.cend(), vals.begin(), f2i);
|
||||
std::transform(listener.OrientUp.cbegin(), listener.OrientUp.cend(), vals.begin()+3, f2i);
|
||||
return;
|
||||
}
|
||||
throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
|
||||
param};
|
||||
}
|
||||
catch(al::context_error& e) {
|
||||
context->setError(e.errorCode(), "%s", e.what());
|
||||
}
|
||||
END_API_FUNC
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
|
|
@ -18,7 +16,7 @@ struct ALlistener {
|
|||
float Gain{1.0f};
|
||||
float mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
DISABLE_ALLOC
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,26 +2,26 @@
|
|||
#define AL_SOURCE_H
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#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 "aldeque.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumbers.h"
|
||||
#include "alnumeric.h"
|
||||
#include "atomic.h"
|
||||
#include "alspan.h"
|
||||
#include "core/context.h"
|
||||
#include "core/voice.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
#include "eax/api.h"
|
||||
#include "eax/call.h"
|
||||
#include "eax/exception.h"
|
||||
#include "eax/fx_slot_index.h"
|
||||
|
|
@ -30,23 +30,23 @@
|
|||
|
||||
struct ALbuffer;
|
||||
struct ALeffectslot;
|
||||
|
||||
enum class Resampler : uint8_t;
|
||||
|
||||
enum class SourceStereo : bool {
|
||||
Normal = AL_NORMAL_SOFT,
|
||||
Enhanced = AL_SUPER_STEREO_SOFT
|
||||
};
|
||||
|
||||
#define DEFAULT_SENDS 2
|
||||
inline constexpr size_t DefaultSendCount{2};
|
||||
|
||||
#define INVALID_VOICE_IDX static_cast<ALuint>(-1)
|
||||
inline constexpr ALuint InvalidVoiceIndex{std::numeric_limits<ALuint>::max()};
|
||||
|
||||
extern bool sBufferSubDataCompat;
|
||||
inline bool sBufferSubDataCompat{false};
|
||||
|
||||
struct ALbufferQueueItem : public VoiceBufferItem {
|
||||
ALbuffer *mBuffer{nullptr};
|
||||
|
||||
DISABLE_ALLOC()
|
||||
DISABLE_ALLOC
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -88,6 +88,7 @@ struct ALsource {
|
|||
DirectMode DirectChannels{DirectMode::Off};
|
||||
SpatializeMode mSpatialize{SpatializeMode::Auto};
|
||||
SourceStereo mStereoMode{SourceStereo::Normal};
|
||||
bool mPanningEnabled{false};
|
||||
|
||||
bool DryGainHFAuto{true};
|
||||
bool WetGainAuto{true};
|
||||
|
|
@ -105,24 +106,27 @@ struct ALsource {
|
|||
|
||||
float Radius{0.0f};
|
||||
float EnhWidth{0.593f};
|
||||
float mPan{0.0f};
|
||||
|
||||
/** Direct filter and auxiliary send info. */
|
||||
struct {
|
||||
float Gain;
|
||||
float GainHF;
|
||||
float HFReference;
|
||||
float GainLF;
|
||||
float LFReference;
|
||||
} Direct;
|
||||
struct SendData {
|
||||
ALeffectslot *Slot;
|
||||
float Gain;
|
||||
float GainHF;
|
||||
float HFReference;
|
||||
float GainLF;
|
||||
float LFReference;
|
||||
struct DirectData {
|
||||
float Gain{};
|
||||
float GainHF{};
|
||||
float HFReference{};
|
||||
float GainLF{};
|
||||
float LFReference{};
|
||||
};
|
||||
std::array<SendData,MAX_SENDS> Send;
|
||||
DirectData Direct;
|
||||
|
||||
struct SendData {
|
||||
ALeffectslot *Slot{};
|
||||
float Gain{};
|
||||
float GainHF{};
|
||||
float HFReference{};
|
||||
float GainLF{};
|
||||
float LFReference{};
|
||||
};
|
||||
std::array<SendData,MaxSendCount> Send;
|
||||
|
||||
/**
|
||||
* Last user-specified offset, and the offset type (bytes, samples, or
|
||||
|
|
@ -138,26 +142,28 @@ struct ALsource {
|
|||
ALenum state{AL_INITIAL};
|
||||
|
||||
/** Source Buffer Queue head. */
|
||||
al::deque<ALbufferQueueItem> mQueue;
|
||||
std::deque<ALbufferQueueItem> mQueue;
|
||||
|
||||
bool mPropsDirty{true};
|
||||
|
||||
/* Index into the context's Voices array. Lazily updated, only checked and
|
||||
* reset when looking up the voice.
|
||||
*/
|
||||
ALuint VoiceIdx{INVALID_VOICE_IDX};
|
||||
ALuint VoiceIdx{InvalidVoiceIndex};
|
||||
|
||||
/** Self ID */
|
||||
ALuint id{0};
|
||||
|
||||
|
||||
ALsource();
|
||||
ALsource() noexcept;
|
||||
~ALsource();
|
||||
|
||||
ALsource(const ALsource&) = delete;
|
||||
ALsource& operator=(const ALsource&) = delete;
|
||||
|
||||
DISABLE_ALLOC()
|
||||
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
|
||||
|
||||
DISABLE_ALLOC
|
||||
|
||||
#ifdef ALSOFT_EAX
|
||||
public:
|
||||
|
|
@ -171,18 +177,18 @@ public:
|
|||
private:
|
||||
using Exception = EaxSourceException;
|
||||
|
||||
static constexpr auto eax_max_speakers = 9;
|
||||
static constexpr auto eax_max_speakers{9u};
|
||||
|
||||
using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS];
|
||||
using EaxFxSlotIds = std::array<const GUID*,EAX_MAX_FXSLOTS>;
|
||||
|
||||
static constexpr const EaxFxSlotIds eax4_fx_slot_ids = {
|
||||
static constexpr const EaxFxSlotIds eax4_fx_slot_ids{
|
||||
&EAXPROPERTYID_EAX40_FXSlot0,
|
||||
&EAXPROPERTYID_EAX40_FXSlot1,
|
||||
&EAXPROPERTYID_EAX40_FXSlot2,
|
||||
&EAXPROPERTYID_EAX40_FXSlot3,
|
||||
};
|
||||
|
||||
static constexpr const EaxFxSlotIds eax5_fx_slot_ids = {
|
||||
static constexpr const EaxFxSlotIds eax5_fx_slot_ids{
|
||||
&EAXPROPERTYID_EAX50_FXSlot0,
|
||||
&EAXPROPERTYID_EAX50_FXSlot1,
|
||||
&EAXPROPERTYID_EAX50_FXSlot2,
|
||||
|
|
@ -215,11 +221,6 @@ private:
|
|||
Eax3Props source;
|
||||
EaxSends sends;
|
||||
EAX40ACTIVEFXSLOTS active_fx_slots;
|
||||
|
||||
bool operator==(const Eax4Props& rhs) noexcept
|
||||
{
|
||||
return std::memcmp(this, &rhs, sizeof(Eax4Props)) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax4State {
|
||||
|
|
@ -232,11 +233,6 @@ private:
|
|||
EaxSends sends;
|
||||
EAX50ACTIVEFXSLOTS active_fx_slots;
|
||||
EaxSpeakerLevels speaker_levels;
|
||||
|
||||
bool operator==(const Eax5Props& rhs) noexcept
|
||||
{
|
||||
return std::memcmp(this, &rhs, sizeof(Eax5Props)) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Eax5State {
|
||||
|
|
@ -546,7 +542,24 @@ private:
|
|||
struct Eax5SourceAllValidator {
|
||||
void operator()(const EAX50SOURCEPROPERTIES& props) const
|
||||
{
|
||||
Eax3SourceAllValidator{}(static_cast<const Eax3Props&>(props));
|
||||
Eax2SourceDirectValidator{}(props.lDirect);
|
||||
Eax2SourceDirectHfValidator{}(props.lDirectHF);
|
||||
Eax2SourceRoomValidator{}(props.lRoom);
|
||||
Eax2SourceRoomHfValidator{}(props.lRoomHF);
|
||||
Eax2SourceObstructionValidator{}(props.lObstruction);
|
||||
Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
|
||||
Eax2SourceOcclusionValidator{}(props.lOcclusion);
|
||||
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
|
||||
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
|
||||
Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
|
||||
Eax3SourceExclusionValidator{}(props.lExclusion);
|
||||
Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
|
||||
Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
|
||||
Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
|
||||
Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
|
||||
Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
|
||||
Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
|
||||
Eax5SourceFlagsValidator{}(props.ulFlags);
|
||||
Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor);
|
||||
}
|
||||
};
|
||||
|
|
@ -809,39 +822,38 @@ private:
|
|||
[[noreturn]] static void eax_fail_unknown_active_fx_slot_id();
|
||||
[[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id();
|
||||
|
||||
void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
|
||||
void eax1_set_defaults(Eax1Props& props) noexcept;
|
||||
static void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
|
||||
static void eax1_set_defaults(Eax1Props& props) noexcept;
|
||||
void eax1_set_defaults() noexcept;
|
||||
void eax2_set_defaults(Eax2Props& props) noexcept;
|
||||
static void eax2_set_defaults(Eax2Props& props) noexcept;
|
||||
void eax2_set_defaults() noexcept;
|
||||
void eax3_set_defaults(Eax3Props& props) noexcept;
|
||||
static void eax3_set_defaults(Eax3Props& props) noexcept;
|
||||
void eax3_set_defaults() noexcept;
|
||||
void eax4_set_sends_defaults(EaxSends& sends) noexcept;
|
||||
void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
|
||||
static void eax4_set_sends_defaults(EaxSends& sends) noexcept;
|
||||
static void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
|
||||
void eax4_set_defaults() noexcept;
|
||||
void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
|
||||
void eax5_set_sends_defaults(EaxSends& sends) noexcept;
|
||||
void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
|
||||
void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
|
||||
void eax5_set_defaults(Eax5Props& props) noexcept;
|
||||
static void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
|
||||
static void eax5_set_sends_defaults(EaxSends& sends) noexcept;
|
||||
static void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
|
||||
static void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
|
||||
static void eax5_set_defaults(Eax5Props& props) noexcept;
|
||||
void eax5_set_defaults() noexcept;
|
||||
void eax_set_defaults() noexcept;
|
||||
|
||||
void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
|
||||
void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
|
||||
void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
|
||||
void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
|
||||
static void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
|
||||
static void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
|
||||
static void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
|
||||
static void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
|
||||
|
||||
static float eax_calculate_dst_occlusion_mb(
|
||||
long src_occlusion_mb,
|
||||
float path_ratio,
|
||||
float lf_ratio) noexcept;
|
||||
|
||||
EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;
|
||||
[[nodiscard]] auto eax_create_direct_filter_param() const noexcept -> EaxAlLowPassParam;
|
||||
|
||||
EaxAlLowPassParam eax_create_room_filter_param(
|
||||
const ALeffectslot& fx_slot,
|
||||
const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;
|
||||
[[nodiscard]] auto eax_create_room_filter_param(const ALeffectslot& fx_slot,
|
||||
const EAXSOURCEALLSENDPROPERTIES& send) const noexcept -> EaxAlLowPassParam;
|
||||
|
||||
void eax_update_direct_filter();
|
||||
void eax_update_room_filters();
|
||||
|
|
@ -894,16 +906,16 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void eax_get_active_fx_slot_id(const EaxCall& call, const GUID* ids, size_t max_count);
|
||||
void eax1_get(const EaxCall& call, const Eax1Props& props);
|
||||
void eax2_get(const EaxCall& call, const Eax2Props& props);
|
||||
void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
|
||||
void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
|
||||
void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
|
||||
void eax3_get(const EaxCall& call, const Eax3Props& props);
|
||||
static void eax_get_active_fx_slot_id(const EaxCall& call, const al::span<const GUID> src_ids);
|
||||
static void eax1_get(const EaxCall& call, const Eax1Props& props);
|
||||
static void eax2_get(const EaxCall& call, const Eax2Props& props);
|
||||
static void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
|
||||
static void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
|
||||
static void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
|
||||
static void eax3_get(const EaxCall& call, const Eax3Props& props);
|
||||
void eax4_get(const EaxCall& call, const Eax4Props& props);
|
||||
void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
|
||||
void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
|
||||
static void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
|
||||
static void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
|
||||
void eax5_get(const EaxCall& call, const Eax5Props& props);
|
||||
void eax_get(const EaxCall& call);
|
||||
|
||||
|
|
@ -976,21 +988,21 @@ private:
|
|||
}
|
||||
|
||||
template<typename TValidator, size_t TIdCount>
|
||||
void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
|
||||
void eax_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
|
||||
{
|
||||
const auto src_ids = call.get_values<const GUID>(TIdCount);
|
||||
std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
|
||||
std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids);
|
||||
std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids.begin());
|
||||
}
|
||||
|
||||
template<size_t TIdCount>
|
||||
void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
|
||||
void eax4_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
|
||||
{
|
||||
eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
|
||||
}
|
||||
|
||||
template<size_t TIdCount>
|
||||
void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
|
||||
void eax5_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
|
||||
{
|
||||
eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
|
||||
}
|
||||
|
|
@ -1022,12 +1034,12 @@ private:
|
|||
void eax_set_efx_wet_gain_auto();
|
||||
void eax_set_efx_wet_gain_hf_auto();
|
||||
|
||||
void eax1_set(const EaxCall& call, Eax1Props& props);
|
||||
void eax2_set(const EaxCall& call, Eax2Props& props);
|
||||
static void eax1_set(const EaxCall& call, Eax1Props& props);
|
||||
static void eax2_set(const EaxCall& call, Eax2Props& props);
|
||||
void eax3_set(const EaxCall& call, Eax3Props& props);
|
||||
void eax4_set(const EaxCall& call, Eax4Props& props);
|
||||
void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
|
||||
void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
|
||||
static void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
|
||||
static void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
|
||||
void eax5_set(const EaxCall& call, Eax5Props& props);
|
||||
void eax_set(const EaxCall& call);
|
||||
|
||||
|
|
@ -1041,4 +1053,19 @@ private:
|
|||
|
||||
void UpdateAllSourceProps(ALCcontext *context);
|
||||
|
||||
struct SourceSubList {
|
||||
uint64_t FreeMask{~0_u64};
|
||||
gsl::owner<std::array<ALsource,64>*> Sources{nullptr};
|
||||
|
||||
SourceSubList() noexcept = default;
|
||||
SourceSubList(const SourceSubList&) = delete;
|
||||
SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
|
||||
{ rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
|
||||
~SourceSubList();
|
||||
|
||||
SourceSubList& operator=(const SourceSubList&) = delete;
|
||||
SourceSubList& operator=(SourceSubList&& rhs) noexcept
|
||||
{ std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue