diff options
Diffstat (limited to 'al')
37 files changed, 1872 insertions, 2134 deletions
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index fb646389..673ca4c9 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -53,33 +53,35 @@ namespace { +using SubListAllocator = typename al::allocator<std::array<ALeffectslot,64>>; + struct FactoryItem { EffectSlotType Type; - EffectStateFactory* (&GetFactory)(void); + EffectStateFactory* (&GetFactory)(); }; -constexpr FactoryItem FactoryList[] = { - { EffectSlotType::None, NullStateFactory_getFactory }, - { EffectSlotType::EAXReverb, ReverbStateFactory_getFactory }, - { EffectSlotType::Reverb, StdReverbStateFactory_getFactory }, - { EffectSlotType::Autowah, AutowahStateFactory_getFactory }, - { EffectSlotType::Chorus, ChorusStateFactory_getFactory }, - { EffectSlotType::Compressor, CompressorStateFactory_getFactory }, - { EffectSlotType::Distortion, DistortionStateFactory_getFactory }, - { EffectSlotType::Echo, EchoStateFactory_getFactory }, - { EffectSlotType::Equalizer, EqualizerStateFactory_getFactory }, - { EffectSlotType::Flanger, FlangerStateFactory_getFactory }, - { EffectSlotType::FrequencyShifter, FshifterStateFactory_getFactory }, - { EffectSlotType::RingModulator, ModulatorStateFactory_getFactory }, - { EffectSlotType::PitchShifter, PshifterStateFactory_getFactory }, - { EffectSlotType::VocalMorpher, VmorpherStateFactory_getFactory }, - { EffectSlotType::DedicatedDialog, DedicatedStateFactory_getFactory }, - { EffectSlotType::DedicatedLFE, DedicatedStateFactory_getFactory }, - { EffectSlotType::Convolution, ConvolutionStateFactory_getFactory }, +constexpr std::array FactoryList{ + FactoryItem{EffectSlotType::None, NullStateFactory_getFactory}, + FactoryItem{EffectSlotType::EAXReverb, ReverbStateFactory_getFactory}, + FactoryItem{EffectSlotType::Reverb, StdReverbStateFactory_getFactory}, + FactoryItem{EffectSlotType::Autowah, AutowahStateFactory_getFactory}, + FactoryItem{EffectSlotType::Chorus, ChorusStateFactory_getFactory}, + FactoryItem{EffectSlotType::Compressor, CompressorStateFactory_getFactory}, + FactoryItem{EffectSlotType::Distortion, DistortionStateFactory_getFactory}, + FactoryItem{EffectSlotType::Echo, EchoStateFactory_getFactory}, + FactoryItem{EffectSlotType::Equalizer, EqualizerStateFactory_getFactory}, + FactoryItem{EffectSlotType::Flanger, FlangerStateFactory_getFactory}, + FactoryItem{EffectSlotType::FrequencyShifter, FshifterStateFactory_getFactory}, + FactoryItem{EffectSlotType::RingModulator, ModulatorStateFactory_getFactory}, + FactoryItem{EffectSlotType::PitchShifter, PshifterStateFactory_getFactory}, + FactoryItem{EffectSlotType::VocalMorpher, VmorpherStateFactory_getFactory}, + FactoryItem{EffectSlotType::DedicatedDialog, DedicatedDialogStateFactory_getFactory}, + FactoryItem{EffectSlotType::DedicatedLFE, DedicatedLfeStateFactory_getFactory}, + FactoryItem{EffectSlotType::Convolution, ConvolutionStateFactory_getFactory}, }; EffectStateFactory *getFactoryByType(EffectSlotType type) { - auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList), + auto iter = std::find_if(FactoryList.begin(), FactoryList.end(), [type](const FactoryItem &item) noexcept -> bool { return item.Type == type; }); return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; @@ -96,7 +98,7 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.EffectSlots + slidx; + return al::to_address(sublist.EffectSlots->begin() + slidx); } inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept @@ -109,7 +111,7 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept 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); } inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept @@ -122,7 +124,7 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept BufferSubList &sublist = device->BufferList[lidx]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Buffers + slidx; + return al::to_address(sublist.Buffers->begin() + slidx); } @@ -155,19 +157,17 @@ void AddActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext *co */ if(newcount < newarray->size()) UNLIKELY { - curarray = newarray; + std::unique_ptr<EffectSlotArray> oldarray{newarray}; newarray = EffectSlot::CreatePtrArray(newcount); - std::copy_n(curarray->begin(), newcount, newarray->begin()); - delete curarray; - curarray = nullptr; + std::copy_n(oldarray->begin(), newcount, newarray->begin()); } std::uninitialized_fill_n(newarray->end(), newcount, nullptr); - curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - context->mDevice->waitForMix(); + std::unique_ptr<EffectSlotArray> oldarray{context->mActiveAuxSlots.exchange(newarray, + std::memory_order_acq_rel)}; + std::ignore = context->mDevice->waitForMix(); - std::destroy_n(curarray->end(), curarray->size()); - delete curarray; + std::destroy_n(oldarray->end(), oldarray->size()); } void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext *context) @@ -193,20 +193,17 @@ void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext auto newsize = static_cast<size_t>(std::distance(newarray->begin(), new_end)); if(newsize != newarray->size()) LIKELY { - curarray = newarray; + std::unique_ptr<EffectSlotArray> oldarray{newarray}; newarray = EffectSlot::CreatePtrArray(newsize); - std::copy_n(curarray->begin(), newsize, newarray->begin()); - - delete curarray; - curarray = nullptr; + std::copy_n(oldarray->begin(), newsize, newarray->begin()); } std::uninitialized_fill_n(newarray->end(), newsize, nullptr); - curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - context->mDevice->waitForMix(); + std::unique_ptr<EffectSlotArray> oldarray{context->mActiveAuxSlots.exchange(newarray, + std::memory_order_acq_rel)}; + std::ignore = context->mDevice->waitForMix(); std::destroy_n(curarray->end(), curarray->size()); - delete curarray; } @@ -243,22 +240,21 @@ bool EnsureEffectSlots(ALCcontext *context, size_t needed) [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - while(needed > count) - { - if(context->mEffectSlotList.size() >= 1<<25) UNLIKELY - return false; - - context->mEffectSlotList.emplace_back(); - auto sublist = context->mEffectSlotList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->EffectSlots = static_cast<ALeffectslot*>( - al_calloc(alignof(ALeffectslot), sizeof(ALeffectslot)*64)); - if(!sublist->EffectSlots) UNLIKELY + try { + while(needed > count) { - context->mEffectSlotList.pop_back(); - return false; + if(context->mEffectSlotList.size() >= 1<<25) UNLIKELY + return false; + + EffectSlotSubList sublist{}; + sublist.FreeMask = ~0_u64; + sublist.EffectSlots = SubListAllocator{}.allocate(1); + context->mEffectSlotList.emplace_back(std::move(sublist)); + count += 64; } - count += 64; + } + catch(...) { + return false; } return true; } @@ -272,7 +268,8 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); ASSUME(slidx < 64); - ALeffectslot *slot{al::construct_at(sublist->EffectSlots + slidx, context)}; + ALeffectslot *slot{al::construct_at(al::to_address(sublist->EffectSlots->begin() + slidx), + context)}; aluInitEffectPanning(slot->mSlot, context); /* Add 1 to avoid ID 0. */ @@ -370,7 +367,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *cont context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[0]); return; } - if(ReadRef(slot->ref) != 0) UNLIKELY + if(slot->ref.load(std::memory_order_relaxed) != 0) UNLIKELY { context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u", effectslots[0]); @@ -390,7 +387,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *cont context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[i]); return; } - if(ReadRef(slot->ref) != 0) UNLIKELY + if(slot->ref.load(std::memory_order_relaxed) != 0) UNLIKELY { context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u", effectslots[i]); @@ -880,12 +877,8 @@ ALeffectslot::~ALeffectslot() DecrementRef(Buffer->ref); Buffer = nullptr; - if(EffectSlotProps *props{mSlot->Update.exchange(nullptr)}) - { - TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", - decltype(std::declval<void*>()){props}); - delete props; - } + if(auto *slot = mSlot->Update.exchange(nullptr, std::memory_order_relaxed)) + slot->State = nullptr; mSlot->mEffectState = nullptr; mSlot->InUse = false; @@ -923,7 +916,7 @@ ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const Effect EffectId = effectId; /* Remove state references from old effect slot property updates. */ - EffectSlotProps *props{context->mFreeEffectslotProps.load()}; + EffectSlotProps *props{context->mFreeEffectSlotProps.load()}; while(props) { props->State = nullptr; @@ -936,17 +929,17 @@ ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const Effect void ALeffectslot::updateProps(ALCcontext *context) { /* Get an unused property container, or allocate a new one as needed. */ - EffectSlotProps *props{context->mFreeEffectslotProps.load(std::memory_order_relaxed)}; + EffectSlotProps *props{context->mFreeEffectSlotProps.load(std::memory_order_acquire)}; if(!props) - props = new EffectSlotProps{}; - else { - EffectSlotProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->mFreeEffectslotProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); + context->allocEffectSlotProps(); + props = context->mFreeEffectSlotProps.load(std::memory_order_acquire); } + EffectSlotProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->mFreeEffectSlotProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == false); /* Copy in current property values. */ props->Gain = Gain; @@ -965,7 +958,7 @@ void ALeffectslot::updateProps(ALCcontext *context) * freelist. */ props->State = nullptr; - AtomicReplaceHead(context->mFreeEffectslotProps, props); + AtomicReplaceHead(context->mFreeEffectSlotProps, props); } } @@ -988,12 +981,12 @@ void UpdateAllEffectSlotProps(ALCcontext *context) uint64_t usemask{~sublist.FreeMask}; while(usemask) { - const int idx{al::countr_zero(usemask)}; + const auto idx = static_cast<uint>(al::countr_zero(usemask)); usemask &= ~(1_u64 << idx); - ALeffectslot *slot{sublist.EffectSlots + idx}; + auto &slot = (*sublist.EffectSlots)[idx]; - if(slot->mState != SlotState::Stopped && std::exchange(slot->mPropsDirty, false)) - slot->updateProps(context); + if(slot.mState != SlotState::Stopped && std::exchange(slot.mPropsDirty, false)) + slot.updateProps(context); } } } @@ -1007,11 +1000,11 @@ EffectSlotSubList::~EffectSlotSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - std::destroy_at(EffectSlots+idx); + std::destroy_at(al::to_address(EffectSlots->begin() + idx)); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; - al_free(EffectSlots); + SubListAllocator{}.deallocate(EffectSlots, 1); EffectSlots = nullptr; } @@ -1530,7 +1523,8 @@ void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot) std::lock_guard<std::mutex> effect_slot_lock{context.mEffectSlotLock}; - if(ReadRef(effect_slot.ref) != 0) { + if(effect_slot.ref.load(std::memory_order_relaxed) != 0) + { ERR(EAX_PREFIX "Deleting in-use effect slot %u.\n", effect_slot.id); return; } diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 1ad0ffc4..6946591e 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -3,6 +3,7 @@ #include <atomic> #include <cstddef> +#include <cstdint> #include <string_view> #include "AL/al.h" @@ -12,6 +13,7 @@ #include "alc/device.h" #include "alc/effects/base.h" #include "almalloc.h" +#include "alnumeric.h" #include "atomic.h" #include "core/effectslot.h" #include "intrusive_ptr.h" @@ -63,7 +65,7 @@ struct ALeffectslot { SlotState mState{SlotState::Initial}; - RefCount ref{0u}; + std::atomic<ALuint> ref{0u}; EffectSlot *mSlot{nullptr}; @@ -81,20 +83,17 @@ struct ALeffectslot { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - /* This can be new'd for the context's default effect slot. */ - DEF_NEWDEL(ALeffectslot) - #ifdef ALSOFT_EAX public: void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index); - EaxFxSlotIndexValue eax_get_index() const noexcept { return eax_fx_slot_index_; } - const EAX50FXSLOTPROPERTIES& eax_get_eax_fx_slot() const noexcept + [[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(); @@ -282,14 +281,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; @@ -312,7 +311,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); @@ -370,4 +369,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 diff --git a/al/buffer.cpp b/al/buffer.cpp index 7d043036..b7ed5b32 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -68,6 +68,8 @@ namespace { +using SubListAllocator = typename al::allocator<std::array<ALbuffer,64>>; + std::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout) { switch(layout) @@ -178,21 +180,21 @@ bool EnsureBuffers(ALCdevice *device, size_t needed) [](size_t cur, const BufferSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - while(needed > count) - { - if(device->BufferList.size() >= 1<<25) UNLIKELY - return false; - - device->BufferList.emplace_back(); - auto sublist = device->BufferList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Buffers = static_cast<ALbuffer*>(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64)); - if(!sublist->Buffers) UNLIKELY + try { + while(needed > count) { - device->BufferList.pop_back(); - return false; + if(device->BufferList.size() >= 1<<25) UNLIKELY + return false; + + BufferSubList sublist{}; + sublist.FreeMask = ~0_u64; + sublist.Buffers = SubListAllocator{}.allocate(1); + device->BufferList.emplace_back(std::move(sublist)); + count += 64; } - count += 64; + } + catch(...) { + return false; } return true; } @@ -206,7 +208,7 @@ ALbuffer *AllocBuffer(ALCdevice *device) auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); ASSUME(slidx < 64); - ALbuffer *buffer{al::construct_at(sublist->Buffers + slidx)}; + ALbuffer *buffer{al::construct_at(al::to_address(sublist->Buffers->begin() + slidx))}; /* Add 1 to avoid buffer ID 0. */ buffer->id = ((lidx<<6) | slidx) + 1; @@ -243,7 +245,7 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) BufferSubList &sublist = device->BufferList[lidx]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Buffers + slidx; + return al::to_address(sublist.Buffers->begin() + slidx); } @@ -286,7 +288,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, const FmtChannels DstChannels, const FmtType DstType, const std::byte *SrcData, ALbitfieldSOFT access) { - if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY + if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u", ALBuf->id); @@ -393,7 +395,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, const FmtChannels DstChannels, const FmtType DstType, ALBUFFERCALLBACKTYPESOFT callback, void *userptr) { - if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY + if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY return context->setError(AL_INVALID_OPERATION, "Modifying callback for in-use buffer %u", ALBuf->id); @@ -402,6 +404,10 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, const ALuint unpackalign{ALBuf->UnpackAlign}; const ALuint align{SanitizeAlignment(DstType, unpackalign)}; + if(align < 1) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %u for %s samples", + unpackalign, NameFromFormat(DstType)); + const ALuint BlockSize{ChannelsFromFmt(DstChannels, ambiorder) * ((DstType == FmtIMA4) ? (align-1)/2 + 4 : (DstType == FmtMSADPCM) ? (align-2)/2 + 7 : @@ -445,7 +451,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, const FmtChannels DstChannels, const FmtType DstType, std::byte *sdata, const ALuint sdatalen) { - if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY + if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u", ALBuf->id); @@ -711,7 +717,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteBuffersDirect(ALCcontext *context, ALsizei context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); return false; } - if(ReadRef(ALBuf->ref) != 0) UNLIKELY + if(ALBuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY { context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); return false; @@ -826,7 +832,8 @@ FORCE_ALIGN void* AL_APIENTRY alMapBufferDirectSOFT(ALCcontext *context, ALuint else { ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY + if(albuf->ref.load(std::memory_order_relaxed) != 0 + && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY context->setError(AL_INVALID_OPERATION, "Mapping in-use buffer %u without persistent mapping", buffer); else if(albuf->MappedAccess != 0) UNLIKELY @@ -1042,7 +1049,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer, break; case AL_AMBISONIC_LAYOUT_SOFT: - if(ReadRef(albuf->ref) != 0) UNLIKELY + if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic layout", buffer); else if(const auto layout = AmbiLayoutFromEnum(value)) @@ -1052,7 +1059,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer, break; case AL_AMBISONIC_SCALING_SOFT: - if(ReadRef(albuf->ref) != 0) UNLIKELY + if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic scaling", buffer); else if(const auto scaling = AmbiScalingFromEnum(value)) @@ -1116,7 +1123,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferivDirect(ALCcontext *context, ALuint buffer else switch(param) { case AL_LOOP_POINTS_SOFT: - if(ReadRef(albuf->ref) != 0) UNLIKELY + if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); else if(values[0] < 0 || values[0] >= values[1] @@ -1366,7 +1373,7 @@ FORCE_ALIGN void AL_APIENTRY alGetBufferPtrDirectSOFT(ALCcontext *context, ALuin else switch(param) { case AL_BUFFER_CALLBACK_FUNCTION_SOFT: - *value = al::bit_cast<void*>(albuf->mCallback); + *value = reinterpret_cast<void*>(albuf->mCallback); break; case AL_BUFFER_CALLBACK_USER_PARAM_SOFT: *value = albuf->mUserData; @@ -1480,11 +1487,11 @@ BufferSubList::~BufferSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - std::destroy_at(Buffers+idx); + std::destroy_at(al::to_address(Buffers->begin() + idx)); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; - al_free(Buffers); + SubListAllocator{}.deallocate(Buffers, 1); Buffers = nullptr; } diff --git a/al/buffer.h b/al/buffer.h index f936cf98..b9e59d68 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -3,12 +3,14 @@ #include <atomic> #include <cstddef> +#include <cstdint> #include <string_view> #include "AL/al.h" #include "alc/inprogext.h" #include "almalloc.h" +#include "alnumeric.h" #include "atomic.h" #include "core/buffer_storage.h" #include "vector.h" @@ -43,14 +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}; static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC #ifdef ALSOFT_EAX EaxStorage eax_x_ram_mode{EaxStorage::Automatic}; @@ -58,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 diff --git a/al/debug.cpp b/al/debug.cpp index b76ec9af..cd79c148 100644 --- a/al/debug.cpp +++ b/al/debug.cpp @@ -4,10 +4,10 @@ #include <algorithm> #include <array> +#include <cstddef> #include <cstring> #include <mutex> #include <optional> -#include <stddef.h> #include <stdexcept> #include <string> #include <utility> diff --git a/al/direct_defs.h b/al/direct_defs.h index 7526b611..a1999668 100644 --- a/al/direct_defs.h +++ b/al/direct_defs.h @@ -12,7 +12,7 @@ constexpr void DefaultVal() noexcept { } } // namespace detail_ #define DECL_FUNC(R, Name) \ -R AL_APIENTRY Name(void) noexcept \ +auto AL_APIENTRY Name() noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -20,7 +20,7 @@ R AL_APIENTRY Name(void) noexcept \ } #define DECL_FUNC1(R, Name, T1) \ -R AL_APIENTRY Name(T1 a) noexcept \ +auto AL_APIENTRY Name(T1 a) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -28,7 +28,7 @@ R AL_APIENTRY Name(T1 a) noexcept \ } #define DECL_FUNC2(R, Name, T1, T2) \ -R AL_APIENTRY Name(T1 a, T2 b) noexcept \ +auto AL_APIENTRY Name(T1 a, T2 b) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -36,7 +36,7 @@ R AL_APIENTRY Name(T1 a, T2 b) noexcept \ } #define DECL_FUNC3(R, Name, T1, T2, T3) \ -R AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept \ +auto AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -44,7 +44,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept \ } #define DECL_FUNC4(R, Name, T1, T2, T3, T4) \ -R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept \ +auto AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -52,7 +52,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept \ } #define DECL_FUNC5(R, Name, T1, T2, T3, T4, T5) \ -R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \ +auto AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -61,7 +61,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \ #define DECL_FUNCEXT(R, Name,Ext) \ -R AL_APIENTRY Name##Ext(void) noexcept \ +auto AL_APIENTRY Name##Ext() noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -69,7 +69,7 @@ R AL_APIENTRY Name##Ext(void) noexcept \ } #define DECL_FUNCEXT1(R, Name,Ext, T1) \ -R AL_APIENTRY Name##Ext(T1 a) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -77,7 +77,7 @@ R AL_APIENTRY Name##Ext(T1 a) noexcept \ } #define DECL_FUNCEXT2(R, Name,Ext, T1, T2) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -85,7 +85,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept \ } #define DECL_FUNCEXT3(R, Name,Ext, T1, T2, T3) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -93,7 +93,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept \ } #define DECL_FUNCEXT4(R, Name,Ext, T1, T2, T3, T4) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -101,7 +101,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept \ } #define DECL_FUNCEXT5(R, Name,Ext, T1, T2, T3, T4, T5) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -109,7 +109,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \ } #define DECL_FUNCEXT6(R, Name,Ext, T1, T2, T3, T4, T5, T6) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ @@ -117,7 +117,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept \ } #define DECL_FUNCEXT8(R, Name,Ext, T1, T2, T3, T4, T5, T6, T7, T8) \ -R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h) noexcept \ +auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h) noexcept -> R \ { \ auto context = GetContextRef(); \ if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ diff --git a/al/eax/api.h b/al/eax/api.h index 18d93ef8..0b019f11 100644 --- a/al/eax/api.h +++ b/al/eax/api.h @@ -22,12 +22,12 @@ #ifndef _WIN32 -typedef struct _GUID { +using GUID = struct _GUID { 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; +}; inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept { return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; } @@ -362,6 +362,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; @@ -654,11 +655,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. diff --git a/al/eax/call.cpp b/al/eax/call.cpp index 689d5cf1..013a3992 100644 --- a/al/eax/call.cpp +++ b/al/eax/call.cpp @@ -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} { diff --git a/al/eax/call.h b/al/eax/call.h index 45ff328c..e7f2329f 100644 --- a/al/eax/call.h +++ b/al/eax/call.h @@ -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,7 +49,7 @@ 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(); @@ -59,22 +59,22 @@ public: } template<typename TValue> - al::span<TValue> get_values() const + [[nodiscard]] auto get_values() const -> al::span<TValue> { 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; diff --git a/al/eax/effect.h b/al/eax/effect.h index afe4d94d..a735fe6c 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -100,7 +100,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); @@ -110,16 +109,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> @@ -144,51 +140,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: @@ -233,51 +315,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) { - 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; } @@ -285,9 +355,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; } @@ -295,47 +365,20 @@ public: } -#define EAXCALL(Props, Callable, ...) \ - if(std::holds_alternative<EAXREVERBPROPERTIES>(Props)) \ - return Callable<EaxReverbCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXCHORUSPROPERTIES>(Props)) \ - return Callable<EaxChorusCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXAUTOWAHPROPERTIES>(Props)) \ - return Callable<EaxAutowahCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXAGCCOMPRESSORPROPERTIES>(Props)) \ - return Callable<EaxCompressorCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXDISTORTIONPROPERTIES>(Props)) \ - return Callable<EaxDistortionCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXECHOPROPERTIES>(Props)) \ - return Callable<EaxEchoCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXEQUALIZERPROPERTIES>(Props)) \ - return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXFLANGERPROPERTIES>(Props)) \ - return Callable<EaxFlangerCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXFREQUENCYSHIFTERPROPERTIES>(Props)) \ - return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXRINGMODULATORPROPERTIES>(Props)) \ - return Callable<EaxModulatorCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXPITCHSHIFTERPROPERTIES>(Props)) \ - return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \ - if(std::holds_alternative<EAXVOCALMORPHERPROPERTIES>(Props)) \ - 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, 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; } @@ -343,32 +386,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, call_get, call, props); } + { + return std::visit([&](auto &arg) + { return CommitterFor<decltype(arg)>::Get(call, arg); }, + props); + } void get(const EaxCall &call) { switch(call.get_version()) { - case 1: call_get<EaxReverbCommitter>(call, state1_.d); break; - case 2: call_get<EaxReverbCommitter>(call, state2_.d); break; - case 3: call_get<EaxReverbCommitter>(call, state3_.d); break; + case 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, call_commit, props); } + { + return std::visit([&](auto &arg) + { return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); }, + props); + } bool commit(int eax_version) { @@ -383,15 +426,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; diff --git a/al/eax/fx_slots.h b/al/eax/fx_slots.h index 18b2d3ad..b7ed1031 100644 --- a/al/eax/fx_slots.h +++ b/al/eax/fx_slots.h @@ -25,11 +25,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 +37,7 @@ private: [[noreturn]] - static void fail( - const char* message); + static void fail(const char* message); void initialize_fx_slots(ALCcontext& al_context); }; // EaxFxSlots diff --git a/al/eax/globals.h b/al/eax/globals.h index ff05d009..4d501ff9 100644 --- a/al/eax/globals.h +++ b/al/eax/globals.h @@ -3,6 +3,7 @@ inline bool eax_g_is_enabled{true}; +/* NOLINTBEGIN(*-avoid-c-arrays) */ inline constexpr char eax1_ext_name[]{"EAX"}; inline constexpr char eax2_ext_name[]{"EAX2.0"}; inline constexpr char eax3_ext_name[]{"EAX3.0"}; @@ -16,5 +17,6 @@ inline constexpr char eax_eax_get_func_name[]{"EAXGet"}; inline constexpr char eax_eax_set_buffer_mode_func_name[]{"EAXSetBufferMode"}; inline constexpr char eax_eax_get_buffer_mode_func_name[]{"EAXGetBufferMode"}; +/* NOLINTEND(*-avoid-c-arrays) */ #endif // !EAX_GLOBALS_INCLUDED diff --git a/al/effect.cpp b/al/effect.cpp index 3e48e91b..071b32c6 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -58,7 +58,7 @@ #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 }, @@ -75,9 +75,7 @@ const EffectList gEffectList[16]{ { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_SOFT }, -}; - -bool DisabledEffects[MAX_EFFECTS]; +}}; effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code} @@ -91,72 +89,36 @@ 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_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable }, -}; - - -void ALeffect_setParami(ALeffect *effect, ALenum param, int value) -{ effect->vtab->setParami(&effect->Props, param, value); } -void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values) -{ effect->vtab->setParamiv(&effect->Props, param, values); } -void ALeffect_setParamf(ALeffect *effect, ALenum param, float value) -{ effect->vtab->setParamf(&effect->Props, param, value); } -void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values) -{ effect->vtab->setParamfv(&effect->Props, param, values); } +using SubListAllocator = typename al::allocator<std::array<ALeffect,64>>; -void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value) -{ effect->vtab->getParami(&effect->Props, param, value); } -void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values) -{ effect->vtab->getParamiv(&effect->Props, param, values); } -void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value) -{ effect->vtab->getParamf(&effect->Props, param, value); } -void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values) -{ effect->vtab->getParamfv(&effect->Props, param, values); } - - -const EffectPropsItem *getEffectPropsItemByType(ALenum type) +auto GetDefaultProps(ALenum type) -> 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) { - const EffectPropsItem *item{getEffectPropsItemByType(type)}; - if(item) - { - effect->Props = item->DefaultProps; - effect->vtab = &item->Vtable; - } - else - { - effect->Props = EffectProps{}; - effect->vtab = &NullEffectVtable; - } + effect->Props = GetDefaultProps(type); effect->type = type; } @@ -166,21 +128,21 @@ bool EnsureEffects(ALCdevice *device, size_t needed) [](size_t cur, const EffectSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - while(needed > count) - { - if(device->EffectList.size() >= 1<<25) UNLIKELY - return false; - - device->EffectList.emplace_back(); - auto sublist = device->EffectList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64)); - if(!sublist->Effects) UNLIKELY + try { + while(needed > count) { - device->EffectList.pop_back(); - return false; + if(device->EffectList.size() >= 1<<25) UNLIKELY + return false; + + EffectSubList sublist{}; + sublist.FreeMask = ~0_u64; + sublist.Effects = SubListAllocator{}.allocate(1); + device->EffectList.emplace_back(std::move(sublist)); + count += 64; } - count += 64; + } + catch(...) { + return false; } return true; } @@ -194,7 +156,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. */ @@ -228,7 +190,7 @@ 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 @@ -328,7 +290,7 @@ FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, { for(const EffectList &effectitem : gEffectList) { - if(value == effectitem.val && !DisabledEffects[effectitem.type]) + if(value == effectitem.val && !DisabledEffects.test(effectitem.type)) { isOk = true; break; @@ -344,7 +306,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, else try { /* Call the appropriate handler */ - ALeffect_setParami(aleffect, param, value); + std::visit([aleffect,param,value](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbSetParami(arg, param, value); + } + return EffectHandler::SetParami(arg, param, value); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -371,7 +342,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect else try { /* Call the appropriate handler */ - ALeffect_setParamiv(aleffect, param, values); + std::visit([aleffect,param,values](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbSetParamiv(arg, param, values); + } + return EffectHandler::SetParamiv(arg, param, values); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -391,7 +371,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, else try { /* Call the appropriate handler */ - ALeffect_setParamf(aleffect, param, value); + std::visit([aleffect,param,value](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbSetParamf(arg, param, value); + } + return EffectHandler::SetParamf(arg, param, value); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -411,7 +400,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect else try { /* Call the appropriate handler */ - ALeffect_setParamfv(aleffect, param, values); + std::visit([aleffect,param,values](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbSetParamfv(arg, param, values); + } + return EffectHandler::SetParamfv(arg, param, values); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -433,7 +431,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effe else try { /* Call the appropriate handler */ - ALeffect_getParami(aleffect, param, value); + std::visit([aleffect,param,value](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbGetParami(arg, param, value); + } + return EffectHandler::GetParami(arg, param, value); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -460,7 +467,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint eff else try { /* Call the appropriate handler */ - ALeffect_getParamiv(aleffect, param, values); + std::visit([aleffect,param,values](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbGetParamiv(arg, param, values); + } + return EffectHandler::GetParamiv(arg, param, values); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -480,7 +496,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effe else try { /* Call the appropriate handler */ - ALeffect_getParamf(aleffect, param, value); + std::visit([aleffect,param,value](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbGetParamf(arg, param, value); + } + return EffectHandler::GetParamf(arg, param, value); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -500,7 +525,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint eff else try { /* Call the appropriate handler */ - ALeffect_getParamfv(aleffect, param, values); + std::visit([aleffect,param,values](auto &arg) + { + using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>; + if constexpr(std::is_same_v<Type,ReverbProps>) + { + if(aleffect->type == AL_EFFECT_REVERB) + return EffectHandler::StdReverbGetParamfv(arg, param, values); + } + return EffectHandler::GetParamfv(arg, param, values); + }, aleffect->Props); } catch(effect_exception &e) { context->setError(e.errorCode(), "%s", e.what()); @@ -535,20 +569,21 @@ EffectSubList::~EffectSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - std::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), @@ -687,48 +722,47 @@ void LoadReverbPreset(const char *name, ALeffect *effect) 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) 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; + 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; } @@ -742,7 +776,7 @@ bool IsValidEffectType(ALenum type) noexcept for(const auto &effect_item : gEffectList) { - if(type == effect_item.val && !DisabledEffects[effect_item.type]) + if(type == effect_item.val && !DisabledEffects.test(effect_item.type)) return true; } return false; diff --git a/al/effect.h b/al/effect.h index 27e9dd72..8f069bee 100644 --- a/al/effect.h +++ b/al/effect.h @@ -1,6 +1,9 @@ #ifndef AL_EFFECT_H #define AL_EFFECT_H +#include <array> +#include <bitset> +#include <cstdint> #include <string_view> #include "AL/al.h" @@ -8,6 +11,8 @@ #include "al/effects/effects.h" #include "alc/effects/base.h" +#include "almalloc.h" +#include "alnumeric.h" enum { @@ -29,16 +34,14 @@ 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; struct ALeffect { @@ -47,14 +50,12 @@ struct ALeffect { EffectProps Props{}; - const EffectVtable *vtab{nullptr}; - /* Self ID */ ALuint id{0u}; static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC }; void InitEffect(ALeffect *effect); @@ -63,4 +64,19 @@ void LoadReverbPreset(const char *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 diff --git a/al/effects/autowah.cpp b/al/effects/autowah.cpp index 1a8b43fc..68704c11 100644 --- a/al/effects/autowah.cpp +++ b/al/effects/autowah.cpp @@ -20,100 +20,87 @@ namespace { -void Autowah_setParamf(EffectProps *props, ALenum param, float val) +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 EffectHandler::SetParami(AutowahProps&, ALenum param, int) +{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; } +void EffectHandler::SetParamiv(AutowahProps&, ALenum param, const int*) +{ + throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", + param}; +} + +void EffectHandler::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 EffectHandler::SetParamfv(AutowahProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Autowah_setParami(EffectProps*, ALenum param, int) +void EffectHandler::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 EffectHandler::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 EffectHandler::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 EffectHandler::GetParamfv(const AutowahProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } #ifdef ALSOFT_EAX namespace { @@ -189,25 +176,25 @@ template<> throw Exception{message}; } -template<> -bool AutowahCommitter::commit(const EaxEffectProps &props) +bool EaxAutowahCommitter::commit(const EAXAUTOWAHPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXAUTOWAHPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - - auto &eaxprops = std::get<EAXAUTOWAHPROPERTIES>(props); - mAlProps.Autowah.AttackTime = eaxprops.flAttackTime; - mAlProps.Autowah.ReleaseTime = eaxprops.flReleaseTime; - mAlProps.Autowah.Resonance = level_mb_to_gain(static_cast<float>(eaxprops.lResonance)); - mAlProps.Autowah.PeakGain = level_mb_to_gain(static_cast<float>(eaxprops.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) { static constexpr EAXAUTOWAHPROPERTIES defprops{[] { @@ -221,10 +208,8 @@ void AutowahCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxAutowahCommitter::Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props) { - auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAUTOWAH_NONE: break; @@ -237,10 +222,8 @@ void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxAutowahCommitter::Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props) { - auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAUTOWAH_NONE: break; diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp index 90b38e4d..913d1215 100644 --- a/al/effects/chorus.cpp +++ b/al/effects/chorus.cpp @@ -46,13 +46,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) +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; +} + +EffectProps genDefaultFlangerProps() noexcept +{ + FlangerProps 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 EffectHandler::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 +88,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 EffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } +void EffectHandler::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 EffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Chorus_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::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 EffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } +void EffectHandler::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); } +void EffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals) +{ 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; -} +const EffectProps FlangerEffectProps{genDefaultFlangerProps()}; -void Flanger_setParami(EffectProps *props, ALenum param, int val) +void EffectHandler::SetParami(FlangerProps &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,124 +178,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 EffectHandler::SetParamiv(FlangerProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } +void EffectHandler::SetParamf(FlangerProps &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 EffectHandler::SetParamfv(FlangerProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Flanger_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::GetParami(const FlangerProps &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 EffectHandler::GetParamiv(const FlangerProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } +void EffectHandler::GetParamf(const FlangerProps &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 EffectHandler::GetParamfv(const FlangerProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } #ifdef ALSOFT_EAX namespace { struct EaxChorusTraits { - using Props = EAXCHORUSPROPERTIES; + using EaxProps = EAXCHORUSPROPERTIES; using Committer = EaxChorusCommitter; + using AlProps = ChorusProps; static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; } @@ -357,8 +322,9 @@ struct EaxChorusTraits { }; // EaxChorusTraits struct EaxFlangerTraits { - using Props = EAXFLANGERPROPERTIES; + using EaxProps = EAXFLANGERPROPERTIES; using Committer = EaxFlangerCommitter; + using AlProps = FlangerProps; static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; } @@ -424,7 +390,9 @@ struct EaxFlangerTraits { template<typename TTraits> struct ChorusFlangerEffect { using Traits = TTraits; + using EaxProps = typename Traits::EaxProps; using Committer = typename Traits::Committer; + using AlProps = typename Traits::AlProps; using Exception = typename Committer::Exception; struct WaveformValidator { @@ -494,7 +462,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); @@ -508,7 +476,7 @@ struct ChorusFlangerEffect { public: static void SetDefaults(EaxEffectProps &props) { - auto&& all = props.emplace<typename Traits::Props>(); + auto&& all = props.emplace<EaxProps>(); all.ulWaveform = Traits::eax_default_waveform(); all.lPhase = Traits::eax_default_phase(); all.flRate = Traits::eax_default_rate(); @@ -518,102 +486,83 @@ public: } - static void Get(const EaxCall &call, const EaxEffectProps &props) + static void Get(const EaxCall &call, const EaxProps &all) { - auto&& all = std::get<typename Traits::Props>(props); 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 = std::get<typename Traits::Props>(props); 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_, AlProps &al_props_) { - if(props == props_) + if(auto *cur = std::get_if<EaxProps>(&props_); cur && *cur == props) return false; props_ = props; - auto&& dst = std::get<typename Traits::Props>(props); - 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; } @@ -638,29 +587,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); @@ -679,29 +624,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<FlangerProps>()); } -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); diff --git a/al/effects/compressor.cpp b/al/effects/compressor.cpp index ca8af84f..9fcc8c61 100644 --- a/al/effects/compressor.cpp +++ b/al/effects/compressor.cpp @@ -16,14 +16,25 @@ namespace { -void Compressor_setParami(EffectProps *props, ALenum param, int val) +EffectProps genDefaultProps() noexcept +{ + CompressorProps props{}; + props.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; + return props; +} + +} // namespace + +const EffectProps CompressorEffectProps{genDefaultProps()}; + +void EffectHandler::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,22 +42,22 @@ 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 EffectHandler::SetParamiv(CompressorProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } +void EffectHandler::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 EffectHandler::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 EffectHandler::GetParami(const CompressorProps &props, ALenum param, int *val) { switch(param) { case AL_COMPRESSOR_ONOFF: - *val = props->Compressor.OnOff; + *val = props.OnOff; break; default: @@ -54,28 +65,16 @@ void Compressor_getParami(const EffectProps *props, ALenum param, int *val) 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 EffectHandler::GetParamiv(const CompressorProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } +void EffectHandler::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 EffectHandler::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,28 +114,24 @@ template<> throw Exception{message}; } -template<> -bool CompressorCommitter::commit(const EaxEffectProps &props) +bool EaxCompressorCommitter::commit(const EAXAGCCOMPRESSORPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXAGCCOMPRESSORPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; + mAlProps = CompressorProps{props.ulOnOff != 0}; - mAlProps.Compressor.OnOff = (std::get<EAXAGCCOMPRESSORPROPERTIES>(props).ulOnOff != 0); return true; } -template<> -void CompressorCommitter::SetDefaults(EaxEffectProps &props) +void EaxCompressorCommitter::SetDefaults(EaxEffectProps &props) { props = EAXAGCCOMPRESSORPROPERTIES{EAXAGCCOMPRESSOR_DEFAULTONOFF}; } -template<> -void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxCompressorCommitter::Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props) { - auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAGCCOMPRESSOR_NONE: break; @@ -146,10 +141,8 @@ void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxCompressorCommitter::Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props) { - auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAGCCOMPRESSOR_NONE: break; diff --git a/al/effects/convolution.cpp b/al/effects/convolution.cpp index 9c091e53..1f8d1111 100644 --- a/al/effects/convolution.cpp +++ b/al/effects/convolution.cpp @@ -12,33 +12,45 @@ namespace { -void Convolution_setParami(EffectProps* /*props*/, ALenum param, int /*val*/) +EffectProps genDefaultProps() noexcept +{ + ConvolutionProps props{}; + props.OrientAt = {0.0f, 0.0f, -1.0f}; + props.OrientUp = {0.0f, 1.0f, 0.0f}; + return props; +} + +} // namespace + +const EffectProps ConvolutionEffectProps{genDefaultProps()}; + +void EffectHandler::SetParami(ConvolutionProps& /*props*/, ALenum param, int /*val*/) { switch(param) { default: - throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", + throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x", param}; } } -void Convolution_setParamiv(EffectProps *props, ALenum param, const int *vals) +void EffectHandler::SetParamiv(ConvolutionProps &props, ALenum param, const int *vals) { switch(param) { default: - Convolution_setParami(props, param, vals[0]); + SetParami(props, param, vals[0]); } } -void Convolution_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/) +void EffectHandler::SetParamf(ConvolutionProps& /*props*/, ALenum param, float /*val*/) { switch(param) { default: - throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", + throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x", param}; } } -void Convolution_setParamfv(EffectProps *props, ALenum param, const float *values) +void EffectHandler::SetParamfv(ConvolutionProps &props, ALenum param, const float *values) { switch(param) { @@ -47,73 +59,59 @@ void Convolution_setParamfv(EffectProps *props, ALenum param, const float *value && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) throw effect_exception{AL_INVALID_VALUE, "Property 0x%04x value out of range", param}; - props->Convolution.OrientAt[0] = values[0]; - props->Convolution.OrientAt[1] = values[1]; - props->Convolution.OrientAt[2] = values[2]; - props->Convolution.OrientUp[0] = values[3]; - props->Convolution.OrientUp[1] = values[4]; - props->Convolution.OrientUp[2] = values[5]; + props.OrientAt[0] = values[0]; + props.OrientAt[1] = values[1]; + props.OrientAt[2] = values[2]; + props.OrientUp[0] = values[3]; + props.OrientUp[1] = values[4]; + props.OrientUp[2] = values[5]; break; default: - Convolution_setParamf(props, param, values[0]); + SetParamf(props, param, values[0]); } } -void Convolution_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/) +void EffectHandler::GetParami(const ConvolutionProps& /*props*/, ALenum param, int* /*val*/) { switch(param) { default: - throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", + throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x", param}; } } -void Convolution_getParamiv(const EffectProps *props, ALenum param, int *vals) +void EffectHandler::GetParamiv(const ConvolutionProps &props, ALenum param, int *vals) { switch(param) { default: - Convolution_getParami(props, param, vals); + GetParami(props, param, vals); } } -void Convolution_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/) +void EffectHandler::GetParamf(const ConvolutionProps& /*props*/, ALenum param, float* /*val*/) { switch(param) { default: - throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", + throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x", param}; } } -void Convolution_getParamfv(const EffectProps *props, ALenum param, float *values) +void EffectHandler::GetParamfv(const ConvolutionProps &props, ALenum param, float *values) { switch(param) { case AL_CONVOLUTION_ORIENTATION_SOFT: - values[0] = props->Convolution.OrientAt[0]; - values[1] = props->Convolution.OrientAt[1]; - values[2] = props->Convolution.OrientAt[2]; - values[3] = props->Convolution.OrientUp[0]; - values[4] = props->Convolution.OrientUp[1]; - values[5] = props->Convolution.OrientUp[2]; + values[0] = props.OrientAt[0]; + values[1] = props.OrientAt[1]; + values[2] = props.OrientAt[2]; + values[3] = props.OrientUp[0]; + values[4] = props.OrientUp[1]; + values[5] = props.OrientUp[2]; break; default: - Convolution_getParamf(props, param, values); + GetParamf(props, param, values); } } - -EffectProps genDefaultProps() noexcept -{ - EffectProps props{}; - props.Convolution.OrientAt = {0.0f, 0.0f, -1.0f}; - props.Convolution.OrientUp = {0.0f, 1.0f, 0.0f}; - return props; -} - -} // namespace - -DEFINE_ALEFFECT_VTABLE(Convolution); - -const EffectProps ConvolutionEffectProps{genDefaultProps()}; diff --git a/al/effects/dedicated.cpp b/al/effects/dedicated.cpp index db57003c..518c224c 100644 --- a/al/effects/dedicated.cpp +++ b/al/effects/dedicated.cpp @@ -12,61 +12,115 @@ namespace { -void Dedicated_setParami(EffectProps*, ALenum param, int) +EffectProps genDefaultDialogProps() noexcept +{ + DedicatedDialogProps props{}; + props.Gain = 1.0f; + return props; +} + +EffectProps genDefaultLfeProps() noexcept +{ + DedicatedLfeProps props{}; + props.Gain = 1.0f; + return props; +} + +} // namespace + +const EffectProps DedicatedDialogEffectProps{genDefaultDialogProps()}; + +void EffectHandler::SetParami(DedicatedDialogProps&, 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 EffectHandler::SetParamiv(DedicatedDialogProps&, 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 EffectHandler::SetParamf(DedicatedDialogProps &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 EffectHandler::SetParamfv(DedicatedDialogProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Dedicated_getParami(const EffectProps*, ALenum param, int*) +void EffectHandler::GetParami(const DedicatedDialogProps&, 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 EffectHandler::GetParamiv(const DedicatedDialogProps&, 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 EffectHandler::GetParamf(const DedicatedDialogProps &props, ALenum param, float *val) { switch(param) { case AL_DEDICATED_GAIN: - *val = props->Dedicated.Gain; + *val = props.Gain; break; default: throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param}; } } -void Dedicated_getParamfv(const EffectProps *props, ALenum param, float *vals) -{ Dedicated_getParamf(props, param, vals); } +void EffectHandler::GetParamfv(const DedicatedDialogProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -EffectProps genDefaultProps() noexcept + +const EffectProps DedicatedLfeEffectProps{genDefaultLfeProps()}; + +void EffectHandler::SetParami(DedicatedLfeProps&, ALenum param, int) +{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; } +void EffectHandler::SetParamiv(DedicatedLfeProps&, ALenum param, const int*) { - EffectProps props{}; - props.Dedicated.Gain = 1.0f; - return props; + throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", + param}; } +void EffectHandler::SetParamf(DedicatedLfeProps &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.Gain = val; + break; -} // namespace + default: + throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param}; + } +} +void EffectHandler::SetParamfv(DedicatedLfeProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -DEFINE_ALEFFECT_VTABLE(Dedicated); +void EffectHandler::GetParami(const DedicatedLfeProps&, ALenum param, int*) +{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; } +void EffectHandler::GetParamiv(const DedicatedLfeProps&, ALenum param, int*) +{ + throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", + param}; +} +void EffectHandler::GetParamf(const DedicatedLfeProps &props, ALenum param, float *val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + *val = props.Gain; + break; -const EffectProps DedicatedEffectProps{genDefaultProps()}; + default: + throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param}; + } +} +void EffectHandler::GetParamfv(const DedicatedLfeProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } diff --git a/al/effects/distortion.cpp b/al/effects/distortion.cpp index e046d8e7..534b6c24 100644 --- a/al/effects/distortion.cpp +++ b/al/effects/distortion.cpp @@ -16,108 +16,93 @@ namespace { -void Distortion_setParami(EffectProps*, ALenum param, int) +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 EffectHandler::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 EffectHandler::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 EffectHandler::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 EffectHandler::SetParamfv(DistortionProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Distortion_getParami(const EffectProps*, ALenum param, int*) +void EffectHandler::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 EffectHandler::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 EffectHandler::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); } - -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; -} +void EffectHandler::GetParamfv(const DistortionProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -} // namespace - -DEFINE_ALEFFECT_VTABLE(Distortion); - -const EffectProps DistortionEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -204,26 +189,26 @@ template<> throw Exception{message}; } -template<> -bool DistortionCommitter::commit(const EaxEffectProps &props) +bool EaxDistortionCommitter::commit(const EAXDISTORTIONPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXDISTORTIONPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - - auto &eaxprops = std::get<EAXDISTORTIONPROPERTIES>(props); - mAlProps.Distortion.Edge = eaxprops.flEdge; - mAlProps.Distortion.Gain = level_mb_to_gain(static_cast<float>(eaxprops.lGain)); - mAlProps.Distortion.LowpassCutoff = eaxprops.flLowPassCutOff; - mAlProps.Distortion.EQCenter = eaxprops.flEQCenter; - mAlProps.Distortion.EQBandwidth = eaxprops.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) { static constexpr EAXDISTORTIONPROPERTIES defprops{[] { @@ -238,10 +223,8 @@ void DistortionCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxDistortionCommitter::Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props) { - auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_); switch(call.get_property_id()) { case EAXDISTORTION_NONE: break; @@ -255,10 +238,8 @@ void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxDistortionCommitter::Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props) { - auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_); switch(call.get_property_id()) { case EAXDISTORTION_NONE: break; diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp index 48aacef3..9412039b 100644 --- a/al/effects/echo.cpp +++ b/al/effects/echo.cpp @@ -19,102 +19,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) +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 EffectHandler::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 EffectHandler::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 EffectHandler::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 EffectHandler::SetParamfv(EchoProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Echo_getParami(const EffectProps*, ALenum param, int*) +void EffectHandler::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 EffectHandler::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 EffectHandler::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); } - -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; -} +void EffectHandler::GetParamfv(const EchoProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -} // namespace - -DEFINE_ALEFFECT_VTABLE(Echo); - -const EffectProps EchoEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -201,26 +186,26 @@ template<> throw Exception{message}; } -template<> -bool EchoCommitter::commit(const EaxEffectProps &props) +bool EaxEchoCommitter::commit(const EAXECHOPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXECHOPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - - auto &eaxprops = std::get<EAXECHOPROPERTIES>(props); - mAlProps.Echo.Delay = eaxprops.flDelay; - mAlProps.Echo.LRDelay = eaxprops.flLRDelay; - mAlProps.Echo.Damping = eaxprops.flDamping; - mAlProps.Echo.Feedback = eaxprops.flFeedback; - mAlProps.Echo.Spread = eaxprops.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) { static constexpr EAXECHOPROPERTIES defprops{[] { @@ -235,10 +220,8 @@ void EchoCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxEchoCommitter::Get(const EaxCall &call, const EAXECHOPROPERTIES &props) { - auto &props = std::get<EAXECHOPROPERTIES>(props_); switch(call.get_property_id()) { case EAXECHO_NONE: break; @@ -252,10 +235,8 @@ void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxEchoCommitter::Set(const EaxCall &call, EAXECHOPROPERTIES &props) { - auto &props = std::get<EAXECHOPROPERTIES>(props_); switch(call.get_property_id()) { case EAXECHO_NONE: break; diff --git a/al/effects/effects.h b/al/effects/effects.h index 9d57dd82..38d47f86 100644 --- a/al/effects/effects.h +++ b/al/effects/effects.h @@ -3,52 +3,69 @@ #include "AL/al.h" +#include "core/effects/base.h" #include "core/except.h" #ifdef ALSOFT_EAX #include "al/eax/effect.h" #endif // ALSOFT_EAX -union EffectProps; +struct EffectHandler { +#define DECL_HANDLER(T) \ + static void SetParami(T &props, ALenum param, int val); \ + static void SetParamiv(T &props, ALenum param, const int *vals); \ + static void SetParamf(T &props, ALenum param, float val); \ + static void SetParamfv(T &props, ALenum param, const float *vals); \ + static void GetParami(const T &props, ALenum param, int *val); \ + static void GetParamiv(const T &props, ALenum param, int *vals); \ + static void GetParamf(const T &props, ALenum param, float *val); \ + static void GetParamfv(const T &props, ALenum param, float *vals); + + DECL_HANDLER(std::monostate) + DECL_HANDLER(ReverbProps) + DECL_HANDLER(ChorusProps) + DECL_HANDLER(AutowahProps) + DECL_HANDLER(CompressorProps) + DECL_HANDLER(ConvolutionProps) + DECL_HANDLER(DedicatedDialogProps) + DECL_HANDLER(DedicatedLfeProps) + DECL_HANDLER(DistortionProps) + DECL_HANDLER(EchoProps) + DECL_HANDLER(EqualizerProps) + DECL_HANDLER(FlangerProps) + DECL_HANDLER(FshifterProps) + DECL_HANDLER(ModulatorProps) + DECL_HANDLER(PshifterProps) + DECL_HANDLER(VmorpherProps) +#undef DECL_HANDLER + + static void StdReverbSetParami(ReverbProps &props, ALenum param, int val); + static void StdReverbSetParamiv(ReverbProps &props, ALenum param, const int *vals); + static void StdReverbSetParamf(ReverbProps &props, ALenum param, float val); + static void StdReverbSetParamfv(ReverbProps &props, ALenum param, const float *vals); + static void StdReverbGetParami(const ReverbProps &props, ALenum param, int *val); + static void StdReverbGetParamiv(const ReverbProps &props, ALenum param, int *vals); + static void StdReverbGetParamf(const ReverbProps &props, ALenum param, float *val); + static void StdReverbGetParamfv(const ReverbProps &props, ALenum param, float *vals); +}; class effect_exception final : public al::base_exception { ALenum mErrorCode; public: -#ifdef __USE_MINGW_ANSI_STDIO - [[gnu::format(gnu_printf, 3, 4)]] +#ifdef __MINGW32__ + [[gnu::format(__MINGW_PRINTF_FORMAT, 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; } + [[nodiscard]] auto errorCode() const noexcept -> ALenum { return mErrorCode; } }; -struct EffectVtable { - void (*const setParami)(EffectProps *props, ALenum param, int val); - void (*const setParamiv)(EffectProps *props, ALenum param, const int *vals); - void (*const setParamf)(EffectProps *props, ALenum param, float val); - void (*const setParamfv)(EffectProps *props, ALenum param, const float *vals); - - void (*const getParami)(const EffectProps *props, ALenum param, int *val); - void (*const getParamiv)(const EffectProps *props, ALenum param, int *vals); - void (*const getParamf)(const EffectProps *props, ALenum param, float *val); - void (*const getParamfv)(const EffectProps *props, ALenum param, float *vals); -}; - -#define DEFINE_ALEFFECT_VTABLE(T) \ -const EffectVtable T##EffectVtable = { \ - T##_setParami, T##_setParamiv, \ - T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, \ - T##_getParamf, T##_getParamfv, \ -} - - /* Default properties for the given effect types. */ extern const EffectProps NullEffectProps; extern const EffectProps ReverbEffectProps; @@ -64,25 +81,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 */ diff --git a/al/effects/equalizer.cpp b/al/effects/equalizer.cpp index 76d5bdef..74fc43fc 100644 --- a/al/effects/equalizer.cpp +++ b/al/effects/equalizer.cpp @@ -16,163 +16,133 @@ namespace { -void Equalizer_setParami(EffectProps*, ALenum param, int) +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 EffectHandler::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 EffectHandler::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 EffectHandler::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 EffectHandler::SetParamfv(EqualizerProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Equalizer_getParami(const EffectProps*, ALenum param, int*) +void EffectHandler::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 EffectHandler::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 EffectHandler::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); } - -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; -} +void EffectHandler::GetParamfv(const EqualizerProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -} // namespace - -DEFINE_ALEFFECT_VTABLE(Equalizer); - -const EffectProps EqualizerEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -319,31 +289,31 @@ template<> throw Exception{message}; } -template<> -bool EqualizerCommitter::commit(const EaxEffectProps &props) +bool EaxEqualizerCommitter::commit(const EAXEQUALIZERPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXEQUALIZERPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - - auto &eaxprops = std::get<EAXEQUALIZERPROPERTIES>(props); - mAlProps.Equalizer.LowGain = level_mb_to_gain(static_cast<float>(eaxprops.lLowGain)); - mAlProps.Equalizer.LowCutoff = eaxprops.flLowCutOff; - mAlProps.Equalizer.Mid1Gain = level_mb_to_gain(static_cast<float>(eaxprops.lMid1Gain)); - mAlProps.Equalizer.Mid1Center = eaxprops.flMid1Center; - mAlProps.Equalizer.Mid1Width = eaxprops.flMid1Width; - mAlProps.Equalizer.Mid2Gain = level_mb_to_gain(static_cast<float>(eaxprops.lMid2Gain)); - mAlProps.Equalizer.Mid2Center = eaxprops.flMid2Center; - mAlProps.Equalizer.Mid2Width = eaxprops.flMid2Width; - mAlProps.Equalizer.HighGain = level_mb_to_gain(static_cast<float>(eaxprops.lHighGain)); - mAlProps.Equalizer.HighCutoff = eaxprops.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) { static constexpr EAXEQUALIZERPROPERTIES defprops{[] { @@ -363,10 +333,8 @@ void EqualizerCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxEqualizerCommitter::Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props) { - auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXEQUALIZER_NONE: break; @@ -385,10 +353,8 @@ void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxEqualizerCommitter::Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props) { - auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXEQUALIZER_NONE: break; diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp index 37c372c3..556244ac 100644 --- a/al/effects/fshifter.cpp +++ b/al/effects/fshifter.cpp @@ -41,31 +41,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) +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 EffectHandler::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 +68,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 +79,52 @@ 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 EffectHandler::SetParamiv(FshifterProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } + +void EffectHandler::SetParamf(FshifterProps &props, ALenum param, float val) +{ + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"}; + props.Frequency = val; + break; + + default: + throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", + param}; + } +} +void EffectHandler::SetParamfv(FshifterProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Fshifter_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::GetParami(const FshifterProps &props, ALenum param, int *val) { switch(param) { case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = EnumFromDirection(props->Fshifter.LeftDirection); + *val = EnumFromDirection(props.LeftDirection); break; case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = EnumFromDirection(props->Fshifter.RightDirection); + *val = EnumFromDirection(props.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 EffectHandler::GetParamiv(const FshifterProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } -void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val) +void EffectHandler::GetParamf(const FshifterProps &props, ALenum param, float *val) { switch(param) { case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = props->Fshifter.Frequency; + *val = props.Frequency; break; default: @@ -118,23 +132,9 @@ 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 EffectHandler::GetParamfv(const FshifterProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -EffectProps genDefaultProps() noexcept -{ - EffectProps props{}; - props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - props.Fshifter.LeftDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION); - props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION); - return props; -} - -} // namespace - -DEFINE_ALEFFECT_VTABLE(Fshifter); - -const EffectProps FshifterEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -197,10 +197,9 @@ template<> throw Exception{message}; } -template<> -bool FrequencyShifterCommitter::commit(const EaxEffectProps &props) +bool EaxFrequencyShifterCommitter::commit(const EAXFREQUENCYSHIFTERPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXFREQUENCYSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; @@ -214,16 +213,18 @@ bool FrequencyShifterCommitter::commit(const EaxEffectProps &props) return FShifterDirection::Off; }; - auto &eaxprops = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props); - mAlProps.Fshifter.Frequency = eaxprops.flFrequency; - mAlProps.Fshifter.LeftDirection = get_direction(eaxprops.ulLeftDirection); - mAlProps.Fshifter.RightDirection = get_direction(eaxprops.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) { static constexpr EAXFREQUENCYSHIFTERPROPERTIES defprops{[] { @@ -236,10 +237,8 @@ void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxFrequencyShifterCommitter::Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props) { - auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXFREQUENCYSHIFTER_NONE: break; @@ -251,10 +250,8 @@ void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &p } } -template<> -void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxFrequencyShifterCommitter::Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props) { - auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXFREQUENCYSHIFTER_NONE: break; diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp index 366e7ef7..7e9424c0 100644 --- a/al/effects/modulator.cpp +++ b/al/effects/modulator.cpp @@ -42,40 +42,31 @@ ALenum EnumFromWaveform(ModulatorWaveform type) std::to_string(static_cast<int>(type))}; } -void Modulator_setParamf(EffectProps *props, ALenum param, float val) +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; + 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; +} - 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; +} // namespace - default: - throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param}; - } -} -void Modulator_setParamfv(EffectProps *props, ALenum param, const float *vals) -{ Modulator_setParamf(props, param, vals[0]); } -void Modulator_setParami(EffectProps *props, ALenum param, int val) +const EffectProps ModulatorEffectProps{genDefaultProps()}; + +void EffectHandler::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 +76,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 EffectHandler::SetParamiv(ModulatorProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } -void Modulator_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::SetParamf(ModulatorProps &props, ALenum param, float val) { switch(param) { case AL_RING_MODULATOR_FREQUENCY: - *val = static_cast<int>(props->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.Frequency = val; 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_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 EffectHandler::SetParamfv(ModulatorProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } + +void EffectHandler::GetParami(const ModulatorProps &props, ALenum param, int *val) +{ + 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 Modulator_getParamiv(const EffectProps *props, ALenum param, int *vals) -{ Modulator_getParami(props, param, vals); } -void Modulator_getParamf(const EffectProps *props, ALenum param, float *val) +void EffectHandler::GetParamiv(const ModulatorProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } +void EffectHandler::GetParamf(const ModulatorProps &props, ALenum param, float *val) { switch(param) { - case AL_RING_MODULATOR_FREQUENCY: - *val = props->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = props->Modulator.HighPassCutoff; - break; + case AL_RING_MODULATOR_FREQUENCY: *val = props.Frequency; break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = props.HighPassCutoff; break; default: throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param}; } } -void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals) -{ Modulator_getParamf(props, param, vals); } +void EffectHandler::GetParamfv(const ModulatorProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -EffectProps genDefaultProps() noexcept -{ - EffectProps props{}; - props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; - props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; - props.Modulator.Waveform = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM); - return props; -} - -} // namespace - -DEFINE_ALEFFECT_VTABLE(Modulator); - -const EffectProps ModulatorEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -203,10 +193,9 @@ template<> throw Exception{message}; } -template<> -bool ModulatorCommitter::commit(const EaxEffectProps &props) +bool EaxModulatorCommitter::commit(const EAXRINGMODULATORPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXRINGMODULATORPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; @@ -222,16 +211,18 @@ bool ModulatorCommitter::commit(const EaxEffectProps &props) return ModulatorWaveform::Sinusoid; }; - auto &eaxprops = std::get<EAXRINGMODULATORPROPERTIES>(props); - mAlProps.Modulator.Frequency = eaxprops.flFrequency; - mAlProps.Modulator.HighPassCutoff = eaxprops.flHighPassCutOff; - mAlProps.Modulator.Waveform = get_waveform(eaxprops.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) { static constexpr EAXRINGMODULATORPROPERTIES defprops{[] { @@ -244,10 +235,8 @@ void ModulatorCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxModulatorCommitter::Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props) { - auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXRINGMODULATOR_NONE: break; @@ -259,11 +248,9 @@ void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) } } -template<> -void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxModulatorCommitter::Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props) { - auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_); - switch (call.get_property_id()) + switch(call.get_property_id()) { case EAXRINGMODULATOR_NONE: break; case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break; diff --git a/al/effects/null.cpp b/al/effects/null.cpp index 1e8787e7..4b00ef4f 100644 --- a/al/effects/null.cpp +++ b/al/effects/null.cpp @@ -14,7 +14,17 @@ namespace { -void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/) +EffectProps genDefaultProps() noexcept +{ + EffectProps props{}; + return props; +} + +} // namespace + +const EffectProps NullEffectProps{genDefaultProps()}; + +void EffectHandler::SetParami(std::monostate& /*props*/, ALenum param, int /*val*/) { switch(param) { @@ -23,15 +33,15 @@ void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/) param}; } } -void Null_setParamiv(EffectProps *props, ALenum param, const int *vals) +void EffectHandler::SetParamiv(std::monostate &props, ALenum param, const int *vals) { switch(param) { default: - Null_setParami(props, param, vals[0]); + SetParami(props, param, vals[0]); } } -void Null_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/) +void EffectHandler::SetParamf(std::monostate& /*props*/, ALenum param, float /*val*/) { switch(param) { @@ -40,16 +50,16 @@ void Null_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/) param}; } } -void Null_setParamfv(EffectProps *props, ALenum param, const float *vals) +void EffectHandler::SetParamfv(std::monostate &props, ALenum param, const float *vals) { switch(param) { default: - Null_setParamf(props, param, vals[0]); + SetParamf(props, param, vals[0]); } } -void Null_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/) +void EffectHandler::GetParami(const std::monostate& /*props*/, ALenum param, int* /*val*/) { switch(param) { @@ -58,15 +68,15 @@ void Null_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/) param}; } } -void Null_getParamiv(const EffectProps *props, ALenum param, int *vals) +void EffectHandler::GetParamiv(const std::monostate &props, ALenum param, int *vals) { switch(param) { default: - Null_getParami(props, param, vals); + GetParami(props, param, vals); } } -void Null_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/) +void EffectHandler::GetParamf(const std::monostate& /*props*/, ALenum param, float* /*val*/) { switch(param) { @@ -75,27 +85,15 @@ void Null_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/) param}; } } -void Null_getParamfv(const EffectProps *props, ALenum param, float *vals) +void EffectHandler::GetParamfv(const std::monostate &props, ALenum param, float *vals) { switch(param) { default: - Null_getParamf(props, param, vals); + GetParamf(props, param, vals); } } -EffectProps genDefaultProps() noexcept -{ - EffectProps props{}; - return props; -} - -} // namespace - -DEFINE_ALEFFECT_VTABLE(Null); - -const EffectProps NullEffectProps{genDefaultProps()}; - #ifdef ALSOFT_EAX namespace { @@ -117,29 +115,26 @@ template<> throw Exception{message}; } -template<> -bool NullCommitter::commit(const EaxEffectProps &props) +bool EaxNullCommitter::commit(const std::monostate &props) { - const bool ret{props != mEaxProps}; + 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.emplace<std::monostate>(); + 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(); diff --git a/al/effects/pshifter.cpp b/al/effects/pshifter.cpp index 10824016..b36fe034 100644 --- a/al/effects/pshifter.cpp +++ b/al/effects/pshifter.cpp @@ -16,28 +16,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*) +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 EffectHandler::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 +49,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 EffectHandler::SetParamiv(PshifterProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } -void Pshifter_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::SetParamf(PshifterProps&, ALenum param, float) +{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; } +void EffectHandler::SetParamfv(PshifterProps&, ALenum param, const float*) +{ + throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", + param}; +} + +void EffectHandler::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 EffectHandler::GetParamiv(const PshifterProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } -void Pshifter_getParamf(const EffectProps*, ALenum param, float*) +void EffectHandler::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 EffectHandler::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,32 +133,30 @@ template<> throw Exception{message}; } -template<> -bool PitchShifterCommitter::commit(const EaxEffectProps &props) +bool EaxPitchShifterCommitter::commit(const EAXPITCHSHIFTERPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXPITCHSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - - auto &eaxprops = std::get<EAXPITCHSHIFTERPROPERTIES>(props); - mAlProps.Pshifter.CoarseTune = static_cast<int>(eaxprops.lCoarseTune); - mAlProps.Pshifter.FineTune = static_cast<int>(eaxprops.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 = EAXPITCHSHIFTERPROPERTIES{EAXPITCHSHIFTER_DEFAULTCOARSETUNE, EAXPITCHSHIFTER_DEFAULTFINETUNE}; } -template<> -void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxPitchShifterCommitter::Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props) { - auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXPITCHSHIFTER_NONE: break; @@ -174,10 +167,8 @@ void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props } } -template<> -void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_) +void EaxPitchShifterCommitter::Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props) { - auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXPITCHSHIFTER_NONE: break; diff --git a/al/effects/reverb.cpp b/al/effects/reverb.cpp index b037443f..f0df51b2 100644 --- a/al/effects/reverb.cpp +++ b/al/effects/reverb.cpp @@ -20,14 +20,80 @@ namespace { -void Reverb_setParami(EffectProps *props, ALenum param, int val) +EffectProps genDefaultProps() noexcept +{ + ReverbProps props{}; + props.Density = AL_EAXREVERB_DEFAULT_DENSITY; + props.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + props.Gain = AL_EAXREVERB_DEFAULT_GAIN; + props.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + props.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + props.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + props.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + props.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + props.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + props.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + props.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + props.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + props.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + props.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + props.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + props.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + props.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + props.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + props.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + props.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + props.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + return props; +} + +EffectProps genDefaultStdProps() noexcept +{ + ReverbProps props{}; + props.Density = AL_REVERB_DEFAULT_DENSITY; + props.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; + props.Gain = AL_REVERB_DEFAULT_GAIN; + props.GainHF = AL_REVERB_DEFAULT_GAINHF; + props.GainLF = 1.0f; + props.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; + props.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + props.DecayLFRatio = 1.0f; + props.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; + props.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + props.ReflectionsPan = {0.0f, 0.0f, 0.0f}; + props.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; + props.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + props.LateReverbPan = {0.0f, 0.0f, 0.0f}; + props.EchoTime = 0.25f; + props.EchoDepth = 0.0f; + props.ModulationTime = 0.25f; + props.ModulationDepth = 0.0f; + props.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + props.HFReference = 5000.0f; + props.LFReference = 250.0f; + props.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + props.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; + return props; +} + +} // namespace + +const EffectProps ReverbEffectProps{genDefaultProps()}; + +void EffectHandler::SetParami(ReverbProps &props, ALenum param, int val) { switch(param) { case AL_EAXREVERB_DECAY_HFLIMIT: if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hflimit out of range"}; - props->Reverb.DecayHFLimit = val != AL_FALSE; + props.DecayHFLimit = val != AL_FALSE; break; default: @@ -35,167 +101,167 @@ void Reverb_setParami(EffectProps *props, ALenum param, int val) param}; } } -void Reverb_setParamiv(EffectProps *props, ALenum param, const int *vals) -{ Reverb_setParami(props, param, vals[0]); } -void Reverb_setParamf(EffectProps *props, ALenum param, float val) +void EffectHandler::SetParamiv(ReverbProps &props, ALenum param, const int *vals) +{ SetParami(props, param, vals[0]); } +void EffectHandler::SetParamf(ReverbProps &props, ALenum param, float val) { switch(param) { case AL_EAXREVERB_DENSITY: if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb density out of range"}; - props->Reverb.Density = val; + props.Density = val; break; case AL_EAXREVERB_DIFFUSION: if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb diffusion out of range"}; - props->Reverb.Diffusion = val; + props.Diffusion = val; break; case AL_EAXREVERB_GAIN: if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gain out of range"}; - props->Reverb.Gain = val; + props.Gain = val; break; case AL_EAXREVERB_GAINHF: if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainhf out of range"}; - props->Reverb.GainHF = val; + props.GainHF = val; break; case AL_EAXREVERB_GAINLF: if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainlf out of range"}; - props->Reverb.GainLF = val; + props.GainLF = val; break; case AL_EAXREVERB_DECAY_TIME: if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay time out of range"}; - props->Reverb.DecayTime = val; + props.DecayTime = val; break; case AL_EAXREVERB_DECAY_HFRATIO: if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hfratio out of range"}; - props->Reverb.DecayHFRatio = val; + props.DecayHFRatio = val; break; case AL_EAXREVERB_DECAY_LFRATIO: if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay lfratio out of range"}; - props->Reverb.DecayLFRatio = val; + props.DecayLFRatio = val; break; case AL_EAXREVERB_REFLECTIONS_GAIN: if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections gain out of range"}; - props->Reverb.ReflectionsGain = val; + props.ReflectionsGain = val; break; case AL_EAXREVERB_REFLECTIONS_DELAY: if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections delay out of range"}; - props->Reverb.ReflectionsDelay = val; + props.ReflectionsDelay = val; break; case AL_EAXREVERB_LATE_REVERB_GAIN: if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb gain out of range"}; - props->Reverb.LateReverbGain = val; + props.LateReverbGain = val; break; case AL_EAXREVERB_LATE_REVERB_DELAY: if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb delay out of range"}; - props->Reverb.LateReverbDelay = val; + props.LateReverbDelay = val; break; case AL_EAXREVERB_ECHO_TIME: if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb echo time out of range"}; - props->Reverb.EchoTime = val; + props.EchoTime = val; break; case AL_EAXREVERB_ECHO_DEPTH: if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb echo depth out of range"}; - props->Reverb.EchoDepth = val; + props.EchoDepth = val; break; case AL_EAXREVERB_MODULATION_TIME: if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb modulation time out of range"}; - props->Reverb.ModulationTime = val; + props.ModulationTime = val; break; case AL_EAXREVERB_MODULATION_DEPTH: if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb modulation depth out of range"}; - props->Reverb.ModulationDepth = val; + props.ModulationDepth = val; break; case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb air absorption gainhf out of range"}; - props->Reverb.AirAbsorptionGainHF = val; + props.AirAbsorptionGainHF = val; break; case AL_EAXREVERB_HFREFERENCE: if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb hfreference out of range"}; - props->Reverb.HFReference = val; + props.HFReference = val; break; case AL_EAXREVERB_LFREFERENCE: if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb lfreference out of range"}; - props->Reverb.LFReference = val; + props.LFReference = val; break; case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb room rolloff factor out of range"}; - props->Reverb.RoomRolloffFactor = val; + props.RoomRolloffFactor = val; break; default: throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param}; } } -void Reverb_setParamfv(EffectProps *props, ALenum param, const float *vals) +void EffectHandler::SetParamfv(ReverbProps &props, ALenum param, const float *vals) { switch(param) { case AL_EAXREVERB_REFLECTIONS_PAN: if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections pan out of range"}; - props->Reverb.ReflectionsPan[0] = vals[0]; - props->Reverb.ReflectionsPan[1] = vals[1]; - props->Reverb.ReflectionsPan[2] = vals[2]; + props.ReflectionsPan[0] = vals[0]; + props.ReflectionsPan[1] = vals[1]; + props.ReflectionsPan[2] = vals[2]; break; case AL_EAXREVERB_LATE_REVERB_PAN: if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb pan out of range"}; - props->Reverb.LateReverbPan[0] = vals[0]; - props->Reverb.LateReverbPan[1] = vals[1]; - props->Reverb.LateReverbPan[2] = vals[2]; + props.LateReverbPan[0] = vals[0]; + props.LateReverbPan[1] = vals[1]; + props.LateReverbPan[2] = vals[2]; break; default: - Reverb_setParamf(props, param, vals[0]); + SetParamf(props, param, vals[0]); break; } } -void Reverb_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::GetParami(const ReverbProps &props, ALenum param, int *val) { switch(param) { case AL_EAXREVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; + *val = props.DecayHFLimit; break; default: @@ -203,365 +269,214 @@ void Reverb_getParami(const EffectProps *props, ALenum param, int *val) param}; } } -void Reverb_getParamiv(const EffectProps *props, ALenum param, int *vals) -{ Reverb_getParami(props, param, vals); } -void Reverb_getParamf(const EffectProps *props, ALenum param, float *val) +void EffectHandler::GetParamiv(const ReverbProps &props, ALenum param, int *vals) +{ GetParami(props, param, vals); } +void EffectHandler::GetParamf(const ReverbProps &props, ALenum param, float *val) { switch(param) { - case AL_EAXREVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_EAXREVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_EAXREVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_EAXREVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_EAXREVERB_GAINLF: - *val = props->Reverb.GainLF; - break; - - case AL_EAXREVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - *val = props->Reverb.DecayLFRatio; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_EAXREVERB_ECHO_TIME: - *val = props->Reverb.EchoTime; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - *val = props->Reverb.EchoDepth; - break; - - case AL_EAXREVERB_MODULATION_TIME: - *val = props->Reverb.ModulationTime; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - *val = props->Reverb.ModulationDepth; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_EAXREVERB_HFREFERENCE: - *val = props->Reverb.HFReference; - break; - - case AL_EAXREVERB_LFREFERENCE: - *val = props->Reverb.LFReference; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; + case AL_EAXREVERB_DENSITY: *val = props.Density; break; + case AL_EAXREVERB_DIFFUSION: *val = props.Diffusion; break; + case AL_EAXREVERB_GAIN: *val = props.Gain; break; + case AL_EAXREVERB_GAINHF: *val = props.GainHF; break; + case AL_EAXREVERB_GAINLF: *val = props.GainLF; break; + case AL_EAXREVERB_DECAY_TIME: *val = props.DecayTime; break; + case AL_EAXREVERB_DECAY_HFRATIO: *val = props.DecayHFRatio; break; + case AL_EAXREVERB_DECAY_LFRATIO: *val = props.DecayLFRatio; break; + case AL_EAXREVERB_REFLECTIONS_GAIN: *val = props.ReflectionsGain; break; + case AL_EAXREVERB_REFLECTIONS_DELAY: *val = props.ReflectionsDelay; break; + case AL_EAXREVERB_LATE_REVERB_GAIN: *val = props.LateReverbGain; break; + case AL_EAXREVERB_LATE_REVERB_DELAY: *val = props.LateReverbDelay; break; + case AL_EAXREVERB_ECHO_TIME: *val = props.EchoTime; break; + case AL_EAXREVERB_ECHO_DEPTH: *val = props.EchoDepth; break; + case AL_EAXREVERB_MODULATION_TIME: *val = props.ModulationTime; break; + case AL_EAXREVERB_MODULATION_DEPTH: *val = props.ModulationDepth; break; + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: *val = props.AirAbsorptionGainHF; break; + case AL_EAXREVERB_HFREFERENCE: *val = props.HFReference; break; + case AL_EAXREVERB_LFREFERENCE: *val = props.LFReference; break; + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: *val = props.RoomRolloffFactor; break; default: throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param}; } } -void Reverb_getParamfv(const EffectProps *props, ALenum param, float *vals) +void EffectHandler::GetParamfv(const ReverbProps &props, ALenum param, float *vals) { switch(param) { case AL_EAXREVERB_REFLECTIONS_PAN: - vals[0] = props->Reverb.ReflectionsPan[0]; - vals[1] = props->Reverb.ReflectionsPan[1]; - vals[2] = props->Reverb.ReflectionsPan[2]; + vals[0] = props.ReflectionsPan[0]; + vals[1] = props.ReflectionsPan[1]; + vals[2] = props.ReflectionsPan[2]; break; case AL_EAXREVERB_LATE_REVERB_PAN: - vals[0] = props->Reverb.LateReverbPan[0]; - vals[1] = props->Reverb.LateReverbPan[1]; - vals[2] = props->Reverb.LateReverbPan[2]; + vals[0] = props.LateReverbPan[0]; + vals[1] = props.LateReverbPan[1]; + vals[2] = props.LateReverbPan[2]; break; default: - Reverb_getParamf(props, param, vals); + GetParamf(props, param, vals); break; } } -EffectProps genDefaultProps() noexcept -{ - EffectProps props{}; - props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; - props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; - props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; - props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; - props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; - props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; - props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; - props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; - props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; - props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; - props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; - props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; - props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; - return props; -} +const EffectProps StdReverbEffectProps{genDefaultStdProps()}; -void StdReverb_setParami(EffectProps *props, ALenum param, int val) +void EffectHandler::StdReverbSetParami(ReverbProps &props, ALenum param, int val) { switch(param) { case AL_REVERB_DECAY_HFLIMIT: if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) - throw effect_exception{AL_INVALID_VALUE, "Reverb decay hflimit out of range"}; - props->Reverb.DecayHFLimit = val != AL_FALSE; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hflimit out of range"}; + props.DecayHFLimit = val != AL_FALSE; break; default: - throw effect_exception{AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param}; + throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param}; } } -void StdReverb_setParamiv(EffectProps *props, ALenum param, const int *vals) -{ StdReverb_setParami(props, param, vals[0]); } -void StdReverb_setParamf(EffectProps *props, ALenum param, float val) +void EffectHandler::StdReverbSetParamiv(ReverbProps &props, ALenum param, const int *vals) +{ StdReverbSetParami(props, param, vals[0]); } +void EffectHandler::StdReverbSetParamf(ReverbProps &props, ALenum param, float val) { switch(param) { case AL_REVERB_DENSITY: if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - throw effect_exception{AL_INVALID_VALUE, "Reverb density out of range"}; - props->Reverb.Density = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb density out of range"}; + props.Density = val; break; case AL_REVERB_DIFFUSION: if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) - throw effect_exception{AL_INVALID_VALUE, "Reverb diffusion out of range"}; - props->Reverb.Diffusion = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb diffusion out of range"}; + props.Diffusion = val; break; case AL_REVERB_GAIN: if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) - throw effect_exception{AL_INVALID_VALUE, "Reverb gain out of range"}; - props->Reverb.Gain = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gain out of range"}; + props.Gain = val; break; case AL_REVERB_GAINHF: if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) - throw effect_exception{AL_INVALID_VALUE, "Reverb gainhf out of range"}; - props->Reverb.GainHF = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainhf out of range"}; + props.GainHF = val; break; case AL_REVERB_DECAY_TIME: if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) - throw effect_exception{AL_INVALID_VALUE, "Reverb decay time out of range"}; - props->Reverb.DecayTime = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay time out of range"}; + props.DecayTime = val; break; case AL_REVERB_DECAY_HFRATIO: if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) - throw effect_exception{AL_INVALID_VALUE, "Reverb decay hfratio out of range"}; - props->Reverb.DecayHFRatio = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hfratio out of range"}; + props.DecayHFRatio = val; break; case AL_REVERB_REFLECTIONS_GAIN: if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) - throw effect_exception{AL_INVALID_VALUE, "Reverb reflections gain out of range"}; - props->Reverb.ReflectionsGain = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections gain out of range"}; + props.ReflectionsGain = val; break; case AL_REVERB_REFLECTIONS_DELAY: if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) - throw effect_exception{AL_INVALID_VALUE, "Reverb reflections delay out of range"}; - props->Reverb.ReflectionsDelay = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections delay out of range"}; + props.ReflectionsDelay = val; break; case AL_REVERB_LATE_REVERB_GAIN: if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) - throw effect_exception{AL_INVALID_VALUE, "Reverb late reverb gain out of range"}; - props->Reverb.LateReverbGain = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb gain out of range"}; + props.LateReverbGain = val; break; case AL_REVERB_LATE_REVERB_DELAY: if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) - throw effect_exception{AL_INVALID_VALUE, "Reverb late reverb delay out of range"}; - props->Reverb.LateReverbDelay = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb delay out of range"}; + props.LateReverbDelay = val; break; case AL_REVERB_AIR_ABSORPTION_GAINHF: if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) - throw effect_exception{AL_INVALID_VALUE, "Reverb air absorption gainhf out of range"}; - props->Reverb.AirAbsorptionGainHF = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb air absorption gainhf out of range"}; + props.AirAbsorptionGainHF = val; break; case AL_REVERB_ROOM_ROLLOFF_FACTOR: if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) - throw effect_exception{AL_INVALID_VALUE, "Reverb room rolloff factor out of range"}; - props->Reverb.RoomRolloffFactor = val; + throw effect_exception{AL_INVALID_VALUE, "EAX Reverb room rolloff factor out of range"}; + props.RoomRolloffFactor = val; break; default: - throw effect_exception{AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param}; + throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param}; + } +} +void EffectHandler::StdReverbSetParamfv(ReverbProps &props, ALenum param, const float *vals) +{ + switch(param) + { + default: + StdReverbSetParamf(props, param, vals[0]); + break; } } -void StdReverb_setParamfv(EffectProps *props, ALenum param, const float *vals) -{ StdReverb_setParamf(props, param, vals[0]); } -void StdReverb_getParami(const EffectProps *props, ALenum param, int *val) +void EffectHandler::StdReverbGetParami(const ReverbProps &props, ALenum param, int *val) { switch(param) { case AL_REVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; + *val = props.DecayHFLimit; break; default: - throw effect_exception{AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param}; + throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param}; } } -void StdReverb_getParamiv(const EffectProps *props, ALenum param, int *vals) -{ StdReverb_getParami(props, param, vals); } -void StdReverb_getParamf(const EffectProps *props, ALenum param, float *val) +void EffectHandler::StdReverbGetParamiv(const ReverbProps &props, ALenum param, int *vals) +{ StdReverbGetParami(props, param, vals); } +void EffectHandler::StdReverbGetParamf(const ReverbProps &props, ALenum param, float *val) { switch(param) { - case AL_REVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_REVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_REVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_REVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_REVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_REVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; + case AL_REVERB_DENSITY: *val = props.Density; break; + case AL_REVERB_DIFFUSION: *val = props.Diffusion; break; + case AL_REVERB_GAIN: *val = props.Gain; break; + case AL_REVERB_GAINHF: *val = props.GainHF; break; + case AL_REVERB_DECAY_TIME: *val = props.DecayTime; break; + case AL_REVERB_DECAY_HFRATIO: *val = props.DecayHFRatio; break; + case AL_REVERB_REFLECTIONS_GAIN: *val = props.ReflectionsGain; break; + case AL_REVERB_REFLECTIONS_DELAY: *val = props.ReflectionsDelay; break; + case AL_REVERB_LATE_REVERB_GAIN: *val = props.LateReverbGain; break; + case AL_REVERB_LATE_REVERB_DELAY: *val = props.LateReverbDelay; break; + case AL_REVERB_AIR_ABSORPTION_GAINHF: *val = props.AirAbsorptionGainHF; break; + case AL_REVERB_ROOM_ROLLOFF_FACTOR: *val = props.RoomRolloffFactor; break; default: - throw effect_exception{AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param}; + throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param}; } } -void StdReverb_getParamfv(const EffectProps *props, ALenum param, float *vals) -{ StdReverb_getParamf(props, param, vals); } - -EffectProps genDefaultStdProps() noexcept +void EffectHandler::StdReverbGetParamfv(const ReverbProps &props, ALenum param, float *vals) { - EffectProps props{}; - props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; - props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; - props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; - props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; - props.Reverb.GainLF = 1.0f; - props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; - props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; - props.Reverb.DecayLFRatio = 1.0f; - props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; - props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; - props.Reverb.ReflectionsPan[0] = 0.0f; - props.Reverb.ReflectionsPan[1] = 0.0f; - props.Reverb.ReflectionsPan[2] = 0.0f; - props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; - props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; - props.Reverb.LateReverbPan[0] = 0.0f; - props.Reverb.LateReverbPan[1] = 0.0f; - props.Reverb.LateReverbPan[2] = 0.0f; - props.Reverb.EchoTime = 0.25f; - props.Reverb.EchoDepth = 0.0f; - props.Reverb.ModulationTime = 0.25f; - props.Reverb.ModulationDepth = 0.0f; - props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - props.Reverb.HFReference = 5000.0f; - props.Reverb.LFReference = 250.0f; - props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - return props; + switch(param) + { + default: + StdReverbGetParamf(props, param, vals); + break; + } } -} // namespace - -DEFINE_ALEFFECT_VTABLE(Reverb); - -const EffectProps ReverbEffectProps{genDefaultProps()}; - -DEFINE_ALEFFECT_VTABLE(StdReverb); - -const EffectProps StdReverbEffectProps{genDefaultStdProps()}; #ifdef ALSOFT_EAX namespace { @@ -1086,98 +1001,87 @@ struct EaxReverbCommitter::Exception : public EaxReverbEffectException throw Exception{message}; } -void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept +void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept { assert(src.environment <= EAX1REVERB_MAXENVIRONMENT); - auto&& eaxprops = dst.emplace<EAXREVERBPROPERTIES>(EAXREVERB_PRESETS[src.environment]); - eaxprops.flDecayTime = src.fDecayTime_sec; - eaxprops.flDecayHFRatio = src.fDamping; - eaxprops.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0); + dst = EAXREVERB_PRESETS[src.environment]; + dst.flDecayTime = src.fDecayTime_sec; + dst.flDecayHFRatio = src.fDamping; + dst.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0); } -void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept +void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept { assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT); - auto&& eaxprops = dst.emplace<EAXREVERBPROPERTIES>(EAXREVERB_PRESETS[src.dwEnvironment]); - eaxprops.ulEnvironment = src.dwEnvironment; - eaxprops.flEnvironmentSize = src.flEnvironmentSize; - eaxprops.flEnvironmentDiffusion = src.flEnvironmentDiffusion; - eaxprops.lRoom = src.lRoom; - eaxprops.lRoomHF = src.lRoomHF; - eaxprops.flDecayTime = src.flDecayTime; - eaxprops.flDecayHFRatio = src.flDecayHFRatio; - eaxprops.lReflections = src.lReflections; - eaxprops.flReflectionsDelay = src.flReflectionsDelay; - eaxprops.lReverb = src.lReverb; - eaxprops.flReverbDelay = src.flReverbDelay; - eaxprops.flAirAbsorptionHF = src.flAirAbsorptionHF; - eaxprops.flRoomRolloffFactor = src.flRoomRolloffFactor; - eaxprops.ulFlags = src.dwFlags; -} - -void EaxReverbCommitter::translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept -{ - dst = src; + dst = EAXREVERB_PRESETS[src.dwEnvironment]; + dst.ulEnvironment = src.dwEnvironment; + dst.flEnvironmentSize = src.flEnvironmentSize; + dst.flEnvironmentDiffusion = src.flEnvironmentDiffusion; + dst.lRoom = src.lRoom; + dst.lRoomHF = src.lRoomHF; + dst.flDecayTime = src.flDecayTime; + dst.flDecayHFRatio = src.flDecayHFRatio; + dst.lReflections = src.lReflections; + dst.flReflectionsDelay = src.flReflectionsDelay; + dst.lReverb = src.lReverb; + dst.flReverbDelay = src.flReverbDelay; + dst.flAirAbsorptionHF = src.flAirAbsorptionHF; + dst.flRoomRolloffFactor = src.flRoomRolloffFactor; + dst.ulFlags = src.dwFlags; } bool EaxReverbCommitter::commit(const EAX_REVERBPROPERTIES &props) { - EaxEffectProps dst{}; + EAXREVERBPROPERTIES dst{}; translate(props, dst); return commit(dst); } bool EaxReverbCommitter::commit(const EAX20LISTENERPROPERTIES &props) { - EaxEffectProps dst{}; + EAXREVERBPROPERTIES dst{}; translate(props, dst); return commit(dst); } bool EaxReverbCommitter::commit(const EAXREVERBPROPERTIES &props) { - EaxEffectProps dst{}; - translate(props, dst); - return commit(dst); -} - -bool EaxReverbCommitter::commit(const EaxEffectProps &props) -{ - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXREVERBPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; - auto &eaxprops = std::get<EAXREVERBPROPERTIES>(props); - const auto size = eaxprops.flEnvironmentSize; - const auto density = (size * size * size) / 16.0F; - mAlProps.Reverb.Density = std::min(density, AL_EAXREVERB_MAX_DENSITY); - mAlProps.Reverb.Diffusion = eaxprops.flEnvironmentDiffusion; - mAlProps.Reverb.Gain = level_mb_to_gain(static_cast<float>(eaxprops.lRoom)); - mAlProps.Reverb.GainHF = level_mb_to_gain(static_cast<float>(eaxprops.lRoomHF)); - mAlProps.Reverb.GainLF = level_mb_to_gain(static_cast<float>(eaxprops.lRoomLF)); - mAlProps.Reverb.DecayTime = eaxprops.flDecayTime; - mAlProps.Reverb.DecayHFRatio = eaxprops.flDecayHFRatio; - mAlProps.Reverb.DecayLFRatio = eaxprops.flDecayLFRatio; - mAlProps.Reverb.ReflectionsGain = level_mb_to_gain(static_cast<float>(eaxprops.lReflections)); - mAlProps.Reverb.ReflectionsDelay = eaxprops.flReflectionsDelay; - mAlProps.Reverb.ReflectionsPan[0] = eaxprops.vReflectionsPan.x; - mAlProps.Reverb.ReflectionsPan[1] = eaxprops.vReflectionsPan.y; - mAlProps.Reverb.ReflectionsPan[2] = eaxprops.vReflectionsPan.z; - mAlProps.Reverb.LateReverbGain = level_mb_to_gain(static_cast<float>(eaxprops.lReverb)); - mAlProps.Reverb.LateReverbDelay = eaxprops.flReverbDelay; - mAlProps.Reverb.LateReverbPan[0] = eaxprops.vReverbPan.x; - mAlProps.Reverb.LateReverbPan[1] = eaxprops.vReverbPan.y; - mAlProps.Reverb.LateReverbPan[2] = eaxprops.vReverbPan.z; - mAlProps.Reverb.EchoTime = eaxprops.flEchoTime; - mAlProps.Reverb.EchoDepth = eaxprops.flEchoDepth; - mAlProps.Reverb.ModulationTime = eaxprops.flModulationTime; - mAlProps.Reverb.ModulationDepth = eaxprops.flModulationDepth; - mAlProps.Reverb.AirAbsorptionGainHF = level_mb_to_gain(eaxprops.flAirAbsorptionHF); - mAlProps.Reverb.HFReference = eaxprops.flHFReference; - mAlProps.Reverb.LFReference = eaxprops.flLFReference; - mAlProps.Reverb.RoomRolloffFactor = eaxprops.flRoomRolloffFactor; - mAlProps.Reverb.DecayHFLimit = ((eaxprops.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); + const auto size = props.flEnvironmentSize; + const auto density = (size * size * size) / 16.0f; + mAlProps = [&]{ + ReverbProps ret{}; + ret.Density = std::min(density, AL_EAXREVERB_MAX_DENSITY); + ret.Diffusion = props.flEnvironmentDiffusion; + ret.Gain = level_mb_to_gain(static_cast<float>(props.lRoom)); + ret.GainHF = level_mb_to_gain(static_cast<float>(props.lRoomHF)); + ret.GainLF = level_mb_to_gain(static_cast<float>(props.lRoomLF)); + ret.DecayTime = props.flDecayTime; + ret.DecayHFRatio = props.flDecayHFRatio; + ret.DecayLFRatio = props.flDecayLFRatio; + ret.ReflectionsGain = level_mb_to_gain(static_cast<float>(props.lReflections)); + ret.ReflectionsDelay = props.flReflectionsDelay; + ret.ReflectionsPan = {props.vReflectionsPan.x, props.vReflectionsPan.y, + props.vReflectionsPan.z}; + ret.LateReverbGain = level_mb_to_gain(static_cast<float>(props.lReverb)); + ret.LateReverbDelay = props.flReverbDelay; + ret.LateReverbPan = {props.vReverbPan.x, props.vReverbPan.y, props.vReverbPan.z}; + ret.EchoTime = props.flEchoTime; + ret.EchoDepth = props.flEchoDepth; + ret.ModulationTime = props.flModulationTime; + ret.ModulationDepth = props.flModulationDepth; + ret.AirAbsorptionGainHF = level_mb_to_gain(props.flAirAbsorptionHF); + ret.HFReference = props.flHFReference; + ret.LFReference = props.flLFReference; + ret.RoomRolloffFactor = props.flRoomRolloffFactor; + ret.DecayHFLimit = ((props.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); + return ret; + }(); + return true; } @@ -1274,11 +1178,6 @@ void EaxReverbCommitter::Get(const EaxCall &call, const EAXREVERBPROPERTIES &pro } } -void EaxReverbCommitter::Get(const EaxCall &call, const EaxEffectProps &props) -{ - Get(call, std::get<EAXREVERBPROPERTIES>(props)); -} - void EaxReverbCommitter::Set(const EaxCall &call, EAX_REVERBPROPERTIES &props) { @@ -1297,71 +1196,23 @@ void EaxReverbCommitter::Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props { switch(call.get_property_id()) { - case DSPROPERTY_EAX20LISTENER_NONE: - break; - - case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: - defer<AllValidator2>(call, props); - break; - - case DSPROPERTY_EAX20LISTENER_ROOM: - defer<RoomValidator>(call, props.lRoom); - break; - - case DSPROPERTY_EAX20LISTENER_ROOMHF: - defer<RoomHFValidator>(call, props.lRoomHF); - break; - - case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: - defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor); - break; - - case DSPROPERTY_EAX20LISTENER_DECAYTIME: - defer<DecayTimeValidator>(call, props.flDecayTime); - break; - - case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: - defer<DecayHFRatioValidator>(call, props.flDecayHFRatio); - break; - - case DSPROPERTY_EAX20LISTENER_REFLECTIONS: - defer<ReflectionsValidator>(call, props.lReflections); - break; - - case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: - defer<ReflectionsDelayValidator>(call, props.flReverbDelay); - break; - - case DSPROPERTY_EAX20LISTENER_REVERB: - defer<ReverbValidator>(call, props.lReverb); - break; - - case DSPROPERTY_EAX20LISTENER_REVERBDELAY: - defer<ReverbDelayValidator>(call, props.flReverbDelay); - break; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: - defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment); - break; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: - defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize); - break; - - case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: - defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion); - break; - - case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: - defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF); - break; - - case DSPROPERTY_EAX20LISTENER_FLAGS: - defer<FlagsValidator2>(call, props.dwFlags); - break; - - default: - fail_unknown_property_id(); + case DSPROPERTY_EAX20LISTENER_NONE: break; + case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: defer<AllValidator2>(call, props); break; + case DSPROPERTY_EAX20LISTENER_ROOM: defer<RoomValidator>(call, props.lRoom); break; + case DSPROPERTY_EAX20LISTENER_ROOMHF: defer<RoomHFValidator>(call, props.lRoomHF); break; + case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor); break; + case DSPROPERTY_EAX20LISTENER_DECAYTIME: defer<DecayTimeValidator>(call, props.flDecayTime); break; + case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: defer<DecayHFRatioValidator>(call, props.flDecayHFRatio); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONS: defer<ReflectionsValidator>(call, props.lReflections); break; + case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: defer<ReflectionsDelayValidator>(call, props.flReverbDelay); break; + case DSPROPERTY_EAX20LISTENER_REVERB: defer<ReverbValidator>(call, props.lReverb); break; + case DSPROPERTY_EAX20LISTENER_REVERBDELAY: defer<ReverbDelayValidator>(call, props.flReverbDelay); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize); break; + case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion); break; + case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF); break; + case DSPROPERTY_EAX20LISTENER_FLAGS: defer<FlagsValidator2>(call, props.dwFlags); break; + default: fail_unknown_property_id(); } } @@ -1369,117 +1220,34 @@ void EaxReverbCommitter::Set(const EaxCall &call, EAXREVERBPROPERTIES &props) { switch(call.get_property_id()) { - case EAXREVERB_NONE: - break; - - case EAXREVERB_ALLPARAMETERS: - defer<AllValidator3>(call, props); - break; - - case EAXREVERB_ENVIRONMENT: - defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment); - break; - - case EAXREVERB_ENVIRONMENTSIZE: - defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize); - break; - - case EAXREVERB_ENVIRONMENTDIFFUSION: - defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion); - break; - - case EAXREVERB_ROOM: - defer3<RoomValidator>(call, props, props.lRoom); - break; - - case EAXREVERB_ROOMHF: - defer3<RoomHFValidator>(call, props, props.lRoomHF); - break; - - case EAXREVERB_ROOMLF: - defer3<RoomLFValidator>(call, props, props.lRoomLF); - break; - - case EAXREVERB_DECAYTIME: - defer3<DecayTimeValidator>(call, props, props.flDecayTime); - break; - - case EAXREVERB_DECAYHFRATIO: - defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio); - break; - - case EAXREVERB_DECAYLFRATIO: - defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio); - break; - - case EAXREVERB_REFLECTIONS: - defer3<ReflectionsValidator>(call, props, props.lReflections); - break; - - case EAXREVERB_REFLECTIONSDELAY: - defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay); - break; - - case EAXREVERB_REFLECTIONSPAN: - defer3<VectorValidator>(call, props, props.vReflectionsPan); - break; - - case EAXREVERB_REVERB: - defer3<ReverbValidator>(call, props, props.lReverb); - break; - - case EAXREVERB_REVERBDELAY: - defer3<ReverbDelayValidator>(call, props, props.flReverbDelay); - break; - - case EAXREVERB_REVERBPAN: - defer3<VectorValidator>(call, props, props.vReverbPan); - break; - - case EAXREVERB_ECHOTIME: - defer3<EchoTimeValidator>(call, props, props.flEchoTime); - break; - - case EAXREVERB_ECHODEPTH: - defer3<EchoDepthValidator>(call, props, props.flEchoDepth); - break; - - case EAXREVERB_MODULATIONTIME: - defer3<ModulationTimeValidator>(call, props, props.flModulationTime); - break; - - case EAXREVERB_MODULATIONDEPTH: - defer3<ModulationDepthValidator>(call, props, props.flModulationDepth); - break; - - case EAXREVERB_AIRABSORPTIONHF: - defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF); - break; - - case EAXREVERB_HFREFERENCE: - defer3<HFReferenceValidator>(call, props, props.flHFReference); - break; - - case EAXREVERB_LFREFERENCE: - defer3<LFReferenceValidator>(call, props, props.flLFReference); - break; - - case EAXREVERB_ROOMROLLOFFFACTOR: - defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor); - break; - - case EAXREVERB_FLAGS: - defer3<FlagsValidator3>(call, props, props.ulFlags); - break; - - default: - fail_unknown_property_id(); + case EAXREVERB_NONE: break; + case EAXREVERB_ALLPARAMETERS: defer<AllValidator3>(call, props); break; + case EAXREVERB_ENVIRONMENT: defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment); break; + case EAXREVERB_ENVIRONMENTSIZE: defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize); break; + case EAXREVERB_ENVIRONMENTDIFFUSION: defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion); break; + case EAXREVERB_ROOM: defer3<RoomValidator>(call, props, props.lRoom); break; + case EAXREVERB_ROOMHF: defer3<RoomHFValidator>(call, props, props.lRoomHF); break; + case EAXREVERB_ROOMLF: defer3<RoomLFValidator>(call, props, props.lRoomLF); break; + case EAXREVERB_DECAYTIME: defer3<DecayTimeValidator>(call, props, props.flDecayTime); break; + case EAXREVERB_DECAYHFRATIO: defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio); break; + case EAXREVERB_DECAYLFRATIO: defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio); break; + case EAXREVERB_REFLECTIONS: defer3<ReflectionsValidator>(call, props, props.lReflections); break; + case EAXREVERB_REFLECTIONSDELAY: defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay); break; + case EAXREVERB_REFLECTIONSPAN: defer3<VectorValidator>(call, props, props.vReflectionsPan); break; + case EAXREVERB_REVERB: defer3<ReverbValidator>(call, props, props.lReverb); break; + case EAXREVERB_REVERBDELAY: defer3<ReverbDelayValidator>(call, props, props.flReverbDelay); break; + case EAXREVERB_REVERBPAN: defer3<VectorValidator>(call, props, props.vReverbPan); break; + case EAXREVERB_ECHOTIME: defer3<EchoTimeValidator>(call, props, props.flEchoTime); break; + case EAXREVERB_ECHODEPTH: defer3<EchoDepthValidator>(call, props, props.flEchoDepth); break; + case EAXREVERB_MODULATIONTIME: defer3<ModulationTimeValidator>(call, props, props.flModulationTime); break; + case EAXREVERB_MODULATIONDEPTH: defer3<ModulationDepthValidator>(call, props, props.flModulationDepth); break; + case EAXREVERB_AIRABSORPTIONHF: defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF); break; + case EAXREVERB_HFREFERENCE: defer3<HFReferenceValidator>(call, props, props.flHFReference); break; + case EAXREVERB_LFREFERENCE: defer3<LFReferenceValidator>(call, props, props.flLFReference); break; + case EAXREVERB_ROOMROLLOFFFACTOR: defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor); break; + case EAXREVERB_FLAGS: defer3<FlagsValidator3>(call, props, props.ulFlags); break; + default: fail_unknown_property_id(); } } -void EaxReverbCommitter::Set(const EaxCall &call, EaxEffectProps &props) -{ - Set(call, std::get<EAXREVERBPROPERTIES>(props)); -} - #endif // ALSOFT_EAX diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp index f2551229..35a64d32 100644 --- a/al/effects/vmorpher.cpp +++ b/al/effects/vmorpher.cpp @@ -122,13 +122,29 @@ ALenum EnumFromWaveform(VMorpherWaveform type) std::to_string(static_cast<int>(type))}; } -void Vmorpher_setParami(EffectProps *props, ALenum param, int val) +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 EffectHandler::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 EffectHandler::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 EffectHandler::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 EffectHandler::SetParamfv(VmorpherProps &props, ALenum param, const float *vals) +{ SetParamf(props, param, vals[0]); } -void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val) +void EffectHandler::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 EffectHandler::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 EffectHandler::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); } - -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 +void EffectHandler::GetParamfv(const VmorpherProps &props, ALenum param, float *vals) +{ GetParamf(props, param, vals); } -DEFINE_ALEFFECT_VTABLE(Vmorpher); - -const EffectProps VmorpherEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { @@ -352,10 +337,9 @@ template<> throw Exception{message}; } -template<> -bool VocalMorpherCommitter::commit(const EaxEffectProps &props) +bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &props) { - if(props == mEaxProps) + if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props) return false; mEaxProps = props; @@ -407,19 +391,21 @@ bool VocalMorpherCommitter::commit(const EaxEffectProps &props) return VMorpherWaveform::Sinusoid; }; - auto &eaxprops = std::get<EAXVOCALMORPHERPROPERTIES>(props); - mAlProps.Vmorpher.PhonemeA = get_phoneme(eaxprops.ulPhonemeA); - mAlProps.Vmorpher.PhonemeACoarseTuning = static_cast<int>(eaxprops.lPhonemeACoarseTuning); - mAlProps.Vmorpher.PhonemeB = get_phoneme(eaxprops.ulPhonemeB); - mAlProps.Vmorpher.PhonemeBCoarseTuning = static_cast<int>(eaxprops.lPhonemeBCoarseTuning); - mAlProps.Vmorpher.Waveform = get_waveform(eaxprops.ulWaveform); - mAlProps.Vmorpher.Rate = eaxprops.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) { static constexpr EAXVOCALMORPHERPROPERTIES defprops{[] { @@ -435,87 +421,35 @@ void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props) props = defprops; } -template<> -void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) +void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props) { - auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_); switch(call.get_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(); + 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) { - auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_); switch(call.get_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(); + 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(); } } diff --git a/al/error.cpp b/al/error.cpp index c2359477..26dc522f 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -99,41 +99,39 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...) /* Special-case alGetError since it (potentially) raises a debug signal and * returns a non-default value for a null context. */ -AL_API ALenum AL_APIENTRY alGetError(void) noexcept +AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum { - auto context = GetContextRef(); - if(!context) UNLIKELY + if(auto context = GetContextRef()) LIKELY + return alGetErrorDirect(context.get()); + + static const ALenum deferror{[](const char *envname, const char *optname) -> ALenum { - static const ALenum deferror{[](const char *envname, const char *optname) -> ALenum - { - auto optstr = al::getenv(envname); - if(!optstr) - optstr = ConfigValueStr(nullptr, "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; - }("__ALSOFT_DEFAULT_ERROR", "default-error")}; - - WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); - if(TrapALError) + 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; + }("__ALSOFT_DEFAULT_ERROR", "default-error")}; + + WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); + if(TrapALError) + { #ifdef _WIN32 - if(IsDebuggerPresent()) - DebugBreak(); + if(IsDebuggerPresent()) + DebugBreak(); #elif defined(SIGTRAP) - raise(SIGTRAP); + raise(SIGTRAP); #endif - } - return deferror; } - return alGetErrorDirect(context.get()); + return deferror; } FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept diff --git a/al/event.cpp b/al/event.cpp index 8b76ceff..95b07dc2 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -118,7 +118,7 @@ int EventThread(ALCcontext *context) }; auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt) { - const std::string_view message{evt.msg}; + const std::string_view message{evt.msg.data()}; context->debugMessage(DebugSource::System, DebugType::Error, 0, DebugSeverity::High, message); diff --git a/al/filter.cpp b/al/filter.cpp index f0a078b7..528d6059 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -49,19 +49,21 @@ namespace { +using SubListAllocator = typename al::allocator<std::array<ALfilter,64>>; + class filter_exception final : public al::base_exception { ALenum mErrorCode; public: -#ifdef __USE_MINGW_ANSI_STDIO - [[gnu::format(gnu_printf, 3, 4)]] +#ifdef __MINGW32__ + [[gnu::format(__MINGW_PRINTF_FORMAT, 3, 4)]] #else [[gnu::format(printf, 3, 4)]] #endif filter_exception(ALenum code, const char *msg, ...); ~filter_exception() override; - ALenum errorCode() const noexcept { return mErrorCode; } + [[nodiscard]] auto errorCode() const noexcept -> ALenum { return mErrorCode; } }; filter_exception::filter_exception(ALenum code, const char* msg, ...) : mErrorCode{code} @@ -80,36 +82,36 @@ void InitFilterParams(ALfilter *filter, ALenum type) { filter->Gain = AL_LOWPASS_DEFAULT_GAIN; filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; + filter->HFReference = LowPassFreqRef; filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; + filter->LFReference = HighPassFreqRef; filter->mTypeVariant.emplace<LowpassFilterTable>(); } else if(type == AL_FILTER_HIGHPASS) { filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; + filter->HFReference = LowPassFreqRef; filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; + filter->LFReference = HighPassFreqRef; filter->mTypeVariant.emplace<HighpassFilterTable>(); } else if(type == AL_FILTER_BANDPASS) { filter->Gain = AL_BANDPASS_DEFAULT_GAIN; filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; + filter->HFReference = LowPassFreqRef; filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; + filter->LFReference = HighPassFreqRef; filter->mTypeVariant.emplace<BandpassFilterTable>(); } else { filter->Gain = 1.0f; filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; + filter->HFReference = LowPassFreqRef; filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; + filter->LFReference = HighPassFreqRef; filter->mTypeVariant.emplace<NullFilterTable>(); } filter->type = type; @@ -121,21 +123,21 @@ bool EnsureFilters(ALCdevice *device, size_t needed) [](size_t cur, const FilterSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - while(needed > count) - { - if(device->FilterList.size() >= 1<<25) UNLIKELY - return false; - - device->FilterList.emplace_back(); - auto sublist = device->FilterList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64)); - if(!sublist->Filters) UNLIKELY + try { + while(needed > count) { - device->FilterList.pop_back(); - return false; + if(device->FilterList.size() >= 1<<25) UNLIKELY + return false; + + FilterSubList sublist{}; + sublist.FreeMask = ~0_u64; + sublist.Filters = SubListAllocator{}.allocate(1); + device->FilterList.emplace_back(std::move(sublist)); + count += 64; } - count += 64; + } + catch(...) { + return false; } return true; } @@ -150,7 +152,7 @@ ALfilter *AllocFilter(ALCdevice *device) auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); ASSUME(slidx < 64); - ALfilter *filter{al::construct_at(sublist->Filters + slidx)}; + ALfilter *filter{al::construct_at(al::to_address(sublist->Filters->begin() + slidx))}; InitFilterParams(filter, AL_FILTER_NULL); /* Add 1 to avoid filter ID 0. */ @@ -185,7 +187,7 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) FilterSubList &sublist = device->FilterList[lidx]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Filters + slidx; + return al::to_address(sublist.Filters->begin() + slidx); } } // namespace @@ -695,10 +697,10 @@ FilterSubList::~FilterSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - std::destroy_at(Filters+idx); + std::destroy_at(al::to_address(Filters->begin() + idx)); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; - al_free(Filters); + SubListAllocator{}.deallocate(Filters, 1); Filters = nullptr; } diff --git a/al/filter.h b/al/filter.h index 505900d4..dffe8c6e 100644 --- a/al/filter.h +++ b/al/filter.h @@ -1,6 +1,8 @@ #ifndef AL_FILTER_H #define AL_FILTER_H +#include <array> +#include <cstdint> #include <string_view> #include <variant> @@ -9,10 +11,11 @@ #include "AL/alext.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 { @@ -38,9 +41,9 @@ 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}; using TableTypes = std::variant<NullFilterTable,LowpassFilterTable,HighpassFilterTable, BandpassFilterTable>; @@ -51,7 +54,22 @@ struct ALfilter { 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 diff --git a/al/listener.h b/al/listener.h index 81532877..a50f118a 100644 --- a/al/listener.h +++ b/al/listener.h @@ -18,7 +18,7 @@ struct ALlistener { float Gain{1.0f}; float mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT}; - DISABLE_ALLOC() + DISABLE_ALLOC }; #endif diff --git a/al/source.cpp b/al/source.cpp index fe5bba40..b3af9428 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -80,7 +80,7 @@ namespace { -using namespace std::placeholders; +using SubListAllocator = typename al::allocator<std::array<ALsource,64>>; using std::chrono::nanoseconds; using seconds_d = std::chrono::duration<double>; @@ -171,7 +171,7 @@ void UpdateSourceProps(const ALsource *source, Voice *voice, ALCcontext *context ret.LFReference = srcsend.LFReference; return ret; }; - std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); + std::transform(source->Send.cbegin(), source->Send.cend(), props->Send.begin(), copy_send); if(!props->Send[0].Slot && context->mDefaultSlot) props->Send[0].Slot = context->mDefaultSlot->mSlot; @@ -202,7 +202,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds do { refcount = device->waitForMix(); - *clocktime = GetDeviceClockTime(device); + *clocktime = device->getClockTime(); voice = GetSourceVoice(Source, context); if(voice) { @@ -212,7 +212,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds readPos += voice->mPositionFrac.load(std::memory_order_relaxed); } std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + } while(refcount != device->mMixCount.load(std::memory_order_relaxed)); if(!voice) return 0; @@ -242,7 +242,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl do { refcount = device->waitForMix(); - *clocktime = GetDeviceClockTime(device); + *clocktime = device->getClockTime(); voice = GetSourceVoice(Source, context); if(voice) { @@ -252,7 +252,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl readPos += voice->mPositionFrac.load(std::memory_order_relaxed); } std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + } while(refcount != device->mMixCount.load(std::memory_order_relaxed)); if(!voice) return 0.0f; @@ -302,7 +302,7 @@ NOINLINE T GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); } std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + } while(refcount != device->mMixCount.load(std::memory_order_relaxed)); if(!voice) return T{0}; @@ -575,7 +575,7 @@ void SendVoiceChanges(ALCcontext *ctx, VoiceChange *tail) oldhead->mNext.store(tail, std::memory_order_release); const bool connected{device->Connected.load(std::memory_order_acquire)}; - device->waitForMix(); + std::ignore = device->waitForMix(); if(!connected) UNLIKELY { if(ctx->mStopVoicesOnDisconnect.load(std::memory_order_acquire)) @@ -681,7 +681,7 @@ bool SetVoiceOffset(Voice *oldvoice, const VoicePos &vpos, ALsource *source, ALC return true; /* Otherwise, wait for any current mix to finish and check one last time. */ - device->waitForMix(); + std::ignore = device->waitForMix(); if(newvoice->mPlayState.load(std::memory_order_acquire) != Voice::Pending) return true; /* The change-over failed because the old voice stopped before the new @@ -721,21 +721,21 @@ bool EnsureSources(ALCcontext *context, size_t needed) [](size_t cur, const SourceSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - while(needed > count) - { - if(context->mSourceList.size() >= 1<<25) UNLIKELY - return false; - - context->mSourceList.emplace_back(); - auto sublist = context->mSourceList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Sources = static_cast<ALsource*>(al_calloc(alignof(ALsource), sizeof(ALsource)*64)); - if(!sublist->Sources) UNLIKELY + try { + while(needed > count) { - context->mSourceList.pop_back(); - return false; + if(context->mSourceList.size() >= 1<<25) UNLIKELY + return false; + + SourceSubList sublist{}; + sublist.FreeMask = ~0_u64; + sublist.Sources = SubListAllocator{}.allocate(1); + context->mSourceList.emplace_back(std::move(sublist)); + count += 64; } - count += 64; + } + catch(...) { + return false; } return true; } @@ -749,7 +749,7 @@ ALsource *AllocSource(ALCcontext *context) auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); ASSUME(slidx < 64); - ALsource *source{al::construct_at(sublist->Sources + slidx)}; + ALsource *source{al::construct_at(al::to_address(sublist->Sources->begin() + slidx))}; /* Add 1 to avoid source ID 0. */ source->id = ((lidx<<6) | slidx) + 1; @@ -797,7 +797,7 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept SourceSubList &sublist{context->mSourceList[lidx]}; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Sources + slidx; + return al::to_address(sublist.Sources->begin() + slidx); } auto LookupBuffer = [](ALCdevice *device, auto id) noexcept -> ALbuffer* @@ -810,7 +810,7 @@ auto LookupBuffer = [](ALCdevice *device, auto id) noexcept -> ALbuffer* BufferSubList &sublist = device->BufferList[static_cast<size_t>(lidx)]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Buffers + static_cast<size_t>(slidx); + return al::to_address(sublist.Buffers->begin() + static_cast<size_t>(slidx)); }; auto LookupFilter = [](ALCdevice *device, auto id) noexcept -> ALfilter* @@ -823,7 +823,7 @@ auto LookupFilter = [](ALCdevice *device, auto id) noexcept -> ALfilter* FilterSubList &sublist = device->FilterList[static_cast<size_t>(lidx)]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Filters + static_cast<size_t>(slidx); + return al::to_address(sublist.Filters->begin() + static_cast<size_t>(slidx)); }; auto LookupEffectSlot = [](ALCcontext *context, auto id) noexcept -> ALeffectslot* @@ -836,7 +836,7 @@ auto LookupEffectSlot = [](ALCcontext *context, auto id) noexcept -> ALeffectslo EffectSlotSubList &sublist{context->mEffectSlotList[static_cast<size_t>(lidx)]}; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.EffectSlots + static_cast<size_t>(slidx); + return al::to_address(sublist.EffectSlots->begin() + static_cast<size_t>(slidx)); }; @@ -1316,11 +1316,11 @@ constexpr ALuint DoubleValsByProp(ALenum prop) struct check_exception : std::exception { }; struct check_size_exception final : check_exception { - const char *what() const noexcept override + [[nodiscard]] auto what() const noexcept -> const char* override { return "check_size_exception"; } }; struct check_value_exception final : check_exception { - const char *what() const noexcept override + [[nodiscard]] auto what() const noexcept -> const char* override { return "check_value_exception"; } }; @@ -1371,21 +1371,22 @@ struct PropType<ALfloat> { static const char *Name() { return "float"; } }; template<> struct PropType<ALdouble> { static const char *Name() { return "double"; } }; -template<typename T> struct HexPrinter { - char mStr[sizeof(T)*2 + 3]{}; + std::array<char,32> mStr{}; + + template<typename T> HexPrinter(T value) { using ST = std::make_signed_t<std::remove_cv_t<T>>; if constexpr(std::is_same_v<ST,int>) - std::snprintf(mStr, std::size(mStr), "0x%x", value); + std::snprintf(mStr.data(), mStr.size(), "0x%x", value); else if constexpr(std::is_same_v<ST,long>) - std::snprintf(mStr, std::size(mStr), "0x%lx", value); + std::snprintf(mStr.data(), mStr.size(), "0x%lx", value); else if constexpr(std::is_same_v<ST,long long>) - std::snprintf(mStr, std::size(mStr), "0x%llx", value); + std::snprintf(mStr.data(), mStr.size(), "0x%llx", value); } - const char *c_str() const noexcept { return mStr; } + [[nodiscard]] auto c_str() const noexcept -> const char* { return mStr.data(); } }; @@ -1579,7 +1580,7 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con * to ensure it isn't currently looping back or reaching the * end. */ - device->waitForMix(); + std::ignore = device->waitForMix(); } return; } @@ -1604,10 +1605,11 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con if(!buffer) UNLIKELY return Context->setError(AL_INVALID_VALUE, "Invalid buffer ID %s", std::to_string(values[0]).c_str()); - if(buffer->MappedAccess && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY + if(buffer->MappedAccess + && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY return Context->setError(AL_INVALID_OPERATION, "Setting non-persistently mapped buffer %u", buffer->id); - if(buffer->mCallback && ReadRef(buffer->ref) != 0) UNLIKELY + if(buffer->mCallback && buffer->ref.load(std::memory_order_relaxed) != 0) UNLIKELY return Context->setError(AL_INVALID_OPERATION, "Setting already-set callback buffer %u", buffer->id); @@ -1793,9 +1795,9 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con { Source->Direct.Gain = 1.0f; Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.HFReference = LowPassFreqRef; Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; + Source->Direct.LFReference = HighPassFreqRef; } return UpdateSourceProps(Source, Context); } @@ -1921,7 +1923,8 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con ALeffectslot *slot{}; if(values[0]) { - if((slot=LookupEffectSlot(Context, slotid)) == nullptr) UNLIKELY + slot = LookupEffectSlot(Context, slotid); + if(!slot) UNLIKELY return Context->setError(AL_INVALID_VALUE, "Invalid effect ID %s", std::to_string(slotid).c_str()); } @@ -1950,9 +1953,9 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con /* Disable filter */ send.Gain = 1.0f; send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; + send.HFReference = LowPassFreqRef; send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; + send.LFReference = HighPassFreqRef; } /* We must force an update if the current auxiliary slot is valid @@ -3404,90 +3407,94 @@ FORCE_ALIGN void AL_APIENTRY alSourceQueueBuffersDirect(ALCcontext *context, ALu std::unique_lock<std::mutex> buflock{device->BufferLock}; const size_t NewListStart{source->mQueue.size()}; - ALbufferQueueItem *BufferList{nullptr}; - for(ALsizei i{0};i < nb;i++) - { - bool fmt_mismatch{false}; - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + try { + ALbufferQueueItem *BufferList{nullptr}; + for(ALsizei i{0};i < nb;i++) { - context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]); - goto buffer_error; - } - if(buffer) - { - if(buffer->mSampleRate < 1) + bool fmt_mismatch{false}; + ALbuffer *buffer{buffers[i] ? LookupBuffer(device, buffers[i]) : nullptr}; + if(buffers[i] && !buffer) { - context->setError(AL_INVALID_OPERATION, "Queueing buffer %u with no format", - buffer->id); - goto buffer_error; + context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]); + throw std::exception{}; } - if(buffer->mCallback) + if(buffer) { - context->setError(AL_INVALID_OPERATION, "Queueing callback buffer %u", buffer->id); - goto buffer_error; + if(buffer->mSampleRate < 1) + { + context->setError(AL_INVALID_OPERATION, "Queueing buffer %u with no format", + buffer->id); + throw std::exception{}; + } + if(buffer->mCallback) + { + context->setError(AL_INVALID_OPERATION, "Queueing callback buffer %u", + buffer->id); + throw std::exception{}; + } + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + context->setError(AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + throw std::exception{}; + } } - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + + source->mQueue.emplace_back(); + if(!BufferList) + BufferList = &source->mQueue.back(); + else { - context->setError(AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); - goto buffer_error; + auto &item = source->mQueue.back(); + BufferList->mNext.store(&item, std::memory_order_relaxed); + BufferList = &item; } - } - - source->mQueue.emplace_back(); - if(!BufferList) - BufferList = &source->mQueue.back(); - else - { - auto &item = source->mQueue.back(); - BufferList->mNext.store(&item, std::memory_order_relaxed); - BufferList = &item; - } - if(!buffer) continue; - BufferList->mBlockAlign = buffer->mBlockAlign; - BufferList->mSampleLen = buffer->mSampleLen; - BufferList->mLoopEnd = buffer->mSampleLen; - BufferList->mSamples = buffer->mData.data(); - BufferList->mBuffer = buffer; - IncrementRef(buffer->ref); - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else - { - fmt_mismatch |= BufferFmt->mSampleRate != buffer->mSampleRate; - fmt_mismatch |= BufferFmt->mChannels != buffer->mChannels; - fmt_mismatch |= BufferFmt->mType != buffer->mType; - if(BufferFmt->isBFormat()) + if(!buffer) continue; + BufferList->mBlockAlign = buffer->mBlockAlign; + BufferList->mSampleLen = buffer->mSampleLen; + BufferList->mLoopEnd = buffer->mSampleLen; + BufferList->mSamples = buffer->mData.data(); + BufferList->mBuffer = buffer; + IncrementRef(buffer->ref); + + if(BufferFmt == nullptr) + BufferFmt = buffer; + else { - fmt_mismatch |= BufferFmt->mAmbiLayout != buffer->mAmbiLayout; - fmt_mismatch |= BufferFmt->mAmbiScaling != buffer->mAmbiScaling; + fmt_mismatch |= BufferFmt->mSampleRate != buffer->mSampleRate; + fmt_mismatch |= BufferFmt->mChannels != buffer->mChannels; + fmt_mismatch |= BufferFmt->mType != buffer->mType; + if(BufferFmt->isBFormat()) + { + fmt_mismatch |= BufferFmt->mAmbiLayout != buffer->mAmbiLayout; + fmt_mismatch |= BufferFmt->mAmbiScaling != buffer->mAmbiScaling; + } + fmt_mismatch |= BufferFmt->mAmbiOrder != buffer->mAmbiOrder; } - fmt_mismatch |= BufferFmt->mAmbiOrder != buffer->mAmbiOrder; - } - if(fmt_mismatch) UNLIKELY - { - context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format\n" - " Expected: %uhz, %s, %s ; Got: %uhz, %s, %s\n", BufferFmt->mSampleRate, - NameFromFormat(BufferFmt->mType), NameFromFormat(BufferFmt->mChannels), - buffer->mSampleRate, NameFromFormat(buffer->mType), - NameFromFormat(buffer->mChannels)); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. - */ - auto iter = source->mQueue.begin() + ptrdiff_t(NewListStart); - for(;iter != source->mQueue.end();++iter) + if(fmt_mismatch) UNLIKELY { - if(ALbuffer *buf{iter->mBuffer}) - DecrementRef(buf->ref); + context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format\n" + " Expected: %uhz, %s, %s ; Got: %uhz, %s, %s\n", BufferFmt->mSampleRate, + NameFromFormat(BufferFmt->mType), NameFromFormat(BufferFmt->mChannels), + buffer->mSampleRate, NameFromFormat(buffer->mType), + NameFromFormat(buffer->mChannels)); + throw std::exception{}; } - source->mQueue.resize(NewListStart); - return; } } + catch(...) { + /* A buffer failed (invalid ID or format), or there was some other + * unexpected error, so unlock and release each buffer we had. + */ + auto iter = source->mQueue.begin() + ptrdiff_t(NewListStart); + for(;iter != source->mQueue.end();++iter) + { + if(ALbuffer *buf{iter->mBuffer}) + DecrementRef(buf->ref); + } + source->mQueue.resize(NewListStart); + return; + } /* All buffers good. */ buflock.unlock(); @@ -3565,17 +3572,17 @@ ALsource::ALsource() { Direct.Gain = 1.0f; Direct.GainHF = 1.0f; - Direct.HFReference = LOWPASSFREQREF; + Direct.HFReference = LowPassFreqRef; Direct.GainLF = 1.0f; - Direct.LFReference = HIGHPASSFREQREF; + Direct.LFReference = HighPassFreqRef; for(auto &send : Send) { send.Slot = nullptr; send.Gain = 1.0f; send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; + send.HFReference = LowPassFreqRef; send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; + send.LFReference = HighPassFreqRef; } } @@ -3632,18 +3639,15 @@ SourceSubList::~SourceSubList() { const int idx{al::countr_zero(usemask)}; usemask &= ~(1_u64 << idx); - std::destroy_at(Sources+idx); + std::destroy_at(al::to_address(Sources->begin() + idx)); } FreeMask = ~usemask; - al_free(Sources); + SubListAllocator{}.deallocate(Sources, 1); Sources = nullptr; } #ifdef ALSOFT_EAX -constexpr const ALsource::EaxFxSlotIds ALsource::eax4_fx_slot_ids; -constexpr const ALsource::EaxFxSlotIds ALsource::eax5_fx_slot_ids; - void ALsource::eaxInitialize(ALCcontext *context) noexcept { assert(context != nullptr); @@ -3916,27 +3920,30 @@ void ALsource::eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept // Active FX slots. // - for (auto i = 0; i < EAX50_MAX_ACTIVE_FXSLOTS; ++i) { + for(size_t i{0};i < EAX50_MAX_ACTIVE_FXSLOTS;++i) + { auto& dst_id = dst.active_fx_slots.guidActiveFXSlots[i]; - if (i < EAX40_MAX_ACTIVE_FXSLOTS) { + if(i < EAX40_MAX_ACTIVE_FXSLOTS) + { const auto& src_id = src.active_fx_slots.guidActiveFXSlots[i]; - if (src_id == EAX_NULL_GUID) + if(src_id == EAX_NULL_GUID) dst_id = EAX_NULL_GUID; - else if (src_id == EAX_PrimaryFXSlotID) + else if(src_id == EAX_PrimaryFXSlotID) dst_id = EAX_PrimaryFXSlotID; - else if (src_id == EAXPROPERTYID_EAX40_FXSlot0) + else if(src_id == EAXPROPERTYID_EAX40_FXSlot0) dst_id = EAXPROPERTYID_EAX50_FXSlot0; - else if (src_id == EAXPROPERTYID_EAX40_FXSlot1) + else if(src_id == EAXPROPERTYID_EAX40_FXSlot1) dst_id = EAXPROPERTYID_EAX50_FXSlot1; - else if (src_id == EAXPROPERTYID_EAX40_FXSlot2) + else if(src_id == EAXPROPERTYID_EAX40_FXSlot2) dst_id = EAXPROPERTYID_EAX50_FXSlot2; - else if (src_id == EAXPROPERTYID_EAX40_FXSlot3) + else if(src_id == EAXPROPERTYID_EAX40_FXSlot3) dst_id = EAXPROPERTYID_EAX50_FXSlot3; else assert(false && "Unknown active FX slot ID."); - } else + } + else dst_id = EAX_NULL_GUID; } @@ -4067,9 +4074,9 @@ void ALsource::eax_update_direct_filter() const auto& direct_param = eax_create_direct_filter_param(); Direct.Gain = direct_param.gain; Direct.GainHF = direct_param.gain_hf; - Direct.HFReference = LOWPASSFREQREF; + Direct.HFReference = LowPassFreqRef; Direct.GainLF = 1.0f; - Direct.LFReference = HIGHPASSFREQREF; + Direct.LFReference = HighPassFreqRef; mPropsDirty = true; } @@ -4358,7 +4365,7 @@ void ALsource::eax4_set(const EaxCall& call, Eax4Props& props) break; case EAXSOURCE_ACTIVEFXSLOTID: - eax4_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots); + eax4_defer_active_fx_slot_id(call, al::span{props.active_fx_slots.guidActiveFXSlots}); break; default: @@ -4439,7 +4446,7 @@ void ALsource::eax5_set(const EaxCall& call, Eax5Props& props) break; case EAXSOURCE_ACTIVEFXSLOTID: - eax5_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots); + eax5_defer_active_fx_slot_id(call, al::span{props.active_fx_slots.guidActiveFXSlots}); break; case EAXSOURCE_MACROFXFACTOR: @@ -4729,7 +4736,8 @@ void ALsource::eax4_get(const EaxCall& call, const Eax4Props& props) break; case EAXSOURCE_ACTIVEFXSLOTID: - eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots, EAX40_MAX_ACTIVE_FXSLOTS); + eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots.data(), + EAX40_MAX_ACTIVE_FXSLOTS); break; default: @@ -4801,7 +4809,8 @@ void ALsource::eax5_get(const EaxCall& call, const Eax5Props& props) break; case EAXSOURCE_ACTIVEFXSLOTID: - eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots, EAX50_MAX_ACTIVE_FXSLOTS); + eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots.data(), + EAX50_MAX_ACTIVE_FXSLOTS); break; case EAXSOURCE_MACROFXFACTOR: @@ -4841,9 +4850,9 @@ void ALsource::eax_set_al_source_send(ALeffectslot *slot, size_t sendidx, const auto &send = Send[sendidx]; send.Gain = filter.gain; send.GainHF = filter.gain_hf; - send.HFReference = LOWPASSFREQREF; + send.HFReference = LowPassFreqRef; send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; + send.LFReference = HighPassFreqRef; if(slot != nullptr) IncrementRef(slot->ref); diff --git a/al/source.h b/al/source.h index c7694f83..84fd7664 100644 --- a/al/source.h +++ b/al/source.h @@ -4,6 +4,7 @@ #include <array> #include <atomic> #include <cstddef> +#include <cstdint> #include <deque> #include <iterator> #include <limits> @@ -37,7 +38,7 @@ enum class SourceStereo : bool { Enhanced = AL_SUPER_STEREO_SOFT }; -#define DEFAULT_SENDS 2 +inline constexpr size_t DefaultSendCount{2}; inline constexpr ALuint InvalidVoiceIndex{std::numeric_limits<ALuint>::max()}; @@ -46,7 +47,7 @@ inline bool sBufferSubDataCompat{false}; struct ALbufferQueueItem : public VoiceBufferItem { ALbuffer *mBuffer{nullptr}; - DISABLE_ALLOC() + DISABLE_ALLOC }; @@ -108,21 +109,21 @@ struct ALsource { /** Direct filter and auxiliary send info. */ struct { - float Gain; - float GainHF; - float HFReference; - float GainLF; - float LFReference; + 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; + ALeffectslot *Slot{}; + float Gain{}; + float GainHF{}; + float HFReference{}; + float GainLF{}; + float LFReference{}; }; - std::array<SendData,MAX_SENDS> Send; + std::array<SendData,MaxSendCount> Send; /** * Last user-specified offset, and the offset type (bytes, samples, or @@ -159,7 +160,7 @@ struct ALsource { static void SetName(ALCcontext *context, ALuint id, std::string_view name); - DISABLE_ALLOC() + DISABLE_ALLOC #ifdef ALSOFT_EAX public: @@ -173,18 +174,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, @@ -839,11 +840,10 @@ private: 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(); @@ -978,21 +978,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); } @@ -1043,4 +1043,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 diff --git a/al/state.cpp b/al/state.cpp index 5131edd9..3ef87fbb 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -60,6 +60,7 @@ namespace { +/* NOLINTBEGIN(*-avoid-c-arrays) */ constexpr ALchar alVendor[] = "OpenAL Community"; constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; constexpr ALchar alRenderer[] = "OpenAL Soft"; @@ -73,6 +74,7 @@ constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; constexpr ALchar alStackOverflow[] = "Stack Overflow"; constexpr ALchar alStackUnderflow[] = "Stack Underflow"; +/* NOLINTEND(*-avoid-c-arrays) */ /* Resampler strings */ template<Resampler rtype> struct ResamplerName { }; @@ -299,7 +301,7 @@ inline void UpdateProps(ALCcontext *context) /* WARNING: Non-standard export! Not part of any extension, or exposed in the * alcFunctions list. */ -AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) noexcept +AL_API auto AL_APIENTRY alsoft_get_version() noexcept -> const ALchar* { static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION"); if(spoof) return spoof->c_str(); @@ -386,7 +388,7 @@ FORCE_ALIGN ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum } #define DECL_GETFUNC(R, Name, Ext) \ -AL_API R AL_APIENTRY Name##Ext(ALenum pname) noexcept \ +AL_API auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \ { \ R value{}; \ auto context = GetContextRef(); \ @@ -394,7 +396,7 @@ AL_API R AL_APIENTRY Name##Ext(ALenum pname) noexcept \ Name##vDirect##Ext(GetContextRef().get(), pname, &value); \ return value; \ } \ -FORCE_ALIGN R AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept \ +FORCE_ALIGN auto AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept -> R \ { \ R value{}; \ Name##vDirect##Ext(context, pname, &value); \ @@ -461,7 +463,7 @@ FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum switch(pname) { case AL_EVENT_CALLBACK_FUNCTION_SOFT: - *values = al::bit_cast<void*>(context->mEventCb); + *values = reinterpret_cast<void*>(context->mEventCb); break; case AL_EVENT_CALLBACK_USER_PARAM_SOFT: @@ -469,7 +471,7 @@ FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum break; case AL_DEBUG_CALLBACK_FUNCTION_EXT: - *values = al::bit_cast<void*>(context->mDebugCb); + *values = reinterpret_cast<void*>(context->mDebugCb); break; case AL_DEBUG_CALLBACK_USER_PARAM_EXT: @@ -641,18 +643,18 @@ AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept void UpdateContextProps(ALCcontext *context) { - /* Get an unused proprty container, or allocate a new one as needed. */ + /* Get an unused property container, or allocate a new one as needed. */ ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)}; if(!props) - props = new ContextProps{}; - else { - ContextProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->mFreeContextProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); + context->allocContextProps(); + props = context->mFreeContextProps.load(std::memory_order_acquire); } + ContextProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->mFreeContextProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == false); /* Copy in current property values. */ ALlistener &listener = context->mListener; |