diff options
Diffstat (limited to 'al')
42 files changed, 3768 insertions, 3762 deletions
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 285da1d4..fb646389 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -47,6 +47,7 @@ #include "core/except.h" #include "core/fpu_ctrl.h" #include "core/logging.h" +#include "direct_defs.h" #include "effect.h" #include "opthelpers.h" @@ -165,7 +166,7 @@ void AddActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext *co curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); context->mDevice->waitForMix(); - al::destroy_n(curarray->end(), curarray->size()); + std::destroy_n(curarray->end(), curarray->size()); delete curarray; } @@ -204,7 +205,7 @@ void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); context->mDevice->waitForMix(); - al::destroy_n(curarray->end(), curarray->size()); + std::destroy_n(curarray->end(), curarray->size()); delete curarray; } @@ -229,7 +230,7 @@ EffectSlotType EffectSlotTypeFromEnum(ALenum type) case AL_EFFECT_EAXREVERB: return EffectSlotType::EAXReverb; case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: return EffectSlotType::DedicatedLFE; case AL_EFFECT_DEDICATED_DIALOGUE: return EffectSlotType::DedicatedDialog; - case AL_EFFECT_CONVOLUTION_REVERB_SOFT: return EffectSlotType::Convolution; + case AL_EFFECT_CONVOLUTION_SOFT: return EffectSlotType::Convolution; } ERR("Unhandled effect enum: 0x%04x\n", type); return EffectSlotType::None; @@ -238,7 +239,7 @@ EffectSlotType EffectSlotTypeFromEnum(ALenum type) bool EnsureEffectSlots(ALCcontext *context, size_t needed) { size_t count{std::accumulate(context->mEffectSlotList.cbegin(), - context->mEffectSlotList.cend(), size_t{0}, + context->mEffectSlotList.cend(), 0_uz, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; @@ -285,11 +286,13 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) { + context->mEffectSlotNames.erase(slot->id); + const ALuint id{slot->id - 1}; const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(slot); + std::destroy_at(slot); context->mEffectSlotList[lidx].FreeMask |= 1_u64 << slidx; context->mNumEffectSlots--; @@ -309,12 +312,10 @@ inline void UpdateProps(ALeffectslot *slot, ALCcontext *context) } // namespace -AL_API void AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) -START_API_FUNC +AL_API DECL_FUNC2(void, alGenAuxiliaryEffectSlots, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alGenAuxiliaryEffectSlotsDirect(ALCcontext *context, ALsizei n, + ALuint *effectslots) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Generating %d effect slots", n); if(n <= 0) UNLIKELY return; @@ -327,7 +328,7 @@ START_API_FUNC device->AuxiliaryEffectSlotMax, context->mNumEffectSlots, n); return; } - if(!EnsureEffectSlots(context.get(), static_cast<ALuint>(n))) + if(!EnsureEffectSlots(context, static_cast<ALuint>(n))) { context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effectslot%s", n, (n==1) ? "" : "s"); @@ -336,29 +337,26 @@ START_API_FUNC if(n == 1) { - ALeffectslot *slot{AllocEffectSlot(context.get())}; + ALeffectslot *slot{AllocEffectSlot(context)}; effectslots[0] = slot->id; } else { - al::vector<ALuint> ids; + std::vector<ALuint> ids; ALsizei count{n}; ids.reserve(static_cast<ALuint>(count)); do { - ALeffectslot *slot{AllocEffectSlot(context.get())}; + ALeffectslot *slot{AllocEffectSlot(context)}; ids.emplace_back(slot->id); } while(--count); std::copy(ids.cbegin(), ids.cend(), effectslots); } } -END_API_FUNC -AL_API void AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) -START_API_FUNC +AL_API DECL_FUNC2(void, alDeleteAuxiliaryEffectSlots, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *context, ALsizei n, + const ALuint *effectslots) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Deleting %d effect slots", n); if(n <= 0) UNLIKELY return; @@ -366,7 +364,7 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mEffectSlotLock}; if(n == 1) { - ALeffectslot *slot{LookupEffectSlot(context.get(), effectslots[0])}; + ALeffectslot *slot{LookupEffectSlot(context, effectslots[0])}; if(!slot) UNLIKELY { context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[0]); @@ -378,15 +376,15 @@ START_API_FUNC effectslots[0]); return; } - RemoveActiveEffectSlots({&slot, 1u}, context.get()); - FreeEffectSlot(context.get(), slot); + RemoveActiveEffectSlots({&slot, 1u}, context); + FreeEffectSlot(context, slot); } else { - auto slots = al::vector<ALeffectslot*>(static_cast<ALuint>(n)); + auto slots = std::vector<ALeffectslot*>(static_cast<ALuint>(n)); for(size_t i{0};i < slots.size();++i) { - ALeffectslot *slot{LookupEffectSlot(context.get(), effectslots[i])}; + ALeffectslot *slot{LookupEffectSlot(context, effectslots[i])}; if(!slot) UNLIKELY { context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[i]); @@ -410,30 +408,24 @@ START_API_FUNC slots.erase(slots_end, slots.end()); /* All effectslots are valid, remove and delete them */ - RemoveActiveEffectSlots(slots, context.get()); + RemoveActiveEffectSlots(slots, context); for(ALeffectslot *slot : slots) - FreeEffectSlot(context.get(), slot); + FreeEffectSlot(context, slot); } } -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsAuxiliaryEffectSlot, ALuint) +FORCE_ALIGN ALboolean AL_APIENTRY alIsAuxiliaryEffectSlotDirect(ALCcontext *context, + ALuint effectslot) noexcept { - ContextRef context{GetContextRef()}; - if(context) LIKELY - { - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - if(LookupEffectSlot(context.get(), effectslot) != nullptr) - return AL_TRUE; - } + std::lock_guard<std::mutex> _{context->mEffectSlotLock}; + if(LookupEffectSlot(context, effectslot) != nullptr) + return AL_TRUE; return AL_FALSE; } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlaySOFT(ALuint slotid) -START_API_FUNC +AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlaySOFT(ALuint slotid) noexcept { ContextRef context{GetContextRef()}; if(!context) UNLIKELY return; @@ -454,10 +446,8 @@ START_API_FUNC AddActiveEffectSlots({&slot, 1}, context.get()); slot->mState = SlotState::Playing; } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlayvSOFT(ALsizei n, const ALuint *slotids) -START_API_FUNC +AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlayvSOFT(ALsizei n, const ALuint *slotids) noexcept { ContextRef context{GetContextRef()}; if(!context) UNLIKELY return; @@ -466,7 +456,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Playing %d effect slots", n); if(n <= 0) UNLIKELY return; - auto slots = al::vector<ALeffectslot*>(static_cast<ALuint>(n)); + auto slots = std::vector<ALeffectslot*>(static_cast<ALuint>(n)); std::lock_guard<std::mutex> _{context->mEffectSlotLock}; for(size_t i{0};i < slots.size();++i) { @@ -489,10 +479,8 @@ START_API_FUNC for(auto slot : slots) slot->mState = SlotState::Playing; } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopSOFT(ALuint slotid) -START_API_FUNC +AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopSOFT(ALuint slotid) noexcept { ContextRef context{GetContextRef()}; if(!context) UNLIKELY return; @@ -508,10 +496,8 @@ START_API_FUNC RemoveActiveEffectSlots({&slot, 1}, context.get()); slot->mState = SlotState::Stopped; } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopvSOFT(ALsizei n, const ALuint *slotids) -START_API_FUNC +AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopvSOFT(ALsizei n, const ALuint *slotids) noexcept { ContextRef context{GetContextRef()}; if(!context) UNLIKELY return; @@ -520,7 +506,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Stopping %d effect slots", n); if(n <= 0) UNLIKELY return; - auto slots = al::vector<ALeffectslot*>(static_cast<ALuint>(n)); + auto slots = std::vector<ALeffectslot*>(static_cast<ALuint>(n)); std::lock_guard<std::mutex> _{context->mEffectSlotLock}; for(size_t i{0};i < slots.size();++i) { @@ -538,18 +524,15 @@ START_API_FUNC for(auto slot : slots) slot->mState = SlotState::Stopped; } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) -START_API_FUNC +AL_API DECL_FUNC3(void, alAuxiliaryEffectSloti, ALuint, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alAuxiliaryEffectSlotiDirect(ALCcontext *context, ALuint effectslot, + ALenum param, ALint value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -565,12 +548,12 @@ START_API_FUNC std::lock_guard<std::mutex> ___{device->EffectLock}; ALeffect *effect{value ? LookupEffect(device, static_cast<ALuint>(value)) : nullptr}; if(effect) - err = slot->initEffect(effect->type, effect->Props, context.get()); + err = slot->initEffect(effect->id, effect->type, effect->Props, context); else { if(value != 0) return context->setError(AL_INVALID_VALUE, "Invalid effect ID %u", value); - err = slot->initEffect(AL_EFFECT_NULL, EffectProps{}, context.get()); + err = slot->initEffect(0, AL_EFFECT_NULL, EffectProps{}, context); } } if(err != AL_NO_ERROR) UNLIKELY @@ -581,9 +564,9 @@ START_API_FUNC if(slot->mState == SlotState::Initial) UNLIKELY { slot->mPropsDirty = false; - slot->updateProps(context.get()); + slot->updateProps(context); - AddActiveEffectSlots({&slot, 1}, context.get()); + AddActiveEffectSlots({&slot, 1}, context); slot->mState = SlotState::Playing; return; } @@ -599,7 +582,7 @@ START_API_FUNC break; case AL_EFFECTSLOT_TARGET_SOFT: - target = LookupEffectSlot(context.get(), static_cast<ALuint>(value)); + target = LookupEffectSlot(context, static_cast<ALuint>(value)); if(value && !target) return context->setError(AL_INVALID_VALUE, "Invalid effect slot target ID"); if(slot->Target == target) UNLIKELY @@ -623,7 +606,7 @@ START_API_FUNC if(target) IncrementRef(target->ref); DecrementRef(oldtarget->ref); slot->Target = target; - slot->updateProps(context.get()); + slot->updateProps(context); return; } @@ -677,12 +660,12 @@ START_API_FUNC return context->setError(AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); } - UpdateProps(slot, context.get()); + UpdateProps(slot, context); } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotiv, ALuint, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alAuxiliaryEffectSlotivDirect(ALCcontext *context, ALuint effectslot, + ALenum param, const ALint *values) noexcept { switch(param) { @@ -691,15 +674,12 @@ START_API_FUNC case AL_EFFECTSLOT_TARGET_SOFT: case AL_EFFECTSLOT_STATE_SOFT: case AL_BUFFER: - alAuxiliaryEffectSloti(effectslot, param, values[0]); + alAuxiliaryEffectSlotiDirect(context, effectslot, param, values[0]); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -710,17 +690,14 @@ START_API_FUNC "Invalid effect slot integer-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) -START_API_FUNC +AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alAuxiliaryEffectSlotfDirect(ALCcontext *context, ALuint effectslot, + ALenum param, ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -738,25 +715,22 @@ START_API_FUNC return context->setError(AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); } - UpdateProps(slot, context.get()); + UpdateProps(slot, context); } -END_API_FUNC -AL_API void AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotfv, ALuint, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alAuxiliaryEffectSlotfvDirect(ALCcontext *context, ALuint effectslot, + ALenum param, const ALfloat *values) noexcept { switch(param) { case AL_EFFECTSLOT_GAIN: - alAuxiliaryEffectSlotf(effectslot, param, values[0]); + alAuxiliaryEffectSlotfDirect(context, effectslot, param, values[0]); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -767,22 +741,23 @@ START_API_FUNC "Invalid effect slot float-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSloti, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetAuxiliaryEffectSlotiDirect(ALCcontext *context, + ALuint effectslot, ALenum param, ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); switch(param) { + case AL_EFFECTSLOT_EFFECT: + *value = static_cast<ALint>(slot->EffectId); + break; + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: *value = slot->AuxSendAuto ? AL_TRUE : AL_FALSE; break; @@ -809,10 +784,10 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotiv, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetAuxiliaryEffectSlotivDirect(ALCcontext *context, + ALuint effectslot, ALenum param, ALint *values) noexcept { switch(param) { @@ -821,15 +796,12 @@ START_API_FUNC case AL_EFFECTSLOT_TARGET_SOFT: case AL_EFFECTSLOT_STATE_SOFT: case AL_BUFFER: - alGetAuxiliaryEffectSloti(effectslot, param, values); + alGetAuxiliaryEffectSlotiDirect(context, effectslot, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -840,16 +812,13 @@ START_API_FUNC param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotf, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetAuxiliaryEffectSlotfDirect(ALCcontext *context, + ALuint effectslot, ALenum param, ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -863,23 +832,20 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotfv, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetAuxiliaryEffectSlotfvDirect(ALCcontext *context, + ALuint effectslot, ALenum param, ALfloat *values) noexcept { switch(param) { case AL_EFFECTSLOT_GAIN: - alGetAuxiliaryEffectSlotf(effectslot, param, values); + alGetAuxiliaryEffectSlotfDirect(context, effectslot, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mEffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + ALeffectslot *slot = LookupEffectSlot(context, effectslot); if(!slot) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot); @@ -890,7 +856,6 @@ START_API_FUNC param); } } -END_API_FUNC ALeffectslot::ALeffectslot(ALCcontext *context) @@ -926,7 +891,7 @@ ALeffectslot::~ALeffectslot() mSlot->InUse = false; } -ALenum ALeffectslot::initEffect(ALenum effectType, const EffectProps &effectProps, +ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps, ALCcontext *context) { EffectSlotType newtype{EffectSlotTypeFromEnum(effectType)}; @@ -955,6 +920,7 @@ ALenum ALeffectslot::initEffect(ALenum effectType, const EffectProps &effectProp } else if(newtype != EffectSlotType::None) Effect.Props = effectProps; + EffectId = effectId; /* Remove state references from old effect slot property updates. */ EffectSlotProps *props{context->mFreeEffectslotProps.load()}; @@ -1003,6 +969,17 @@ void ALeffectslot::updateProps(ALCcontext *context) } } +void ALeffectslot::SetName(ALCcontext* context, ALuint id, std::string_view name) +{ + std::lock_guard<std::mutex> _{context->mEffectSlotLock}; + + auto slot = LookupEffectSlot(context, id); + if(!slot) UNLIKELY + return context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id); + + context->mEffectSlotNames.insert_or_assign(id, name); +} + void UpdateAllEffectSlotProps(ALCcontext *context) { std::lock_guard<std::mutex> _{context->mEffectSlotLock}; @@ -1023,11 +1000,14 @@ void UpdateAllEffectSlotProps(ALCcontext *context) EffectSlotSubList::~EffectSlotSubList() { + if(!EffectSlots) + return; + uint64_t usemask{~FreeMask}; while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(EffectSlots+idx); + std::destroy_at(EffectSlots+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; @@ -1272,7 +1252,7 @@ void ALeffectslot::eax_fx_slot_load_effect(int version, ALenum altype) void ALeffectslot::eax_fx_slot_set_volume() { - const auto volume = clamp(eax_.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME); + const auto volume = std::clamp(eax_.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME); const auto gain = level_mb_to_gain(static_cast<float>(volume)); eax_set_efx_slot_gain(gain); } @@ -1470,7 +1450,8 @@ void ALeffectslot::eax_set_efx_slot_effect(EaxEffect &effect) { #define EAX_PREFIX "[EAX_SET_EFFECT_SLOT_EFFECT] " - const auto error = initEffect(effect.al_effect_type_, effect.al_effect_props_, eax_al_context_); + const auto error = initEffect(0, effect.al_effect_type_, effect.al_effect_props_, + eax_al_context_); if(error != AL_NO_ERROR) { ERR(EAX_PREFIX "%s\n", "Failed to initialize an effect."); diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 3e9a2a4e..1ad0ffc4 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -3,6 +3,7 @@ #include <atomic> #include <cstddef> +#include <string_view> #include "AL/al.h" #include "AL/alc.h" @@ -45,6 +46,7 @@ enum class SlotState : ALenum { }; struct ALeffectslot { + ALuint EffectId{}; float Gain{1.0f}; bool AuxSendAuto{true}; ALeffectslot *Target{nullptr}; @@ -73,9 +75,12 @@ struct ALeffectslot { ALeffectslot& operator=(const ALeffectslot&) = delete; ~ALeffectslot(); - ALenum initEffect(ALenum effectType, const EffectProps &effectProps, ALCcontext *context); + ALenum initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps, + ALCcontext *context); void updateProps(ALCcontext *context); + 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) diff --git a/al/buffer.cpp b/al/buffer.cpp index ee506596..7d043036 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -26,6 +26,7 @@ #include <array> #include <atomic> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstdlib> #include <cstring> @@ -35,28 +36,31 @@ #include <mutex> #include <new> #include <numeric> +#include <optional> #include <stdexcept> #include <utility> +#include <vector> #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "albit.h" -#include "albyte.h" #include "alc/context.h" #include "alc/device.h" #include "alc/inprogext.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "atomic.h" #include "core/except.h" #include "core/logging.h" #include "core/voice.h" +#include "direct_defs.h" #include "opthelpers.h" #ifdef ALSOFT_EAX +#include <unordered_set> + #include "eax/globals.h" #include "eax/x_ram.h" #endif // ALSOFT_EAX @@ -64,14 +68,14 @@ namespace { -al::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout) +std::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout) { switch(layout) { case AL_FUMA_SOFT: return AmbiLayout::FuMa; case AL_ACN_SOFT: return AmbiLayout::ACN; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromAmbiLayout(AmbiLayout layout) { @@ -83,7 +87,7 @@ ALenum EnumFromAmbiLayout(AmbiLayout layout) throw std::runtime_error{"Invalid AmbiLayout: "+std::to_string(int(layout))}; } -al::optional<AmbiScaling> AmbiScalingFromEnum(ALenum scale) +std::optional<AmbiScaling> AmbiScalingFromEnum(ALenum scale) { switch(scale) { @@ -91,7 +95,7 @@ al::optional<AmbiScaling> AmbiScalingFromEnum(ALenum scale) case AL_SN3D_SOFT: return AmbiScaling::SN3D; case AL_N3D_SOFT: return AmbiScaling::N3D; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromAmbiScaling(AmbiScaling scale) { @@ -106,7 +110,7 @@ ALenum EnumFromAmbiScaling(AmbiScaling scale) } #ifdef ALSOFT_EAX -al::optional<EaxStorage> EaxStorageFromEnum(ALenum scale) +std::optional<EaxStorage> EaxStorageFromEnum(ALenum scale) { switch(scale) { @@ -114,7 +118,7 @@ al::optional<EaxStorage> EaxStorageFromEnum(ALenum scale) case AL_STORAGE_ACCESSIBLE: return EaxStorage::Accessible; case AL_STORAGE_HARDWARE: return EaxStorage::Hardware; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromEaxStorage(EaxStorage storage) { @@ -170,7 +174,7 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M bool EnsureBuffers(ALCdevice *device, size_t needed) { - size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0}, + size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), 0_uz, [](size_t cur, const BufferSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; @@ -218,11 +222,13 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) eax_x_ram_clear(*device, *buffer); #endif // ALSOFT_EAX + device->mBufferNames.erase(buffer->id); + const ALuint id{buffer->id - 1}; const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(buffer); + std::destroy_at(buffer); device->BufferList[lidx].FreeMask |= 1_u64 << slidx; } @@ -277,7 +283,7 @@ ALuint SanitizeAlignment(FmtType type, ALuint align) /** Loads the specified data into the buffer, using the specified format. */ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, - const FmtChannels DstChannels, const FmtType DstType, const al::byte *SrcData, + const FmtChannels DstChannels, const FmtType DstType, const std::byte *SrcData, ALbitfieldSOFT access) { if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY @@ -343,7 +349,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, */ if(newsize != ALBuf->mDataStorage.size()) { - auto newdata = al::vector<al::byte,16>(newsize, al::byte{}); + auto newdata = decltype(ALBuf->mDataStorage)(newsize, std::byte{}); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { const size_t tocopy{minz(newdata.size(), ALBuf->mDataStorage.size())}; @@ -437,7 +443,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, /** Prepares the buffer to use caller-specified storage. */ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, - const FmtChannels DstChannels, const FmtType DstType, al::byte *sdata, const ALuint sdatalen) + const FmtChannels DstChannels, const FmtType DstType, std::byte *sdata, const ALuint sdatalen) { if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u", @@ -458,6 +464,7 @@ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, { case FmtUByte: return alignof(ALubyte); case FmtShort: return alignof(ALshort); + case FmtInt: return alignof(ALint); case FmtFloat: return alignof(ALfloat); case FmtDouble: return alignof(ALdouble); case FmtMulaw: return alignof(ALubyte); @@ -506,7 +513,7 @@ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, #endif decltype(ALBuf->mDataStorage){}.swap(ALBuf->mDataStorage); - ALBuf->mData = {static_cast<al::byte*>(sdata), sdatalen}; + ALBuf->mData = {static_cast<std::byte*>(sdata), sdatalen}; #ifdef ALSOFT_EAX eax_x_ram_clear(*context->mALDevice, *ALBuf); @@ -536,108 +543,120 @@ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, struct DecompResult { FmtChannels channels; FmtType type; }; -al::optional<DecompResult> DecomposeUserFormat(ALenum format) +std::optional<DecompResult> DecomposeUserFormat(ALenum format) { struct FormatMap { ALenum format; FmtChannels channels; FmtType type; }; - static const std::array<FormatMap,63> UserFmtList{{ - { AL_FORMAT_MONO8, FmtMono, FmtUByte }, - { AL_FORMAT_MONO16, FmtMono, FmtShort }, - { AL_FORMAT_MONO_FLOAT32, FmtMono, FmtFloat }, - { AL_FORMAT_MONO_DOUBLE_EXT, FmtMono, FmtDouble }, - { AL_FORMAT_MONO_IMA4, FmtMono, FmtIMA4 }, - { AL_FORMAT_MONO_MSADPCM_SOFT, FmtMono, FmtMSADPCM }, - { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, - - { AL_FORMAT_STEREO8, FmtStereo, FmtUByte }, - { AL_FORMAT_STEREO16, FmtStereo, FmtShort }, - { AL_FORMAT_STEREO_FLOAT32, FmtStereo, FmtFloat }, - { AL_FORMAT_STEREO_DOUBLE_EXT, FmtStereo, FmtDouble }, - { AL_FORMAT_STEREO_IMA4, FmtStereo, FmtIMA4 }, - { AL_FORMAT_STEREO_MSADPCM_SOFT, FmtStereo, FmtMSADPCM }, - { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, - - { AL_FORMAT_REAR8, FmtRear, FmtUByte }, - { AL_FORMAT_REAR16, FmtRear, FmtShort }, - { AL_FORMAT_REAR32, FmtRear, FmtFloat }, - { AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtUByte }, - { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, - - { AL_FORMAT_QUAD8, FmtQuad, FmtUByte }, - { AL_FORMAT_QUAD16, FmtQuad, FmtShort }, - { AL_FORMAT_QUAD32, FmtQuad, FmtFloat }, - { AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw }, - - { AL_FORMAT_51CHN8, FmtX51, FmtUByte }, - { AL_FORMAT_51CHN16, FmtX51, FmtShort }, - { AL_FORMAT_51CHN32, FmtX51, FmtFloat }, - { AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw }, - - { AL_FORMAT_61CHN8, FmtX61, FmtUByte }, - { AL_FORMAT_61CHN16, FmtX61, FmtShort }, - { AL_FORMAT_61CHN32, FmtX61, FmtFloat }, - { AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw }, - - { AL_FORMAT_71CHN8, FmtX71, FmtUByte }, - { AL_FORMAT_71CHN16, FmtX71, FmtShort }, - { AL_FORMAT_71CHN32, FmtX71, FmtFloat }, - { AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtUByte }, - { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtUByte }, - { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, - - { AL_FORMAT_UHJ2CHN8_SOFT, FmtUHJ2, FmtUByte }, - { AL_FORMAT_UHJ2CHN16_SOFT, FmtUHJ2, FmtShort }, - { AL_FORMAT_UHJ2CHN_FLOAT32_SOFT, FmtUHJ2, FmtFloat }, - { AL_FORMAT_UHJ2CHN_MULAW_SOFT, FmtUHJ2, FmtMulaw }, - { AL_FORMAT_UHJ2CHN_ALAW_SOFT, FmtUHJ2, FmtAlaw }, - { AL_FORMAT_UHJ2CHN_IMA4_SOFT, FmtUHJ2, FmtIMA4 }, - { AL_FORMAT_UHJ2CHN_MSADPCM_SOFT, FmtUHJ2, FmtMSADPCM }, - - { AL_FORMAT_UHJ3CHN8_SOFT, FmtUHJ3, FmtUByte }, - { AL_FORMAT_UHJ3CHN16_SOFT, FmtUHJ3, FmtShort }, - { AL_FORMAT_UHJ3CHN_FLOAT32_SOFT, FmtUHJ3, FmtFloat }, - { AL_FORMAT_UHJ3CHN_MULAW_SOFT, FmtUHJ3, FmtMulaw }, - { AL_FORMAT_UHJ3CHN_ALAW_SOFT, FmtUHJ3, FmtAlaw }, - - { AL_FORMAT_UHJ4CHN8_SOFT, FmtUHJ4, FmtUByte }, - { AL_FORMAT_UHJ4CHN16_SOFT, FmtUHJ4, FmtShort }, - { AL_FORMAT_UHJ4CHN_FLOAT32_SOFT, FmtUHJ4, FmtFloat }, - { AL_FORMAT_UHJ4CHN_MULAW_SOFT, FmtUHJ4, FmtMulaw }, - { AL_FORMAT_UHJ4CHN_ALAW_SOFT, FmtUHJ4, FmtAlaw }, - }}; + static constexpr std::array UserFmtList{ + FormatMap{AL_FORMAT_MONO8, FmtMono, FmtUByte }, + FormatMap{AL_FORMAT_MONO16, FmtMono, FmtShort }, + FormatMap{AL_FORMAT_MONO_I32, FmtMono, FmtInt }, + FormatMap{AL_FORMAT_MONO_FLOAT32, FmtMono, FmtFloat }, + FormatMap{AL_FORMAT_MONO_DOUBLE_EXT, FmtMono, FmtDouble }, + FormatMap{AL_FORMAT_MONO_IMA4, FmtMono, FmtIMA4 }, + FormatMap{AL_FORMAT_MONO_MSADPCM_SOFT, FmtMono, FmtMSADPCM}, + FormatMap{AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, + FormatMap{AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, + + FormatMap{AL_FORMAT_STEREO8, FmtStereo, FmtUByte }, + FormatMap{AL_FORMAT_STEREO16, FmtStereo, FmtShort }, + FormatMap{AL_FORMAT_STEREO_I32, FmtStereo, FmtInt }, + FormatMap{AL_FORMAT_STEREO_FLOAT32, FmtStereo, FmtFloat }, + FormatMap{AL_FORMAT_STEREO_DOUBLE_EXT, FmtStereo, FmtDouble }, + FormatMap{AL_FORMAT_STEREO_IMA4, FmtStereo, FmtIMA4 }, + FormatMap{AL_FORMAT_STEREO_MSADPCM_SOFT, FmtStereo, FmtMSADPCM}, + FormatMap{AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, + FormatMap{AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, + + FormatMap{AL_FORMAT_REAR8, FmtRear, FmtUByte}, + FormatMap{AL_FORMAT_REAR16, FmtRear, FmtShort}, + FormatMap{AL_FORMAT_REAR32, FmtRear, FmtFloat}, + FormatMap{AL_FORMAT_REAR_I32, FmtRear, FmtInt }, + FormatMap{AL_FORMAT_REAR_FLOAT32, FmtRear, FmtFloat}, + FormatMap{AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw}, + + FormatMap{AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtUByte}, + FormatMap{AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort}, + + FormatMap{AL_FORMAT_QUAD8, FmtQuad, FmtUByte}, + FormatMap{AL_FORMAT_QUAD16, FmtQuad, FmtShort}, + FormatMap{AL_FORMAT_QUAD32, FmtQuad, FmtFloat}, + FormatMap{AL_FORMAT_QUAD_I32, FmtQuad, FmtInt }, + FormatMap{AL_FORMAT_QUAD_FLOAT32, FmtQuad, FmtFloat}, + FormatMap{AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw}, + + FormatMap{AL_FORMAT_51CHN8, FmtX51, FmtUByte}, + FormatMap{AL_FORMAT_51CHN16, FmtX51, FmtShort}, + FormatMap{AL_FORMAT_51CHN32, FmtX51, FmtFloat}, + FormatMap{AL_FORMAT_51CHN_I32, FmtX51, FmtInt }, + FormatMap{AL_FORMAT_51CHN_FLOAT32, FmtX51, FmtFloat}, + FormatMap{AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw}, + + FormatMap{AL_FORMAT_61CHN8, FmtX61, FmtUByte}, + FormatMap{AL_FORMAT_61CHN16, FmtX61, FmtShort}, + FormatMap{AL_FORMAT_61CHN32, FmtX61, FmtFloat}, + FormatMap{AL_FORMAT_61CHN_I32, FmtX61, FmtInt }, + FormatMap{AL_FORMAT_61CHN_FLOAT32, FmtX61, FmtFloat}, + FormatMap{AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw}, + + FormatMap{AL_FORMAT_71CHN8, FmtX71, FmtUByte}, + FormatMap{AL_FORMAT_71CHN16, FmtX71, FmtShort}, + FormatMap{AL_FORMAT_71CHN32, FmtX71, FmtFloat}, + FormatMap{AL_FORMAT_71CHN_I32, FmtX71, FmtInt }, + FormatMap{AL_FORMAT_71CHN_FLOAT32, FmtX71, FmtFloat}, + FormatMap{AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw}, + + FormatMap{AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtUByte}, + FormatMap{AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort}, + FormatMap{AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat}, + FormatMap{AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw}, + + FormatMap{AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtUByte}, + FormatMap{AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort}, + FormatMap{AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat}, + FormatMap{AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw}, + + FormatMap{AL_FORMAT_UHJ2CHN8_SOFT, FmtUHJ2, FmtUByte }, + FormatMap{AL_FORMAT_UHJ2CHN16_SOFT, FmtUHJ2, FmtShort }, + FormatMap{AL_FORMAT_UHJ2CHN_I32, FmtUHJ2, FmtInt }, + FormatMap{AL_FORMAT_UHJ2CHN_FLOAT32_SOFT, FmtUHJ2, FmtFloat }, + FormatMap{AL_FORMAT_UHJ2CHN_MULAW_SOFT, FmtUHJ2, FmtMulaw }, + FormatMap{AL_FORMAT_UHJ2CHN_ALAW_SOFT, FmtUHJ2, FmtAlaw }, + FormatMap{AL_FORMAT_UHJ2CHN_IMA4_SOFT, FmtUHJ2, FmtIMA4 }, + FormatMap{AL_FORMAT_UHJ2CHN_MSADPCM_SOFT, FmtUHJ2, FmtMSADPCM}, + + FormatMap{AL_FORMAT_UHJ3CHN8_SOFT, FmtUHJ3, FmtUByte}, + FormatMap{AL_FORMAT_UHJ3CHN16_SOFT, FmtUHJ3, FmtShort}, + FormatMap{AL_FORMAT_UHJ3CHN_I32, FmtUHJ3, FmtInt }, + FormatMap{AL_FORMAT_UHJ3CHN_FLOAT32_SOFT, FmtUHJ3, FmtFloat}, + FormatMap{AL_FORMAT_UHJ3CHN_MULAW_SOFT, FmtUHJ3, FmtMulaw}, + FormatMap{AL_FORMAT_UHJ3CHN_ALAW_SOFT, FmtUHJ3, FmtAlaw }, + + FormatMap{AL_FORMAT_UHJ4CHN8_SOFT, FmtUHJ4, FmtUByte}, + FormatMap{AL_FORMAT_UHJ4CHN16_SOFT, FmtUHJ4, FmtShort}, + FormatMap{AL_FORMAT_UHJ4CHN_I32, FmtUHJ4, FmtInt }, + FormatMap{AL_FORMAT_UHJ4CHN_FLOAT32_SOFT, FmtUHJ4, FmtFloat}, + FormatMap{AL_FORMAT_UHJ4CHN_MULAW_SOFT, FmtUHJ4, FmtMulaw}, + FormatMap{AL_FORMAT_UHJ4CHN_ALAW_SOFT, FmtUHJ4, FmtAlaw }, + }; for(const auto &fmt : UserFmtList) { if(fmt.format == format) - return al::make_optional<DecompResult>({fmt.channels, fmt.type}); + return DecompResult{fmt.channels, fmt.type}; } - return al::nullopt; + return std::nullopt; } } // namespace -AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) -START_API_FUNC +AL_API DECL_FUNC2(void, alGenBuffers, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alGenBuffersDirect(ALCcontext *context, ALsizei n, ALuint *buffers) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Generating %d buffers", n); if(n <= 0) UNLIKELY return; @@ -661,7 +680,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector<ALuint> ids; + std::vector<ALuint> ids; ids.reserve(static_cast<ALuint>(n)); do { ALbuffer *buffer{AllocBuffer(device)}; @@ -670,14 +689,11 @@ START_API_FUNC std::copy(ids.begin(), ids.end(), buffers); } } -END_API_FUNC -AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) -START_API_FUNC +AL_API DECL_FUNC2(void, alDeleteBuffers, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alDeleteBuffersDirect(ALCcontext *context, ALsizei n, + const ALuint *buffers) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Deleting %d buffers", n); if(n <= 0) UNLIKELY return; @@ -714,35 +730,32 @@ START_API_FUNC }; std::for_each(buffers, buffers_end, delete_buffer); } -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsBuffer, ALuint) +FORCE_ALIGN ALboolean AL_APIENTRY alIsBufferDirect(ALCcontext *context, ALuint buffer) noexcept { - ContextRef context{GetContextRef()}; - if(context) LIKELY - { - ALCdevice *device{context->mALDevice.get()}; - std::lock_guard<std::mutex> _{device->BufferLock}; - if(!buffer || LookupBuffer(device, buffer)) - return AL_TRUE; - } + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->BufferLock}; + if(!buffer || LookupBuffer(device, buffer)) + return AL_TRUE; return AL_FALSE; } -END_API_FUNC - -AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) -START_API_FUNC -{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } -END_API_FUNC -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) -START_API_FUNC +AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) noexcept { - ContextRef context{GetContextRef()}; + auto context = GetContextRef(); if(!context) UNLIKELY return; + alBufferStorageDirectSOFT(context.get(), buffer, format, data, size, freq, 0); +} +FORCE_ALIGN void AL_APIENTRY alBufferDataDirect(ALCcontext *context, ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) noexcept +{ alBufferStorageDirectSOFT(context, buffer, format, data, size, freq, 0); } + +AL_API DECL_FUNCEXT6(void, alBufferStorage,SOFT, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei, ALbitfieldSOFT) +FORCE_ALIGN void AL_APIENTRY alBufferStorageDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) noexcept +{ ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -766,20 +779,16 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); else { - LoadData(context.get(), albuf, freq, static_cast<ALuint>(size), usrfmt->channels, - usrfmt->type, static_cast<const al::byte*>(data), flags); + LoadData(context, albuf, freq, static_cast<ALuint>(size), usrfmt->channels, + usrfmt->type, static_cast<const std::byte*>(data), flags); } } } -END_API_FUNC -void AL_APIENTRY alBufferDataStatic(const ALuint buffer, ALenum format, ALvoid *data, ALsizei size, - ALsizei freq) -START_API_FUNC +DECL_FUNC5(void, alBufferDataStatic, ALuint, ALenum, ALvoid*, ALsizei, ALsizei) +FORCE_ALIGN void AL_APIENTRY alBufferDataStaticDirect(ALCcontext *context, const ALuint buffer, + ALenum format, ALvoid *data, ALsizei size, ALsizei freq) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -795,17 +804,14 @@ START_API_FUNC if(!usrfmt) UNLIKELY return context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); - PrepareUserPtr(context.get(), albuf, freq, usrfmt->channels, usrfmt->type, - static_cast<al::byte*>(data), static_cast<ALuint>(size)); + PrepareUserPtr(context, albuf, freq, usrfmt->channels, usrfmt->type, + static_cast<std::byte*>(data), static_cast<ALuint>(size)); } -END_API_FUNC -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) -START_API_FUNC +AL_API DECL_FUNCEXT4(void*, alMapBuffer,SOFT, ALuint, ALsizei, ALsizei, ALbitfieldSOFT) +FORCE_ALIGN void* AL_APIENTRY alMapBufferDirectSOFT(ALCcontext *context, ALuint buffer, + ALsizei offset, ALsizei length, ALbitfieldSOFT access) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return nullptr; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -852,14 +858,10 @@ START_API_FUNC return nullptr; } -END_API_FUNC -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) -START_API_FUNC +AL_API DECL_FUNCEXT1(void, alUnmapBuffer,SOFT, ALuint) +FORCE_ALIGN void AL_APIENTRY alUnmapBufferDirectSOFT(ALCcontext *context, ALuint buffer) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -875,14 +877,11 @@ START_API_FUNC albuf->MappedSize = 0; } } -END_API_FUNC -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alFlushMappedBuffer,SOFT, ALuint, ALsizei, ALsizei) +FORCE_ALIGN void AL_APIENTRY alFlushMappedBufferDirectSOFT(ALCcontext *context, ALuint buffer, + ALsizei offset, ALsizei length) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -900,21 +899,18 @@ START_API_FUNC else { /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered + * app to hold separate memory, which can be safely transferred * asynchronously. Currently we just say the app shouldn't write where * OpenAL's reading, and hope for the best... */ std::atomic_thread_fence(std::memory_order_seq_cst); } } -END_API_FUNC -AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alBufferSubData,SOFT, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) +FORCE_ALIGN void AL_APIENTRY alBufferSubDataDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -966,61 +962,12 @@ START_API_FUNC assert(al::to_underlying(usrfmt->type) == al::to_underlying(albuf->mType)); memcpy(albuf->mData.data()+offset, data, static_cast<ALuint>(length)); } -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, - ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, - const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); -} -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return AL_FALSE; - - context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); - return AL_FALSE; -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) -START_API_FUNC +AL_API DECL_FUNC3(void, alBufferf, ALuint, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alBufferfDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALfloat /*value*/) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1032,15 +979,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, - ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) -START_API_FUNC +AL_API DECL_FUNC5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +FORCE_ALIGN void AL_APIENTRY alBuffer3fDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1052,14 +995,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alBufferfv, ALuint, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alBufferfvDirect(ALCcontext *context, ALuint buffer, ALenum param, + const ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1073,15 +1013,12 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) -START_API_FUNC +AL_API DECL_FUNC3(void, alBufferi, ALuint, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALint value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1135,15 +1072,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, - ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) -START_API_FUNC +AL_API DECL_FUNC5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint) +FORCE_ALIGN void AL_APIENTRY alBuffer3iDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1155,36 +1088,31 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alBufferiv, ALuint, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alBufferivDirect(ALCcontext *context, ALuint buffer, ALenum param, + const ALint *values) noexcept { - if(values) + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + switch(param) { - switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - case AL_AMBISONIC_LAYOUT_SOFT: - case AL_AMBISONIC_SCALING_SOFT: - case AL_UNPACK_AMBISONIC_ORDER_SOFT: - alBufferi(buffer, param, values[0]); - return; - } + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + case AL_AMBISONIC_LAYOUT_SOFT: + case AL_AMBISONIC_SCALING_SOFT: + case AL_UNPACK_AMBISONIC_ORDER_SOFT: + alBufferiDirect(context, buffer, param, values[0]); + return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(!albuf) UNLIKELY context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(!values) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_LOOP_POINTS_SOFT: @@ -1206,15 +1134,12 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetBufferf, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetBufferfDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1234,14 +1159,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetBuffer3fDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1255,21 +1177,18 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetBufferfv, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetBufferfvDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALfloat *values) noexcept { switch(param) { case AL_SEC_LENGTH_SOFT: - alGetBufferf(buffer, param, values); + alGetBufferfDirect(context, buffer, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1283,15 +1202,12 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetBufferi, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetBufferiDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1351,14 +1267,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetBuffer3iDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALint *value1, ALint *value2, ALint *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; if(LookupBuffer(device, buffer) == nullptr) UNLIKELY @@ -1371,10 +1284,10 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetBufferiv, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetBufferivDirect(ALCcontext *context, ALuint buffer, ALenum param, + ALint *values) noexcept { switch(param) { @@ -1390,13 +1303,10 @@ START_API_FUNC case AL_AMBISONIC_LAYOUT_SOFT: case AL_AMBISONIC_SCALING_SOFT: case AL_UNPACK_AMBISONIC_ORDER_SOFT: - alGetBufferi(buffer, param, values); + alGetBufferiDirect(context, buffer, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1415,16 +1325,12 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq, - ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alBufferCallback,SOFT, ALuint, ALenum, ALsizei, ALBUFFERCALLBACKTYPESOFT, ALvoid*) +FORCE_ALIGN void AL_APIENTRY alBufferCallbackDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; @@ -1441,18 +1347,15 @@ START_API_FUNC if(!usrfmt) UNLIKELY context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - PrepareCallback(context.get(), albuf, freq, usrfmt->channels, usrfmt->type, callback, + PrepareCallback(context, albuf, freq, usrfmt->channels, usrfmt->type, callback, userptr); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **value) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetBufferPtr,SOFT, ALuint, ALenum, ALvoid**) +FORCE_ALIGN void AL_APIENTRY alGetBufferPtrDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum param, ALvoid **value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1463,7 +1366,7 @@ START_API_FUNC else switch(param) { case AL_BUFFER_CALLBACK_FUNCTION_SOFT: - *value = reinterpret_cast<void*>(albuf->mCallback); + *value = al::bit_cast<void*>(albuf->mCallback); break; case AL_BUFFER_CALLBACK_USER_PARAM_SOFT: *value = albuf->mUserData; @@ -1473,14 +1376,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer pointer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alGetBuffer3Ptr,SOFT, ALuint, ALenum, ALvoid**, ALvoid**, ALvoid**) +FORCE_ALIGN void AL_APIENTRY alGetBuffer3PtrDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; if(LookupBuffer(device, buffer) == nullptr) UNLIKELY @@ -1493,22 +1393,19 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer 3-pointer property 0x%04x", param); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **values) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetBufferPtrv,SOFT, ALuint, ALenum, ALvoid**) +FORCE_ALIGN void AL_APIENTRY alGetBufferPtrvDirectSOFT(ALCcontext *context, ALuint buffer, + ALenum param, ALvoid **values) noexcept { switch(param) { case AL_BUFFER_CALLBACK_FUNCTION_SOFT: case AL_BUFFER_CALLBACK_USER_PARAM_SOFT: - alGetBufferPtrSOFT(buffer, param, values); + alGetBufferPtrDirectSOFT(context, buffer, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->BufferLock}; if(LookupBuffer(device, buffer) == nullptr) UNLIKELY @@ -1521,16 +1418,69 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid buffer pointer-vector property 0x%04x", param); } } -END_API_FUNC + + +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, + ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, + const ALvoid* /*data*/) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); +} + +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); +} + +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); +} + +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return AL_FALSE; + + context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); + return AL_FALSE; +} + + +void ALbuffer::SetName(ALCcontext *context, ALuint id, std::string_view name) +{ + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->BufferLock}; + + auto buffer = LookupBuffer(device, id); + if(!buffer) UNLIKELY + return context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", id); + + device->mBufferNames.insert_or_assign(id, name); +} BufferSubList::~BufferSubList() { + if(!Buffers) + return; + uint64_t usemask{~FreeMask}; while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Buffers+idx); + std::destroy_at(Buffers+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; @@ -1540,93 +1490,82 @@ BufferSubList::~BufferSubList() #ifdef ALSOFT_EAX -FORCE_ALIGN ALboolean AL_APIENTRY EAXSetBufferMode(ALsizei n, const ALuint* buffers, ALint value) -START_API_FUNC +FORCE_ALIGN DECL_FUNC3(ALboolean, EAXSetBufferMode, ALsizei, const ALuint*, ALint) +FORCE_ALIGN ALboolean AL_APIENTRY EAXSetBufferModeDirect(ALCcontext *context, ALsizei n, + const ALuint *buffers, ALint value) noexcept { #define EAX_PREFIX "[EAXSetBufferMode] " - const auto context = ContextRef{GetContextRef()}; - if(!context) - { - ERR(EAX_PREFIX "%s\n", "No current context."); - return ALC_FALSE; - } - if(!eax_g_is_enabled) { context->setError(AL_INVALID_OPERATION, EAX_PREFIX "%s", "EAX not enabled."); - return ALC_FALSE; + return AL_FALSE; } const auto storage = EaxStorageFromEnum(value); if(!storage) { context->setError(AL_INVALID_ENUM, EAX_PREFIX "Unsupported X-RAM mode 0x%x", value); - return ALC_FALSE; + return AL_FALSE; } if(n == 0) - return ALC_TRUE; + return AL_TRUE; if(n < 0) { context->setError(AL_INVALID_VALUE, EAX_PREFIX "Buffer count %d out of range", n); - return ALC_FALSE; + return AL_FALSE; } if(!buffers) { context->setError(AL_INVALID_VALUE, EAX_PREFIX "%s", "Null AL buffers"); - return ALC_FALSE; + return AL_FALSE; } auto device = context->mALDevice.get(); std::lock_guard<std::mutex> device_lock{device->BufferLock}; - size_t total_needed{0}; - // Validate the buffers. - // - for(auto i = 0;i < n;++i) + /* Special-case setting a single buffer, to avoid extraneous allocations. */ + if(n == 1) { - const auto bufid = buffers[i]; + const auto bufid = buffers[0]; if(bufid == AL_NONE) - continue; + return AL_TRUE; const auto buffer = LookupBuffer(device, bufid); if(!buffer) UNLIKELY { ERR(EAX_PREFIX "Invalid buffer ID %u.\n", bufid); - return ALC_FALSE; + return AL_FALSE; } /* TODO: Is the store location allowed to change for in-use buffers, or * only when not set/queued on a source? */ - if(*storage == EaxStorage::Hardware && !buffer->eax_x_ram_is_hardware) + if(*storage == EaxStorage::Hardware) { - /* FIXME: This doesn't account for duplicate buffers. When the same - * buffer ID is specified multiple times in the provided list, it - * counts each instance as more memory that needs to fit in X-RAM. - */ - if(std::numeric_limits<size_t>::max()-buffer->OriginalSize < total_needed) UNLIKELY + if(!buffer->eax_x_ram_is_hardware + && buffer->OriginalSize > device->eax_x_ram_free_size) UNLIKELY { - context->setError(AL_OUT_OF_MEMORY, EAX_PREFIX "Size overflow (%u + %zu)\n", - buffer->OriginalSize, total_needed); - return ALC_FALSE; + context->setError(AL_OUT_OF_MEMORY, + EAX_PREFIX "Out of X-RAM memory (need: %u, avail: %u)", buffer->OriginalSize, + device->eax_x_ram_free_size); + return AL_FALSE; } - total_needed += buffer->OriginalSize; + + eax_x_ram_apply(*device, *buffer); } - } - if(total_needed > device->eax_x_ram_free_size) - { - context->setError(AL_OUT_OF_MEMORY,EAX_PREFIX "Out of X-RAM memory (need: %zu, avail: %u)", - total_needed, device->eax_x_ram_free_size); - return ALC_FALSE; + else + eax_x_ram_clear(*device, *buffer); + buffer->eax_x_ram_mode = *storage; + return AL_TRUE; } - // Update the mode. - // + /* Validate the buffers. */ + std::unordered_set<ALbuffer*> buflist; for(auto i = 0;i < n;++i) { const auto bufid = buffers[i]; @@ -1634,8 +1573,47 @@ START_API_FUNC continue; const auto buffer = LookupBuffer(device, bufid); - assert(buffer); + if(!buffer) UNLIKELY + { + ERR(EAX_PREFIX "Invalid buffer ID %u.\n", bufid); + return AL_FALSE; + } + + /* TODO: Is the store location allowed to change for in-use buffers, or + * only when not set/queued on a source? + */ + + buflist.emplace(buffer); + } + + if(*storage == EaxStorage::Hardware) + { + size_t total_needed{0}; + for(ALbuffer *buffer : buflist) + { + if(!buffer->eax_x_ram_is_hardware) + { + if(std::numeric_limits<size_t>::max()-buffer->OriginalSize < total_needed) UNLIKELY + { + context->setError(AL_OUT_OF_MEMORY, EAX_PREFIX "Size overflow (%u + %zu)\n", + buffer->OriginalSize, total_needed); + return AL_FALSE; + } + total_needed += buffer->OriginalSize; + } + } + if(total_needed > device->eax_x_ram_free_size) + { + context->setError(AL_OUT_OF_MEMORY, + EAX_PREFIX "Out of X-RAM memory (need: %zu, avail: %u)", total_needed, + device->eax_x_ram_free_size); + return AL_FALSE; + } + } + /* Update the mode. */ + for(ALbuffer *buffer : buflist) + { if(*storage == EaxStorage::Hardware) eax_x_ram_apply(*device, *buffer); else @@ -1647,20 +1625,13 @@ START_API_FUNC #undef EAX_PREFIX } -END_API_FUNC -FORCE_ALIGN ALenum AL_APIENTRY EAXGetBufferMode(ALuint buffer, ALint* pReserved) -START_API_FUNC +FORCE_ALIGN DECL_FUNC2(ALenum, EAXGetBufferMode, ALuint, ALint*) +FORCE_ALIGN ALenum AL_APIENTRY EAXGetBufferModeDirect(ALCcontext *context, ALuint buffer, + ALint *pReserved) noexcept { #define EAX_PREFIX "[EAXGetBufferMode] " - const auto context = ContextRef{GetContextRef()}; - if(!context) - { - ERR(EAX_PREFIX "%s\n", "No current context."); - return AL_NONE; - } - if(!eax_g_is_enabled) { context->setError(AL_INVALID_OPERATION, EAX_PREFIX "%s", "EAX not enabled."); @@ -1687,6 +1658,5 @@ START_API_FUNC #undef EAX_PREFIX } -END_API_FUNC #endif // ALSOFT_EAX diff --git a/al/buffer.h b/al/buffer.h index 64ebe1f3..f936cf98 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -2,10 +2,11 @@ #define AL_BUFFER_H #include <atomic> +#include <cstddef> +#include <string_view> #include "AL/al.h" -#include "albyte.h" #include "alc/inprogext.h" #include "almalloc.h" #include "atomic.h" @@ -26,7 +27,7 @@ enum class EaxStorage : uint8_t { struct ALbuffer : public BufferStorage { ALbitfieldSOFT Access{0u}; - al::vector<al::byte,16> mDataStorage; + al::vector<std::byte,16> mDataStorage; ALuint OriginalSize{0}; @@ -47,6 +48,8 @@ struct ALbuffer : public BufferStorage { /* Self ID */ ALuint id{0}; + static void SetName(ALCcontext *context, ALuint id, std::string_view name); + DISABLE_ALLOC() #ifdef ALSOFT_EAX diff --git a/al/debug.cpp b/al/debug.cpp new file mode 100644 index 00000000..b76ec9af --- /dev/null +++ b/al/debug.cpp @@ -0,0 +1,570 @@ +#include "config.h" + +#include "debug.h" + +#include <algorithm> +#include <array> +#include <cstring> +#include <mutex> +#include <optional> +#include <stddef.h> +#include <stdexcept> +#include <string> +#include <utility> + +#include "AL/al.h" + +#include "alc/context.h" +#include "alc/inprogext.h" +#include "alspan.h" +#include "auxeffectslot.h" +#include "buffer.h" +#include "core/logging.h" +#include "direct_defs.h" +#include "effect.h" +#include "filter.h" +#include "opthelpers.h" +#include "source.h" + + +/* Declared here to prevent compilers from thinking it should be inlined, which + * GCC warns about increasing code size. + */ +DebugGroup::~DebugGroup() = default; + +namespace { + +static_assert(DebugSeverityBase+DebugSeverityCount <= 32, "Too many debug bits"); + +template<typename T, T ...Vals> +constexpr auto make_array_sequence(std::integer_sequence<T, Vals...>) +{ return std::array<T,sizeof...(Vals)>{Vals...}; } + +template<typename T, size_t N> +constexpr auto make_array_sequence() +{ return make_array_sequence(std::make_integer_sequence<T,N>{}); } + + +constexpr std::optional<DebugSource> GetDebugSource(ALenum source) noexcept +{ + switch(source) + { + case AL_DEBUG_SOURCE_API_EXT: return DebugSource::API; + case AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT: return DebugSource::System; + case AL_DEBUG_SOURCE_THIRD_PARTY_EXT: return DebugSource::ThirdParty; + case AL_DEBUG_SOURCE_APPLICATION_EXT: return DebugSource::Application; + case AL_DEBUG_SOURCE_OTHER_EXT: return DebugSource::Other; + } + return std::nullopt; +} + +constexpr std::optional<DebugType> GetDebugType(ALenum type) noexcept +{ + switch(type) + { + case AL_DEBUG_TYPE_ERROR_EXT: return DebugType::Error; + case AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT: return DebugType::DeprecatedBehavior; + case AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT: return DebugType::UndefinedBehavior; + case AL_DEBUG_TYPE_PORTABILITY_EXT: return DebugType::Portability; + case AL_DEBUG_TYPE_PERFORMANCE_EXT: return DebugType::Performance; + case AL_DEBUG_TYPE_MARKER_EXT: return DebugType::Marker; + case AL_DEBUG_TYPE_PUSH_GROUP_EXT: return DebugType::PushGroup; + case AL_DEBUG_TYPE_POP_GROUP_EXT: return DebugType::PopGroup; + case AL_DEBUG_TYPE_OTHER_EXT: return DebugType::Other; + } + return std::nullopt; +} + +constexpr std::optional<DebugSeverity> GetDebugSeverity(ALenum severity) noexcept +{ + switch(severity) + { + case AL_DEBUG_SEVERITY_HIGH_EXT: return DebugSeverity::High; + case AL_DEBUG_SEVERITY_MEDIUM_EXT: return DebugSeverity::Medium; + case AL_DEBUG_SEVERITY_LOW_EXT: return DebugSeverity::Low; + case AL_DEBUG_SEVERITY_NOTIFICATION_EXT: return DebugSeverity::Notification; + } + return std::nullopt; +} + + +ALenum GetDebugSourceEnum(DebugSource source) +{ + switch(source) + { + case DebugSource::API: return AL_DEBUG_SOURCE_API_EXT; + case DebugSource::System: return AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT; + case DebugSource::ThirdParty: return AL_DEBUG_SOURCE_THIRD_PARTY_EXT; + case DebugSource::Application: return AL_DEBUG_SOURCE_APPLICATION_EXT; + case DebugSource::Other: return AL_DEBUG_SOURCE_OTHER_EXT; + } + throw std::runtime_error{"Unexpected debug source value "+std::to_string(al::to_underlying(source))}; +} + +ALenum GetDebugTypeEnum(DebugType type) +{ + switch(type) + { + case DebugType::Error: return AL_DEBUG_TYPE_ERROR_EXT; + case DebugType::DeprecatedBehavior: return AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT; + case DebugType::UndefinedBehavior: return AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT; + case DebugType::Portability: return AL_DEBUG_TYPE_PORTABILITY_EXT; + case DebugType::Performance: return AL_DEBUG_TYPE_PERFORMANCE_EXT; + case DebugType::Marker: return AL_DEBUG_TYPE_MARKER_EXT; + case DebugType::PushGroup: return AL_DEBUG_TYPE_PUSH_GROUP_EXT; + case DebugType::PopGroup: return AL_DEBUG_TYPE_POP_GROUP_EXT; + case DebugType::Other: return AL_DEBUG_TYPE_OTHER_EXT; + } + throw std::runtime_error{"Unexpected debug type value "+std::to_string(al::to_underlying(type))}; +} + +ALenum GetDebugSeverityEnum(DebugSeverity severity) +{ + switch(severity) + { + case DebugSeverity::High: return AL_DEBUG_SEVERITY_HIGH_EXT; + case DebugSeverity::Medium: return AL_DEBUG_SEVERITY_MEDIUM_EXT; + case DebugSeverity::Low: return AL_DEBUG_SEVERITY_LOW_EXT; + case DebugSeverity::Notification: return AL_DEBUG_SEVERITY_NOTIFICATION_EXT; + } + throw std::runtime_error{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity))}; +} + + +const char *GetDebugSourceName(DebugSource source) +{ + switch(source) + { + case DebugSource::API: return "API"; + case DebugSource::System: return "Audio System"; + case DebugSource::ThirdParty: return "Third Party"; + case DebugSource::Application: return "Application"; + case DebugSource::Other: return "Other"; + } + return "<invalid source>"; +} + +const char *GetDebugTypeName(DebugType type) +{ + switch(type) + { + case DebugType::Error: return "Error"; + case DebugType::DeprecatedBehavior: return "Deprecated Behavior"; + case DebugType::UndefinedBehavior: return "Undefined Behavior"; + case DebugType::Portability: return "Portability"; + case DebugType::Performance: return "Performance"; + case DebugType::Marker: return "Marker"; + case DebugType::PushGroup: return "Push Group"; + case DebugType::PopGroup: return "Pop Group"; + case DebugType::Other: return "Other"; + } + return "<invalid type>"; +} + +const char *GetDebugSeverityName(DebugSeverity severity) +{ + switch(severity) + { + case DebugSeverity::High: return "High"; + case DebugSeverity::Medium: return "Medium"; + case DebugSeverity::Low: return "Low"; + case DebugSeverity::Notification: return "Notification"; + } + return "<invalid severity>"; +} + +} // namespace + + +void ALCcontext::sendDebugMessage(std::unique_lock<std::mutex> &debuglock, DebugSource source, + DebugType type, ALuint id, DebugSeverity severity, std::string_view message) +{ + if(!mDebugEnabled.load()) UNLIKELY + return; + + if(message.length() >= MaxDebugMessageLength) UNLIKELY + { + ERR("Debug message too long (%zu >= %d):\n-> %.*s\n", message.length(), + MaxDebugMessageLength, static_cast<int>(message.length()), message.data()); + return; + } + + DebugGroup &debug = mDebugGroups.back(); + + const uint64_t idfilter{(1_u64 << (DebugSourceBase+al::to_underlying(source))) + | (1_u64 << (DebugTypeBase+al::to_underlying(type))) + | (uint64_t{id} << 32)}; + auto iditer = std::lower_bound(debug.mIdFilters.cbegin(), debug.mIdFilters.cend(), idfilter); + if(iditer != debug.mIdFilters.cend() && *iditer == idfilter) + return; + + const uint filter{(1u << (DebugSourceBase+al::to_underlying(source))) + | (1u << (DebugTypeBase+al::to_underlying(type))) + | (1u << (DebugSeverityBase+al::to_underlying(severity)))}; + auto iter = std::lower_bound(debug.mFilters.cbegin(), debug.mFilters.cend(), filter); + if(iter != debug.mFilters.cend() && *iter == filter) + return; + + if(mDebugCb) + { + auto callback = mDebugCb; + auto param = mDebugParam; + debuglock.unlock(); + callback(GetDebugSourceEnum(source), GetDebugTypeEnum(type), id, + GetDebugSeverityEnum(severity), static_cast<ALsizei>(message.length()), message.data(), + param); + } + else + { + if(mDebugLog.size() < MaxDebugLoggedMessages) + mDebugLog.emplace_back(source, type, id, severity, message); + else UNLIKELY + ERR("Debug message log overflow. Lost message:\n" + " Source: %s\n" + " Type: %s\n" + " ID: %u\n" + " Severity: %s\n" + " Message: \"%.*s\"\n", + GetDebugSourceName(source), GetDebugTypeName(type), id, + GetDebugSeverityName(severity), static_cast<int>(message.length()), + message.data()); + } +} + + +FORCE_ALIGN DECL_FUNCEXT2(void, alDebugMessageCallback,EXT, ALDEBUGPROCEXT, void*) +FORCE_ALIGN void AL_APIENTRY alDebugMessageCallbackDirectEXT(ALCcontext *context, + ALDEBUGPROCEXT callback, void *userParam) noexcept +{ + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + context->mDebugCb = callback; + context->mDebugParam = userParam; +} + + +FORCE_ALIGN DECL_FUNCEXT6(void, alDebugMessageInsert,EXT, ALenum, ALenum, ALuint, ALenum, ALsizei, const ALchar*) +FORCE_ALIGN void AL_APIENTRY alDebugMessageInsertDirectEXT(ALCcontext *context, ALenum source, + ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) noexcept +{ + if(!context->mContextFlags.test(ContextFlags::DebugBit)) + return; + + if(!message) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Null message pointer"); + + auto msgview = (length < 0) ? std::string_view{message} + : std::string_view{message, static_cast<uint>(length)}; + if(msgview.length() >= MaxDebugMessageLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Debug message too long (%zu >= %d)", + msgview.length(), MaxDebugMessageLength); + + auto dsource = GetDebugSource(source); + if(!dsource) + return context->setError(AL_INVALID_ENUM, "Invalid debug source 0x%04x", source); + if(*dsource != DebugSource::ThirdParty && *dsource != DebugSource::Application) + return context->setError(AL_INVALID_ENUM, "Debug source 0x%04x not allowed", source); + + auto dtype = GetDebugType(type); + if(!dtype) + return context->setError(AL_INVALID_ENUM, "Invalid debug type 0x%04x", type); + + auto dseverity = GetDebugSeverity(severity); + if(!dseverity) + return context->setError(AL_INVALID_ENUM, "Invalid debug severity 0x%04x", severity); + + context->debugMessage(*dsource, *dtype, id, *dseverity, msgview); +} + + +FORCE_ALIGN DECL_FUNCEXT6(void, alDebugMessageControl,EXT, ALenum, ALenum, ALenum, ALsizei, const ALuint*, ALboolean) +FORCE_ALIGN void AL_APIENTRY alDebugMessageControlDirectEXT(ALCcontext *context, ALenum source, + ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) noexcept +{ + if(count > 0) + { + if(!ids) + return context->setError(AL_INVALID_VALUE, "IDs is null with non-0 count"); + if(source == AL_DONT_CARE_EXT) + return context->setError(AL_INVALID_OPERATION, + "Debug source cannot be AL_DONT_CARE_EXT with IDs"); + if(type == AL_DONT_CARE_EXT) + return context->setError(AL_INVALID_OPERATION, + "Debug type cannot be AL_DONT_CARE_EXT with IDs"); + if(severity != AL_DONT_CARE_EXT) + return context->setError(AL_INVALID_OPERATION, + "Debug severity must be AL_DONT_CARE_EXT with IDs"); + } + + if(enable != AL_TRUE && enable != AL_FALSE) + return context->setError(AL_INVALID_ENUM, "Invalid debug enable %d", enable); + + static constexpr size_t ElemCount{DebugSourceCount + DebugTypeCount + DebugSeverityCount}; + static constexpr auto Values = make_array_sequence<uint8_t,ElemCount>(); + + auto srcIndices = al::span{Values}.subspan(DebugSourceBase,DebugSourceCount); + if(source != AL_DONT_CARE_EXT) + { + auto dsource = GetDebugSource(source); + if(!dsource) + return context->setError(AL_INVALID_ENUM, "Invalid debug source 0x%04x", source); + srcIndices = srcIndices.subspan(al::to_underlying(*dsource), 1); + } + + auto typeIndices = al::span{Values}.subspan(DebugTypeBase,DebugTypeCount); + if(type != AL_DONT_CARE_EXT) + { + auto dtype = GetDebugType(type); + if(!dtype) + return context->setError(AL_INVALID_ENUM, "Invalid debug type 0x%04x", type); + typeIndices = typeIndices.subspan(al::to_underlying(*dtype), 1); + } + + auto svrIndices = al::span{Values}.subspan(DebugSeverityBase,DebugSeverityCount); + if(severity != AL_DONT_CARE_EXT) + { + auto dseverity = GetDebugSeverity(severity); + if(!dseverity) + return context->setError(AL_INVALID_ENUM, "Invalid debug severity 0x%04x", severity); + svrIndices = svrIndices.subspan(al::to_underlying(*dseverity), 1); + } + + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + DebugGroup &debug = context->mDebugGroups.back(); + if(count > 0) + { + const uint filterbase{(1u<<srcIndices[0]) | (1u<<typeIndices[0])}; + + for(const uint id : al::span{ids, static_cast<uint>(count)}) + { + const uint64_t filter{filterbase | (uint64_t{id} << 32)}; + + auto iter = std::lower_bound(debug.mIdFilters.cbegin(), debug.mIdFilters.cend(), + filter); + if(!enable && (iter == debug.mIdFilters.cend() || *iter != filter)) + debug.mIdFilters.insert(iter, filter); + else if(enable && iter != debug.mIdFilters.cend() && *iter == filter) + debug.mIdFilters.erase(iter); + } + } + else + { + auto apply_filter = [enable,&debug](const uint filter) + { + auto iter = std::lower_bound(debug.mFilters.cbegin(), debug.mFilters.cend(), filter); + if(!enable && (iter == debug.mFilters.cend() || *iter != filter)) + debug.mFilters.insert(iter, filter); + else if(enable && iter != debug.mFilters.cend() && *iter == filter) + debug.mFilters.erase(iter); + }; + auto apply_severity = [apply_filter,svrIndices](const uint filter) + { + std::for_each(svrIndices.cbegin(), svrIndices.cend(), + [apply_filter,filter](const uint idx){ apply_filter(filter | (1<<idx)); }); + }; + auto apply_type = [apply_severity,typeIndices](const uint filter) + { + std::for_each(typeIndices.cbegin(), typeIndices.cend(), + [apply_severity,filter](const uint idx){ apply_severity(filter | (1<<idx)); }); + }; + std::for_each(srcIndices.cbegin(), srcIndices.cend(), + [apply_type](const uint idx){ apply_type(1<<idx); }); + } +} + + +FORCE_ALIGN DECL_FUNCEXT4(void, alPushDebugGroup,EXT, ALenum, ALuint, ALsizei, const ALchar*) +FORCE_ALIGN void AL_APIENTRY alPushDebugGroupDirectEXT(ALCcontext *context, ALenum source, + ALuint id, ALsizei length, const ALchar *message) noexcept +{ + if(length < 0) + { + size_t newlen{std::strlen(message)}; + if(newlen >= MaxDebugMessageLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Debug message too long (%zu >= %d)", + newlen, MaxDebugMessageLength); + length = static_cast<ALsizei>(newlen); + } + else if(length >= MaxDebugMessageLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Debug message too long (%d >= %d)", length, + MaxDebugMessageLength); + + auto dsource = GetDebugSource(source); + if(!dsource) + return context->setError(AL_INVALID_ENUM, "Invalid debug source 0x%04x", source); + if(*dsource != DebugSource::ThirdParty && *dsource != DebugSource::Application) + return context->setError(AL_INVALID_ENUM, "Debug source 0x%04x not allowed", source); + + std::unique_lock<std::mutex> debuglock{context->mDebugCbLock}; + if(context->mDebugGroups.size() >= MaxDebugGroupDepth) + { + debuglock.unlock(); + return context->setError(AL_STACK_OVERFLOW_EXT, "Pushing too many debug groups"); + } + + context->mDebugGroups.emplace_back(*dsource, id, + std::string_view{message, static_cast<uint>(length)}); + auto &oldback = *(context->mDebugGroups.end()-2); + auto &newback = context->mDebugGroups.back(); + + newback.mFilters = oldback.mFilters; + newback.mIdFilters = oldback.mIdFilters; + + if(context->mContextFlags.test(ContextFlags::DebugBit)) + context->sendDebugMessage(debuglock, newback.mSource, DebugType::PushGroup, newback.mId, + DebugSeverity::Notification, newback.mMessage); +} + +FORCE_ALIGN DECL_FUNCEXT(void, alPopDebugGroup,EXT) +FORCE_ALIGN void AL_APIENTRY alPopDebugGroupDirectEXT(ALCcontext *context) noexcept +{ + std::unique_lock<std::mutex> debuglock{context->mDebugCbLock}; + if(context->mDebugGroups.size() <= 1) + { + debuglock.unlock(); + return context->setError(AL_STACK_UNDERFLOW_EXT, + "Attempting to pop the default debug group"); + } + + DebugGroup &debug = context->mDebugGroups.back(); + const auto source = debug.mSource; + const auto id = debug.mId; + std::string message{std::move(debug.mMessage)}; + + context->mDebugGroups.pop_back(); + if(context->mContextFlags.test(ContextFlags::DebugBit)) + context->sendDebugMessage(debuglock, source, DebugType::PopGroup, id, + DebugSeverity::Notification, message); +} + + +FORCE_ALIGN DECL_FUNCEXT8(ALuint, alGetDebugMessageLog,EXT, ALuint, ALsizei, ALenum*, ALenum*, ALuint*, ALenum*, ALsizei*, ALchar*) +FORCE_ALIGN ALuint AL_APIENTRY alGetDebugMessageLogDirectEXT(ALCcontext *context, ALuint count, + ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, + ALsizei *lengths, ALchar *logBuf) noexcept +{ + if(logBufSize < 0) + { + context->setError(AL_INVALID_VALUE, "Negative debug log buffer size"); + return 0; + } + + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + ALsizei logBufWritten{0}; + for(ALuint i{0};i < count;++i) + { + if(context->mDebugLog.empty()) + return i; + + auto &entry = context->mDebugLog.front(); + const size_t tocopy{entry.mMessage.size() + 1}; + if(logBuf) + { + const size_t avail{static_cast<ALuint>(logBufSize - logBufWritten)}; + if(avail < tocopy) + return i; + std::copy_n(entry.mMessage.data(), tocopy, logBuf+logBufWritten); + logBufWritten += static_cast<ALsizei>(tocopy); + } + + if(sources) sources[i] = GetDebugSourceEnum(entry.mSource); + if(types) types[i] = GetDebugTypeEnum(entry.mType); + if(ids) ids[i] = entry.mId; + if(severities) severities[i] = GetDebugSeverityEnum(entry.mSeverity); + if(lengths) lengths[i] = static_cast<ALsizei>(tocopy); + + context->mDebugLog.pop_front(); + } + + return count; +} + +FORCE_ALIGN DECL_FUNCEXT4(void, alObjectLabel,EXT, ALenum, ALuint, ALsizei, const ALchar*) +FORCE_ALIGN void AL_APIENTRY alObjectLabelDirectEXT(ALCcontext *context, ALenum identifier, + ALuint name, ALsizei length, const ALchar *label) noexcept +{ + if(!label && length != 0) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Null label pointer"); + + auto objname = (length < 0) ? std::string_view{label} + : std::string_view{label, static_cast<uint>(length)}; + if(objname.length() >= MaxObjectLabelLength) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Object label length too long (%zu >= %d)", + objname.length(), MaxObjectLabelLength); + + if(identifier == AL_SOURCE_EXT) + return ALsource::SetName(context, name, objname); + if(identifier == AL_BUFFER) + return ALbuffer::SetName(context, name, objname); + if(identifier == AL_FILTER_EXT) + return ALfilter::SetName(context, name, objname); + if(identifier == AL_EFFECT_EXT) + return ALeffect::SetName(context, name, objname); + if(identifier == AL_AUXILIARY_EFFECT_SLOT_EXT) + return ALeffectslot::SetName(context, name, objname); + + return context->setError(AL_INVALID_ENUM, "Invalid name identifier 0x%04x", identifier); +} + +FORCE_ALIGN DECL_FUNCEXT5(void, alGetObjectLabel,EXT, ALenum, ALuint, ALsizei, ALsizei*, ALchar*) +FORCE_ALIGN void AL_APIENTRY alGetObjectLabelDirectEXT(ALCcontext *context, ALenum identifier, + ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) noexcept +{ + if(bufSize < 0) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Negative label bufSize"); + + if(!label && !length) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Null length and label"); + if(label && bufSize == 0) UNLIKELY + return context->setError(AL_INVALID_VALUE, "Zero label bufSize"); + + auto copy_name = [name,bufSize,length,label](std::unordered_map<ALuint,std::string> &names) + { + std::string_view objname; + + auto iter = names.find(name); + if(iter != names.end()) + objname = iter->second; + + if(!label) + *length = static_cast<ALsizei>(objname.length()); + else + { + const size_t tocopy{minz(objname.length(), static_cast<uint>(bufSize)-1)}; + std::memcpy(label, objname.data(), tocopy); + label[tocopy] = '\0'; + if(length) + *length = static_cast<ALsizei>(tocopy); + } + }; + + if(identifier == AL_SOURCE_EXT) + { + std::lock_guard _{context->mSourceLock}; + copy_name(context->mSourceNames); + } + else if(identifier == AL_BUFFER) + { + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard _{device->BufferLock}; + copy_name(device->mBufferNames); + } + else if(identifier == AL_FILTER_EXT) + { + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard _{device->FilterLock}; + copy_name(device->mFilterNames); + } + else if(identifier == AL_EFFECT_EXT) + { + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard _{device->EffectLock}; + copy_name(device->mEffectNames); + } + else if(identifier == AL_AUXILIARY_EFFECT_SLOT_EXT) + { + std::lock_guard _{context->mEffectSlotLock}; + copy_name(context->mEffectSlotNames); + } + else + context->setError(AL_INVALID_ENUM, "Invalid name identifier 0x%04x", identifier); +} diff --git a/al/debug.h b/al/debug.h new file mode 100644 index 00000000..351be9c0 --- /dev/null +++ b/al/debug.h @@ -0,0 +1,69 @@ +#ifndef AL_DEBUG_H +#define AL_DEBUG_H + +#include <stdint.h> +#include <string> +#include <vector> + +using uint = unsigned int; + + +/* Somewhat arbitrary. Avoid letting it get out of control if the app enables + * logging but never reads it. + */ +inline constexpr uint8_t MaxDebugLoggedMessages{64}; +inline constexpr uint16_t MaxDebugMessageLength{1024}; +inline constexpr uint8_t MaxDebugGroupDepth{64}; +inline constexpr uint16_t MaxObjectLabelLength{1024}; + + +inline constexpr uint DebugSourceBase{0}; +enum class DebugSource : uint8_t { + API = 0, + System, + ThirdParty, + Application, + Other, +}; +inline constexpr uint DebugSourceCount{5}; + +inline constexpr uint DebugTypeBase{DebugSourceBase + DebugSourceCount}; +enum class DebugType : uint8_t { + Error = 0, + DeprecatedBehavior, + UndefinedBehavior, + Portability, + Performance, + Marker, + PushGroup, + PopGroup, + Other, +}; +inline constexpr uint DebugTypeCount{9}; + +inline constexpr uint DebugSeverityBase{DebugTypeBase + DebugTypeCount}; +enum class DebugSeverity : uint8_t { + High = 0, + Medium, + Low, + Notification, +}; +inline constexpr uint DebugSeverityCount{4}; + +struct DebugGroup { + const uint mId; + const DebugSource mSource; + std::string mMessage; + std::vector<uint> mFilters; + std::vector<uint64_t> mIdFilters; + + template<typename T> + DebugGroup(DebugSource source, uint id, T&& message) + : mId{id}, mSource{source}, mMessage{std::forward<T>(message)} + { } + DebugGroup(const DebugGroup&) = default; + DebugGroup(DebugGroup&&) = default; + ~DebugGroup(); +}; + +#endif /* AL_DEBUG_H */ diff --git a/al/direct_defs.h b/al/direct_defs.h new file mode 100644 index 00000000..7526b611 --- /dev/null +++ b/al/direct_defs.h @@ -0,0 +1,127 @@ +#ifndef AL_DIRECT_DEFS_H +#define AL_DIRECT_DEFS_H + +namespace detail_ { + +template<typename T> +constexpr T DefaultVal() noexcept { return T{}; } + +template<> +constexpr void DefaultVal() noexcept { } + +} // namespace detail_ + +#define DECL_FUNC(R, Name) \ +R AL_APIENTRY Name(void) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get()); \ +} + +#define DECL_FUNC1(R, Name, T1) \ +R AL_APIENTRY Name(T1 a) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get(), a); \ +} + +#define DECL_FUNC2(R, Name, T1, T2) \ +R AL_APIENTRY Name(T1 a, T2 b) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get(), a, b); \ +} + +#define DECL_FUNC3(R, Name, T1, T2, T3) \ +R AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get(), a, b, c); \ +} + +#define DECL_FUNC4(R, Name, T1, T2, T3, T4) \ +R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get(), a, b, c, d); \ +} + +#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 context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct(context.get(), a, b, c, d, e); \ +} + + +#define DECL_FUNCEXT(R, Name,Ext) \ +R AL_APIENTRY Name##Ext(void) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get()); \ +} + +#define DECL_FUNCEXT1(R, Name,Ext, T1) \ +R AL_APIENTRY Name##Ext(T1 a) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a); \ +} + +#define DECL_FUNCEXT2(R, Name,Ext, T1, T2) \ +R AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b); \ +} + +#define DECL_FUNCEXT3(R, Name,Ext, T1, T2, T3) \ +R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept \ +{ \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b, c); \ +} + +#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 context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b, c, d); \ +} + +#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 context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b, c, d, e); \ +} + +#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 context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b, c, d, e, f); \ +} + +#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 context = GetContextRef(); \ + if(!context) UNLIKELY return detail_::DefaultVal<R>(); \ + return Name##Direct##Ext(context.get(), a, b, c, d, e, f, g, h); \ +} + +#endif /* AL_DIRECT_DEFS_H */ diff --git a/al/eax/api.h b/al/eax/api.h index d254da1f..18d93ef8 100644 --- a/al/eax/api.h +++ b/al/eax/api.h @@ -10,17 +10,18 @@ // +#include <array> #include <cfloat> #include <cstdint> #include <cstring> - -#include <array> +#ifdef _WIN32 +#include <guiddef.h> +#endif #include "AL/al.h" -#ifndef GUID_DEFINED -#define GUID_DEFINED +#ifndef _WIN32 typedef struct _GUID { std::uint32_t Data1; std::uint16_t Data2; @@ -28,16 +29,16 @@ typedef struct _GUID { std::uint8_t Data4[8]; } GUID; -#ifndef _SYS_GUID_OPERATOR_EQ_ -#define _SYS_GUID_OPERATOR_EQ_ inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept { return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; } inline bool operator!=(const GUID& lhs, const GUID& rhs) noexcept { return !(lhs == rhs); } -#endif // _SYS_GUID_OPERATOR_EQ_ -#endif // GUID_DEFINED +#endif // _WIN32 +#define DECL_EQOP(T) \ +friend bool operator==(const T &lhs, const T &rhs) noexcept { return std::memcmp(&lhs, &rhs, sizeof(T)) == 0; } \ +friend bool operator!=(const T &lhs, const T &rhs) noexcept { return !(lhs == rhs); } extern const GUID DSPROPSETID_EAX_ReverbProperties; @@ -613,7 +614,7 @@ struct EAX30SOURCEPROPERTIES { float flOcclusionLFRatio; // occlusion low-frequency level re. main control float flOcclusionRoomRatio; // relative occlusion control for room effect float flOcclusionDirectRatio; // relative occlusion control for direct path - long lExclusion; // main exlusion control (attenuation at high frequencies) + long lExclusion; // main exclusion control (attenuation at high frequencies) float flExclusionLFRatio; // exclusion low-frequency level re. main control long lOutsideVolumeHF; // outside sound cone level at high frequencies float flDopplerFactor; // like DS3D flDopplerFactor but per source @@ -836,6 +837,7 @@ struct EAXREVERBPROPERTIES { float flLFReference; // reference low frequency float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect unsigned long ulFlags; // modifies the behavior of properties + DECL_EQOP(EAXREVERBPROPERTIES) }; // EAXREVERBPROPERTIES @@ -965,6 +967,7 @@ enum EAXAGCCOMPRESSOR_PROPERTY : unsigned int { struct EAXAGCCOMPRESSORPROPERTIES { unsigned long ulOnOff; // Switch Compressor on or off + DECL_EQOP(EAXAGCCOMPRESSORPROPERTIES) }; // EAXAGCCOMPRESSORPROPERTIES @@ -991,6 +994,7 @@ struct EAXAUTOWAHPROPERTIES { float flReleaseTime; // Release time (seconds) long lResonance; // Resonance (mB) long lPeakLevel; // Peak level (mB) + DECL_EQOP(EAXAUTOWAHPROPERTIES) }; // EAXAUTOWAHPROPERTIES @@ -1038,6 +1042,7 @@ struct EAXCHORUSPROPERTIES { float flDepth; // Depth (0 to 1) float flFeedback; // Feedback (-1 to 1) float flDelay; // Delay (seconds) + DECL_EQOP(EAXCHORUSPROPERTIES) }; // EAXCHORUSPROPERTIES @@ -1086,6 +1091,7 @@ struct EAXDISTORTIONPROPERTIES { float flLowPassCutOff; // Controls the cut-off of the filter pre-distortion (Hz) float flEQCenter; // Controls the center frequency of the EQ post-distortion (Hz) float flEQBandwidth; // Controls the bandwidth of the EQ post-distortion (Hz) + DECL_EQOP(EAXDISTORTIONPROPERTIES) }; // EAXDISTORTIONPROPERTIES @@ -1130,6 +1136,7 @@ struct EAXECHOPROPERTIES { float flDamping; // Controls a low-pass filter that dampens the echoes (0 to 1) float flFeedback; // Controls the duration of echo repetition (0 to 1) float flSpread; // Controls the left-right spread of the echoes + DECL_EQOP(EAXECHOPROPERTIES) }; // EAXECHOPROPERTIES @@ -1184,6 +1191,7 @@ struct EAXEQUALIZERPROPERTIES { float flMid2Width; // (octaves) long lHighGain; // (mB) float flHighCutOff; // (Hz) + DECL_EQOP(EAXEQUALIZERPROPERTIES) }; // EAXEQUALIZERPROPERTIES @@ -1255,6 +1263,7 @@ struct EAXFLANGERPROPERTIES { float flDepth; // Depth (0 to 1) float flFeedback; // Feedback (0 to 1) float flDelay; // Delay (seconds) + DECL_EQOP(EAXFLANGERPROPERTIES) }; // EAXFLANGERPROPERTIES @@ -1305,6 +1314,7 @@ struct EAXFREQUENCYSHIFTERPROPERTIES { float flFrequency; // (Hz) unsigned long ulLeftDirection; // see enum above unsigned long ulRightDirection; // see enum above + DECL_EQOP(EAXFREQUENCYSHIFTERPROPERTIES) }; // EAXFREQUENCYSHIFTERPROPERTIES @@ -1383,6 +1393,7 @@ struct EAXVOCALMORPHERPROPERTIES { long lPhonemeBCoarseTuning; // (semitones) unsigned long ulWaveform; // Waveform selector - see enum above float flRate; // (Hz) + DECL_EQOP(EAXVOCALMORPHERPROPERTIES) }; // EAXVOCALMORPHERPROPERTIES @@ -1425,6 +1436,7 @@ enum EAXPITCHSHIFTER_PROPERTY : unsigned int { struct EAXPITCHSHIFTERPROPERTIES { long lCoarseTune; // Amount of pitch shift (semitones) long lFineTune; // Amount of pitch shift (cents) + DECL_EQOP(EAXPITCHSHIFTERPROPERTIES) }; // EAXPITCHSHIFTERPROPERTIES @@ -1460,6 +1472,7 @@ struct EAXRINGMODULATORPROPERTIES { float flFrequency; // Frequency of modulation (Hz) float flHighPassCutOff; // Cut-off frequency of high-pass filter (Hz) unsigned long ulWaveform; // Waveform selector - see enum above + DECL_EQOP(EAXRINGMODULATORPROPERTIES) }; // EAXRINGMODULATORPROPERTIES @@ -1490,4 +1503,5 @@ using LPEAXGET = ALenum(AL_APIENTRY*)( ALvoid* property_buffer, ALuint property_size); +#undef DECL_EQOP #endif // !EAX_API_INCLUDED diff --git a/al/eax/call.h b/al/eax/call.h index 5ec33b0f..45ff328c 100644 --- a/al/eax/call.h +++ b/al/eax/call.h @@ -55,13 +55,13 @@ public: fail_too_small(); const auto count = minz(mPropertyBufferSize / sizeof(TValue), max_count); - return al::as_span(static_cast<TValue*>(mPropertyBuffer), count); + return {static_cast<TValue*>(mPropertyBuffer), count}; } template<typename TValue> al::span<TValue> get_values() const { - return get_values<TValue>(~size_t{}); + return get_values<TValue>(~0_uz); } template<typename TException, typename TValue> diff --git a/al/eax/effect.h b/al/eax/effect.h index a0b4e71b..afe4d94d 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -4,60 +4,55 @@ #include <cassert> #include <memory> +#include <variant> #include "alnumeric.h" #include "AL/al.h" #include "core/effects/base.h" #include "call.h" -struct EaxEffectErrorMessages -{ +struct EaxEffectErrorMessages { static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; } static constexpr auto unknown_version() noexcept { return "Unknown version."; } }; // EaxEffectErrorMessages -/* TODO: Use std::variant (C++17). */ -enum class EaxEffectType { - None, Reverb, Chorus, Autowah, Compressor, Distortion, Echo, Equalizer, Flanger, - FrequencyShifter, Modulator, PitchShifter, VocalMorpher -}; -struct EaxEffectProps { - EaxEffectType mType; - union { - EAXREVERBPROPERTIES mReverb; - EAXCHORUSPROPERTIES mChorus; - EAXAUTOWAHPROPERTIES mAutowah; - EAXAGCCOMPRESSORPROPERTIES mCompressor; - EAXDISTORTIONPROPERTIES mDistortion; - EAXECHOPROPERTIES mEcho; - EAXEQUALIZERPROPERTIES mEqualizer; - EAXFLANGERPROPERTIES mFlanger; - EAXFREQUENCYSHIFTERPROPERTIES mFrequencyShifter; - EAXRINGMODULATORPROPERTIES mModulator; - EAXPITCHSHIFTERPROPERTIES mPitchShifter; - EAXVOCALMORPHERPROPERTIES mVocalMorpher; - }; -}; - -constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props) +using EaxEffectProps = std::variant<std::monostate, + EAXREVERBPROPERTIES, + EAXCHORUSPROPERTIES, + EAXAUTOWAHPROPERTIES, + EAXAGCCOMPRESSORPROPERTIES, + EAXDISTORTIONPROPERTIES, + EAXECHOPROPERTIES, + EAXEQUALIZERPROPERTIES, + EAXFLANGERPROPERTIES, + EAXFREQUENCYSHIFTERPROPERTIES, + EAXRINGMODULATORPROPERTIES, + EAXPITCHSHIFTERPROPERTIES, + EAXVOCALMORPHERPROPERTIES>; + +template<typename... Ts> +struct overloaded : Ts... { using Ts::operator()...; }; + +template<typename... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + +constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props) noexcept { - switch(props.mType) - { - case EaxEffectType::None: break; - case EaxEffectType::Reverb: return AL_EFFECT_EAXREVERB; - case EaxEffectType::Chorus: return AL_EFFECT_CHORUS; - case EaxEffectType::Autowah: return AL_EFFECT_AUTOWAH; - case EaxEffectType::Compressor: return AL_EFFECT_COMPRESSOR; - case EaxEffectType::Distortion: return AL_EFFECT_DISTORTION; - case EaxEffectType::Echo: return AL_EFFECT_ECHO; - case EaxEffectType::Equalizer: return AL_EFFECT_EQUALIZER; - case EaxEffectType::Flanger: return AL_EFFECT_FLANGER; - case EaxEffectType::FrequencyShifter: return AL_EFFECT_FREQUENCY_SHIFTER; - case EaxEffectType::Modulator: return AL_EFFECT_RING_MODULATOR; - case EaxEffectType::PitchShifter: return AL_EFFECT_PITCH_SHIFTER; - case EaxEffectType::VocalMorpher: return AL_EFFECT_VOCAL_MORPHER; - } - return AL_EFFECT_NULL; + return std::visit(overloaded{ + [](const std::monostate&) noexcept { return AL_EFFECT_NULL; }, + [](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; }, + [](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; }, + [](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; }, + [](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; }, + [](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; }, + [](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; }, + [](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; }, + [](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; }, + [](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; }, + [](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; }, + [](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; }, + [](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; } + }, props); } struct EaxReverbCommitter { @@ -300,30 +295,30 @@ public: } -#define EAXCALL(T, Callable, ...) \ - if(T == EaxEffectType::Reverb) \ +#define EAXCALL(Props, Callable, ...) \ + if(std::holds_alternative<EAXREVERBPROPERTIES>(Props)) \ return Callable<EaxReverbCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Chorus) \ + if(std::holds_alternative<EAXCHORUSPROPERTIES>(Props)) \ return Callable<EaxChorusCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Autowah) \ + if(std::holds_alternative<EAXAUTOWAHPROPERTIES>(Props)) \ return Callable<EaxAutowahCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Compressor) \ + if(std::holds_alternative<EAXAGCCOMPRESSORPROPERTIES>(Props)) \ return Callable<EaxCompressorCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Distortion) \ + if(std::holds_alternative<EAXDISTORTIONPROPERTIES>(Props)) \ return Callable<EaxDistortionCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Echo) \ + if(std::holds_alternative<EAXECHOPROPERTIES>(Props)) \ return Callable<EaxEchoCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Equalizer) \ + if(std::holds_alternative<EAXEQUALIZERPROPERTIES>(Props)) \ return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Flanger) \ + if(std::holds_alternative<EAXFLANGERPROPERTIES>(Props)) \ return Callable<EaxFlangerCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::FrequencyShifter) \ + if(std::holds_alternative<EAXFREQUENCYSHIFTERPROPERTIES>(Props)) \ return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::Modulator) \ + if(std::holds_alternative<EAXRINGMODULATORPROPERTIES>(Props)) \ return Callable<EaxModulatorCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::PitchShifter) \ + if(std::holds_alternative<EAXPITCHSHIFTERPROPERTIES>(Props)) \ return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \ - if(T == EaxEffectType::VocalMorpher) \ + if(std::holds_alternative<EAXVOCALMORPHERPROPERTIES>(Props)) \ return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \ return Callable<EaxNullCommitter>(__VA_ARGS__) @@ -332,7 +327,7 @@ public: { return T::Set(std::forward<Args>(args)...); } static void call_set(const EaxCall &call, EaxEffectProps &props) - { EAXCALL(props.mType, call_set, call, props); } + { EAXCALL(props, call_set, call, props); } void set(const EaxCall &call) { @@ -353,7 +348,7 @@ public: { return T::Get(std::forward<Args>(args)...); } static void call_get(const EaxCall &call, const EaxEffectProps &props) - { EAXCALL(props.mType, call_get, call, props); } + { EAXCALL(props, call_get, call, props); } void get(const EaxCall &call) { @@ -373,7 +368,7 @@ public: { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); } bool call_commit(const EaxEffectProps &props) - { EAXCALL(props.mType, call_commit, props); } + { EAXCALL(props, call_commit, props); } bool commit(int eax_version) { diff --git a/al/eax/exception.cpp b/al/eax/exception.cpp index 435e7442..e4945d88 100644 --- a/al/eax/exception.cpp +++ b/al/eax/exception.cpp @@ -6,54 +6,27 @@ #include <string> -EaxException::EaxException(const char *context, const char *message) +EaxException::EaxException(std::string_view context, std::string_view message) : std::runtime_error{make_message(context, message)} { } EaxException::~EaxException() = default; -std::string EaxException::make_message(const char *context, const char *message) +std::string EaxException::make_message(std::string_view context, std::string_view message) { - const auto context_size = (context ? std::string::traits_type::length(context) : 0); - const auto has_contex = (context_size > 0); - - const auto message_size = (message ? std::string::traits_type::length(message) : 0); - const auto has_message = (message_size > 0); - - if (!has_contex && !has_message) - { - return std::string{}; - } - - static constexpr char left_prefix[] = "["; - const auto left_prefix_size = std::string::traits_type::length(left_prefix); - - static constexpr char right_prefix[] = "] "; - const auto right_prefix_size = std::string::traits_type::length(right_prefix); - - const auto what_size = - ( - has_contex ? - left_prefix_size + context_size + right_prefix_size : - 0) + - message_size + - 1; - auto what = std::string{}; - what.reserve(what_size); - - if (has_contex) - { - what.append(left_prefix, left_prefix_size); - what.append(context, context_size); - what.append(right_prefix, right_prefix_size); - } + if(context.empty() && message.empty()) + return what; - if (has_message) + what.reserve((!context.empty() ? context.size() + 3 : 0) + message.length() + 1); + if(!context.empty()) { - what.append(message, message_size); + what += "["; + what += context; + what += "] "; } + what += message; return what; } diff --git a/al/eax/exception.h b/al/eax/exception.h index 3ae88cdc..336654f0 100644 --- a/al/eax/exception.h +++ b/al/eax/exception.h @@ -1,16 +1,16 @@ #ifndef EAX_EXCEPTION_INCLUDED #define EAX_EXCEPTION_INCLUDED - #include <stdexcept> #include <string> +#include <string_view> class EaxException : public std::runtime_error { - static std::string make_message(const char *context, const char *message); + static std::string make_message(std::string_view context, std::string_view message); public: - EaxException(const char *context, const char *message); + EaxException(std::string_view context, std::string_view message); ~EaxException() override; }; // EaxException diff --git a/al/eax/fx_slot_index.h b/al/eax/fx_slot_index.h index 63dba037..9f350d9b 100644 --- a/al/eax/fx_slot_index.h +++ b/al/eax/fx_slot_index.h @@ -3,17 +3,16 @@ #include <cstddef> +#include <optional> -#include "aloptional.h" #include "api.h" using EaxFxSlotIndexValue = std::size_t; -class EaxFxSlotIndex : public al::optional<EaxFxSlotIndexValue> -{ +class EaxFxSlotIndex : public std::optional<EaxFxSlotIndexValue> { public: - using al::optional<EaxFxSlotIndexValue>::optional; + using std::optional<EaxFxSlotIndexValue>::optional; EaxFxSlotIndex& operator=(const EaxFxSlotIndexValue &value) { set(value); return *this; } EaxFxSlotIndex& operator=(const GUID &guid) { set(guid); return *this; } diff --git a/al/eax/globals.cpp b/al/eax/globals.cpp deleted file mode 100644 index 80e9dbfe..00000000 --- a/al/eax/globals.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "config.h" - -#include "globals.h" - - -bool eax_g_is_enabled = true; - - -const char eax1_ext_name[] = "EAX"; -const char eax2_ext_name[] = "EAX2.0"; -const char eax3_ext_name[] = "EAX3.0"; -const char eax4_ext_name[] = "EAX4.0"; -const char eax5_ext_name[] = "EAX5.0"; - -const char eax_x_ram_ext_name[] = "EAX-RAM"; - -const char eax_eax_set_func_name[] = "EAXSet"; -const char eax_eax_get_func_name[] = "EAXGet"; - -const char eax_eax_set_buffer_mode_func_name[] = "EAXSetBufferMode"; -const char eax_eax_get_buffer_mode_func_name[] = "EAXGetBufferMode"; diff --git a/al/eax/globals.h b/al/eax/globals.h index 1b4d63b8..ff05d009 100644 --- a/al/eax/globals.h +++ b/al/eax/globals.h @@ -1,22 +1,20 @@ #ifndef EAX_GLOBALS_INCLUDED #define EAX_GLOBALS_INCLUDED +inline bool eax_g_is_enabled{true}; -extern bool eax_g_is_enabled; +inline constexpr char eax1_ext_name[]{"EAX"}; +inline constexpr char eax2_ext_name[]{"EAX2.0"}; +inline constexpr char eax3_ext_name[]{"EAX3.0"}; +inline constexpr char eax4_ext_name[]{"EAX4.0"}; +inline constexpr char eax5_ext_name[]{"EAX5.0"}; +inline constexpr char eax_x_ram_ext_name[]{"EAX-RAM"}; -extern const char eax1_ext_name[]; -extern const char eax2_ext_name[]; -extern const char eax3_ext_name[]; -extern const char eax4_ext_name[]; -extern const char eax5_ext_name[]; +inline constexpr char eax_eax_set_func_name[]{"EAXSet"}; +inline constexpr char eax_eax_get_func_name[]{"EAXGet"}; -extern const char eax_x_ram_ext_name[]; - -extern const char eax_eax_set_func_name[]; -extern const char eax_eax_get_func_name[]; - -extern const char eax_eax_set_buffer_mode_func_name[]; -extern const char eax_eax_get_buffer_mode_func_name[]; +inline constexpr char eax_eax_set_buffer_mode_func_name[]{"EAXSetBufferMode"}; +inline constexpr char eax_eax_get_buffer_mode_func_name[]{"EAXGetBufferMode"}; #endif // !EAX_GLOBALS_INCLUDED diff --git a/al/eax/utils.cpp b/al/eax/utils.cpp index b3ed6ca1..53599ac5 100644 --- a/al/eax/utils.cpp +++ b/al/eax/utils.cpp @@ -8,7 +8,7 @@ #include "core/logging.h" -void eax_log_exception(const char *message) noexcept +void eax_log_exception(std::string_view message) noexcept { const auto exception_ptr = std::current_exception(); assert(exception_ptr); @@ -18,9 +18,9 @@ void eax_log_exception(const char *message) noexcept } catch(const std::exception& ex) { const auto ex_message = ex.what(); - ERR("%s %s\n", message ? message : "", ex_message); + ERR("%.*s %s\n", static_cast<int>(message.length()), message.data(), ex_message); } catch(...) { - ERR("%s %s\n", message ? message : "", "Generic exception."); + ERR("%.*s %s\n", static_cast<int>(message.length()), message.data(), "Generic exception."); } } diff --git a/al/eax/utils.h b/al/eax/utils.h index 8ff75a18..8e0f975f 100644 --- a/al/eax/utils.h +++ b/al/eax/utils.h @@ -4,8 +4,11 @@ #include <algorithm> #include <cstdint> #include <string> +#include <string_view> #include <type_traits> +#include "opthelpers.h" + using EaxDirtyFlags = unsigned int; struct EaxAlLowPassParam { @@ -13,16 +16,13 @@ struct EaxAlLowPassParam { float gain_hf; }; -void eax_log_exception(const char *message) noexcept; +void eax_log_exception(std::string_view message) noexcept; template<typename TException, typename TValue> -void eax_validate_range( - const char* value_name, - const TValue& value, - const TValue& min_value, +void eax_validate_range(std::string_view value_name, const TValue& value, const TValue& min_value, const TValue& max_value) { - if (value >= min_value && value <= max_value) + if(value >= min_value && value <= max_value) LIKELY return; const auto message = diff --git a/al/eax/x_ram.h b/al/eax/x_ram.h index 438b9916..d10fe697 100644 --- a/al/eax/x_ram.h +++ b/al/eax/x_ram.h @@ -25,14 +25,7 @@ constexpr auto AL_STORAGE_HARDWARE_NAME = "AL_STORAGE_HARDWARE"; constexpr auto AL_STORAGE_ACCESSIBLE_NAME = "AL_STORAGE_ACCESSIBLE"; -ALboolean AL_APIENTRY EAXSetBufferMode( - ALsizei n, - const ALuint* buffers, - ALint value); - -ALenum AL_APIENTRY EAXGetBufferMode( - ALuint buffer, - ALint* pReserved); - +ALboolean AL_APIENTRY EAXSetBufferMode(ALsizei n, const ALuint *buffers, ALint value) noexcept; +ALenum AL_APIENTRY EAXGetBufferMode(ALuint buffer, ALint *pReserved) noexcept; #endif // !EAX_X_RAM_INCLUDED diff --git a/al/effect.cpp b/al/effect.cpp index bde89912..3e48e91b 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -31,6 +31,7 @@ #include <new> #include <numeric> #include <utility> +#include <vector> #include "AL/al.h" #include "AL/alc.h" @@ -48,8 +49,8 @@ #include "alstring.h" #include "core/except.h" #include "core/logging.h" +#include "direct_defs.h" #include "opthelpers.h" -#include "vector.h" #ifdef ALSOFT_EAX #include <cassert> @@ -73,7 +74,7 @@ const EffectList gEffectList[16]{ { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, - { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_REVERB_SOFT }, + { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_SOFT }, }; bool DisabledEffects[MAX_EFFECTS]; @@ -112,7 +113,7 @@ constexpr EffectPropsItem EffectPropsList[] = { { AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable }, { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable }, { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable }, - { AL_EFFECT_CONVOLUTION_REVERB_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable }, + { AL_EFFECT_CONVOLUTION_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable }, }; @@ -161,7 +162,7 @@ void InitEffectParams(ALeffect *effect, ALenum type) bool EnsureEffects(ALCdevice *device, size_t needed) { - size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0}, + size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), 0_uz, [](size_t cur, const EffectSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; @@ -206,11 +207,13 @@ ALeffect *AllocEffect(ALCdevice *device) void FreeEffect(ALCdevice *device, ALeffect *effect) { + device->mEffectNames.erase(effect->id); + const ALuint id{effect->id - 1}; const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(effect); + std::destroy_at(effect); device->EffectList[lidx].FreeMask |= 1_u64 << slidx; } @@ -230,12 +233,9 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) } // namespace -AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) -START_API_FUNC +AL_API DECL_FUNC2(void, alGenEffects, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alGenEffectsDirect(ALCcontext *context, ALsizei n, ALuint *effects) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Generating %d effects", n); if(n <= 0) UNLIKELY return; @@ -259,7 +259,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector<ALuint> ids; + std::vector<ALuint> ids; ids.reserve(static_cast<ALuint>(n)); do { ALeffect *effect{AllocEffect(device)}; @@ -268,14 +268,11 @@ START_API_FUNC std::copy(ids.cbegin(), ids.cend(), effects); } } -END_API_FUNC -AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) -START_API_FUNC +AL_API DECL_FUNC2(void, alDeleteEffects, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alDeleteEffectsDirect(ALCcontext *context, ALsizei n, + const ALuint *effects) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Deleting %d effects", n); if(n <= 0) UNLIKELY return; @@ -303,29 +300,21 @@ START_API_FUNC }; std::for_each(effects, effects_end, delete_effect); } -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsEffect, ALuint) +FORCE_ALIGN ALboolean AL_APIENTRY alIsEffectDirect(ALCcontext *context, ALuint effect) noexcept { - ContextRef context{GetContextRef()}; - if(context) LIKELY - { - ALCdevice *device{context->mALDevice.get()}; - std::lock_guard<std::mutex> _{device->EffectLock}; - if(!effect || LookupEffect(device, effect)) - return AL_TRUE; - } + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->EffectLock}; + if(!effect || LookupEffect(device, effect)) + return AL_TRUE; return AL_FALSE; } -END_API_FUNC -AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) -START_API_FUNC +AL_API DECL_FUNC3(void, alEffecti, ALuint, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, ALenum param, + ALint value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -361,21 +350,18 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alEffectiv, ALuint, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect, ALenum param, + const ALint *values) noexcept { switch(param) { case AL_EFFECT_TYPE: - alEffecti(effect, param, values[0]); + alEffectiDirect(context, effect, param, values[0]); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -391,14 +377,11 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) -START_API_FUNC +AL_API DECL_FUNC3(void, alEffectf, ALuint, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, ALenum param, + ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -414,14 +397,11 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alEffectfv, ALuint, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param, + const ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -437,14 +417,11 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetEffecti, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effect, ALenum param, + ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -462,21 +439,18 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetEffectiv, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint effect, ALenum param, + ALint *values) noexcept { switch(param) { case AL_EFFECT_TYPE: - alGetEffecti(effect, param, values); + alGetEffectiDirect(context, effect, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -492,14 +466,11 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetEffectf, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effect, ALenum param, + ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -515,14 +486,11 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetEffectfv, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param, + ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->EffectLock}; @@ -538,7 +506,6 @@ START_API_FUNC context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC void InitEffect(ALeffect *effect) @@ -546,13 +513,29 @@ void InitEffect(ALeffect *effect) InitEffectParams(effect, AL_EFFECT_NULL); } +void ALeffect::SetName(ALCcontext* context, ALuint id, std::string_view name) +{ + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->EffectLock}; + + auto effect = LookupEffect(device, id); + if(!effect) UNLIKELY + return context->setError(AL_INVALID_NAME, "Invalid effect ID %u", id); + + device->mEffectNames.insert_or_assign(id, name); +} + + EffectSubList::~EffectSubList() { + if(!Effects) + return; + uint64_t usemask{~FreeMask}; while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Effects+idx); + std::destroy_at(Effects+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/al/effect.h b/al/effect.h index a1d43313..27e9dd72 100644 --- a/al/effect.h +++ b/al/effect.h @@ -1,6 +1,8 @@ #ifndef AL_EFFECT_H #define AL_EFFECT_H +#include <string_view> + #include "AL/al.h" #include "AL/efx.h" @@ -50,6 +52,8 @@ struct ALeffect { /* Self ID */ ALuint id{0u}; + static void SetName(ALCcontext *context, ALuint id, std::string_view name); + DISABLE_ALLOC() }; diff --git a/al/effects/autowah.cpp b/al/effects/autowah.cpp index 129318f4..1a8b43fc 100644 --- a/al/effects/autowah.cpp +++ b/al/effects/autowah.cpp @@ -192,19 +192,16 @@ template<> template<> bool AutowahCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && mEaxProps.mAutowah.flAttackTime == props.mAutowah.flAttackTime - && mEaxProps.mAutowah.flReleaseTime == props.mAutowah.flReleaseTime - && mEaxProps.mAutowah.lResonance == props.mAutowah.lResonance - && mEaxProps.mAutowah.lPeakLevel == props.mAutowah.lPeakLevel) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Autowah.AttackTime = props.mAutowah.flAttackTime; - mAlProps.Autowah.ReleaseTime = props.mAutowah.flReleaseTime; - mAlProps.Autowah.Resonance = level_mb_to_gain(static_cast<float>(props.mAutowah.lResonance)); - mAlProps.Autowah.PeakGain = level_mb_to_gain(static_cast<float>(props.mAutowah.lPeakLevel)); + 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)); return true; } @@ -212,39 +209,46 @@ bool AutowahCommitter::commit(const EaxEffectProps &props) template<> void AutowahCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Autowah; - props.mAutowah.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME; - props.mAutowah.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME; - props.mAutowah.lResonance = EAXAUTOWAH_DEFAULTRESONANCE; - props.mAutowah.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL; + static constexpr EAXAUTOWAHPROPERTIES defprops{[] + { + EAXAUTOWAHPROPERTIES ret{}; + ret.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME; + ret.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME; + ret.lResonance = EAXAUTOWAH_DEFAULTRESONANCE; + ret.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL; + return ret; + }()}; + props = defprops; } template<> -void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAUTOWAH_NONE: break; - case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props.mAutowah); break; - case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.mAutowah.flAttackTime); break; - case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.mAutowah.flReleaseTime); break; - case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.mAutowah.lResonance); break; - case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(props.mAutowah.lPeakLevel); break; + case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.flAttackTime); break; + case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.flReleaseTime); break; + case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.lResonance); break; + case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(props.lPeakLevel); break; default: fail_unknown_property_id(); } } template<> -void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAUTOWAH_NONE: break; - case EAXAUTOWAH_ALLPARAMETERS: defer<AllValidator>(call, props.mAutowah); break; - case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.mAutowah.flAttackTime); break; - case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.mAutowah.flReleaseTime); break; - case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.mAutowah.lResonance); break; - case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(call, props.mAutowah.lPeakLevel); break; + case EAXAUTOWAH_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.flAttackTime); break; + case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.flReleaseTime); break; + case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.lResonance); break; + case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(call, props.lPeakLevel); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp index 305259a4..90b38e4d 100644 --- a/al/effects/chorus.cpp +++ b/al/effects/chorus.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include <optional> #include <stdexcept> #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "core/logging.h" #include "effects.h" @@ -27,14 +27,14 @@ static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too sm static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); -inline al::optional<ChorusWaveform> WaveformFromEnum(ALenum type) +inline std::optional<ChorusWaveform> WaveformFromEnum(ALenum type) { switch(type) { case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid; case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle; } - return al::nullopt; + return std::nullopt; } inline ALenum EnumFromWaveform(ChorusWaveform type) { @@ -294,9 +294,7 @@ namespace { struct EaxChorusTraits { using Props = EAXCHORUSPROPERTIES; using Committer = EaxChorusCommitter; - static constexpr auto Field = &EaxEffectProps::mChorus; - static constexpr auto eax_effect_type() { return EaxEffectType::Chorus; } static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; } static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; } @@ -361,9 +359,7 @@ struct EaxChorusTraits { struct EaxFlangerTraits { using Props = EAXFLANGERPROPERTIES; using Committer = EaxFlangerCommitter; - static constexpr auto Field = &EaxEffectProps::mFlanger; - static constexpr auto eax_effect_type() { return EaxEffectType::Flanger; } static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; } static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; } @@ -431,8 +427,6 @@ struct ChorusFlangerEffect { using Committer = typename Traits::Committer; using Exception = typename Committer::Exception; - static constexpr auto Field = Traits::Field; - struct WaveformValidator { void operator()(unsigned long ulWaveform) const { @@ -514,8 +508,7 @@ struct ChorusFlangerEffect { public: static void SetDefaults(EaxEffectProps &props) { - auto&& all = props.*Field; - props.mType = Traits::eax_effect_type(); + auto&& all = props.emplace<typename Traits::Props>(); all.ulWaveform = Traits::eax_default_waveform(); all.lPhase = Traits::eax_default_phase(); all.flRate = Traits::eax_default_rate(); @@ -527,7 +520,7 @@ public: static void Get(const EaxCall &call, const EaxEffectProps &props) { - auto&& all = props.*Field; + auto&& all = std::get<typename Traits::Props>(props); switch(call.get_property_id()) { case Traits::eax_none_param_id(): @@ -568,7 +561,7 @@ public: static void Set(const EaxCall &call, EaxEffectProps &props) { - auto&& all = props.*Field; + auto&& all = std::get<typename Traits::Props>(props); switch(call.get_property_id()) { case Traits::eax_none_param_id(): @@ -609,18 +602,11 @@ public: static bool Commit(const EaxEffectProps &props, EaxEffectProps &props_, EffectProps &al_props_) { - if(props.mType == props_.mType) - { - auto&& src = props_.*Field; - auto&& dst = props.*Field; - if(dst.ulWaveform == src.ulWaveform && dst.lPhase == src.lPhase - && dst.flRate == src.flRate && dst.flDepth == src.flDepth - && dst.flFeedback == src.flFeedback && dst.flDelay == src.flDelay) - return false; - } + if(props == props_) + return false; props_ = props; - auto&& dst = props.*Field; + 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); diff --git a/al/effects/compressor.cpp b/al/effects/compressor.cpp index a4aa8e77..ca8af84f 100644 --- a/al/effects/compressor.cpp +++ b/al/effects/compressor.cpp @@ -118,43 +118,43 @@ template<> template<> bool CompressorCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && props.mCompressor.ulOnOff == mEaxProps.mCompressor.ulOnOff) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Compressor.OnOff = (props.mCompressor.ulOnOff != 0); + mAlProps.Compressor.OnOff = (std::get<EAXAGCCOMPRESSORPROPERTIES>(props).ulOnOff != 0); return true; } template<> void CompressorCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Compressor; - props.mCompressor.ulOnOff = EAXAGCCOMPRESSOR_DEFAULTONOFF; + props = EAXAGCCOMPRESSORPROPERTIES{EAXAGCCOMPRESSOR_DEFAULTONOFF}; } template<> -void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAGCCOMPRESSOR_NONE: break; - case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value<Exception>(props.mCompressor); break; - case EAXAGCCOMPRESSOR_ONOFF: call.set_value<Exception>(props.mCompressor.ulOnOff); break; + case EAXAGCCOMPRESSOR_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXAGCCOMPRESSOR_ONOFF: call.set_value<Exception>(props.ulOnOff); break; default: fail_unknown_property_id(); } } template<> -void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXAGCCOMPRESSOR_NONE: break; - case EAXAGCCOMPRESSOR_ALLPARAMETERS: defer<AllValidator>(call, props.mCompressor); break; - case EAXAGCCOMPRESSOR_ONOFF: defer<OnOffValidator>(call, props.mCompressor.ulOnOff); break; + case EAXAGCCOMPRESSOR_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXAGCCOMPRESSOR_ONOFF: defer<OnOffValidator>(call, props.ulOnOff); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/convolution.cpp b/al/effects/convolution.cpp index 8e850fd3..9c091e53 100644 --- a/al/effects/convolution.cpp +++ b/al/effects/convolution.cpp @@ -1,6 +1,8 @@ #include "config.h" +#include <cmath> + #include "AL/al.h" #include "alc/inprogext.h" @@ -36,12 +38,25 @@ void Convolution_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/) param}; } } -void Convolution_setParamfv(EffectProps *props, ALenum param, const float *vals) +void Convolution_setParamfv(EffectProps *props, ALenum param, const float *values) { switch(param) { + case AL_CONVOLUTION_ORIENTATION_SOFT: + if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) + && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) + 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]; + break; + default: - Convolution_setParamf(props, param, vals[0]); + Convolution_setParamf(props, param, values[0]); } } @@ -71,18 +86,29 @@ void Convolution_getParamf(const EffectProps* /*props*/, ALenum param, float* /* param}; } } -void Convolution_getParamfv(const EffectProps *props, ALenum param, float *vals) +void Convolution_getParamfv(const EffectProps *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]; + break; + default: - Convolution_getParamf(props, param, vals); + Convolution_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; } diff --git a/al/effects/distortion.cpp b/al/effects/distortion.cpp index ee298ddf..e046d8e7 100644 --- a/al/effects/distortion.cpp +++ b/al/effects/distortion.cpp @@ -207,20 +207,17 @@ template<> template<> bool DistortionCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType && mEaxProps.mDistortion.flEdge == props.mDistortion.flEdge - && mEaxProps.mDistortion.lGain == props.mDistortion.lGain - && mEaxProps.mDistortion.flLowPassCutOff == props.mDistortion.flLowPassCutOff - && mEaxProps.mDistortion.flEQCenter == props.mDistortion.flEQCenter - && mEaxProps.mDistortion.flEQBandwidth == props.mDistortion.flEQBandwidth) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Distortion.Edge = props.mDistortion.flEdge; - mAlProps.Distortion.Gain = level_mb_to_gain(static_cast<float>(props.mDistortion.lGain)); - mAlProps.Distortion.LowpassCutoff = props.mDistortion.flLowPassCutOff; - mAlProps.Distortion.EQCenter = props.mDistortion.flEQCenter; - mAlProps.Distortion.EQBandwidth = props.mDistortion.flEdge; + 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; return true; } @@ -228,42 +225,49 @@ bool DistortionCommitter::commit(const EaxEffectProps &props) template<> void DistortionCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Distortion; - props.mDistortion.flEdge = EAXDISTORTION_DEFAULTEDGE; - props.mDistortion.lGain = EAXDISTORTION_DEFAULTGAIN; - props.mDistortion.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF; - props.mDistortion.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER; - props.mDistortion.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH; + static constexpr EAXDISTORTIONPROPERTIES defprops{[] + { + EAXDISTORTIONPROPERTIES ret{}; + ret.flEdge = EAXDISTORTION_DEFAULTEDGE; + ret.lGain = EAXDISTORTION_DEFAULTGAIN; + ret.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF; + ret.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER; + ret.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH; + return ret; + }()}; + props = defprops; } template<> -void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_); switch(call.get_property_id()) { case EAXDISTORTION_NONE: break; - case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props.mDistortion); break; - case EAXDISTORTION_EDGE: call.set_value<Exception>(props.mDistortion.flEdge); break; - case EAXDISTORTION_GAIN: call.set_value<Exception>(props.mDistortion.lGain); break; - case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.mDistortion.flLowPassCutOff); break; - case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.mDistortion.flEQCenter); break; - case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.mDistortion.flEQBandwidth); break; + case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXDISTORTION_EDGE: call.set_value<Exception>(props.flEdge); break; + case EAXDISTORTION_GAIN: call.set_value<Exception>(props.lGain); break; + case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.flLowPassCutOff); break; + case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.flEQCenter); break; + case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.flEQBandwidth); break; default: fail_unknown_property_id(); } } template<> -void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_); switch(call.get_property_id()) { case EAXDISTORTION_NONE: break; - case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props.mDistortion); break; - case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.mDistortion.flEdge); break; - case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.mDistortion.lGain); break; - case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.mDistortion.flLowPassCutOff); break; - case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.mDistortion.flEQCenter); break; - case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.mDistortion.flEQBandwidth); break; + case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.flEdge); break; + case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.lGain); break; + case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.flLowPassCutOff); break; + case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.flEQCenter); break; + case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.flEQBandwidth); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp index 2eb37603..48aacef3 100644 --- a/al/effects/echo.cpp +++ b/al/effects/echo.cpp @@ -204,20 +204,17 @@ template<> template<> bool EchoCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType && mEaxProps.mEcho.flDelay == props.mEcho.flDelay - && mEaxProps.mEcho.flLRDelay == props.mEcho.flLRDelay - && mEaxProps.mEcho.flDamping == props.mEcho.flDamping - && mEaxProps.mEcho.flFeedback == props.mEcho.flFeedback - && mEaxProps.mEcho.flSpread == props.mEcho.flSpread) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Echo.Delay = props.mEcho.flDelay; - mAlProps.Echo.LRDelay = props.mEcho.flLRDelay; - mAlProps.Echo.Damping = props.mEcho.flDamping; - mAlProps.Echo.Feedback = props.mEcho.flFeedback; - mAlProps.Echo.Spread = props.mEcho.flSpread; + 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; return true; } @@ -225,42 +222,49 @@ bool EchoCommitter::commit(const EaxEffectProps &props) template<> void EchoCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Echo; - props.mEcho.flDelay = EAXECHO_DEFAULTDELAY; - props.mEcho.flLRDelay = EAXECHO_DEFAULTLRDELAY; - props.mEcho.flDamping = EAXECHO_DEFAULTDAMPING; - props.mEcho.flFeedback = EAXECHO_DEFAULTFEEDBACK; - props.mEcho.flSpread = EAXECHO_DEFAULTSPREAD; + static constexpr EAXECHOPROPERTIES defprops{[] + { + EAXECHOPROPERTIES ret{}; + ret.flDelay = EAXECHO_DEFAULTDELAY; + ret.flLRDelay = EAXECHO_DEFAULTLRDELAY; + ret.flDamping = EAXECHO_DEFAULTDAMPING; + ret.flFeedback = EAXECHO_DEFAULTFEEDBACK; + ret.flSpread = EAXECHO_DEFAULTSPREAD; + return ret; + }()}; + props = defprops; } template<> -void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXECHOPROPERTIES>(props_); switch(call.get_property_id()) { case EAXECHO_NONE: break; - case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props.mEcho); break; - case EAXECHO_DELAY: call.set_value<Exception>(props.mEcho.flDelay); break; - case EAXECHO_LRDELAY: call.set_value<Exception>(props.mEcho.flLRDelay); break; - case EAXECHO_DAMPING: call.set_value<Exception>(props.mEcho.flDamping); break; - case EAXECHO_FEEDBACK: call.set_value<Exception>(props.mEcho.flFeedback); break; - case EAXECHO_SPREAD: call.set_value<Exception>(props.mEcho.flSpread); break; + case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break; + case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break; + case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break; + case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break; + case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break; default: fail_unknown_property_id(); } } template<> -void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXECHOPROPERTIES>(props_); switch(call.get_property_id()) { case EAXECHO_NONE: break; - case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props.mEcho); break; - case EAXECHO_DELAY: defer<DelayValidator>(call, props.mEcho.flDelay); break; - case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.mEcho.flLRDelay); break; - case EAXECHO_DAMPING: defer<DampingValidator>(call, props.mEcho.flDamping); break; - case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.mEcho.flFeedback); break; - case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.mEcho.flSpread); break; + case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break; + case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break; + case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break; + case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break; + case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.flSpread); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/equalizer.cpp b/al/effects/equalizer.cpp index 7dc703db..76d5bdef 100644 --- a/al/effects/equalizer.cpp +++ b/al/effects/equalizer.cpp @@ -322,30 +322,22 @@ template<> template<> bool EqualizerCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType && mEaxProps.mEqualizer.lLowGain == props.mEqualizer.lLowGain - && mEaxProps.mEqualizer.flLowCutOff == props.mEqualizer.flLowCutOff - && mEaxProps.mEqualizer.lMid1Gain == props.mEqualizer.lMid1Gain - && mEaxProps.mEqualizer.flMid1Center == props.mEqualizer.flMid1Center - && mEaxProps.mEqualizer.flMid1Width == props.mEqualizer.flMid1Width - && mEaxProps.mEqualizer.lMid2Gain == props.mEqualizer.lMid2Gain - && mEaxProps.mEqualizer.flMid2Center == props.mEqualizer.flMid2Center - && mEaxProps.mEqualizer.flMid2Width == props.mEqualizer.flMid2Width - && mEaxProps.mEqualizer.lHighGain == props.mEqualizer.lHighGain - && mEaxProps.mEqualizer.flHighCutOff == props.mEqualizer.flHighCutOff) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Equalizer.LowGain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lLowGain)); - mAlProps.Equalizer.LowCutoff = props.mEqualizer.flLowCutOff; - mAlProps.Equalizer.Mid1Gain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lMid1Gain)); - mAlProps.Equalizer.Mid1Center = props.mEqualizer.flMid1Center; - mAlProps.Equalizer.Mid1Width = props.mEqualizer.flMid1Width; - mAlProps.Equalizer.Mid2Gain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lMid2Gain)); - mAlProps.Equalizer.Mid2Center = props.mEqualizer.flMid2Center; - mAlProps.Equalizer.Mid2Width = props.mEqualizer.flMid2Width; - mAlProps.Equalizer.HighGain = level_mb_to_gain(static_cast<float>(props.mEqualizer.lHighGain)); - mAlProps.Equalizer.HighCutoff = props.mEqualizer.flHighCutOff; + 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; return true; } @@ -353,57 +345,64 @@ bool EqualizerCommitter::commit(const EaxEffectProps &props) template<> void EqualizerCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Equalizer; - props.mEqualizer.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN; - props.mEqualizer.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF; - props.mEqualizer.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN; - props.mEqualizer.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER; - props.mEqualizer.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH; - props.mEqualizer.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN; - props.mEqualizer.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER; - props.mEqualizer.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH; - props.mEqualizer.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN; - props.mEqualizer.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF; + static constexpr EAXEQUALIZERPROPERTIES defprops{[] + { + EAXEQUALIZERPROPERTIES ret{}; + ret.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN; + ret.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF; + ret.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN; + ret.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER; + ret.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH; + ret.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN; + ret.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER; + ret.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH; + ret.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN; + ret.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF; + return ret; + }()}; + props = defprops; } template<> -void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXEQUALIZER_NONE: break; - case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props.mEqualizer); break; - case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.mEqualizer.lLowGain); break; - case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.mEqualizer.flLowCutOff); break; - case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.mEqualizer.lMid1Gain); break; - case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.mEqualizer.flMid1Center); break; - case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.mEqualizer.flMid1Width); break; - case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.mEqualizer.lMid2Gain); break; - case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.mEqualizer.flMid2Center); break; - case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.mEqualizer.flMid2Width); break; - case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.mEqualizer.lHighGain); break; - case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.mEqualizer.flHighCutOff); break; + case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.lLowGain); break; + case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.flLowCutOff); break; + case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.lMid1Gain); break; + case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.flMid1Center); break; + case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.flMid1Width); break; + case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.lMid2Gain); break; + case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.flMid2Center); break; + case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.flMid2Width); break; + case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.lHighGain); break; + case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.flHighCutOff); break; default: fail_unknown_property_id(); } } template<> -void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXEQUALIZER_NONE: break; - case EAXEQUALIZER_ALLPARAMETERS: defer<AllValidator>(call, props.mEqualizer); break; - case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.mEqualizer.lLowGain); break; - case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.mEqualizer.flLowCutOff); break; - case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.mEqualizer.lMid1Gain); break; - case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.mEqualizer.flMid1Center); break; - case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.mEqualizer.flMid1Width); break; - case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.mEqualizer.lMid2Gain); break; - case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.mEqualizer.flMid2Center); break; - case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.mEqualizer.flMid2Width); break; - case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.mEqualizer.lHighGain); break; - case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(call, props.mEqualizer.flHighCutOff); break; + case EAXEQUALIZER_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.lLowGain); break; + case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.flLowCutOff); break; + case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.lMid1Gain); break; + case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.flMid1Center); break; + case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.flMid1Width); break; + case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.lMid2Gain); break; + case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.flMid2Center); break; + case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.flMid2Width); break; + case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.lHighGain); break; + case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(call, props.flHighCutOff); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp index 949db203..37c372c3 100644 --- a/al/effects/fshifter.cpp +++ b/al/effects/fshifter.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include <optional> #include <stdexcept> #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional<FShifterDirection> DirectionFromEmum(ALenum value) +std::optional<FShifterDirection> DirectionFromEmum(ALenum value) { switch(value) { @@ -28,7 +28,7 @@ al::optional<FShifterDirection> DirectionFromEmum(ALenum value) case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return FShifterDirection::Up; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return FShifterDirection::Off; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromDirection(FShifterDirection dir) { @@ -200,10 +200,7 @@ template<> template<> bool FrequencyShifterCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && mEaxProps.mFrequencyShifter.flFrequency == props.mFrequencyShifter.flFrequency - && mEaxProps.mFrequencyShifter.ulLeftDirection == props.mFrequencyShifter.ulLeftDirection - && mEaxProps.mFrequencyShifter.ulRightDirection == props.mFrequencyShifter.ulRightDirection) + if(props == mEaxProps) return false; mEaxProps = props; @@ -217,9 +214,10 @@ bool FrequencyShifterCommitter::commit(const EaxEffectProps &props) return FShifterDirection::Off; }; - mAlProps.Fshifter.Frequency = props.mFrequencyShifter.flFrequency; - mAlProps.Fshifter.LeftDirection = get_direction(props.mFrequencyShifter.ulLeftDirection); - mAlProps.Fshifter.RightDirection = get_direction(props.mFrequencyShifter.ulRightDirection); + 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); return true; } @@ -227,36 +225,43 @@ bool FrequencyShifterCommitter::commit(const EaxEffectProps &props) template<> void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::FrequencyShifter; - props.mFrequencyShifter.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY; - props.mFrequencyShifter.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION; - props.mFrequencyShifter.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION; + static constexpr EAXFREQUENCYSHIFTERPROPERTIES defprops{[] + { + EAXFREQUENCYSHIFTERPROPERTIES ret{}; + ret.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY; + ret.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION; + ret.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION; + return ret; + }()}; + props = defprops; } template<> -void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXFREQUENCYSHIFTER_NONE: break; - case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mFrequencyShifter); break; - case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.mFrequencyShifter.flFrequency); break; - case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.mFrequencyShifter.ulLeftDirection); break; - case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.mFrequencyShifter.ulRightDirection); break; + case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.flFrequency); break; + case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.ulLeftDirection); break; + case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.ulRightDirection); break; default: fail_unknown_property_id(); } } template<> -void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXFREQUENCYSHIFTER_NONE: break; - case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mFrequencyShifter); break; - case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.mFrequencyShifter.flFrequency); break; - case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.mFrequencyShifter.ulLeftDirection); break; - case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(call, props.mFrequencyShifter.ulRightDirection); break; + case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break; + case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.ulLeftDirection); break; + case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(call, props.ulRightDirection); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp index 5f37d08f..366e7ef7 100644 --- a/al/effects/modulator.cpp +++ b/al/effects/modulator.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include <optional> #include <stdexcept> #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) +std::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) { switch(value) { @@ -28,7 +28,7 @@ al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth; case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromWaveform(ModulatorWaveform type) { @@ -206,10 +206,7 @@ template<> template<> bool ModulatorCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && mEaxProps.mModulator.flFrequency == props.mModulator.flFrequency - && mEaxProps.mModulator.flHighPassCutOff == props.mModulator.flHighPassCutOff - && mEaxProps.mModulator.ulWaveform == props.mModulator.ulWaveform) + if(props == mEaxProps) return false; mEaxProps = props; @@ -225,9 +222,10 @@ bool ModulatorCommitter::commit(const EaxEffectProps &props) return ModulatorWaveform::Sinusoid; }; - mAlProps.Modulator.Frequency = props.mModulator.flFrequency; - mAlProps.Modulator.HighPassCutoff = props.mModulator.flHighPassCutOff; - mAlProps.Modulator.Waveform = get_waveform(props.mModulator.ulWaveform); + auto &eaxprops = std::get<EAXRINGMODULATORPROPERTIES>(props); + mAlProps.Modulator.Frequency = eaxprops.flFrequency; + mAlProps.Modulator.HighPassCutoff = eaxprops.flHighPassCutOff; + mAlProps.Modulator.Waveform = get_waveform(eaxprops.ulWaveform); return true; } @@ -235,36 +233,43 @@ bool ModulatorCommitter::commit(const EaxEffectProps &props) template<> void ModulatorCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Modulator; - props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; - props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; - props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; + static constexpr EAXRINGMODULATORPROPERTIES defprops{[] + { + EAXRINGMODULATORPROPERTIES ret{}; + ret.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY; + ret.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF; + ret.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM; + return ret; + }()}; + props = defprops; } template<> -void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_); switch(call.get_property_id()) { case EAXRINGMODULATOR_NONE: break; - case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props.mModulator); break; - case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.mModulator.flFrequency); break; - case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.mModulator.flHighPassCutOff); break; - case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.mModulator.ulWaveform); break; + case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break; default: fail_unknown_property_id(); } } template<> -void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_); switch (call.get_property_id()) { case EAXRINGMODULATOR_NONE: break; - case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props.mModulator); break; - case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.mModulator.flFrequency); break; - case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.mModulator.flHighPassCutOff); break; - case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.mModulator.ulWaveform); break; + case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break; + case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.flHighPassCutOff); break; + case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/null.cpp b/al/effects/null.cpp index 0bbc183a..1e8787e7 100644 --- a/al/effects/null.cpp +++ b/al/effects/null.cpp @@ -120,7 +120,7 @@ template<> template<> bool NullCommitter::commit(const EaxEffectProps &props) { - const bool ret{props.mType != mEaxProps.mType}; + const bool ret{props != mEaxProps}; mEaxProps = props; return ret; } @@ -128,8 +128,7 @@ bool NullCommitter::commit(const EaxEffectProps &props) template<> void NullCommitter::SetDefaults(EaxEffectProps &props) { - props = EaxEffectProps{}; - props.mType = EaxEffectType::None; + props.emplace<std::monostate>(); } template<> diff --git a/al/effects/pshifter.cpp b/al/effects/pshifter.cpp index 634eb186..10824016 100644 --- a/al/effects/pshifter.cpp +++ b/al/effects/pshifter.cpp @@ -141,15 +141,14 @@ template<> template<> bool PitchShifterCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && mEaxProps.mPitchShifter.lCoarseTune == props.mPitchShifter.lCoarseTune - && mEaxProps.mPitchShifter.lFineTune == props.mPitchShifter.lFineTune) + if(props == mEaxProps) return false; mEaxProps = props; - mAlProps.Pshifter.CoarseTune = static_cast<int>(mEaxProps.mPitchShifter.lCoarseTune); - mAlProps.Pshifter.FineTune = static_cast<int>(mEaxProps.mPitchShifter.lFineTune); + auto &eaxprops = std::get<EAXPITCHSHIFTERPROPERTIES>(props); + mAlProps.Pshifter.CoarseTune = static_cast<int>(eaxprops.lCoarseTune); + mAlProps.Pshifter.FineTune = static_cast<int>(eaxprops.lFineTune); return true; } @@ -157,33 +156,34 @@ bool PitchShifterCommitter::commit(const EaxEffectProps &props) template<> void PitchShifterCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::PitchShifter; - props.mPitchShifter.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE; - props.mPitchShifter.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE; + props = EAXPITCHSHIFTERPROPERTIES{EAXPITCHSHIFTER_DEFAULTCOARSETUNE, + EAXPITCHSHIFTER_DEFAULTFINETUNE}; } template<> -void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXPITCHSHIFTER_NONE: break; - case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props.mPitchShifter); break; - case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.mPitchShifter.lCoarseTune); break; - case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.mPitchShifter.lFineTune); break; + case EAXPITCHSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXPITCHSHIFTER_COARSETUNE: call.set_value<Exception>(props.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: call.set_value<Exception>(props.lFineTune); break; default: fail_unknown_property_id(); } } template<> -void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXPITCHSHIFTER_NONE: break; - case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props.mPitchShifter); break; - case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.mPitchShifter.lCoarseTune); break; - case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.mPitchShifter.lFineTune); break; + case EAXPITCHSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXPITCHSHIFTER_COARSETUNE: defer<CoarseTuneValidator>(call, props.lCoarseTune); break; + case EAXPITCHSHIFTER_FINETUNE: defer<FineTuneValidator>(call, props.lFineTune); break; default: fail_unknown_property_id(); } } diff --git a/al/effects/reverb.cpp b/al/effects/reverb.cpp index 440d7b4e..b037443f 100644 --- a/al/effects/reverb.cpp +++ b/al/effects/reverb.cpp @@ -945,7 +945,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_DECAYTIMESCALE) != 0) { - props.flDecayTime = clamp( + props.flDecayTime = std::clamp( props.flDecayTime * scale, EAXREVERB_MINDECAYTIME, EAXREVERB_MAXDECAYTIME); @@ -954,7 +954,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSSCALE) != 0 && (props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.lReflections = clamp( + props.lReflections = std::clamp( props.lReflections - static_cast<long>(gain_to_level_mb(scale)), EAXREVERB_MINREFLECTIONS, EAXREVERB_MAXREFLECTIONS); @@ -962,7 +962,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.flReflectionsDelay = clamp( + props.flReflectionsDelay = std::clamp( props.flReflectionsDelay * scale, EAXREVERB_MINREFLECTIONSDELAY, EAXREVERB_MAXREFLECTIONSDELAY); @@ -972,7 +972,7 @@ struct EnvironmentSizeDeferrer2 { { const auto log_scalar = ((props.dwFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - props.lReverb = clamp( + props.lReverb = std::clamp( props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), EAXREVERB_MINREVERB, EAXREVERB_MAXREVERB); @@ -980,7 +980,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBDELAYSCALE) != 0) { - props.flReverbDelay = clamp( + props.flReverbDelay = std::clamp( props.flReverbDelay * scale, EAXREVERB_MINREVERBDELAY, EAXREVERB_MAXREVERBDELAY); @@ -1015,7 +1015,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) { - props.flDecayTime = clamp( + props.flDecayTime = std::clamp( props.flDecayTime * scale, EAXREVERB_MINDECAYTIME, EAXREVERB_MAXDECAYTIME); @@ -1024,7 +1024,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0 && (props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.lReflections = clamp( + props.lReflections = std::clamp( props.lReflections - static_cast<long>(gain_to_level_mb(scale)), EAXREVERB_MINREFLECTIONS, EAXREVERB_MAXREFLECTIONS); @@ -1032,7 +1032,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.flReflectionsDelay = clamp( + props.flReflectionsDelay = std::clamp( props.flReflectionsDelay * scale, EAXREVERB_MINREFLECTIONSDELAY, EAXREVERB_MAXREFLECTIONSDELAY); @@ -1041,7 +1041,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) { const auto log_scalar = ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - props.lReverb = clamp( + props.lReverb = std::clamp( props.lReverb - static_cast<long>(std::log10(scale) * log_scalar), EAXREVERB_MINREVERB, EAXREVERB_MAXREVERB); @@ -1049,7 +1049,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) { - props.flReverbDelay = clamp( + props.flReverbDelay = std::clamp( props.flReverbDelay * scale, EAXREVERB_MINREVERBDELAY, EAXREVERB_MAXREVERBDELAY); @@ -1057,7 +1057,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) { - props.flEchoTime = clamp( + props.flEchoTime = std::clamp( props.flEchoTime * scale, EAXREVERB_MINECHOTIME, EAXREVERB_MAXECHOTIME); @@ -1065,7 +1065,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) { - props.flModulationTime = clamp( + props.flModulationTime = std::clamp( props.flModulationTime * scale, EAXREVERB_MINMODULATIONTIME, EAXREVERB_MAXMODULATIONTIME); @@ -1089,48 +1089,35 @@ struct EaxReverbCommitter::Exception : public EaxReverbEffectException void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept { assert(src.environment <= EAX1REVERB_MAXENVIRONMENT); - dst.mType = EaxEffectType::Reverb; - dst.mReverb = EAXREVERB_PRESETS[src.environment]; - dst.mReverb.flDecayTime = src.fDecayTime_sec; - dst.mReverb.flDecayHFRatio = src.fDamping; - dst.mReverb.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0); + 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); } void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept { assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT); - const auto& env = EAXREVERB_PRESETS[src.dwEnvironment]; - dst.mType = EaxEffectType::Reverb; - dst.mReverb.ulEnvironment = src.dwEnvironment; - dst.mReverb.flEnvironmentSize = src.flEnvironmentSize; - dst.mReverb.flEnvironmentDiffusion = src.flEnvironmentDiffusion; - dst.mReverb.lRoom = src.lRoom; - dst.mReverb.lRoomHF = src.lRoomHF; - dst.mReverb.lRoomLF = env.lRoomLF; - dst.mReverb.flDecayTime = src.flDecayTime; - dst.mReverb.flDecayHFRatio = src.flDecayHFRatio; - dst.mReverb.flDecayLFRatio = env.flDecayLFRatio; - dst.mReverb.lReflections = src.lReflections; - dst.mReverb.flReflectionsDelay = src.flReflectionsDelay; - dst.mReverb.vReflectionsPan = env.vReflectionsPan; - dst.mReverb.lReverb = src.lReverb; - dst.mReverb.flReverbDelay = src.flReverbDelay; - dst.mReverb.vReverbPan = env.vReverbPan; - dst.mReverb.flEchoTime = env.flEchoTime; - dst.mReverb.flEchoDepth = env.flEchoDepth; - dst.mReverb.flModulationTime = env.flModulationTime; - dst.mReverb.flModulationDepth = env.flModulationDepth; - dst.mReverb.flAirAbsorptionHF = src.flAirAbsorptionHF; - dst.mReverb.flHFReference = env.flHFReference; - dst.mReverb.flLFReference = env.flLFReference; - dst.mReverb.flRoomRolloffFactor = src.flRoomRolloffFactor; - dst.mReverb.ulFlags = src.dwFlags; + 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.mType = EaxEffectType::Reverb; - dst.mReverb = src; + dst = src; } bool EaxReverbCommitter::commit(const EAX_REVERBPROPERTIES &props) @@ -1156,41 +1143,41 @@ bool EaxReverbCommitter::commit(const EAXREVERBPROPERTIES &props) bool EaxReverbCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && memcmp(&props.mReverb, &mEaxProps.mReverb, sizeof(mEaxProps.mReverb)) == 0) + if(props == mEaxProps) return false; mEaxProps = props; - const auto size = props.mReverb.flEnvironmentSize; + 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 = props.mReverb.flEnvironmentDiffusion; - mAlProps.Reverb.Gain = level_mb_to_gain(static_cast<float>(props.mReverb.lRoom)); - mAlProps.Reverb.GainHF = level_mb_to_gain(static_cast<float>(props.mReverb.lRoomHF)); - mAlProps.Reverb.GainLF = level_mb_to_gain(static_cast<float>(props.mReverb.lRoomLF)); - mAlProps.Reverb.DecayTime = props.mReverb.flDecayTime; - mAlProps.Reverb.DecayHFRatio = props.mReverb.flDecayHFRatio; - mAlProps.Reverb.DecayLFRatio = mEaxProps.mReverb.flDecayLFRatio; - mAlProps.Reverb.ReflectionsGain = level_mb_to_gain(static_cast<float>(props.mReverb.lReflections)); - mAlProps.Reverb.ReflectionsDelay = props.mReverb.flReflectionsDelay; - mAlProps.Reverb.ReflectionsPan[0] = props.mReverb.vReflectionsPan.x; - mAlProps.Reverb.ReflectionsPan[1] = props.mReverb.vReflectionsPan.y; - mAlProps.Reverb.ReflectionsPan[2] = props.mReverb.vReflectionsPan.z; - mAlProps.Reverb.LateReverbGain = level_mb_to_gain(static_cast<float>(props.mReverb.lReverb)); - mAlProps.Reverb.LateReverbDelay = props.mReverb.flReverbDelay; - mAlProps.Reverb.LateReverbPan[0] = props.mReverb.vReverbPan.x; - mAlProps.Reverb.LateReverbPan[1] = props.mReverb.vReverbPan.y; - mAlProps.Reverb.LateReverbPan[2] = props.mReverb.vReverbPan.z; - mAlProps.Reverb.EchoTime = props.mReverb.flEchoTime; - mAlProps.Reverb.EchoDepth = props.mReverb.flEchoDepth; - mAlProps.Reverb.ModulationTime = props.mReverb.flModulationTime; - mAlProps.Reverb.ModulationDepth = props.mReverb.flModulationDepth; - mAlProps.Reverb.AirAbsorptionGainHF = level_mb_to_gain(props.mReverb.flAirAbsorptionHF); - mAlProps.Reverb.HFReference = props.mReverb.flHFReference; - mAlProps.Reverb.LFReference = props.mReverb.flLFReference; - mAlProps.Reverb.RoomRolloffFactor = props.mReverb.flRoomRolloffFactor; - mAlProps.Reverb.DecayHFLimit = ((props.mReverb.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0); + 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); return true; } @@ -1212,8 +1199,7 @@ void EaxReverbCommitter::SetDefaults(EAXREVERBPROPERTIES &props) void EaxReverbCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::Reverb; - SetDefaults(props.mReverb); + SetDefaults(props.emplace<EAXREVERBPROPERTIES>()); } @@ -1290,7 +1276,7 @@ void EaxReverbCommitter::Get(const EaxCall &call, const EAXREVERBPROPERTIES &pro void EaxReverbCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { - Get(call, props.mReverb); + Get(call, std::get<EAXREVERBPROPERTIES>(props)); } @@ -1493,7 +1479,7 @@ void EaxReverbCommitter::Set(const EaxCall &call, EAXREVERBPROPERTIES &props) void EaxReverbCommitter::Set(const EaxCall &call, EaxEffectProps &props) { - Set(call, props.mReverb); + Set(call, std::get<EAXREVERBPROPERTIES>(props)); } #endif // ALSOFT_EAX diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp index 21ea3680..f2551229 100644 --- a/al/effects/vmorpher.cpp +++ b/al/effects/vmorpher.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include <optional> #include <stdexcept> #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) +std::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) { #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \ return VMorpherPhenome::x @@ -57,7 +57,7 @@ al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) HANDLE_PHENOME(V); HANDLE_PHENOME(Z); } - return al::nullopt; + return std::nullopt; #undef HANDLE_PHENOME } ALenum EnumFromPhenome(VMorpherPhenome phenome) @@ -100,7 +100,7 @@ ALenum EnumFromPhenome(VMorpherPhenome phenome) #undef HANDLE_PHENOME } -al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) +std::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) { switch(value) { @@ -108,7 +108,7 @@ al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle; case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromWaveform(VMorpherWaveform type) { @@ -355,13 +355,7 @@ template<> template<> bool VocalMorpherCommitter::commit(const EaxEffectProps &props) { - if(props.mType == mEaxProps.mType - && mEaxProps.mVocalMorpher.ulPhonemeA == props.mVocalMorpher.ulPhonemeA - && mEaxProps.mVocalMorpher.lPhonemeACoarseTuning == props.mVocalMorpher.lPhonemeACoarseTuning - && mEaxProps.mVocalMorpher.ulPhonemeB == props.mVocalMorpher.ulPhonemeB - && mEaxProps.mVocalMorpher.lPhonemeBCoarseTuning == props.mVocalMorpher.lPhonemeBCoarseTuning - && mEaxProps.mVocalMorpher.ulWaveform == props.mVocalMorpher.ulWaveform - && mEaxProps.mVocalMorpher.flRate == props.mVocalMorpher.flRate) + if(props == mEaxProps) return false; mEaxProps = props; @@ -413,12 +407,13 @@ bool VocalMorpherCommitter::commit(const EaxEffectProps &props) return VMorpherWaveform::Sinusoid; }; - mAlProps.Vmorpher.PhonemeA = get_phoneme(props.mVocalMorpher.ulPhonemeA); - mAlProps.Vmorpher.PhonemeACoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeACoarseTuning); - mAlProps.Vmorpher.PhonemeB = get_phoneme(props.mVocalMorpher.ulPhonemeB); - mAlProps.Vmorpher.PhonemeBCoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeBCoarseTuning); - mAlProps.Vmorpher.Waveform = get_waveform(props.mVocalMorpher.ulWaveform); - mAlProps.Vmorpher.Rate = props.mVocalMorpher.flRate; + 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; return true; } @@ -426,49 +421,55 @@ bool VocalMorpherCommitter::commit(const EaxEffectProps &props) template<> void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props) { - props.mType = EaxEffectType::VocalMorpher; - props.mVocalMorpher.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA; - props.mVocalMorpher.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING; - props.mVocalMorpher.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB; - props.mVocalMorpher.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING; - props.mVocalMorpher.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM; - props.mVocalMorpher.flRate = EAXVOCALMORPHER_DEFAULTRATE; + static constexpr EAXVOCALMORPHERPROPERTIES defprops{[] + { + EAXVOCALMORPHERPROPERTIES ret{}; + ret.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA; + ret.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING; + ret.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB; + ret.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING; + ret.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM; + ret.flRate = EAXVOCALMORPHER_DEFAULTRATE; + return ret; + }()}; + props = defprops; } template<> -void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props_) { + auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXVOCALMORPHER_NONE: break; case EAXVOCALMORPHER_ALLPARAMETERS: - call.set_value<Exception>(props.mVocalMorpher); + call.set_value<Exception>(props); break; case EAXVOCALMORPHER_PHONEMEA: - call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA); + call.set_value<Exception>(props.ulPhonemeA); break; case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning); + call.set_value<Exception>(props.lPhonemeACoarseTuning); break; case EAXVOCALMORPHER_PHONEMEB: - call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB); + call.set_value<Exception>(props.ulPhonemeB); break; case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning); + call.set_value<Exception>(props.lPhonemeBCoarseTuning); break; case EAXVOCALMORPHER_WAVEFORM: - call.set_value<Exception>(props.mVocalMorpher.ulWaveform); + call.set_value<Exception>(props.ulWaveform); break; case EAXVOCALMORPHER_RATE: - call.set_value<Exception>(props.mVocalMorpher.flRate); + call.set_value<Exception>(props.flRate); break; default: @@ -477,39 +478,40 @@ void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props } template<> -void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props) +void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props_) { + auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_); switch(call.get_property_id()) { case EAXVOCALMORPHER_NONE: break; case EAXVOCALMORPHER_ALLPARAMETERS: - defer<AllValidator>(call, props.mVocalMorpher); + defer<AllValidator>(call, props); break; case EAXVOCALMORPHER_PHONEMEA: - defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA); + defer<PhonemeAValidator>(call, props.ulPhonemeA); break; case EAXVOCALMORPHER_PHONEMEACOARSETUNING: - defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning); + defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break; case EAXVOCALMORPHER_PHONEMEB: - defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB); + defer<PhonemeBValidator>(call, props.ulPhonemeB); break; case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: - defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning); + defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break; case EAXVOCALMORPHER_WAVEFORM: - defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform); + defer<WaveformValidator>(call, props.ulWaveform); break; case EAXVOCALMORPHER_RATE: - defer<RateValidator>(call, props.mVocalMorpher.flRate); + defer<RateValidator>(call, props.flRate); break; default: diff --git a/al/error.cpp b/al/error.cpp index afa7019a..c2359477 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -29,25 +29,32 @@ #include <csignal> #include <cstdarg> #include <cstdio> +#include <cstdlib> #include <cstring> +#include <limits> #include <mutex> +#include <vector> #include "AL/al.h" #include "AL/alc.h" +#include "al/debug.h" +#include "alc/alconfig.h" #include "alc/context.h" #include "almalloc.h" +#include "alstring.h" #include "core/except.h" #include "core/logging.h" +#include "direct_defs.h" #include "opthelpers.h" -#include "vector.h" +#include "strutils.h" bool TrapALError{false}; void ALCcontext::setError(ALenum errorCode, const char *msg, ...) { - auto message = al::vector<char>(256); + auto message = std::vector<char>(256); va_list args, args2; va_start(args, msg); @@ -61,8 +68,13 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...) va_end(args2); va_end(args); - if(msglen >= 0) msg = message.data(); - else msg = "<internal error constructing message>"; + if(msglen >= 0) + msg = message.data(); + else + { + msg = "<internal error constructing message>"; + msglen = static_cast<int>(strlen(msg)); + } WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", decltype(std::declval<void*>()){this}, errorCode, msg); @@ -79,15 +91,36 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...) ALenum curerr{AL_NO_ERROR}; mLastError.compare_exchange_strong(curerr, errorCode); + + debugMessage(DebugSource::API, DebugType::Error, 0, DebugSeverity::High, + {msg, static_cast<uint>(msglen)}); } -AL_API ALenum AL_APIENTRY alGetError(void) -START_API_FUNC +/* Special-case alGetError since it (potentially) raises a debug signal and + * returns a non-default value for a null context. + */ +AL_API ALenum AL_APIENTRY alGetError(void) noexcept { - ContextRef context{GetContextRef()}; + auto context = GetContextRef(); if(!context) UNLIKELY { - static constexpr ALenum deferror{AL_INVALID_OPERATION}; + 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) { @@ -100,7 +133,10 @@ START_API_FUNC } return deferror; } + return alGetErrorDirect(context.get()); +} +FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept +{ return context->mLastError.exchange(AL_NO_ERROR); } -END_API_FUNC diff --git a/al/event.cpp b/al/event.cpp index 1bc39d1e..8b76ceff 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -10,14 +10,15 @@ #include <memory> #include <mutex> #include <new> +#include <optional> #include <string> +#include <string_view> #include <thread> #include <utility> #include "AL/al.h" #include "AL/alc.h" -#include "albyte.h" #include "alc/context.h" #include "alc/effects/base.h" #include "alc/inprogext.h" @@ -26,12 +27,21 @@ #include "core/except.h" #include "core/logging.h" #include "core/voice_change.h" +#include "debug.h" +#include "direct_defs.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" -static int EventThread(ALCcontext *context) +namespace { + +template<typename... Ts> +struct overloaded : Ts... { using Ts::operator()...; }; + +template<typename... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + +int EventThread(ALCcontext *context) { RingBuffer *ring{context->mAsyncEvents.get()}; bool quitnow{false}; @@ -46,74 +56,101 @@ static int EventThread(ALCcontext *context) std::lock_guard<std::mutex> _{context->mEventCbLock}; do { - auto *evt_ptr = reinterpret_cast<AsyncEvent*>(evt_data.buf); + auto *evt_ptr = std::launder(reinterpret_cast<AsyncEvent*>(evt_data.buf)); evt_data.buf += sizeof(AsyncEvent); evt_data.len -= 1; - AsyncEvent evt{*evt_ptr}; - al::destroy_at(evt_ptr); + AsyncEvent event{std::move(*evt_ptr)}; + std::destroy_at(evt_ptr); ring->readAdvance(1); - quitnow = evt.EnumType == AsyncEvent::KillThread; + quitnow = std::holds_alternative<AsyncKillThread>(event); if(quitnow) UNLIKELY break; - if(evt.EnumType == AsyncEvent::ReleaseEffectState) - { - al::intrusive_ptr<EffectState>{evt.u.mEffectState}; - continue; - } - auto enabledevts = context->mEnabledEvts.load(std::memory_order_acquire); - if(!context->mEventCb || !enabledevts.test(evt.EnumType)) - continue; - - if(evt.EnumType == AsyncEvent::SourceStateChange) + auto proc_killthread = [](AsyncKillThread&) { }; + auto proc_release = [](AsyncEffectReleaseEvent &evt) + { + al::intrusive_ptr<EffectState>{evt.mEffectState}; + }; + auto proc_srcstate = [context,enabledevts](AsyncSourceStateEvent &evt) { + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::SourceState))) + return; + ALuint state{}; - std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; + std::string msg{"Source ID " + std::to_string(evt.mId)}; msg += " state has changed to "; - switch(evt.u.srcstate.state) + switch(evt.mState) { - case AsyncEvent::SrcState::Reset: + case AsyncSrcState::Reset: msg += "AL_INITIAL"; state = AL_INITIAL; break; - case AsyncEvent::SrcState::Stop: + case AsyncSrcState::Stop: msg += "AL_STOPPED"; state = AL_STOPPED; break; - case AsyncEvent::SrcState::Play: + case AsyncSrcState::Play: msg += "AL_PLAYING"; state = AL_PLAYING; break; - case AsyncEvent::SrcState::Pause: + case AsyncSrcState::Pause: msg += "AL_PAUSED"; state = AL_PAUSED; break; } - context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - state, static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::BufferCompleted) + context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.mId, state, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_buffercomp = [context,enabledevts](AsyncBufferCompleteEvent &evt) { - std::string msg{std::to_string(evt.u.bufcomp.count)}; - if(evt.u.bufcomp.count == 1) msg += " buffer completed"; + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted))) + return; + + std::string msg{std::to_string(evt.mCount)}; + if(evt.mCount == 1) msg += " buffer completed"; else msg += " buffers completed"; - context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, - evt.u.bufcomp.count, static_cast<ALsizei>(msg.length()), msg.c_str(), - context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::Disconnected) + context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.mId, evt.mCount, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt) { - context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, - static_cast<ALsizei>(strlen(evt.u.disconnect.msg)), evt.u.disconnect.msg, - context->mEventParam); - } + const std::string_view message{evt.msg}; + + context->debugMessage(DebugSource::System, DebugType::Error, 0, + DebugSeverity::High, message); + + if(context->mEventCb + && enabledevts.test(al::to_underlying(AsyncEnableBits::Disconnected))) + context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, + static_cast<ALsizei>(message.length()), message.data(), + context->mEventParam); + }; + + std::visit(overloaded{proc_srcstate, proc_buffercomp, proc_release, proc_disconnect, + proc_killthread}, event); } while(evt_data.len != 0); } return 0; } +constexpr std::optional<AsyncEnableBits> GetEventType(ALenum etype) noexcept +{ + switch(etype) + { + case AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT: return AsyncEnableBits::BufferCompleted; + case AL_EVENT_TYPE_DISCONNECTED_SOFT: return AsyncEnableBits::Disconnected; + case AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT: return AsyncEnableBits::SourceState; + } + return std::nullopt; +} + +} // namespace + + void StartEventThrd(ALCcontext *ctx) { try { @@ -138,7 +175,7 @@ void StopEventThrd(ALCcontext *ctx) evt_data = ring->getWriteVector().first; } while(evt_data.len == 0); } - al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread); + std::ignore = InitAsyncEvent<AsyncKillThread>(evt_data.buf); ring->writeAdvance(1); ctx->mEventSem.post(); @@ -146,34 +183,22 @@ void StopEventThrd(ALCcontext *ctx) ctx->mEventThread.join(); } -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alEventControl,SOFT, ALsizei, const ALenum*, ALboolean) +FORCE_ALIGN void AL_APIENTRY alEventControlDirectSOFT(ALCcontext *context, ALsizei count, + const ALenum *types, ALboolean enable) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(count < 0) context->setError(AL_INVALID_VALUE, "Controlling %d events", count); if(count <= 0) return; if(!types) return context->setError(AL_INVALID_VALUE, "NULL pointer"); ContextBase::AsyncEventBitset flags{}; - const ALenum *types_end = types+count; - auto bad_type = std::find_if_not(types, types_end, - [&flags](ALenum type) noexcept -> bool - { - if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) - flags.set(AsyncEvent::BufferCompleted); - else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) - flags.set(AsyncEvent::SourceStateChange); - else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) - flags.set(AsyncEvent::Disconnected); - else - return false; - return true; - } - ); - if(bad_type != types_end) - return context->setError(AL_INVALID_ENUM, "Invalid event type 0x%04x", *bad_type); + for(ALenum evttype : al::span{types, static_cast<uint>(count)}) + { + auto etype = GetEventType(evttype); + if(!etype) + return context->setError(AL_INVALID_ENUM, "Invalid event type 0x%04x", evttype); + flags.set(al::to_underlying(*etype)); + } if(enable) { @@ -199,17 +224,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mEventCbLock}; } } -END_API_FUNC -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) -START_API_FUNC +AL_API DECL_FUNCEXT2(void, alEventCallback,SOFT, ALEVENTPROCSOFT, void*) +FORCE_ALIGN void AL_APIENTRY alEventCallbackDirectSOFT(ALCcontext *context, + ALEVENTPROCSOFT callback, void *userParam) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - std::lock_guard<std::mutex> _{context->mPropLock}; - std::lock_guard<std::mutex> __{context->mEventCbLock}; + std::lock_guard<std::mutex> _{context->mEventCbLock}; context->mEventCb = callback; context->mEventParam = userParam; } -END_API_FUNC diff --git a/al/extension.cpp b/al/extension.cpp index 3ead0af8..6d1ac327 100644 --- a/al/extension.cpp +++ b/al/extension.cpp @@ -30,15 +30,13 @@ #include "alc/context.h" #include "alstring.h" #include "core/except.h" +#include "direct_defs.h" #include "opthelpers.h" -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsExtensionPresent, const ALchar*) +FORCE_ALIGN ALboolean AL_APIENTRY alIsExtensionPresentDirect(ALCcontext *context, const ALchar *extName) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return AL_FALSE; - if(!extName) UNLIKELY { context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -46,37 +44,36 @@ START_API_FUNC } size_t len{strlen(extName)}; - const char *ptr{context->mExtensionList}; - while(ptr && *ptr) + for(std::string_view ext : context->mExtensions) { - if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) + if(len == ext.length() && al::strncasecmp(ext.data(), extName, len) == 0) return AL_TRUE; - - if((ptr=strchr(ptr, ' ')) != nullptr) - { - do { - ++ptr; - } while(isspace(*ptr)); - } } return AL_FALSE; } -END_API_FUNC -AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) -START_API_FUNC +AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) noexcept +{ + if(!funcName) return nullptr; + return alcGetProcAddress(nullptr, funcName); +} + +FORCE_ALIGN ALvoid* AL_APIENTRY alGetProcAddressDirect(ALCcontext*, const ALchar *funcName) noexcept { if(!funcName) return nullptr; return alcGetProcAddress(nullptr, funcName); } -END_API_FUNC -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) -START_API_FUNC +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) noexcept +{ + if(!enumName) return static_cast<ALenum>(0); + return alcGetEnumValue(nullptr, enumName); +} + +FORCE_ALIGN ALenum AL_APIENTRY alGetEnumValueDirect(ALCcontext*, const ALchar *enumName) noexcept { if(!enumName) return static_cast<ALenum>(0); return alcGetEnumValue(nullptr, enumName); } -END_API_FUNC diff --git a/al/filter.cpp b/al/filter.cpp index 73efa01f..f0a078b7 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -31,6 +31,7 @@ #include <mutex> #include <new> #include <numeric> +#include <vector> #include "AL/al.h" #include "AL/alc.h" @@ -42,8 +43,8 @@ #include "almalloc.h" #include "alnumeric.h" #include "core/except.h" +#include "direct_defs.h" #include "opthelpers.h" -#include "vector.h" namespace { @@ -73,20 +74,157 @@ filter_exception::filter_exception(ALenum code, const char* msg, ...) : mErrorCo filter_exception::~filter_exception() = default; -#define DEFINE_ALFILTER_VTABLE(T) \ -const ALfilter::Vtable T##_vtable = { \ - T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ +void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->mTypeVariant.emplace<LowpassFilterTable>(); + } + else if(type == AL_FILTER_HIGHPASS) + { + filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->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->GainLF = AL_BANDPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->mTypeVariant.emplace<BandpassFilterTable>(); + } + else + { + filter->Gain = 1.0f; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->mTypeVariant.emplace<NullFilterTable>(); + } + filter->type = type; } -void ALlowpass_setParami(ALfilter*, ALenum param, int) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; } -void ALlowpass_setParamiv(ALfilter*, ALenum param, const int*) +bool EnsureFilters(ALCdevice *device, size_t needed) +{ + size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), 0_uz, + [](size_t cur, const FilterSubList &sublist) noexcept -> size_t + { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; + + while(needed > count) + { + if(device->FilterList.size() >= 1<<25) UNLIKELY + return false; + + device->FilterList.emplace_back(); + auto sublist = device->FilterList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64)); + if(!sublist->Filters) UNLIKELY + { + device->FilterList.pop_back(); + return false; + } + count += 64; + } + return true; +} + + +ALfilter *AllocFilter(ALCdevice *device) +{ + auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), + [](const FilterSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; }); + auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist)); + auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); + ASSUME(slidx < 64); + + ALfilter *filter{al::construct_at(sublist->Filters + slidx)}; + InitFilterParams(filter, AL_FILTER_NULL); + + /* Add 1 to avoid filter ID 0. */ + filter->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return filter; +} + +void FreeFilter(ALCdevice *device, ALfilter *filter) { - throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", - param}; + device->mFilterNames.erase(filter->id); + + const ALuint id{filter->id - 1}; + const size_t lidx{id >> 6}; + const ALuint slidx{id & 0x3f}; + + std::destroy_at(filter); + + device->FilterList[lidx].FreeMask |= 1_u64 << slidx; } -void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val) + + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; + + if(lidx >= device->FilterList.size()) UNLIKELY + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY + return nullptr; + return sublist.Filters + slidx; +} + +} // namespace + +/* Null filter parameter handlers */ +template<> +void FilterTable<NullFilterTable>::setParami(ALfilter*, ALenum param, int) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::setParamiv(ALfilter*, ALenum param, const int*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::setParamf(ALfilter*, ALenum param, float) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::setParamfv(ALfilter*, ALenum param, const float*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::getParami(const ALfilter*, ALenum param, int*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::getParamiv(const ALfilter*, ALenum param, int*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::getParamf(const ALfilter*, ALenum param, float*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } +template<> +void FilterTable<NullFilterTable>::getParamfv(const ALfilter*, ALenum param, float*) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } + +/* Lowpass parameter handlers */ +template<> +void FilterTable<LowpassFilterTable>::setParami(ALfilter*, ALenum param, int) +{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; } +template<> +void FilterTable<LowpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values) +{ setParami(filter, param, values[0]); } +template<> +void FilterTable<LowpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val) { switch(param) { @@ -106,17 +244,17 @@ void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val) throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param}; } } -void ALlowpass_setParamfv(ALfilter *filter, ALenum param, const float *vals) -{ ALlowpass_setParamf(filter, param, vals[0]); } - -void ALlowpass_getParami(const ALfilter*, ALenum param, int*) +template<> +void FilterTable<LowpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals) +{ setParamf(filter, param, vals[0]); } +template<> +void FilterTable<LowpassFilterTable>::getParami(const ALfilter*, ALenum param, int*) { throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; } -void ALlowpass_getParamiv(const ALfilter*, ALenum param, int*) -{ - throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", - param}; -} -void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val) +template<> +void FilterTable<LowpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values) +{ getParami(filter, param, values); } +template<> +void FilterTable<LowpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val) { switch(param) { @@ -132,20 +270,19 @@ void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val) throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param}; } } -void ALlowpass_getParamfv(const ALfilter *filter, ALenum param, float *vals) -{ ALlowpass_getParamf(filter, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALlowpass); - +template<> +void FilterTable<LowpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals) +{ getParamf(filter, param, vals); } -void ALhighpass_setParami(ALfilter*, ALenum param, int) +/* Highpass parameter handlers */ +template<> +void FilterTable<HighpassFilterTable>::setParami(ALfilter*, ALenum param, int) { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; } -void ALhighpass_setParamiv(ALfilter*, ALenum param, const int*) -{ - throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", - param}; -} -void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val) +template<> +void FilterTable<HighpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values) +{ setParami(filter, param, values[0]); } +template<> +void FilterTable<HighpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val) { switch(param) { @@ -165,17 +302,17 @@ void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val) throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param}; } } -void ALhighpass_setParamfv(ALfilter *filter, ALenum param, const float *vals) -{ ALhighpass_setParamf(filter, param, vals[0]); } - -void ALhighpass_getParami(const ALfilter*, ALenum param, int*) +template<> +void FilterTable<HighpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals) +{ setParamf(filter, param, vals[0]); } +template<> +void FilterTable<HighpassFilterTable>::getParami(const ALfilter*, ALenum param, int*) { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; } -void ALhighpass_getParamiv(const ALfilter*, ALenum param, int*) -{ - throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", - param}; -} -void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val) +template<> +void FilterTable<HighpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values) +{ getParami(filter, param, values); } +template<> +void FilterTable<HighpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val) { switch(param) { @@ -191,20 +328,19 @@ void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val) throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param}; } } -void ALhighpass_getParamfv(const ALfilter *filter, ALenum param, float *vals) -{ ALhighpass_getParamf(filter, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALhighpass); - +template<> +void FilterTable<HighpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals) +{ getParamf(filter, param, vals); } -void ALbandpass_setParami(ALfilter*, ALenum param, int) +/* Bandpass parameter handlers */ +template<> +void FilterTable<BandpassFilterTable>::setParami(ALfilter*, ALenum param, int) { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; } -void ALbandpass_setParamiv(ALfilter*, ALenum param, const int*) -{ - throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", - param}; -} -void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val) +template<> +void FilterTable<BandpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values) +{ setParami(filter, param, values[0]); } +template<> +void FilterTable<BandpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val) { switch(param) { @@ -230,17 +366,17 @@ void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val) throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param}; } } -void ALbandpass_setParamfv(ALfilter *filter, ALenum param, const float *vals) -{ ALbandpass_setParamf(filter, param, vals[0]); } - -void ALbandpass_getParami(const ALfilter*, ALenum param, int*) +template<> +void FilterTable<BandpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals) +{ setParamf(filter, param, vals[0]); } +template<> +void FilterTable<BandpassFilterTable>::getParami(const ALfilter*, ALenum param, int*) { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; } -void ALbandpass_getParamiv(const ALfilter*, ALenum param, int*) -{ - throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", - param}; -} -void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val) +template<> +void FilterTable<BandpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values) +{ getParami(filter, param, values); } +template<> +void FilterTable<BandpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val) { switch(param) { @@ -260,153 +396,14 @@ void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val) throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param}; } } -void ALbandpass_getParamfv(const ALfilter *filter, ALenum param, float *vals) -{ ALbandpass_getParamf(filter, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALbandpass); - - -void ALnullfilter_setParami(ALfilter*, ALenum param, int) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_setParamiv(ALfilter*, ALenum param, const int*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_setParamf(ALfilter*, ALenum param, float) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_setParamfv(ALfilter*, ALenum param, const float*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } - -void ALnullfilter_getParami(const ALfilter*, ALenum param, int*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_getParamiv(const ALfilter*, ALenum param, int*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_getParamf(const ALfilter*, ALenum param, float*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } -void ALnullfilter_getParamfv(const ALfilter*, ALenum param, float*) -{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; } - -DEFINE_ALFILTER_VTABLE(ALnullfilter); - - -void InitFilterParams(ALfilter *filter, ALenum type) -{ - if(type == AL_FILTER_LOWPASS) - { - filter->Gain = AL_LOWPASS_DEFAULT_GAIN; - filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALlowpass_vtable; - } - else if(type == AL_FILTER_HIGHPASS) - { - filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALhighpass_vtable; - } - else if(type == AL_FILTER_BANDPASS) - { - filter->Gain = AL_BANDPASS_DEFAULT_GAIN; - filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALbandpass_vtable; - } - else - { - filter->Gain = 1.0f; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALnullfilter_vtable; - } - filter->type = type; -} - -bool EnsureFilters(ALCdevice *device, size_t needed) -{ - size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0}, - [](size_t cur, const FilterSubList &sublist) noexcept -> size_t - { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; - - while(needed > count) - { - if(device->FilterList.size() >= 1<<25) UNLIKELY - return false; - - device->FilterList.emplace_back(); - auto sublist = device->FilterList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64)); - if(!sublist->Filters) UNLIKELY - { - device->FilterList.pop_back(); - return false; - } - count += 64; - } - return true; -} - - -ALfilter *AllocFilter(ALCdevice *device) -{ - auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), - [](const FilterSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; }); - auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist)); - auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask)); - ASSUME(slidx < 64); - - ALfilter *filter{al::construct_at(sublist->Filters + slidx)}; - InitFilterParams(filter, AL_FILTER_NULL); - - /* Add 1 to avoid filter ID 0. */ - filter->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return filter; -} - -void FreeFilter(ALCdevice *device, ALfilter *filter) -{ - const ALuint id{filter->id - 1}; - const size_t lidx{id >> 6}; - const ALuint slidx{id & 0x3f}; - - al::destroy_at(filter); - - device->FilterList[lidx].FreeMask |= 1_u64 << slidx; -} - - -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - const size_t lidx{(id-1) >> 6}; - const ALuint slidx{(id-1) & 0x3f}; - - if(lidx >= device->FilterList.size()) UNLIKELY - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY - return nullptr; - return sublist.Filters + slidx; -} +template<> +void FilterTable<BandpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals) +{ getParamf(filter, param, vals); } -} // namespace -AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) -START_API_FUNC +AL_API DECL_FUNC2(void, alGenFilters, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alGenFiltersDirect(ALCcontext *context, ALsizei n, ALuint *filters) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Generating %d filters", n); if(n <= 0) UNLIKELY return; @@ -430,7 +427,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector<ALuint> ids; + std::vector<ALuint> ids; ids.reserve(static_cast<ALuint>(n)); do { ALfilter *filter{AllocFilter(device)}; @@ -439,14 +436,11 @@ START_API_FUNC std::copy(ids.begin(), ids.end(), filters); } } -END_API_FUNC -AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) -START_API_FUNC +AL_API DECL_FUNC2(void, alDeleteFilters, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alDeleteFiltersDirect(ALCcontext *context, ALsizei n, + const ALuint *filters) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Deleting %d filters", n); if(n <= 0) UNLIKELY return; @@ -474,71 +468,58 @@ START_API_FUNC }; std::for_each(filters, filters_end, delete_filter); } -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsFilter, ALuint) +FORCE_ALIGN ALboolean AL_APIENTRY alIsFilterDirect(ALCcontext *context, ALuint filter) noexcept { - ContextRef context{GetContextRef()}; - if(context) LIKELY - { - ALCdevice *device{context->mALDevice.get()}; - std::lock_guard<std::mutex> _{device->FilterLock}; - if(!filter || LookupFilter(device, filter)) - return AL_TRUE; - } + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->FilterLock}; + if(!filter || LookupFilter(device, filter)) + return AL_TRUE; return AL_FALSE; } -END_API_FUNC -AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) -START_API_FUNC +AL_API DECL_FUNC3(void, alFilteri, ALuint, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alFilteriDirect(ALCcontext *context, ALuint filter, ALenum param, + ALint value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(!alfilt) UNLIKELY context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); - else + else if(param == AL_FILTER_TYPE) { - if(param == AL_FILTER_TYPE) - { - if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS - || value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) - InitFilterParams(alfilt, value); - else - context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); - } - else try - { - /* Call the appropriate handler */ - alfilt->setParami(param, value); - } - catch(filter_exception &e) { - context->setError(e.errorCode(), "%s", e.what()); - } + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS + || value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) + InitFilterParams(alfilt, value); + else + context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + } + else try + { + /* Call the appropriate handler */ + std::visit([alfilt,param,value](auto&& thunk){thunk.setParami(alfilt, param, value);}, + alfilt->mTypeVariant); + } + catch(filter_exception &e) { + context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alFilteriv, ALuint, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alFilterivDirect(ALCcontext *context, ALuint filter, ALenum param, + const ALint *values) noexcept { switch(param) { case AL_FILTER_TYPE: - alFilteri(filter, param, values[0]); + alFilteriDirect(context, filter, param, values[0]); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -548,20 +529,18 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->setParamiv(param, values); + std::visit([alfilt,param,values](auto&& thunk){thunk.setParamiv(alfilt, param, values);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) -START_API_FUNC +AL_API DECL_FUNC3(void, alFilterf, ALuint, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alFilterfDirect(ALCcontext *context, ALuint filter, ALenum param, + ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -571,20 +550,18 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->setParamf(param, value); + std::visit([alfilt,param,value](auto&& thunk){thunk.setParamf(alfilt, param, value);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alFilterfv, ALuint, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param, + const ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -594,55 +571,48 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->setParamfv(param, values); + std::visit([alfilt,param,values](auto&& thunk){thunk.setParamfv(alfilt, param, values);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetFilteri, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetFilteriDirect(ALCcontext *context, ALuint filter, ALenum param, + ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; const ALfilter *alfilt{LookupFilter(device, filter)}; if(!alfilt) UNLIKELY context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); - else + else if(param == AL_FILTER_TYPE) + *value = alfilt->type; + else try { - if(param == AL_FILTER_TYPE) - *value = alfilt->type; - else try - { - /* Call the appropriate handler */ - alfilt->getParami(param, value); - } - catch(filter_exception &e) { - context->setError(e.errorCode(), "%s", e.what()); - } + /* Call the appropriate handler */ + std::visit([alfilt,param,value](auto&& thunk){thunk.getParami(alfilt, param, value);}, + alfilt->mTypeVariant); + } + catch(filter_exception &e) { + context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetFilteriv, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetFilterivDirect(ALCcontext *context, ALuint filter, ALenum param, + ALint *values) noexcept { switch(param) { case AL_FILTER_TYPE: - alGetFilteri(filter, param, values); + alGetFilteriDirect(context, filter, param, values); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -652,20 +622,18 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->getParamiv(param, values); + std::visit([alfilt,param,values](auto&& thunk){thunk.getParamiv(alfilt, param, values);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetFilterf, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetFilterfDirect(ALCcontext *context, ALuint filter, ALenum param, + ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -675,20 +643,18 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->getParamf(param, value); + std::visit([alfilt,param,value](auto&& thunk){thunk.getParamf(alfilt, param, value);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetFilterfv, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param, + ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALCdevice *device{context->mALDevice.get()}; std::lock_guard<std::mutex> _{device->FilterLock}; @@ -698,22 +664,38 @@ START_API_FUNC else try { /* Call the appropriate handler */ - alfilt->getParamfv(param, values); + std::visit([alfilt,param,values](auto&& thunk){thunk.getParamfv(alfilt, param, values);}, + alfilt->mTypeVariant); } catch(filter_exception &e) { context->setError(e.errorCode(), "%s", e.what()); } } -END_API_FUNC + + +void ALfilter::SetName(ALCcontext *context, ALuint id, std::string_view name) +{ + ALCdevice *device{context->mALDevice.get()}; + std::lock_guard<std::mutex> _{device->FilterLock}; + + auto filter = LookupFilter(device, id); + if(!filter) UNLIKELY + return context->setError(AL_INVALID_NAME, "Invalid filter ID %u", id); + + device->mFilterNames.insert_or_assign(id, name); +} FilterSubList::~FilterSubList() { + if(!Filters) + return; + uint64_t usemask{~FreeMask}; while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Filters+idx); + std::destroy_at(Filters+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/al/filter.h b/al/filter.h index 65a9e30f..505900d4 100644 --- a/al/filter.h +++ b/al/filter.h @@ -1,6 +1,8 @@ #ifndef AL_FILTER_H #define AL_FILTER_H +#include <string_view> +#include <variant> #include "AL/al.h" #include "AL/alc.h" @@ -12,6 +14,25 @@ #define HIGHPASSFREQREF 250.0f +template<typename T> +struct FilterTable { + static void setParami(struct ALfilter*, ALenum, int); + static void setParamiv(struct ALfilter*, ALenum, const int*); + static void setParamf(struct ALfilter*, ALenum, float); + static void setParamfv(struct ALfilter*, ALenum, const float*); + + static void getParami(const struct ALfilter*, ALenum, int*); + static void getParamiv(const struct ALfilter*, ALenum, int*); + static void getParamf(const struct ALfilter*, ALenum, float*); + static void getParamfv(const struct ALfilter*, ALenum, float*); +}; + +struct NullFilterTable : public FilterTable<NullFilterTable> { }; +struct LowpassFilterTable : public FilterTable<LowpassFilterTable> { }; +struct HighpassFilterTable : public FilterTable<HighpassFilterTable> { }; +struct BandpassFilterTable : public FilterTable<BandpassFilterTable> { }; + + struct ALfilter { ALenum type{AL_FILTER_NULL}; @@ -21,30 +42,14 @@ struct ALfilter { float GainLF{1.0f}; float LFReference{HIGHPASSFREQREF}; - struct Vtable { - void (*const setParami )(ALfilter *filter, ALenum param, int val); - void (*const setParamiv)(ALfilter *filter, ALenum param, const int *vals); - void (*const setParamf )(ALfilter *filter, ALenum param, float val); - void (*const setParamfv)(ALfilter *filter, ALenum param, const float *vals); - - void (*const getParami )(const ALfilter *filter, ALenum param, int *val); - void (*const getParamiv)(const ALfilter *filter, ALenum param, int *vals); - void (*const getParamf )(const ALfilter *filter, ALenum param, float *val); - void (*const getParamfv)(const ALfilter *filter, ALenum param, float *vals); - }; - const Vtable *vtab{nullptr}; + using TableTypes = std::variant<NullFilterTable,LowpassFilterTable,HighpassFilterTable, + BandpassFilterTable>; + TableTypes mTypeVariant; /* Self ID */ ALuint id{0}; - void setParami(ALenum param, int value) { vtab->setParami(this, param, value); } - void setParamiv(ALenum param, const int *values) { vtab->setParamiv(this, param, values); } - void setParamf(ALenum param, float value) { vtab->setParamf(this, param, value); } - void setParamfv(ALenum param, const float *values) { vtab->setParamfv(this, param, values); } - void getParami(ALenum param, int *value) const { vtab->getParami(this, param, value); } - void getParamiv(ALenum param, int *values) const { vtab->getParamiv(this, param, values); } - void getParamf(ALenum param, float *value) const { vtab->getParamf(this, param, value); } - void getParamfv(ALenum param, float *values) const { vtab->getParamfv(this, param, values); } + static void SetName(ALCcontext *context, ALuint id, std::string_view name); DISABLE_ALLOC() }; diff --git a/al/listener.cpp b/al/listener.cpp index 06d7c370..ea2ebb3f 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -33,6 +33,7 @@ #include "almalloc.h" #include "atomic.h" #include "core/except.h" +#include "direct_defs.h" #include "opthelpers.h" @@ -68,12 +69,9 @@ inline void CommitAndUpdateProps(ALCcontext *context) } // namespace -AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value) -START_API_FUNC +AL_API DECL_FUNC2(void, alListenerf, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alListenerfDirect(ALCcontext *context, ALenum param, ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; switch(param) @@ -82,28 +80,25 @@ START_API_FUNC if(!(value >= 0.0f && std::isfinite(value))) return context->setError(AL_INVALID_VALUE, "Listener gain out of range"); listener.Gain = value; - UpdateProps(context.get()); + UpdateProps(context); break; case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) return context->setError(AL_INVALID_VALUE, "Listener meters per unit out of range"); listener.mMetersPerUnit = value; - UpdateProps(context.get()); + UpdateProps(context); break; default: context->setError(AL_INVALID_ENUM, "Invalid listener float property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC +AL_API DECL_FUNC4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat) +FORCE_ALIGN void AL_APIENTRY alListener3fDirect(ALCcontext *context, ALenum param, ALfloat value1, + ALfloat value2, ALfloat value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; switch(param) @@ -114,7 +109,7 @@ START_API_FUNC listener.Position[0] = value1; listener.Position[1] = value2; listener.Position[2] = value3; - CommitAndUpdateProps(context.get()); + CommitAndUpdateProps(context); break; case AL_VELOCITY: @@ -123,40 +118,34 @@ START_API_FUNC listener.Velocity[0] = value1; listener.Velocity[1] = value2; listener.Velocity[2] = value3; - CommitAndUpdateProps(context.get()); + CommitAndUpdateProps(context); break; default: context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alListenerfv, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alListenerfvDirect(ALCcontext *context, ALenum param, + const ALfloat *values) noexcept { - if(values) + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + switch(param) { - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alListenerf(param, values[0]); - return; + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerfDirect(context, param, values[0]); + return; - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, values[0], values[1], values[2]); - return; - } + case AL_POSITION: + case AL_VELOCITY: + alListener3fDirect(context, param, values[0], values[1], values[2]); + return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - if(!values) UNLIKELY - return context->setError(AL_INVALID_VALUE, "NULL pointer"); - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; switch(param) @@ -172,22 +161,18 @@ START_API_FUNC listener.OrientUp[0] = values[3]; listener.OrientUp[1] = values[4]; listener.OrientUp[2] = values[5]; - CommitAndUpdateProps(context.get()); + CommitAndUpdateProps(context); break; default: context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) -START_API_FUNC +AL_API DECL_FUNC2(void, alListeneri, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alListeneriDirect(ALCcontext *context, ALenum param, ALint /*value*/) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; switch(param) { @@ -195,23 +180,20 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener integer property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC +AL_API DECL_FUNC4(void, alListener3i, ALenum, ALint, ALint, ALint) +FORCE_ALIGN void AL_APIENTRY alListener3iDirect(ALCcontext *context, ALenum param, ALint value1, + ALint value2, ALint value3) noexcept { switch(param) { case AL_POSITION: case AL_VELOCITY: - alListener3f(param, static_cast<ALfloat>(value1), static_cast<ALfloat>(value2), - static_cast<ALfloat>(value3)); + alListener3fDirect(context, param, static_cast<ALfloat>(value1), + static_cast<ALfloat>(value2), static_cast<ALfloat>(value3)); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; switch(param) { @@ -219,55 +201,48 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alListeneriv, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alListenerivDirect(ALCcontext *context, ALenum param, + const ALint *values) noexcept { - if(values) + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + switch(param) { - ALfloat fvals[6]; - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, static_cast<ALfloat>(values[0]), static_cast<ALfloat>(values[1]), - static_cast<ALfloat>(values[2])); - return; + case AL_POSITION: + case AL_VELOCITY: + alListener3fDirect(context, param, static_cast<ALfloat>(values[0]), + static_cast<ALfloat>(values[1]), static_cast<ALfloat>(values[2])); + return; - case AL_ORIENTATION: - fvals[0] = static_cast<ALfloat>(values[0]); - fvals[1] = static_cast<ALfloat>(values[1]); - fvals[2] = static_cast<ALfloat>(values[2]); - fvals[3] = static_cast<ALfloat>(values[3]); - fvals[4] = static_cast<ALfloat>(values[4]); - fvals[5] = static_cast<ALfloat>(values[5]); - alListenerfv(param, fvals); - return; - } + case AL_ORIENTATION: + const ALfloat fvals[6]{ + static_cast<ALfloat>(values[0]), + static_cast<ALfloat>(values[1]), + static_cast<ALfloat>(values[2]), + static_cast<ALfloat>(values[3]), + static_cast<ALfloat>(values[4]), + static_cast<ALfloat>(values[5]), + }; + alListenerfvDirect(context, param, fvals); + return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; - if(!values) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(param) + switch(param) { default: context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetListenerf, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetListenerfDirect(ALCcontext *context, ALenum param, + ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; if(!value) @@ -286,14 +261,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener float property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC +AL_API DECL_FUNC4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetListener3fDirect(ALCcontext *context, ALenum param, + ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; if(!value1 || !value2 || !value3) @@ -316,27 +288,24 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetListenerfv, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetListenerfvDirect(ALCcontext *context, ALenum param, + ALfloat *values) noexcept { switch(param) { case AL_GAIN: case AL_METERS_PER_UNIT: - alGetListenerf(param, values); + alGetListenerfDirect(context, param, values); return; case AL_POSITION: case AL_VELOCITY: - alGetListener3f(param, values+0, values+1, values+2); + alGetListener3fDirect(context, param, values+0, values+1, values+2); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; if(!values) @@ -357,15 +326,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetListeneri, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetListeneriDirect(ALCcontext *context, ALenum param, ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; if(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -375,14 +340,11 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener integer property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC +AL_API DECL_FUNC4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetListener3iDirect(ALCcontext *context, ALenum param, + ALint *value1, ALint *value2, ALint *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; if(!value1 || !value2 || !value3) @@ -405,22 +367,19 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property"); } } -END_API_FUNC -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetListeneriv, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetListenerivDirect(ALCcontext *context, ALenum param, + ALint *values) noexcept { switch(param) { case AL_POSITION: case AL_VELOCITY: - alGetListener3i(param, values+0, values+1, values+2); + alGetListener3iDirect(context, param, values+0, values+1, values+2); return; } - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - ALlistener &listener = context->mListener; std::lock_guard<std::mutex> _{context->mPropLock}; if(!values) @@ -441,4 +400,3 @@ START_API_FUNC context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property"); } } -END_API_FUNC diff --git a/al/source.cpp b/al/source.cpp index cba33862..fe5bba40 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -27,20 +27,22 @@ #include <atomic> #include <cassert> #include <chrono> +#include <cinttypes> #include <climits> #include <cmath> #include <cstdint> #include <functional> -#include <inttypes.h> #include <iterator> #include <limits> #include <memory> #include <mutex> #include <new> #include <numeric> +#include <optional> #include <stdexcept> #include <thread> #include <utility> +#include <vector> #include "AL/al.h" #include "AL/alc.h" @@ -55,7 +57,6 @@ #include "alc/inprogext.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "atomic.h" #include "auxeffectslot.h" @@ -67,22 +68,21 @@ #include "core/filters/splitter.h" #include "core/logging.h" #include "core/voice_change.h" +#include "direct_defs.h" #include "event.h" #include "filter.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" #ifdef ALSOFT_EAX #include <cassert> #endif // ALSOFT_EAX -bool sBufferSubDataCompat{false}; - namespace { using namespace std::placeholders; using std::chrono::nanoseconds; +using seconds_d = std::chrono::duration<double>; Voice *GetSourceVoice(ALsource *source, ALCcontext *context) { @@ -95,7 +95,7 @@ Voice *GetSourceVoice(ALsource *source, ALCcontext *context) if(voice->mSourceID.load(std::memory_order_acquire) == sid) return voice; } - source->VoiceIdx = INVALID_VOICE_IDX; + source->VoiceIdx = InvalidVoiceIndex; return nullptr; } @@ -281,7 +281,8 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl * (Bytes, Samples or Seconds). The offset is relative to the start of the * queue (not the start of the current buffer). */ -double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) +template<typename T> +NOINLINE T GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { ALCdevice *device{context->mALDevice.get()}; const VoiceBufferItem *Current{}; @@ -304,7 +305,7 @@ double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) } while(refcount != device->MixCount.load(std::memory_order_relaxed)); if(!voice) - return 0.0; + return T{0}; const ALbuffer *BufferFmt{nullptr}; auto BufferList = Source->mQueue.cbegin(); @@ -321,24 +322,48 @@ double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) } ASSUME(BufferFmt != nullptr); - double offset{}; + T offset{}; switch(name) { case AL_SEC_OFFSET: - offset = static_cast<double>(readPos) + readPosFrac/double{MixerFracOne}; - offset /= BufferFmt->mSampleRate; + if constexpr(std::is_floating_point_v<T>) + { + offset = static_cast<T>(readPos) + static_cast<T>(readPosFrac)/T{MixerFracOne}; + offset /= static_cast<T>(BufferFmt->mSampleRate); + } + else + { + readPos /= BufferFmt->mSampleRate; + offset = static_cast<T>(clampi64(readPos, std::numeric_limits<T>::min(), + std::numeric_limits<T>::max())); + } break; case AL_SAMPLE_OFFSET: - offset = static_cast<double>(readPos) + readPosFrac/double{MixerFracOne}; + if constexpr(std::is_floating_point_v<T>) + offset = static_cast<T>(readPos) + static_cast<T>(readPosFrac)/T{MixerFracOne}; + else + offset = static_cast<T>(clampi64(readPos, std::numeric_limits<T>::min(), + std::numeric_limits<T>::max())); break; case AL_BYTE_OFFSET: const ALuint BlockSamples{BufferFmt->mBlockAlign}; const ALuint BlockSize{BufferFmt->blockSizeFromFmt()}; - /* Round down to the block boundary. */ - offset = static_cast<double>(readPos / BlockSamples) * BlockSize; + readPos = readPos / BlockSamples * BlockSize; + + if constexpr(std::is_floating_point_v<T>) + offset = static_cast<T>(readPos); + else + { + if(readPos > std::numeric_limits<T>::max()) + offset = RoundDown(std::numeric_limits<T>::max(), static_cast<T>(BlockSize)); + else if(readPos < std::numeric_limits<T>::min()) + offset = RoundUp(std::numeric_limits<T>::min(), static_cast<T>(BlockSize)); + else + offset = static_cast<T>(readPos); + } break; } return offset; @@ -349,7 +374,8 @@ double GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) * Gets the length of the given Source's buffer queue, in the appropriate * format (Bytes, Samples or Seconds). */ -double GetSourceLength(const ALsource *source, ALenum name) +template<typename T> +NOINLINE T GetSourceLength(const ALsource *source, ALenum name) { uint64_t length{0}; const ALbuffer *BufferFmt{nullptr}; @@ -360,25 +386,40 @@ double GetSourceLength(const ALsource *source, ALenum name) length += listitem.mSampleLen; } if(length == 0) - return 0.0; + return T{0}; ASSUME(BufferFmt != nullptr); switch(name) { case AL_SEC_LENGTH_SOFT: - return static_cast<double>(length) / BufferFmt->mSampleRate; + if constexpr(std::is_floating_point_v<T>) + return static_cast<T>(length) / static_cast<T>(BufferFmt->mSampleRate); + else + return static_cast<T>(minu64(length/BufferFmt->mSampleRate, + std::numeric_limits<T>::max())); case AL_SAMPLE_LENGTH_SOFT: - return static_cast<double>(length); + if constexpr(std::is_floating_point_v<T>) + return static_cast<T>(length); + else + return static_cast<T>(minu64(length, std::numeric_limits<T>::max())); case AL_BYTE_LENGTH_SOFT: const ALuint BlockSamples{BufferFmt->mBlockAlign}; const ALuint BlockSize{BufferFmt->blockSizeFromFmt()}; - /* Round down to the block boundary. */ - return static_cast<double>(length / BlockSamples) * BlockSize; + length = length / BlockSamples * BlockSize; + + if constexpr(std::is_floating_point_v<T>) + return static_cast<T>(length); + else + { + if(length > std::numeric_limits<T>::max()) + return RoundDown(std::numeric_limits<T>::max(), static_cast<T>(BlockSize)); + return static_cast<T>(length); + } } - return 0.0; + return T{0}; } @@ -392,11 +433,11 @@ struct VoicePos { * GetSampleOffset * * Retrieves the voice position, fixed-point fraction, and bufferlist item - * using the givem offset type and offset. If the offset is out of range, + * using the given offset type and offset. If the offset is out of range, * returns an empty optional. */ -al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, ALenum OffsetType, - double Offset) +std::optional<VoicePos> GetSampleOffset(std::deque<ALbufferQueueItem> &BufferList, + ALenum OffsetType, double Offset) { /* Find the first valid Buffer in the Queue */ const ALbuffer *BufferFmt{nullptr}; @@ -406,7 +447,7 @@ al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, if(BufferFmt) break; } if(!BufferFmt) UNLIKELY - return al::nullopt; + return std::nullopt; /* Get sample frame offset */ int64_t offset{}; @@ -452,12 +493,12 @@ al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, if(offset < 0) { if(offset < std::numeric_limits<int>::min()) - return al::nullopt; + return std::nullopt; return VoicePos{static_cast<int>(offset), frac, &BufferList.front()}; } if(BufferFmt->mCallback) - return al::nullopt; + return std::nullopt; int64_t totalBufferLen{0}; for(auto &item : BufferList) @@ -473,7 +514,7 @@ al::optional<VoicePos> GetSampleOffset(al::deque<ALbufferQueueItem> &BufferList, } /* Offset is out of range of the queue */ - return al::nullopt; + return std::nullopt; } @@ -676,8 +717,7 @@ inline ALenum GetSourceState(ALsource *source, Voice *voice) bool EnsureSources(ALCcontext *context, size_t needed) { - size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), - size_t{0}, + size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), 0_uz, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })}; @@ -722,6 +762,8 @@ ALsource *AllocSource(ALCcontext *context) void FreeSource(ALCcontext *context, ALsource *source) { + context->mSourceNames.erase(source->id); + const ALuint id{source->id - 1}; const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; @@ -738,7 +780,7 @@ void FreeSource(ALCcontext *context, ALsource *source) SendVoiceChanges(context, vchg); } - al::destroy_at(source); + std::destroy_at(source); context->mSourceList[lidx].FreeMask |= 1_u64 << slidx; context->mNumSources--; @@ -758,56 +800,55 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept return sublist.Sources + slidx; } -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept +auto LookupBuffer = [](ALCdevice *device, auto id) noexcept -> ALbuffer* { - const size_t lidx{(id-1) >> 6}; - const ALuint slidx{(id-1) & 0x3f}; + const auto lidx{(id-1) >> 6}; + const auto slidx{(id-1) & 0x3f}; if(lidx >= device->BufferList.size()) UNLIKELY return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; + BufferSubList &sublist = device->BufferList[static_cast<size_t>(lidx)]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Buffers + slidx; -} + return sublist.Buffers + static_cast<size_t>(slidx); +}; -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept +auto LookupFilter = [](ALCdevice *device, auto id) noexcept -> ALfilter* { - const size_t lidx{(id-1) >> 6}; - const ALuint slidx{(id-1) & 0x3f}; + const auto lidx{(id-1) >> 6}; + const auto slidx{(id-1) & 0x3f}; if(lidx >= device->FilterList.size()) UNLIKELY return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; + FilterSubList &sublist = device->FilterList[static_cast<size_t>(lidx)]; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.Filters + slidx; -} + return sublist.Filters + static_cast<size_t>(slidx); +}; -inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +auto LookupEffectSlot = [](ALCcontext *context, auto id) noexcept -> ALeffectslot* { - const size_t lidx{(id-1) >> 6}; - const ALuint slidx{(id-1) & 0x3f}; + const auto lidx{(id-1) >> 6}; + const auto slidx{(id-1) & 0x3f}; if(lidx >= context->mEffectSlotList.size()) UNLIKELY return nullptr; - EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; + EffectSlotSubList &sublist{context->mEffectSlotList[static_cast<size_t>(lidx)]}; if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY return nullptr; - return sublist.EffectSlots + slidx; -} + return sublist.EffectSlots + static_cast<size_t>(slidx); +}; -al::optional<SourceStereo> StereoModeFromEnum(ALenum mode) +auto StereoModeFromEnum = [](auto mode) noexcept -> std::optional<SourceStereo> { switch(mode) { case AL_NORMAL_SOFT: return SourceStereo::Normal; case AL_SUPER_STEREO_SOFT: return SourceStereo::Enhanced; } - WARN("Unsupported stereo mode: 0x%04x\n", mode); - return al::nullopt; -} + return std::nullopt; +}; ALenum EnumFromStereoMode(SourceStereo mode) { switch(mode) @@ -818,7 +859,7 @@ ALenum EnumFromStereoMode(SourceStereo mode) throw std::runtime_error{"Invalid SourceStereo: "+std::to_string(int(mode))}; } -al::optional<SpatializeMode> SpatializeModeFromEnum(ALenum mode) +auto SpatializeModeFromEnum = [](auto mode) noexcept -> std::optional<SpatializeMode> { switch(mode) { @@ -826,9 +867,8 @@ al::optional<SpatializeMode> SpatializeModeFromEnum(ALenum mode) case AL_TRUE: return SpatializeMode::On; case AL_AUTO_SOFT: return SpatializeMode::Auto; } - WARN("Unsupported spatialize mode: 0x%04x\n", mode); - return al::nullopt; -} + return std::nullopt; +}; ALenum EnumFromSpatializeMode(SpatializeMode mode) { switch(mode) @@ -840,7 +880,7 @@ ALenum EnumFromSpatializeMode(SpatializeMode mode) throw std::runtime_error{"Invalid SpatializeMode: "+std::to_string(int(mode))}; } -al::optional<DirectMode> DirectModeFromEnum(ALenum mode) +auto DirectModeFromEnum = [](auto mode) noexcept -> std::optional<DirectMode> { switch(mode) { @@ -848,9 +888,8 @@ al::optional<DirectMode> DirectModeFromEnum(ALenum mode) case AL_DROP_UNMATCHED_SOFT: return DirectMode::DropMismatch; case AL_REMIX_UNMATCHED_SOFT: return DirectMode::RemixMismatch; } - WARN("Unsupported direct mode: 0x%04x\n", mode); - return al::nullopt; -} + return std::nullopt; +}; ALenum EnumFromDirectMode(DirectMode mode) { switch(mode) @@ -862,7 +901,7 @@ ALenum EnumFromDirectMode(DirectMode mode) throw std::runtime_error{"Invalid DirectMode: "+std::to_string(int(mode))}; } -al::optional<DistanceModel> DistanceModelFromALenum(ALenum model) +auto DistanceModelFromALenum = [](auto model) noexcept -> std::optional<DistanceModel> { switch(model) { @@ -874,8 +913,8 @@ al::optional<DistanceModel> DistanceModelFromALenum(ALenum model) case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent; case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped; } - return al::nullopt; -} + return std::nullopt; +}; ALenum ALenumFromDistanceModel(DistanceModel model) { switch(model) @@ -973,8 +1012,6 @@ enum SourceProp : ALenum { }; -constexpr size_t MaxValues{6u}; - constexpr ALuint IntValsByProp(ALenum prop) { switch(static_cast<SourceProp>(prop)) @@ -1276,10 +1313,6 @@ constexpr ALuint DoubleValsByProp(ALenum prop) } -void SetSourcefv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<const float> values); -void SetSourceiv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<const int> values); -void SetSourcei64v(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<const int64_t> values); - struct check_exception : std::exception { }; struct check_size_exception final : check_exception { @@ -1327,10 +1360,39 @@ inline void CommitAndUpdateSourceProps(ALsource *source, ALCcontext *context) #endif +template<typename T> +struct PropType { }; +template<> +struct PropType<ALint> { static const char *Name() { return "integer"; } }; +template<> +struct PropType<ALint64SOFT> { static const char *Name() { return "int64"; } }; +template<> +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]{}; + 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); + else if constexpr(std::is_same_v<ST,long>) + std::snprintf(mStr, std::size(mStr), "0x%lx", value); + else if constexpr(std::is_same_v<ST,long long>) + std::snprintf(mStr, std::size(mStr), "0x%llx", value); + } + + const char *c_str() const noexcept { return mStr; } +}; + + /** - * Returns a pair of lambdas to check the following setters and getters. + * Returns a pair of lambdas to check the following setter. * - * The first lambda checks the size of the span is valid for its given size, + * The first lambda checks the size of the span is valid for the required size, * setting the proper context error and throwing a check_size_exception if it * fails. * @@ -1357,19 +1419,33 @@ auto GetCheckers(ALCcontext *const Context, const SourceProp prop, const al::spa ); } -void SetSourcefv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<const float> values) -try { - /* Structured bindings would be nice (C++17). */ - auto Checkers = GetCheckers(Context, prop, values); - auto &CheckSize = Checkers.first; - auto &CheckValue = Checkers.second; - int ival; +template<typename T> +NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, + const al::span<const T> values) try +{ + auto&& [CheckSize, CheckValue] = GetCheckers(Context, prop, values); + ALCdevice *device{Context->mALDevice.get()}; switch(prop) { + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + if constexpr(std::is_integral_v<T>) + { + /* Query only */ + return Context->setError(AL_INVALID_OPERATION, + "Setting read-only source property 0x%04x", prop); + } + break; + + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: /* Query only */ return Context->setError(AL_INVALID_OPERATION, @@ -1377,712 +1453,540 @@ try { case AL_PITCH: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->Pitch = values[0]; + Source->Pitch = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_CONE_INNER_ANGLE: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 360.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{360}); - Source->InnerAngle = values[0]; + Source->InnerAngle = static_cast<float>(values[0]); return CommitAndUpdateSourceProps(Source, Context); case AL_CONE_OUTER_ANGLE: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 360.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{360}); - Source->OuterAngle = values[0]; + Source->OuterAngle = static_cast<float>(values[0]); return CommitAndUpdateSourceProps(Source, Context); case AL_GAIN: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->Gain = values[0]; + Source->Gain = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_MAX_DISTANCE: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->MaxDistance = values[0]; + Source->MaxDistance = static_cast<float>(values[0]); return CommitAndUpdateSourceProps(Source, Context); case AL_ROLLOFF_FACTOR: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->RolloffFactor = values[0]; + Source->RolloffFactor = static_cast<float>(values[0]); return CommitAndUpdateSourceProps(Source, Context); case AL_REFERENCE_DISTANCE: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->RefDistance = values[0]; + Source->RefDistance = static_cast<float>(values[0]); return CommitAndUpdateSourceProps(Source, Context); case AL_MIN_GAIN: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->MinGain = values[0]; + Source->MinGain = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_MAX_GAIN: CheckSize(1); - CheckValue(values[0] >= 0.0f); + CheckValue(values[0] >= T{0}); - Source->MaxGain = values[0]; + Source->MaxGain = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_CONE_OUTER_GAIN: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 1.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{1}); - Source->OuterGain = values[0]; + Source->OuterGain = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_CONE_OUTER_GAINHF: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 1.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{1}); - Source->OuterGainHF = values[0]; + Source->OuterGainHF = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_AIR_ABSORPTION_FACTOR: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 10.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{10}); - Source->AirAbsorptionFactor = values[0]; + Source->AirAbsorptionFactor = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_ROOM_ROLLOFF_FACTOR: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 10.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{1}); - Source->RoomRolloffFactor = values[0]; + Source->RoomRolloffFactor = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_DOPPLER_FACTOR: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 1.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{1}); - Source->DopplerFactor = values[0]; + Source->DopplerFactor = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); + + case AL_SOURCE_RELATIVE: + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); + + Source->HeadRelative = values[0] != AL_FALSE; + return CommitAndUpdateSourceProps(Source, Context); + } + break; + + case AL_LOOPING: + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); + + Source->Looping = values[0] != AL_FALSE; + if(Voice *voice{GetSourceVoice(Source, Context)}) + { + if(Source->Looping) + voice->mLoopBuffer.store(&Source->mQueue.front(), std::memory_order_release); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + device->waitForMix(); + } + return; + } + break; + + case AL_BUFFER: + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + { + const ALenum state{GetSourceState(Source, GetSourceVoice(Source, Context))}; + if(state == AL_PLAYING || state == AL_PAUSED) + return Context->setError(AL_INVALID_OPERATION, + "Setting buffer on playing or paused source %u", Source->id); + } + std::deque<ALbufferQueueItem> oldlist; + if(values[0]) + { + using UT = std::make_unsigned_t<T>; + std::lock_guard<std::mutex> _{device->BufferLock}; + ALbuffer *buffer{LookupBuffer(device, static_cast<UT>(values[0]))}; + 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 + return Context->setError(AL_INVALID_OPERATION, + "Setting non-persistently mapped buffer %u", buffer->id); + if(buffer->mCallback && ReadRef(buffer->ref) != 0) UNLIKELY + return Context->setError(AL_INVALID_OPERATION, + "Setting already-set callback buffer %u", buffer->id); + + /* Add the selected buffer to a one-item queue */ + std::deque<ALbufferQueueItem> newlist; + newlist.emplace_back(); + newlist.back().mCallback = buffer->mCallback; + newlist.back().mUserData = buffer->mUserData; + newlist.back().mBlockAlign = buffer->mBlockAlign; + newlist.back().mSampleLen = buffer->mSampleLen; + newlist.back().mLoopStart = buffer->mLoopStart; + newlist.back().mLoopEnd = buffer->mLoopEnd; + newlist.back().mSamples = buffer->mData.data(); + newlist.back().mBuffer = buffer; + IncrementRef(buffer->ref); + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + Source->mQueue.swap(oldlist); + Source->mQueue.swap(newlist); + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + Source->mQueue.swap(oldlist); + } + + /* Delete all elements in the previous queue */ + for(auto &item : oldlist) + { + if(ALbuffer *buffer{item.mBuffer}) + DecrementRef(buffer->ref); + } + return; + } + break; + + case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: CheckSize(1); - CheckValue(std::isfinite(values[0])); + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(values[0])); if(Voice *voice{GetSourceVoice(Source, Context)}) { - auto vpos = GetSampleOffset(Source->mQueue, prop, values[0]); + auto vpos = GetSampleOffset(Source->mQueue, prop, static_cast<double>(values[0])); if(!vpos) return Context->setError(AL_INVALID_VALUE, "Invalid offset"); if(SetVoiceOffset(voice, *vpos, Source, Context, Context->mALDevice.get())) return; } Source->OffsetType = prop; - Source->Offset = values[0]; + Source->Offset = static_cast<double>(values[0]); return; case AL_SAMPLE_RW_OFFSETS_SOFT: + if(sBufferSubDataCompat) + { + if constexpr(std::is_integral_v<T>) + { + /* Query only */ + return Context->setError(AL_INVALID_OPERATION, + "Setting read-only source property 0x%04x", prop); + } + } break; case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ if(sBufferSubDataCompat) + { + if constexpr(std::is_integral_v<T>) + { + /* Query only */ + return Context->setError(AL_INVALID_OPERATION, + "Setting read-only source property 0x%04x", prop); + } break; + } CheckSize(1); - CheckValue(values[0] >= 0.0f && std::isfinite(values[0])); + if constexpr(std::is_floating_point_v<T>) + CheckValue(values[0] >= T{0} && std::isfinite(static_cast<float>(values[0]))); + else + CheckValue(values[0] >= T{0}); - Source->Radius = values[0]; + Source->Radius = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_SUPER_STEREO_WIDTH_SOFT: CheckSize(1); - CheckValue(values[0] >= 0.0f && values[0] <= 1.0f); + CheckValue(values[0] >= T{0} && values[0] <= T{1}); - Source->EnhWidth = values[0]; + Source->EnhWidth = static_cast<float>(values[0]); return UpdateSourceProps(Source, Context); case AL_STEREO_ANGLES: CheckSize(2); - CheckValue(std::isfinite(values[0]) && std::isfinite(values[1])); + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(static_cast<float>(values[0])) + && std::isfinite(static_cast<float>(values[1]))); - Source->StereoPan[0] = values[0]; - Source->StereoPan[1] = values[1]; + Source->StereoPan[0] = static_cast<float>(values[0]); + Source->StereoPan[1] = static_cast<float>(values[1]); return UpdateSourceProps(Source, Context); case AL_POSITION: CheckSize(3); - CheckValue(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(static_cast<float>(values[0])) + && std::isfinite(static_cast<float>(values[1])) + && std::isfinite(static_cast<float>(values[2]))); + + Source->Position[0] = static_cast<float>(values[0]); + Source->Position[1] = static_cast<float>(values[1]); + Source->Position[2] = static_cast<float>(values[2]); return CommitAndUpdateSourceProps(Source, Context); case AL_VELOCITY: CheckSize(3); - CheckValue(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(static_cast<float>(values[0])) + && std::isfinite(static_cast<float>(values[1])) + && std::isfinite(static_cast<float>(values[2]))); + + Source->Velocity[0] = static_cast<float>(values[0]); + Source->Velocity[1] = static_cast<float>(values[1]); + Source->Velocity[2] = static_cast<float>(values[2]); return CommitAndUpdateSourceProps(Source, Context); case AL_DIRECTION: CheckSize(3); - CheckValue(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Direction[0] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = values[2]; + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(static_cast<float>(values[0])) + && std::isfinite(static_cast<float>(values[1])) + && std::isfinite(static_cast<float>(values[2]))); + + Source->Direction[0] = static_cast<float>(values[0]); + Source->Direction[1] = static_cast<float>(values[1]); + Source->Direction[2] = static_cast<float>(values[2]); return CommitAndUpdateSourceProps(Source, Context); case AL_ORIENTATION: CheckSize(6); - CheckValue(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) - && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); - - Source->OrientAt[0] = values[0]; - Source->OrientAt[1] = values[1]; - Source->OrientAt[2] = values[2]; - Source->OrientUp[0] = values[3]; - Source->OrientUp[1] = values[4]; - Source->OrientUp[2] = values[5]; + if constexpr(std::is_floating_point_v<T>) + CheckValue(std::isfinite(static_cast<float>(values[0])) + && std::isfinite(static_cast<float>(values[1])) + && std::isfinite(static_cast<float>(values[2])) + && std::isfinite(static_cast<float>(values[3])) + && std::isfinite(static_cast<float>(values[4])) + && std::isfinite(static_cast<float>(values[5]))); + + Source->OrientAt[0] = static_cast<float>(values[0]); + Source->OrientAt[1] = static_cast<float>(values[1]); + Source->OrientAt[2] = static_cast<float>(values[2]); + Source->OrientUp[0] = static_cast<float>(values[3]); + Source->OrientUp[1] = static_cast<float>(values[4]); + Source->OrientUp[2] = static_cast<float>(values[5]); return UpdateSourceProps(Source, Context); - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_DISTANCE_MODEL: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_STEREO_MODE_SOFT: - CheckSize(1); - ival = static_cast<int>(values[0]); - return SetSourceiv(Source, Context, prop, {&ival, 1u}); - - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - CheckSize(1); - ival = static_cast<int>(static_cast<ALuint>(values[0])); - return SetSourceiv(Source, Context, prop, {&ival, 1u}); - - case AL_BUFFER: case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source float property 0x%04x", prop); -} -catch(check_exception&) { -} - -void SetSourceiv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<const int> values) -try { - auto Checkers = GetCheckers(Context, prop, values); - auto &CheckSize = Checkers.first; - auto &CheckValue = Checkers.second; - ALCdevice *device{Context->mALDevice.get()}; - ALeffectslot *slot{nullptr}; - al::deque<ALbufferQueueItem> oldlist; - std::unique_lock<std::mutex> slotlock; - float fvals[6]; - - switch(prop) - { - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - /* Query only */ - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); - - case AL_SOURCE_RELATIVE: - CheckSize(1); - CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->HeadRelative = values[0] != AL_FALSE; - return CommitAndUpdateSourceProps(Source, Context); - - case AL_LOOPING: - CheckSize(1); - CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->Looping = values[0] != AL_FALSE; - if(Voice *voice{GetSourceVoice(Source, Context)}) + if constexpr(std::is_integral_v<T>) { - if(Source->Looping) - voice->mLoopBuffer.store(&Source->mQueue.front(), std::memory_order_release); + CheckSize(1); + const auto filterid = static_cast<std::make_unsigned_t<T>>(values[0]); + if(values[0]) + { + std::lock_guard<std::mutex> _{device->FilterLock}; + ALfilter *filter{LookupFilter(device, filterid)}; + if(!filter) UNLIKELY + return Context->setError(AL_INVALID_VALUE, "Invalid filter ID %s", + std::to_string(filterid).c_str()); + Source->Direct.Gain = filter->Gain; + Source->Direct.GainHF = filter->GainHF; + Source->Direct.HFReference = filter->HFReference; + Source->Direct.GainLF = filter->GainLF; + Source->Direct.LFReference = filter->LFReference; + } else - voice->mLoopBuffer.store(nullptr, std::memory_order_release); - - /* If the source is playing, wait for the current mix to finish to - * ensure it isn't currently looping back or reaching the end. - */ - device->waitForMix(); + { + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + } + return UpdateSourceProps(Source, Context); } - return; + break; - case AL_BUFFER: - CheckSize(1); - { - const ALenum state{GetSourceState(Source, GetSourceVoice(Source, Context))}; - if(state == AL_PLAYING || state == AL_PAUSED) - return Context->setError(AL_INVALID_OPERATION, - "Setting buffer on playing or paused source %u", Source->id); - } - if(values[0]) - { - std::lock_guard<std::mutex> _{device->BufferLock}; - ALbuffer *buffer{LookupBuffer(device, static_cast<ALuint>(values[0]))}; - if(!buffer) - return Context->setError(AL_INVALID_VALUE, "Invalid buffer ID %u", - static_cast<ALuint>(values[0])); - if(buffer->MappedAccess && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - return Context->setError(AL_INVALID_OPERATION, - "Setting non-persistently mapped buffer %u", buffer->id); - if(buffer->mCallback && ReadRef(buffer->ref) != 0) - return Context->setError(AL_INVALID_OPERATION, - "Setting already-set callback buffer %u", buffer->id); - - /* Add the selected buffer to a one-item queue */ - al::deque<ALbufferQueueItem> newlist; - newlist.emplace_back(); - newlist.back().mCallback = buffer->mCallback; - newlist.back().mUserData = buffer->mUserData; - newlist.back().mBlockAlign = buffer->mBlockAlign; - newlist.back().mSampleLen = buffer->mSampleLen; - newlist.back().mLoopStart = buffer->mLoopStart; - newlist.back().mLoopEnd = buffer->mLoopEnd; - newlist.back().mSamples = buffer->mData.data(); - newlist.back().mBuffer = buffer; - IncrementRef(buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - Source->mQueue.swap(oldlist); - Source->mQueue.swap(newlist); - } - else + case AL_DIRECT_FILTER_GAINHF_AUTO: + if constexpr(std::is_integral_v<T>) { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - Source->mQueue.swap(oldlist); - } + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - /* Delete all elements in the previous queue */ - for(auto &item : oldlist) - { - if(ALbuffer *buffer{item.mBuffer}) - DecrementRef(buffer->ref); + Source->DryGainHFAuto = values[0] != AL_FALSE; + return UpdateSourceProps(Source, Context); } - return; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CheckSize(1); + break; - if(Voice *voice{GetSourceVoice(Source, Context)}) + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + if constexpr(std::is_integral_v<T>) { - auto vpos = GetSampleOffset(Source->mQueue, prop, values[0]); - if(!vpos) return Context->setError(AL_INVALID_VALUE, "Invalid source offset"); + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - if(SetVoiceOffset(voice, *vpos, Source, Context, device)) - return; - } - Source->OffsetType = prop; - Source->Offset = values[0]; - return; - - case AL_DIRECT_FILTER: - CheckSize(1); - if(values[0]) - { - std::lock_guard<std::mutex> _{device->FilterLock}; - ALfilter *filter{LookupFilter(device, static_cast<ALuint>(values[0]))}; - if(!filter) - return Context->setError(AL_INVALID_VALUE, "Invalid filter ID %u", - static_cast<ALuint>(values[0])); - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - else - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; + Source->WetGainAuto = values[0] != AL_FALSE; + return UpdateSourceProps(Source, Context); } - return UpdateSourceProps(Source, Context); - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CheckSize(1); - CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->DryGainHFAuto = values[0] != AL_FALSE; - return UpdateSourceProps(Source, Context); - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CheckSize(1); - CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->WetGainAuto = values[0] != AL_FALSE; - return UpdateSourceProps(Source, Context); + break; case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CheckSize(1); - CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainHFAuto = values[0] != AL_FALSE; - return UpdateSourceProps(Source, Context); + Source->WetGainHFAuto = values[0] != AL_FALSE; + return UpdateSourceProps(Source, Context); + } + break; case AL_DIRECT_CHANNELS_SOFT: - CheckSize(1); - if(auto mode = DirectModeFromEnum(values[0])) + if constexpr(std::is_integral_v<T>) { - Source->DirectChannels = *mode; - return UpdateSourceProps(Source, Context); + CheckSize(1); + if(auto mode = DirectModeFromEnum(values[0])) + { + Source->DirectChannels = *mode; + return UpdateSourceProps(Source, Context); + } + return Context->setError(AL_INVALID_VALUE, "Invalid direct channels mode: %s\n", + HexPrinter{values[0]}.c_str()); } - Context->setError(AL_INVALID_VALUE, "Unsupported AL_DIRECT_CHANNELS_SOFT: 0x%04x\n", - values[0]); - return; + break; case AL_DISTANCE_MODEL: - CheckSize(1); - if(auto model = DistanceModelFromALenum(values[0])) + if constexpr(std::is_integral_v<T>) { - Source->mDistanceModel = *model; - if(Context->mSourceDistanceModel) - UpdateSourceProps(Source, Context); - return; + CheckSize(1); + if(auto model = DistanceModelFromALenum(values[0])) + { + Source->mDistanceModel = *model; + if(Context->mSourceDistanceModel) + UpdateSourceProps(Source, Context); + return; + } + return Context->setError(AL_INVALID_VALUE, "Invalid distance model: %s\n", + HexPrinter{values[0]}.c_str()); } - Context->setError(AL_INVALID_VALUE, "Distance model out of range: 0x%04x", values[0]); - return; + break; case AL_SOURCE_RESAMPLER_SOFT: - CheckSize(1); - CheckValue(values[0] >= 0 && values[0] <= static_cast<int>(Resampler::Max)); - - Source->mResampler = static_cast<Resampler>(values[0]); - return UpdateSourceProps(Source, Context); - - case AL_SOURCE_SPATIALIZE_SOFT: - CheckSize(1); - if(auto mode = SpatializeModeFromEnum(values[0])) + if constexpr(std::is_integral_v<T>) { - Source->mSpatialize = *mode; - return UpdateSourceProps(Source, Context); - } - Context->setError(AL_INVALID_VALUE, "Unsupported AL_SOURCE_SPATIALIZE_SOFT: 0x%04x\n", - values[0]); - return; + CheckSize(1); + CheckValue(values[0] >= 0 && values[0] <= static_cast<int>(Resampler::Max)); - case AL_STEREO_MODE_SOFT: - CheckSize(1); - { - const ALenum state{GetSourceState(Source, GetSourceVoice(Source, Context))}; - if(state == AL_PLAYING || state == AL_PAUSED) - return Context->setError(AL_INVALID_OPERATION, - "Modifying stereo mode on playing or paused source %u", Source->id); - } - if(auto mode = StereoModeFromEnum(values[0])) - { - Source->mStereoMode = *mode; - return; - } - Context->setError(AL_INVALID_VALUE, "Unsupported AL_STEREO_MODE_SOFT: 0x%04x\n", - values[0]); - return; - - case AL_AUXILIARY_SEND_FILTER: - CheckSize(3); - slotlock = std::unique_lock<std::mutex>{Context->mEffectSlotLock}; - if(values[0] && (slot=LookupEffectSlot(Context, static_cast<ALuint>(values[0]))) == nullptr) - return Context->setError(AL_INVALID_VALUE, "Invalid effect ID %u", values[0]); - if(static_cast<ALuint>(values[1]) >= device->NumAuxSends) - return Context->setError(AL_INVALID_VALUE, "Invalid send %u", values[1]); - - if(values[2]) - { - std::lock_guard<std::mutex> _{device->FilterLock}; - ALfilter *filter{LookupFilter(device, static_cast<ALuint>(values[2]))}; - if(!filter) - return Context->setError(AL_INVALID_VALUE, "Invalid filter ID %u", values[2]); - - auto &send = Source->Send[static_cast<ALuint>(values[1])]; - send.Gain = filter->Gain; - send.GainHF = filter->GainHF; - send.HFReference = filter->HFReference; - send.GainLF = filter->GainLF; - send.LFReference = filter->LFReference; - } - else - { - /* Disable filter */ - auto &send = Source->Send[static_cast<ALuint>(values[1])]; - send.Gain = 1.0f; - send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; - send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; + Source->mResampler = static_cast<Resampler>(values[0]); + return UpdateSourceProps(Source, Context); } + break; - /* We must force an update if the current auxiliary slot is valid and - * about to be changed on an active source, in case the old slot is - * about to be deleted. - */ - if(Source->Send[static_cast<ALuint>(values[1])].Slot - && slot != Source->Send[static_cast<ALuint>(values[1])].Slot - && IsPlayingOrPaused(Source)) - { - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(slot->ref); - if(auto *oldslot = Source->Send[static_cast<ALuint>(values[1])].Slot) - DecrementRef(oldslot->ref); - Source->Send[static_cast<ALuint>(values[1])].Slot = slot; - - Voice *voice{GetSourceVoice(Source, Context)}; - if(voice) UpdateSourceProps(Source, voice, Context); - else Source->mPropsDirty = true; - } - else + case AL_SOURCE_SPATIALIZE_SOFT: + if constexpr(std::is_integral_v<T>) { - if(slot) IncrementRef(slot->ref); - if(auto *oldslot = Source->Send[static_cast<ALuint>(values[1])].Slot) - DecrementRef(oldslot->ref); - Source->Send[static_cast<ALuint>(values[1])].Slot = slot; - UpdateSourceProps(Source, Context); + CheckSize(1); + if(auto mode = SpatializeModeFromEnum(values[0])) + { + Source->mSpatialize = *mode; + return UpdateSourceProps(Source, Context); + } + return Context->setError(AL_INVALID_VALUE, "Invalid source spatialize mode: %s\n", + HexPrinter{values[0]}.c_str()); } - return; - - - case AL_SAMPLE_RW_OFFSETS_SOFT: - if(sBufferSubDataCompat) - /* Query only */ - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); - break; - - case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ - if(sBufferSubDataCompat) - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); - /*fall-through*/ - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SEC_LENGTH_SOFT: - case AL_SUPER_STEREO_WIDTH_SOFT: - CheckSize(1); - fvals[0] = static_cast<float>(values[0]); - return SetSourcefv(Source, Context, prop, {fvals, 1u}); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CheckSize(3); - fvals[0] = static_cast<float>(values[0]); - fvals[1] = static_cast<float>(values[1]); - fvals[2] = static_cast<float>(values[2]); - return SetSourcefv(Source, Context, prop, {fvals, 3u}); - - /* 6x float */ - case AL_ORIENTATION: - CheckSize(6); - fvals[0] = static_cast<float>(values[0]); - fvals[1] = static_cast<float>(values[1]); - fvals[2] = static_cast<float>(values[2]); - fvals[3] = static_cast<float>(values[3]); - fvals[4] = static_cast<float>(values[4]); - fvals[5] = static_cast<float>(values[5]); - return SetSourcefv(Source, Context, prop, {fvals, 6u}); - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: break; - } - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); -} -catch(check_exception&) { -} - -void SetSourcei64v(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<const int64_t> values) -try { - auto Checkers = GetCheckers(Context, prop, values); - auto &CheckSize = Checkers.first; - auto &CheckValue = Checkers.second; - float fvals[MaxValues]; - int ivals[MaxValues]; - - switch(prop) - { - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_STATE: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - /* Query only */ - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: case AL_STEREO_MODE_SOFT: - CheckSize(1); - CheckValue(values[0] <= INT_MAX && values[0] >= INT_MIN); - - ivals[0] = static_cast<int>(values[0]); - return SetSourceiv(Source, Context, prop, {ivals, 1u}); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CheckSize(1); - CheckValue(values[0] <= UINT_MAX && values[0] >= 0); - - ivals[0] = static_cast<int>(values[0]); - return SetSourceiv(Source, Context, prop, {ivals, 1u}); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CheckSize(3); - CheckValue(values[0] <= UINT_MAX && values[0] >= 0 && values[1] <= UINT_MAX - && values[1] >= 0 && values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = static_cast<int>(values[0]); - ivals[1] = static_cast<int>(values[1]); - ivals[2] = static_cast<int>(values[2]); - return SetSourceiv(Source, Context, prop, {ivals, 3u}); - - case AL_SAMPLE_RW_OFFSETS_SOFT: - if(sBufferSubDataCompat) + if constexpr(std::is_integral_v<T>) { - /* Query only */ - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); + CheckSize(1); + { + const ALenum state{GetSourceState(Source, GetSourceVoice(Source, Context))}; + if(state == AL_PLAYING || state == AL_PAUSED) + return Context->setError(AL_INVALID_OPERATION, + "Modifying stereo mode on playing or paused source %u", Source->id); + } + if(auto mode = StereoModeFromEnum(values[0])) + { + Source->mStereoMode = *mode; + return; + } + return Context->setError(AL_INVALID_VALUE, "Invalid stereo mode: %s\n", + HexPrinter{values[0]}.c_str()); } break; - case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ - if(sBufferSubDataCompat) - return Context->setError(AL_INVALID_OPERATION, - "Setting read-only source property 0x%04x", prop); - /*fall-through*/ - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SEC_LENGTH_SOFT: - case AL_SUPER_STEREO_WIDTH_SOFT: - CheckSize(1); - fvals[0] = static_cast<float>(values[0]); - return SetSourcefv(Source, Context, prop, {fvals, 1u}); + case AL_AUXILIARY_SEND_FILTER: + if constexpr(std::is_integral_v<T>) + { + CheckSize(3); + const auto slotid = static_cast<std::make_unsigned_t<T>>(values[0]); + const auto sendidx = static_cast<std::make_unsigned_t<T>>(values[1]); + const auto filterid = static_cast<std::make_unsigned_t<T>>(values[2]); + + std::unique_lock slotlock{Context->mEffectSlotLock}; + ALeffectslot *slot{}; + if(values[0]) + { + if((slot=LookupEffectSlot(Context, slotid)) == nullptr) UNLIKELY + return Context->setError(AL_INVALID_VALUE, "Invalid effect ID %s", + std::to_string(slotid).c_str()); + } - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CheckSize(3); - fvals[0] = static_cast<float>(values[0]); - fvals[1] = static_cast<float>(values[1]); - fvals[2] = static_cast<float>(values[2]); - return SetSourcefv(Source, Context, prop, {fvals, 3u}); + if(sendidx >= device->NumAuxSends) UNLIKELY + return Context->setError(AL_INVALID_VALUE, "Invalid send %s", + std::to_string(sendidx).c_str()); + auto &send = Source->Send[static_cast<size_t>(sendidx)]; - /* 6x float */ - case AL_ORIENTATION: - CheckSize(6); - fvals[0] = static_cast<float>(values[0]); - fvals[1] = static_cast<float>(values[1]); - fvals[2] = static_cast<float>(values[2]); - fvals[3] = static_cast<float>(values[3]); - fvals[4] = static_cast<float>(values[4]); - fvals[5] = static_cast<float>(values[5]); - return SetSourcefv(Source, Context, prop, {fvals, 6u}); + if(values[2]) + { + std::lock_guard<std::mutex> _{device->FilterLock}; + ALfilter *filter{LookupFilter(device, filterid)}; + if(!filter) UNLIKELY + return Context->setError(AL_INVALID_VALUE, "Invalid filter ID %s", + std::to_string(filterid).c_str()); + + send.Gain = filter->Gain; + send.GainHF = filter->GainHF; + send.HFReference = filter->HFReference; + send.GainLF = filter->GainLF; + send.LFReference = filter->LFReference; + } + else + { + /* Disable filter */ + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; + } - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: + /* We must force an update if the current auxiliary slot is valid + * and about to be changed on an active source, in case the old + * slot is about to be deleted. + */ + if(send.Slot && slot != send.Slot && IsPlayingOrPaused(Source)) + { + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(slot->ref); + if(auto *oldslot = send.Slot) + DecrementRef(oldslot->ref); + send.Slot = slot; + + Voice *voice{GetSourceVoice(Source, Context)}; + if(voice) UpdateSourceProps(Source, voice, Context); + else Source->mPropsDirty = true; + } + else + { + if(slot) IncrementRef(slot->ref); + if(auto *oldslot = send.Slot) + DecrementRef(oldslot->ref); + send.Slot = slot; + UpdateSourceProps(Source, Context); + } + return; + } break; } - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); + ERR("Unexpected %s property: 0x%04x\n", PropType<T>::Name(), prop); + Context->setError(AL_INVALID_ENUM, "Invalid source %s property 0x%04x", PropType<T>::Name(), + prop); } catch(check_exception&) { } @@ -2100,245 +2004,292 @@ auto GetSizeChecker(ALCcontext *const Context, const SourceProp prop, const al:: }; } -bool GetSourcedv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<double> values); -bool GetSourceiv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<int> values); -bool GetSourcei64v(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, const al::span<int64_t> values); - -bool GetSourcedv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<double> values) -try { +template<typename T> +[[nodiscard]] NOINLINE +bool GetProperty(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, + const al::span<T> values) try +{ + using std::chrono::duration_cast; auto CheckSize = GetSizeChecker(Context, prop, values); ALCdevice *device{Context->mALDevice.get()}; - ClockLatency clocktime; - nanoseconds srcclock; - int ivals[MaxValues]; - bool err; switch(prop) { case AL_GAIN: CheckSize(1); - values[0] = Source->Gain; + values[0] = static_cast<T>(Source->Gain); return true; case AL_PITCH: CheckSize(1); - values[0] = Source->Pitch; + values[0] = static_cast<T>(Source->Pitch); return true; case AL_MAX_DISTANCE: CheckSize(1); - values[0] = Source->MaxDistance; + values[0] = static_cast<T>(Source->MaxDistance); return true; case AL_ROLLOFF_FACTOR: CheckSize(1); - values[0] = Source->RolloffFactor; + values[0] = static_cast<T>(Source->RolloffFactor); return true; case AL_REFERENCE_DISTANCE: CheckSize(1); - values[0] = Source->RefDistance; + values[0] = static_cast<T>(Source->RefDistance); return true; case AL_CONE_INNER_ANGLE: CheckSize(1); - values[0] = Source->InnerAngle; + values[0] = static_cast<T>(Source->InnerAngle); return true; case AL_CONE_OUTER_ANGLE: CheckSize(1); - values[0] = Source->OuterAngle; + values[0] = static_cast<T>(Source->OuterAngle); return true; case AL_MIN_GAIN: CheckSize(1); - values[0] = Source->MinGain; + values[0] = static_cast<T>(Source->MinGain); return true; case AL_MAX_GAIN: CheckSize(1); - values[0] = Source->MaxGain; + values[0] = static_cast<T>(Source->MaxGain); return true; case AL_CONE_OUTER_GAIN: CheckSize(1); - values[0] = Source->OuterGain; + values[0] = static_cast<T>(Source->OuterGain); return true; case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: CheckSize(1); - values[0] = GetSourceOffset(Source, prop, Context); + values[0] = GetSourceOffset<T>(Source, prop, Context); return true; case AL_CONE_OUTER_GAINHF: CheckSize(1); - values[0] = Source->OuterGainHF; + values[0] = static_cast<T>(Source->OuterGainHF); return true; case AL_AIR_ABSORPTION_FACTOR: CheckSize(1); - values[0] = Source->AirAbsorptionFactor; + values[0] = static_cast<T>(Source->AirAbsorptionFactor); return true; case AL_ROOM_ROLLOFF_FACTOR: CheckSize(1); - values[0] = Source->RoomRolloffFactor; + values[0] = static_cast<T>(Source->RoomRolloffFactor); return true; case AL_DOPPLER_FACTOR: CheckSize(1); - values[0] = Source->DopplerFactor; + values[0] = static_cast<T>(Source->DopplerFactor); return true; case AL_SAMPLE_RW_OFFSETS_SOFT: + if constexpr(std::is_integral_v<T>) + { + if(sBufferSubDataCompat) + { + CheckSize(2); + values[0] = GetSourceOffset<T>(Source, AL_SAMPLE_OFFSET, Context); + /* FIXME: values[1] should be ahead of values[0] by the device + * update time. It needs to clamp or wrap the length of the + * buffer queue. + */ + values[1] = values[0]; + return true; + } + } break; case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ - if(sBufferSubDataCompat) - break; + if constexpr(std::is_floating_point_v<T>) + { + if(sBufferSubDataCompat) + break; - CheckSize(1); - values[0] = Source->Radius; - return true; + CheckSize(1); + values[0] = static_cast<T>(Source->Radius); + return true; + } + else + { + if(sBufferSubDataCompat) + { + CheckSize(2); + values[0] = GetSourceOffset<T>(Source, AL_BYTE_OFFSET, Context); + /* FIXME: values[1] should be ahead of values[0] by the device + * update time. It needs to clamp or wrap the length of the + * buffer queue. + */ + values[1] = values[0]; + return true; + } + break; + } case AL_SUPER_STEREO_WIDTH_SOFT: CheckSize(1); - values[0] = Source->EnhWidth; + values[0] = static_cast<T>(Source->EnhWidth); return true; case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: CheckSize(1); - values[0] = GetSourceLength(Source, prop); + values[0] = GetSourceLength<T>(Source, prop); return true; case AL_STEREO_ANGLES: - CheckSize(2); - values[0] = Source->StereoPan[0]; - values[1] = Source->StereoPan[1]; - return true; + if constexpr(std::is_floating_point_v<T>) + { + CheckSize(2); + values[0] = static_cast<T>(Source->StereoPan[0]); + values[1] = static_cast<T>(Source->StereoPan[1]); + return true; + } + break; - case AL_SEC_OFFSET_LATENCY_SOFT: - CheckSize(2); - /* Get the source offset with the clock time first. Then get the clock - * time with the device latency. Order is important. - */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + if constexpr(std::is_same_v<T,int64_t>) { - std::lock_guard<std::mutex> _{device->StateLock}; - clocktime = GetClockLatency(device, device->Backend.get()); + CheckSize(2); + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + ClockLatency clocktime{}; + nanoseconds srcclock{}; + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + { + std::lock_guard<std::mutex> _{device->StateLock}; + clocktime = GetClockLatency(device, device->Backend.get()); + } + if(srcclock == clocktime.ClockTime) + values[1] = nanoseconds{clocktime.Latency}.count(); + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + const auto diff = std::min(clocktime.Latency, clocktime.ClockTime-srcclock); + values[1] = nanoseconds{clocktime.Latency - diff}.count(); + } + return true; } - if(srcclock == clocktime.ClockTime) - values[1] = static_cast<double>(clocktime.Latency.count()) / 1000000000.0; - else + break; + + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + if constexpr(std::is_same_v<T,int64_t>) + { + CheckSize(2); + nanoseconds srcclock{}; + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock.count(); + return true; + } + break; + + case AL_SEC_OFFSET_LATENCY_SOFT: + if constexpr(std::is_same_v<T,double>) { - /* If the clock time incremented, reduce the latency by that much - * since it's that much closer to the source offset it got earlier. + CheckSize(2); + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. */ - const nanoseconds diff{clocktime.ClockTime - srcclock}; - const nanoseconds latency{clocktime.Latency - std::min(clocktime.Latency, diff)}; - values[1] = static_cast<double>(latency.count()) / 1000000000.0; + ClockLatency clocktime{}; + nanoseconds srcclock{}; + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + { + std::lock_guard<std::mutex> _{device->StateLock}; + clocktime = GetClockLatency(device, device->Backend.get()); + } + if(srcclock == clocktime.ClockTime) + values[1] = duration_cast<seconds_d>(clocktime.Latency).count(); + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + const auto diff = std::min(clocktime.Latency, clocktime.ClockTime-srcclock); + values[1] = duration_cast<seconds_d>(clocktime.Latency - diff).count(); + } + return true; } - return true; + break; case AL_SEC_OFFSET_CLOCK_SOFT: - CheckSize(2); - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = static_cast<double>(srcclock.count()) / 1000000000.0; - return true; + if constexpr(std::is_same_v<T,double>) + { + CheckSize(2); + nanoseconds srcclock{}; + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = duration_cast<seconds_d>(srcclock).count(); + return true; + } + break; case AL_POSITION: CheckSize(3); - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; + values[0] = static_cast<T>(Source->Position[0]); + values[1] = static_cast<T>(Source->Position[1]); + values[2] = static_cast<T>(Source->Position[2]); return true; case AL_VELOCITY: CheckSize(3); - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; + values[0] = static_cast<T>(Source->Velocity[0]); + values[1] = static_cast<T>(Source->Velocity[1]); + values[2] = static_cast<T>(Source->Velocity[2]); return true; case AL_DIRECTION: CheckSize(3); - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; + values[0] = static_cast<T>(Source->Direction[0]); + values[1] = static_cast<T>(Source->Direction[1]); + values[2] = static_cast<T>(Source->Direction[2]); return true; case AL_ORIENTATION: CheckSize(6); - values[0] = Source->OrientAt[0]; - values[1] = Source->OrientAt[1]; - values[2] = Source->OrientAt[2]; - values[3] = Source->OrientUp[0]; - values[4] = Source->OrientUp[1]; - values[5] = Source->OrientUp[2]; + values[0] = static_cast<T>(Source->OrientAt[0]); + values[1] = static_cast<T>(Source->OrientAt[1]); + values[2] = static_cast<T>(Source->OrientAt[2]); + values[3] = static_cast<T>(Source->OrientUp[0]); + values[4] = static_cast<T>(Source->OrientUp[1]); + values[5] = static_cast<T>(Source->OrientUp[2]); return true; - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - case AL_STEREO_MODE_SOFT: - CheckSize(1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = static_cast<double>(ivals[0]); - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source double property 0x%04x", prop); - return false; -} -catch(check_exception&) { - return false; -} - -bool GetSourceiv(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<int> values) -try { - auto CheckSize = GetSizeChecker(Context, prop, values); - double dvals[MaxValues]; - bool err; - switch(prop) - { case AL_SOURCE_RELATIVE: - CheckSize(1); - values[0] = Source->HeadRelative; - return true; + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + values[0] = Source->HeadRelative; + return true; + } + break; case AL_LOOPING: - CheckSize(1); - values[0] = Source->Looping; - return true; + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + values[0] = Source->Looping; + return true; + } + break; case AL_BUFFER: - CheckSize(1); + if constexpr(std::is_integral_v<T>) { + CheckSize(1); ALbufferQueueItem *BufferList{}; /* HACK: This query should technically only return the buffer set * on a static source. However, some apps had used it to detect @@ -2356,377 +2307,150 @@ try { BufferList = static_cast<ALbufferQueueItem*>(Current); } ALbuffer *buffer{BufferList ? BufferList->mBuffer : nullptr}; - values[0] = buffer ? static_cast<int>(buffer->id) : 0; + values[0] = buffer ? static_cast<T>(buffer->id) : T{0}; + return true; } - return true; + break; case AL_SOURCE_STATE: - CheckSize(1); - values[0] = GetSourceState(Source, GetSourceVoice(Source, Context)); - return true; + if constexpr(std::is_integral_v<T>) + { + CheckSize(1); + values[0] = GetSourceState(Source, GetSourceVoice(Source, Context)); + return true; + } + break; case AL_BUFFERS_QUEUED: - CheckSize(1); - values[0] = static_cast<int>(Source->mQueue.size()); - return true; - - case AL_BUFFERS_PROCESSED: - CheckSize(1); - if(Source->Looping || Source->SourceType != AL_STREAMING) + if constexpr(std::is_integral_v<T>) { - /* Buffers on a looping source are in a perpetual state of PENDING, - * so don't report any as PROCESSED - */ - values[0] = 0; + CheckSize(1); + values[0] = static_cast<T>(Source->mQueue.size()); + return true; } - else + break; + + case AL_BUFFERS_PROCESSED: + if constexpr(std::is_integral_v<T>) { - int played{0}; - if(Source->state != AL_INITIAL) + CheckSize(1); + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED + */ + values[0] = 0; + } + else { - const VoiceBufferItem *Current{nullptr}; - if(Voice *voice{GetSourceVoice(Source, Context)}) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - for(auto &item : Source->mQueue) + int played{0}; + if(Source->state != AL_INITIAL) { - if(&item == Current) - break; - ++played; + const VoiceBufferItem *Current{nullptr}; + if(Voice *voice{GetSourceVoice(Source, Context)}) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + for(auto &item : Source->mQueue) + { + if(&item == Current) + break; + ++played; + } } + values[0] = played; } - values[0] = played; + return true; } - return true; + break; case AL_SOURCE_TYPE: - CheckSize(1); - values[0] = Source->SourceType; - return true; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CheckSize(1); - values[0] = Source->DryGainHFAuto; - return true; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CheckSize(1); - values[0] = Source->WetGainAuto; - return true; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CheckSize(1); - values[0] = Source->WetGainHFAuto; - return true; - - case AL_DIRECT_CHANNELS_SOFT: - CheckSize(1); - values[0] = EnumFromDirectMode(Source->DirectChannels); - return true; - - case AL_DISTANCE_MODEL: - CheckSize(1); - values[0] = ALenumFromDistanceModel(Source->mDistanceModel); - return true; - - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: - CheckSize(1); - values[0] = static_cast<int>(mind(GetSourceLength(Source, prop), - std::numeric_limits<int>::max())); - return true; - - case AL_SOURCE_RESAMPLER_SOFT: - CheckSize(1); - values[0] = static_cast<int>(Source->mResampler); - return true; - - case AL_SOURCE_SPATIALIZE_SOFT: - CheckSize(1); - values[0] = EnumFromSpatializeMode(Source->mSpatialize); - return true; - - case AL_STEREO_MODE_SOFT: - CheckSize(1); - values[0] = EnumFromStereoMode(Source->mStereoMode); - return true; - - case AL_SAMPLE_RW_OFFSETS_SOFT: - if(sBufferSubDataCompat) + if constexpr(std::is_integral_v<T>) { - CheckSize(2); - const auto offset = GetSourceOffset(Source, AL_SAMPLE_OFFSET, Context); - /* FIXME: values[1] should be ahead of values[0] by the device - * update time. It needs to clamp or wrap the length of the buffer - * queue. - */ - values[0] = static_cast<int>(mind(offset, std::numeric_limits<int>::max())); - values[1] = values[0]; + CheckSize(1); + values[0] = Source->SourceType; return true; } break; - case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ - if(sBufferSubDataCompat) + + case AL_DIRECT_FILTER_GAINHF_AUTO: + if constexpr(std::is_integral_v<T>) { - CheckSize(2); - const auto offset = GetSourceOffset(Source, AL_BYTE_OFFSET, Context); - /* FIXME: values[1] should be ahead of values[0] by the device - * update time. It needs to clamp or wrap the length of the buffer - * queue. - */ - values[0] = static_cast<int>(mind(offset, std::numeric_limits<int>::max())); - values[1] = values[0]; + CheckSize(1); + values[0] = Source->DryGainHFAuto; return true; } - /*fall-through*/ - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SUPER_STEREO_WIDTH_SOFT: - CheckSize(1); - if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) - values[0] = static_cast<int>(dvals[0]); - return err; + break; - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CheckSize(3); - if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + if constexpr(std::is_integral_v<T>) { - values[0] = static_cast<int>(dvals[0]); - values[1] = static_cast<int>(dvals[1]); - values[2] = static_cast<int>(dvals[2]); + CheckSize(1); + values[0] = Source->WetGainAuto; + return true; } - return err; + break; - /* 6x float/double */ - case AL_ORIENTATION: - CheckSize(6); - if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + if constexpr(std::is_integral_v<T>) { - values[0] = static_cast<int>(dvals[0]); - values[1] = static_cast<int>(dvals[1]); - values[2] = static_cast<int>(dvals[2]); - values[3] = static_cast<int>(dvals[3]); - values[4] = static_cast<int>(dvals[4]); - values[5] = static_cast<int>(dvals[5]); + CheckSize(1); + values[0] = Source->WetGainHFAuto; + return true; } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); - return false; -} -catch(check_exception&) { - return false; -} - -bool GetSourcei64v(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, - const al::span<int64_t> values) -try { - auto CheckSize = GetSizeChecker(Context, prop, values); - ALCdevice *device{Context->mALDevice.get()}; - ClockLatency clocktime; - nanoseconds srcclock; - double dvals[MaxValues]; - int ivals[MaxValues]; - bool err; - - switch(prop) - { - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: - CheckSize(1); - values[0] = static_cast<int64_t>(GetSourceLength(Source, prop)); - return true; + break; - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - CheckSize(2); - /* Get the source offset with the clock time first. Then get the clock - * time with the device latency. Order is important. - */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { - std::lock_guard<std::mutex> _{device->StateLock}; - clocktime = GetClockLatency(device, device->Backend.get()); - } - if(srcclock == clocktime.ClockTime) - values[1] = clocktime.Latency.count(); - else + case AL_DIRECT_CHANNELS_SOFT: + if constexpr(std::is_integral_v<T>) { - /* If the clock time incremented, reduce the latency by that much - * since it's that much closer to the source offset it got earlier. - */ - const nanoseconds diff{clocktime.ClockTime - srcclock}; - values[1] = nanoseconds{clocktime.Latency - std::min(clocktime.Latency, diff)}.count(); + CheckSize(1); + values[0] = EnumFromDirectMode(Source->DirectChannels); + return true; } - return true; - - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - CheckSize(2); - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock.count(); - return true; + break; - case AL_SAMPLE_RW_OFFSETS_SOFT: - if(sBufferSubDataCompat) + case AL_DISTANCE_MODEL: + if constexpr(std::is_integral_v<T>) { - CheckSize(2); - /* FIXME: values[1] should be ahead of values[0] by the device - * update time. It needs to clamp or wrap the length of the buffer - * queue. - */ - values[0] = static_cast<int64_t>(GetSourceOffset(Source, AL_SAMPLE_OFFSET, Context)); - values[1] = values[0]; + CheckSize(1); + values[0] = ALenumFromDistanceModel(Source->mDistanceModel); return true; } break; - case AL_SOURCE_RADIUS: /*AL_BYTE_RW_OFFSETS_SOFT:*/ - if(sBufferSubDataCompat) + + case AL_SOURCE_RESAMPLER_SOFT: + if constexpr(std::is_integral_v<T>) { - CheckSize(2); - /* FIXME: values[1] should be ahead of values[0] by the device - * update time. It needs to clamp or wrap the length of the buffer - * queue. - */ - values[0] = static_cast<int64_t>(GetSourceOffset(Source, AL_BYTE_OFFSET, Context)); - values[1] = values[0]; + CheckSize(1); + values[0] = static_cast<T>(Source->mResampler); return true; } - /*fall-through*/ - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SUPER_STEREO_WIDTH_SOFT: - CheckSize(1); - if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) - values[0] = static_cast<int64_t>(dvals[0]); - return err; + break; - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CheckSize(3); - if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) + case AL_SOURCE_SPATIALIZE_SOFT: + if constexpr(std::is_integral_v<T>) { - values[0] = static_cast<int64_t>(dvals[0]); - values[1] = static_cast<int64_t>(dvals[1]); - values[2] = static_cast<int64_t>(dvals[2]); + CheckSize(1); + values[0] = EnumFromSpatializeMode(Source->mSpatialize); + return true; } - return err; + break; - /* 6x float/double */ - case AL_ORIENTATION: - CheckSize(6); - if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) + case AL_STEREO_MODE_SOFT: + if constexpr(std::is_integral_v<T>) { - values[0] = static_cast<int64_t>(dvals[0]); - values[1] = static_cast<int64_t>(dvals[1]); - values[2] = static_cast<int64_t>(dvals[2]); - values[3] = static_cast<int64_t>(dvals[3]); - values[4] = static_cast<int64_t>(dvals[4]); - values[5] = static_cast<int64_t>(dvals[5]); + CheckSize(1); + values[0] = EnumFromStereoMode(Source->mStereoMode); + return true; } - return err; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - case AL_STEREO_MODE_SOFT: - CheckSize(1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = ivals[0]; - return err; + break; - /* 1x uint */ - case AL_BUFFER: case AL_DIRECT_FILTER: - CheckSize(1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = static_cast<ALuint>(ivals[0]); - return err; - - /* 3x uint */ case AL_AUXILIARY_SEND_FILTER: - CheckSize(3); - if((err=GetSourceiv(Source, Context, prop, {ivals, 3u})) != false) - { - values[0] = static_cast<ALuint>(ivals[0]); - values[1] = static_cast<ALuint>(ivals[1]); - values[2] = static_cast<ALuint>(ivals[2]); - } - return err; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ + break; } - ERR("Unexpected property: 0x%04x\n", prop); - Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); + ERR("Unexpected %s query property: 0x%04x\n", PropType<T>::Name(), prop); + Context->setError(AL_INVALID_ENUM, "Invalid source %s query property 0x%04x", + PropType<T>::Name(), prop); return false; } catch(check_exception&) { @@ -2905,12 +2629,9 @@ void StartSources(ALCcontext *const context, const al::span<ALsource*> srchandle } // namespace -AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alGenSources, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alGenSourcesDirect(ALCcontext *context, ALsizei n, ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Generating %d sources", n); if(n <= 0) UNLIKELY return; @@ -2923,7 +2644,7 @@ START_API_FUNC device->SourcesMax, context->mNumSources, n); return; } - if(!EnsureSources(context.get(), static_cast<ALuint>(n))) + if(!EnsureSources(context, static_cast<ALuint>(n))) { context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d source%s", n, (n==1)?"":"s"); return; @@ -2931,36 +2652,33 @@ START_API_FUNC if(n == 1) { - ALsource *source{AllocSource(context.get())}; + ALsource *source{AllocSource(context)}; sources[0] = source->id; #ifdef ALSOFT_EAX - source->eaxInitialize(context.get()); + source->eaxInitialize(context); #endif // ALSOFT_EAX } else { - al::vector<ALuint> ids; + std::vector<ALuint> ids; ids.reserve(static_cast<ALuint>(n)); do { - ALsource *source{AllocSource(context.get())}; + ALsource *source{AllocSource(context)}; ids.emplace_back(source->id); #ifdef ALSOFT_EAX - source->eaxInitialize(context.get()); + source->eaxInitialize(context); #endif // ALSOFT_EAX } while(--n); std::copy(ids.cbegin(), ids.cend(), sources); } } -END_API_FUNC -AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alDeleteSources, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alDeleteSourcesDirect(ALCcontext *context, ALsizei n, + const ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Deleting %d sources", n); if(n <= 0) UNLIKELY return; @@ -2968,8 +2686,8 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; /* Check that all Sources are valid */ - auto validate_source = [&context](const ALuint sid) -> bool - { return LookupSource(context.get(), sid) != nullptr; }; + auto validate_source = [context](const ALuint sid) -> bool + { return LookupSource(context, sid) != nullptr; }; const ALuint *sources_end = sources + n; auto invsrc = std::find_if_not(sources, sources_end, validate_source); @@ -2979,577 +2697,462 @@ START_API_FUNC /* All good. Delete source IDs. */ auto delete_source = [&context](const ALuint sid) -> void { - ALsource *src{LookupSource(context.get(), sid)}; - if(src) FreeSource(context.get(), src); + ALsource *src{LookupSource(context, sid)}; + if(src) FreeSource(context, src); }; std::for_each(sources, sources_end, delete_source); } -END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsSource, ALuint) +FORCE_ALIGN ALboolean AL_APIENTRY alIsSourceDirect(ALCcontext *context, ALuint source) noexcept { - ContextRef context{GetContextRef()}; - if(context) LIKELY - { - std::lock_guard<std::mutex> _{context->mSourceLock}; - if(LookupSource(context.get(), source) != nullptr) - return AL_TRUE; - } + std::lock_guard<std::mutex> _{context->mSourceLock}; + if(LookupSource(context, source) != nullptr) + return AL_TRUE; return AL_FALSE; } -END_API_FUNC -AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourcef, ALuint, ALenum, ALfloat) +FORCE_ALIGN void AL_APIENTRY alSourcefDirect(ALCcontext *context, ALuint source, ALenum param, + ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + SetProperty<float>(Source, context, static_cast<SourceProp>(param), al::span{&value, 1u}); } -END_API_FUNC -AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +FORCE_ALIGN void AL_APIENTRY alSource3fDirect(ALCcontext *context, ALuint source, ALenum param, + ALfloat value1, ALfloat value2, ALfloat value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - { - const float fvals[3]{ value1, value2, value3 }; - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + const float fvals[3]{ value1, value2, value3 }; + SetProperty<float>(Source, context, static_cast<SourceProp>(param), al::span{fvals}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourcefv, ALuint, ALenum, const ALfloat*) +FORCE_ALIGN void AL_APIENTRY alSourcefvDirect(ALCcontext *context, ALuint source, ALenum param, + const ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{FloatValsByProp(param)}; - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + SetProperty(Source, context, static_cast<SourceProp>(param), al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alSourced,SOFT, ALuint, ALenum, ALdouble) +FORCE_ALIGN void AL_APIENTRY alSourcedDirectSOFT(ALCcontext *context, ALuint source, ALenum param, + ALdouble value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - { - const float fval[1]{static_cast<float>(value)}; - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fval); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + SetProperty<double>(Source, context, static_cast<SourceProp>(param), al::span{&value, 1}); } -END_API_FUNC -AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alSource3d,SOFT, ALuint, ALenum, ALdouble, ALdouble, ALdouble) +FORCE_ALIGN void AL_APIENTRY alSource3dDirectSOFT(ALCcontext *context, ALuint source, ALenum param, + ALdouble value1, ALdouble value2, ALdouble value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - { - const float fvals[3]{static_cast<float>(value1), static_cast<float>(value2), - static_cast<float>(value3)}; - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + const double dvals[3]{value1, value2, value3}; + SetProperty<double>(Source, context, static_cast<SourceProp>(param), al::span{dvals}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alSourcedv,SOFT, ALuint, ALenum, const ALdouble*) +FORCE_ALIGN void AL_APIENTRY alSourcedvDirectSOFT(ALCcontext *context, ALuint source, ALenum param, + const ALdouble *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{DoubleValsByProp(param)}; - float fvals[MaxValues]; - std::copy_n(values, count, fvals); - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {fvals, count}); + SetProperty(Source, context, static_cast<SourceProp>(param), al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourcei, ALuint, ALenum, ALint) +FORCE_ALIGN void AL_APIENTRY alSourceiDirect(ALCcontext *context, ALuint source, ALenum param, + ALint value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + SetProperty<int>(Source, context, static_cast<SourceProp>(param), al::span{&value, 1u}); } -END_API_FUNC -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint) +FORCE_ALIGN void AL_APIENTRY alSource3iDirect(ALCcontext *context, ALuint source, ALenum param, + ALint value1, ALint value2, ALint value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - { - const int ivals[3]{ value1, value2, value3 }; - SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + const int ivals[3]{ value1, value2, value3 }; + SetProperty<int>(Source, context, static_cast<SourceProp>(param), al::span{ivals}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourceiv, ALuint, ALenum, const ALint*) +FORCE_ALIGN void AL_APIENTRY alSourceivDirect(ALCcontext *context, ALuint source, ALenum param, + const ALint *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source = LookupSource(context.get(), source); + ALsource *Source = LookupSource(context, source); if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{IntValsByProp(param)}; - SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + SetProperty(Source, context, static_cast<SourceProp>(param), al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alSourcei64,SOFT, ALuint, ALenum, ALint64SOFT) +FORCE_ALIGN void AL_APIENTRY alSourcei64DirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALint64SOFT value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + SetProperty<int64_t>(Source, context, static_cast<SourceProp>(param), al::span{&value, 1u}); } -END_API_FUNC -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alSource3i64,SOFT, ALuint, ALenum, ALint64SOFT, ALint64SOFT, ALint64SOFT) +FORCE_ALIGN void AL_APIENTRY alSource3i64DirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else - { - const int64_t i64vals[3]{ value1, value2, value3 }; - SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + + const int64_t i64vals[3]{ value1, value2, value3 }; + SetProperty<int64_t>(Source, context, static_cast<SourceProp>(param), al::span{i64vals}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alSourcei64v,SOFT, ALuint, ALenum, const ALint64SOFT*) +FORCE_ALIGN void AL_APIENTRY alSourcei64vDirectSOFT(ALCcontext *context, ALuint source, + ALenum param, const ALint64SOFT *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; std::lock_guard<std::mutex> __{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{Int64ValsByProp(param)}; - SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + SetProperty(Source, context, static_cast<SourceProp>(param), al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetSourcef, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetSourcefDirect(ALCcontext *context, ALuint source, ALenum param, + ALfloat *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else - { - double dval[1]; - if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dval)) - *value = static_cast<float>(dval[0]); - } + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!value) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), al::span{value, 1}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetSource3fDirect(ALCcontext *context, ALuint source, ALenum param, + ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!(value1 && value2 && value3)) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + float fvals[3]; + if(GetProperty<float>(Source, context, static_cast<SourceProp>(param), al::span{fvals})) { - double dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals)) - { - *value1 = static_cast<float>(dvals[0]); - *value2 = static_cast<float>(dvals[1]); - *value3 = static_cast<float>(dvals[2]); - } + *value1 = fvals[0]; + *value2 = fvals[1]; + *value3 = fvals[2]; } } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetSourcefv, ALuint, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetSourcefvDirect(ALCcontext *context, ALuint source, ALenum param, + ALfloat *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{FloatValsByProp(param)}; - double dvals[MaxValues]; - if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {dvals, count})) - std::copy_n(dvals, count, values); + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), + al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetSourced,SOFT, ALuint, ALenum, ALdouble*) +FORCE_ALIGN void AL_APIENTRY alGetSourcedDirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALdouble *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else - GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!value) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), al::span{value, 1}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alGetSource3d,SOFT, ALuint, ALenum, ALdouble*, ALdouble*, ALdouble*) +FORCE_ALIGN void AL_APIENTRY alGetSource3dDirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!(value1 && value2 && value3)) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + double dvals[3]; + if(GetProperty<double>(Source, context, static_cast<SourceProp>(param), al::span{dvals})) { - double dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; } } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetSourcedv,SOFT, ALuint, ALenum, ALdouble*) +FORCE_ALIGN void AL_APIENTRY alGetSourcedvDirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALdouble *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{DoubleValsByProp(param)}; - GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), + al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetSourcei, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetSourceiDirect(ALCcontext *context, ALuint source, ALenum param, + ALint *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else - GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!value) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), al::span{value, 1}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC +AL_API DECL_FUNC5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetSource3iDirect(ALCcontext *context, ALuint source, ALenum param, + ALint *value1, ALint *value2, ALint *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!(value1 && value2 && value3)) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + int ivals[3]; + if(GetProperty<int>(Source, context, static_cast<SourceProp>(param), al::span{ivals})) { - int ivals[3]; - if(GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; } } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) -START_API_FUNC +AL_API DECL_FUNC3(void, alGetSourceiv, ALuint, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetSourceivDirect(ALCcontext *context, ALuint source, ALenum param, + ALint *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{IntValsByProp(param)}; - GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), + al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetSourcei64,SOFT, ALuint, ALenum, ALint64SOFT*) +FORCE_ALIGN void AL_APIENTRY alGetSourcei64DirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT *value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else - GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {value, 1u}); + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!value) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), al::span{value, 1}); } -END_API_FUNC -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) -START_API_FUNC +AL_API DECL_FUNCEXT5(void, alGetSource3i64,SOFT, ALuint, ALenum, ALint64SOFT*, ALint64SOFT*, ALint64SOFT*) +FORCE_ALIGN void AL_APIENTRY alGetSource3i64DirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY - context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) UNLIKELY - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); + if(!(value1 && value2 && value3)) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + int64_t i64vals[3]; + if(GetProperty<int64_t>(Source, context, static_cast<SourceProp>(param), al::span{i64vals})) { - int64_t i64vals[3]; - if(GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; } } -END_API_FUNC -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alGetSourcei64v,SOFT, ALuint, ALenum, ALint64SOFT*) +FORCE_ALIGN void AL_APIENTRY alGetSourcei64vDirectSOFT(ALCcontext *context, ALuint source, + ALenum param, ALint64SOFT *values) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + ALsource *Source{LookupSource(context, source)}; if(!Source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); if(!values) UNLIKELY return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{Int64ValsByProp(param)}; - GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {values, count}); + std::ignore = GetProperty(Source, context, static_cast<SourceProp>(param), + al::span{values, count}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcePlay(ALuint source) -START_API_FUNC +AL_API DECL_FUNC1(void, alSourcePlay, ALuint) +FORCE_ALIGN void AL_APIENTRY alSourcePlayDirect(ALCcontext *context, ALuint source) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *srchandle{LookupSource(context.get(), source)}; + ALsource *srchandle{LookupSource(context, source)}; if(!srchandle) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - StartSources(context.get(), {&srchandle, 1}); + StartSources(context, {&srchandle, 1}); } -END_API_FUNC -void AL_APIENTRY alSourcePlayAtTimeSOFT(ALuint source, ALint64SOFT start_time) -START_API_FUNC +FORCE_ALIGN DECL_FUNCEXT2(void, alSourcePlayAtTime,SOFT, ALuint, ALint64SOFT) +FORCE_ALIGN void AL_APIENTRY alSourcePlayAtTimeDirectSOFT(ALCcontext *context, ALuint source, + ALint64SOFT start_time) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(start_time < 0) UNLIKELY return context->setError(AL_INVALID_VALUE, "Invalid time point %" PRId64, start_time); std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *srchandle{LookupSource(context.get(), source)}; + ALsource *srchandle{LookupSource(context, source)}; if(!srchandle) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - StartSources(context.get(), {&srchandle, 1}, nanoseconds{start_time}); + StartSources(context, {&srchandle, 1}, nanoseconds{start_time}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alSourcePlayv, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourcePlayvDirect(ALCcontext *context, ALsizei n, + const ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Playing %d sources", n); if(n <= 0) UNLIKELY return; - al::vector<ALsource*> extra_sources; + std::vector<ALsource*> extra_sources; std::array<ALsource*,8> source_storage; al::span<ALsource*> srchandles; if(static_cast<ALuint>(n) <= source_storage.size()) LIKELY - srchandles = {source_storage.data(), static_cast<ALuint>(n)}; + srchandles = al::span{source_storage}.first(static_cast<ALuint>(n)); else { extra_sources.resize(static_cast<ALuint>(n)); - srchandles = {extra_sources.data(), extra_sources.size()}; + srchandles = extra_sources; } std::lock_guard<std::mutex> _{context->mSourceLock}; for(auto &srchdl : srchandles) { - srchdl = LookupSource(context.get(), *sources); + srchdl = LookupSource(context, *sources); if(!srchdl) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", *sources); ++sources; } - StartSources(context.get(), srchandles); + StartSources(context, srchandles); } -END_API_FUNC -void AL_APIENTRY alSourcePlayAtTimevSOFT(ALsizei n, const ALuint *sources, ALint64SOFT start_time) -START_API_FUNC +FORCE_ALIGN DECL_FUNCEXT3(void, alSourcePlayAtTimev,SOFT, ALsizei, const ALuint*, ALint64SOFT) +FORCE_ALIGN void AL_APIENTRY alSourcePlayAtTimevDirectSOFT(ALCcontext *context, ALsizei n, + const ALuint *sources, ALint64SOFT start_time) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Playing %d sources", n); if(n <= 0) UNLIKELY return; @@ -3557,61 +3160,57 @@ START_API_FUNC if(start_time < 0) UNLIKELY return context->setError(AL_INVALID_VALUE, "Invalid time point %" PRId64, start_time); - al::vector<ALsource*> extra_sources; + std::vector<ALsource*> extra_sources; std::array<ALsource*,8> source_storage; al::span<ALsource*> srchandles; if(static_cast<ALuint>(n) <= source_storage.size()) LIKELY - srchandles = {source_storage.data(), static_cast<ALuint>(n)}; + srchandles = al::span{source_storage}.first(static_cast<ALuint>(n)); else { extra_sources.resize(static_cast<ALuint>(n)); - srchandles = {extra_sources.data(), extra_sources.size()}; + srchandles = extra_sources; } std::lock_guard<std::mutex> _{context->mSourceLock}; for(auto &srchdl : srchandles) { - srchdl = LookupSource(context.get(), *sources); + srchdl = LookupSource(context, *sources); if(!srchdl) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", *sources); ++sources; } - StartSources(context.get(), srchandles, nanoseconds{start_time}); + StartSources(context, srchandles, nanoseconds{start_time}); } -END_API_FUNC -AL_API void AL_APIENTRY alSourcePause(ALuint source) -START_API_FUNC -{ alSourcePausev(1, &source); } -END_API_FUNC +AL_API DECL_FUNC1(void, alSourcePause, ALuint) +FORCE_ALIGN void AL_APIENTRY alSourcePauseDirect(ALCcontext *context, ALuint source) noexcept +{ alSourcePausevDirect(context, 1, &source); } -AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alSourcePausev, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourcePausevDirect(ALCcontext *context, ALsizei n, + const ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Pausing %d sources", n); if(n <= 0) UNLIKELY return; - al::vector<ALsource*> extra_sources; + std::vector<ALsource*> extra_sources; std::array<ALsource*,8> source_storage; al::span<ALsource*> srchandles; if(static_cast<ALuint>(n) <= source_storage.size()) LIKELY - srchandles = {source_storage.data(), static_cast<ALuint>(n)}; + srchandles = al::span{source_storage}.first(static_cast<ALuint>(n)); else { extra_sources.resize(static_cast<ALuint>(n)); - srchandles = {extra_sources.data(), extra_sources.size()}; + srchandles = extra_sources; } std::lock_guard<std::mutex> _{context->mSourceLock}; for(auto &srchdl : srchandles) { - srchdl = LookupSource(context.get(), *sources); + srchdl = LookupSource(context, *sources); if(!srchdl) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", *sources); ++sources; @@ -3624,14 +3223,14 @@ START_API_FUNC VoiceChange *tail{}, *cur{}; for(ALsource *source : srchandles) { - Voice *voice{GetSourceVoice(source, context.get())}; + Voice *voice{GetSourceVoice(source, context)}; if(GetSourceState(source, voice) == AL_PLAYING) { if(!cur) - cur = tail = GetVoiceChanger(context.get()); + cur = tail = GetVoiceChanger(context); else { - cur->mNext.store(GetVoiceChanger(context.get()), std::memory_order_relaxed); + cur->mNext.store(GetVoiceChanger(context), std::memory_order_relaxed); cur = cur->mNext.load(std::memory_order_relaxed); } cur->mVoice = voice; @@ -3641,7 +3240,7 @@ START_API_FUNC } if(tail) LIKELY { - SendVoiceChanges(context.get(), tail); + SendVoiceChanges(context, tail); /* Second, now that the voice changes have been sent, because it's * possible that the voice stopped after it was detected playing and * before the voice got paused, recheck that the source is still @@ -3649,45 +3248,41 @@ START_API_FUNC */ for(ALsource *source : srchandles) { - Voice *voice{GetSourceVoice(source, context.get())}; + Voice *voice{GetSourceVoice(source, context)}; if(GetSourceState(source, voice) == AL_PLAYING) source->state = AL_PAUSED; } } } -END_API_FUNC -AL_API void AL_APIENTRY alSourceStop(ALuint source) -START_API_FUNC -{ alSourceStopv(1, &source); } -END_API_FUNC +AL_API DECL_FUNC1(void, alSourceStop, ALuint) +FORCE_ALIGN void AL_APIENTRY alSourceStopDirect(ALCcontext *context, ALuint source) noexcept +{ alSourceStopvDirect(context, 1, &source); } -AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alSourceStopv, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourceStopvDirect(ALCcontext *context, ALsizei n, + const ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Stopping %d sources", n); if(n <= 0) UNLIKELY return; - al::vector<ALsource*> extra_sources; + std::vector<ALsource*> extra_sources; std::array<ALsource*,8> source_storage; al::span<ALsource*> srchandles; if(static_cast<ALuint>(n) <= source_storage.size()) LIKELY - srchandles = {source_storage.data(), static_cast<ALuint>(n)}; + srchandles = al::span{source_storage}.first(static_cast<ALuint>(n)); else { extra_sources.resize(static_cast<ALuint>(n)); - srchandles = {extra_sources.data(), extra_sources.size()}; + srchandles = extra_sources; } std::lock_guard<std::mutex> _{context->mSourceLock}; for(auto &srchdl : srchandles) { - srchdl = LookupSource(context.get(), *sources); + srchdl = LookupSource(context, *sources); if(!srchdl) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", *sources); ++sources; @@ -3696,13 +3291,13 @@ START_API_FUNC VoiceChange *tail{}, *cur{}; for(ALsource *source : srchandles) { - if(Voice *voice{GetSourceVoice(source, context.get())}) + if(Voice *voice{GetSourceVoice(source, context)}) { if(!cur) - cur = tail = GetVoiceChanger(context.get()); + cur = tail = GetVoiceChanger(context); else { - cur->mNext.store(GetVoiceChanger(context.get()), std::memory_order_relaxed); + cur->mNext.store(GetVoiceChanger(context), std::memory_order_relaxed); cur = cur->mNext.load(std::memory_order_relaxed); } voice->mPendingChange.store(true, std::memory_order_relaxed); @@ -3713,44 +3308,40 @@ START_API_FUNC } source->Offset = 0.0; source->OffsetType = AL_NONE; - source->VoiceIdx = INVALID_VOICE_IDX; + source->VoiceIdx = InvalidVoiceIndex; } if(tail) LIKELY - SendVoiceChanges(context.get(), tail); + SendVoiceChanges(context, tail); } -END_API_FUNC -AL_API void AL_APIENTRY alSourceRewind(ALuint source) -START_API_FUNC -{ alSourceRewindv(1, &source); } -END_API_FUNC +AL_API DECL_FUNC1(void, alSourceRewind, ALuint) +FORCE_ALIGN void AL_APIENTRY alSourceRewindDirect(ALCcontext *context, ALuint source) noexcept +{ alSourceRewindvDirect(context, 1, &source); } -AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) -START_API_FUNC +AL_API DECL_FUNC2(void, alSourceRewindv, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourceRewindvDirect(ALCcontext *context, ALsizei n, + const ALuint *sources) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(n < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Rewinding %d sources", n); if(n <= 0) UNLIKELY return; - al::vector<ALsource*> extra_sources; + std::vector<ALsource*> extra_sources; std::array<ALsource*,8> source_storage; al::span<ALsource*> srchandles; if(static_cast<ALuint>(n) <= source_storage.size()) LIKELY - srchandles = {source_storage.data(), static_cast<ALuint>(n)}; + srchandles = al::span{source_storage}.first(static_cast<ALuint>(n)); else { extra_sources.resize(static_cast<ALuint>(n)); - srchandles = {extra_sources.data(), extra_sources.size()}; + srchandles = extra_sources; } std::lock_guard<std::mutex> _{context->mSourceLock}; for(auto &srchdl : srchandles) { - srchdl = LookupSource(context.get(), *sources); + srchdl = LookupSource(context, *sources); if(!srchdl) return context->setError(AL_INVALID_NAME, "Invalid source ID %u", *sources); ++sources; @@ -3759,14 +3350,14 @@ START_API_FUNC VoiceChange *tail{}, *cur{}; for(ALsource *source : srchandles) { - Voice *voice{GetSourceVoice(source, context.get())}; + Voice *voice{GetSourceVoice(source, context)}; if(source->state != AL_INITIAL) { if(!cur) - cur = tail = GetVoiceChanger(context.get()); + cur = tail = GetVoiceChanger(context); else { - cur->mNext.store(GetVoiceChanger(context.get()), std::memory_order_relaxed); + cur->mNext.store(GetVoiceChanger(context), std::memory_order_relaxed); cur = cur->mNext.load(std::memory_order_relaxed); } if(voice) @@ -3778,26 +3369,23 @@ START_API_FUNC } source->Offset = 0.0; source->OffsetType = AL_NONE; - source->VoiceIdx = INVALID_VOICE_IDX; + source->VoiceIdx = InvalidVoiceIndex; } if(tail) LIKELY - SendVoiceChanges(context.get(), tail); + SendVoiceChanges(context, tail); } -END_API_FUNC -AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourceQueueBuffersDirect(ALCcontext *context, ALuint src, + ALsizei nb, const ALuint *buffers) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(nb < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Queueing %d buffers", nb); if(nb <= 0) UNLIKELY return; std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *source{LookupSource(context.get(),src)}; + ALsource *source{LookupSource(context,src)}; if(!source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", src); @@ -3912,20 +3500,17 @@ START_API_FUNC (iter-1)->mNext.store(al::to_address(iter), std::memory_order_release); } } -END_API_FUNC -AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) -START_API_FUNC +AL_API DECL_FUNC3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*) +FORCE_ALIGN void AL_APIENTRY alSourceUnqueueBuffersDirect(ALCcontext *context, ALuint src, + ALsizei nb, ALuint *buffers) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(nb < 0) UNLIKELY context->setError(AL_INVALID_VALUE, "Unqueueing %d buffers", nb); if(nb <= 0) UNLIKELY return; std::lock_guard<std::mutex> _{context->mSourceLock}; - ALsource *source{LookupSource(context.get(),src)}; + ALsource *source{LookupSource(context,src)}; if(!source) UNLIKELY return context->setError(AL_INVALID_NAME, "Invalid source ID %u", src); @@ -3940,7 +3525,7 @@ START_API_FUNC if(source->state != AL_INITIAL) LIKELY { VoiceBufferItem *Current{nullptr}; - if(Voice *voice{GetSourceVoice(source, context.get())}) + if(Voice *voice{GetSourceVoice(source, context)}) Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); for(auto &item : source->mQueue) { @@ -3965,18 +3550,15 @@ START_API_FUNC source->mQueue.pop_front(); } while(--nb); } -END_API_FUNC -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint, ALsizei, const ALuint*) -START_API_FUNC +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint, ALsizei, const ALuint*) noexcept { ContextRef context{GetContextRef()}; if(!context) UNLIKELY return; context->setError(AL_INVALID_OPERATION, "alSourceQueueBufferLayersSOFT not supported"); } -END_API_FUNC ALsource::ALsource() @@ -4028,14 +3610,29 @@ void UpdateAllSourceProps(ALCcontext *context) } } +void ALsource::SetName(ALCcontext *context, ALuint id, std::string_view name) +{ + std::lock_guard<std::mutex> _{context->mSourceLock}; + + auto source = LookupSource(context, id); + if(!source) UNLIKELY + return context->setError(AL_INVALID_NAME, "Invalid source ID %u", id); + + context->mSourceNames.insert_or_assign(id, name); +} + + SourceSubList::~SourceSubList() { + if(!Sources) + return; + uint64_t usemask{~FreeMask}; while(usemask) { const int idx{al::countr_zero(usemask)}; usemask &= ~(1_u64 << idx); - al::destroy_at(Sources+idx); + std::destroy_at(Sources+idx); } FreeMask = ~usemask; al_free(Sources); @@ -4097,7 +3694,8 @@ ALsource* ALsource::EaxLookupSource(ALCcontext& al_context, ALuint source_id) no void ALsource::eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept { - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) + { auto& send = sends[i]; send.guidReceivingFXSlotID = *(ids[i]); send.lSend = EAXSOURCE_DEFAULTSEND; @@ -4209,7 +3807,8 @@ void ALsource::eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noex void ALsource::eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept { - for (auto i = size_t{}; i < eax_max_speakers; ++i) { + for(size_t i{0};i < eax_max_speakers;++i) + { auto& speaker_level = speaker_levels[i]; speaker_level.lSpeakerID = static_cast<long>(EAXSPEAKER_FRONT_LEFT + i); speaker_level.lLevel = EAXSOURCE_DEFAULTSPEAKERLEVEL; @@ -4251,7 +3850,7 @@ void ALsource::eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept else { dst.source.ulFlags &= ~EAXSOURCEFLAGS_ROOMAUTO; - dst.sends[0].lSend = clamp(static_cast<long>(gain_to_level_mb(src.fMix)), + dst.sends[0].lSend = std::clamp(static_cast<long>(gain_to_level_mb(src.fMix)), EAXSOURCE_MINSEND, EAXSOURCE_MAXSEND); } } @@ -4280,7 +3879,7 @@ void ALsource::eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept dst.source.ulFlags = src.dwFlags; dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; - // Set everyting else to defaults. + // Set everything else to defaults. // eax5_set_sends_defaults(dst.sends); eax5_set_active_fx_slots_defaults(dst.active_fx_slots); @@ -4294,7 +3893,7 @@ void ALsource::eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept static_cast<Eax3Props&>(dst.source) = src; dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; - // Set everyting else to defaults. + // Set everything else to defaults. // eax5_set_sends_defaults(dst.sends); eax5_set_active_fx_slots_defaults(dst.active_fx_slots); @@ -4312,7 +3911,7 @@ void ALsource::eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept // dst.sends = src.sends; - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) dst.sends[i].guidReceivingFXSlotID = *(eax5_fx_slot_ids[i]); // Active FX slots. @@ -4374,19 +3973,21 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept static_cast<float>(mEax.source.lDirectHF) + static_cast<float>(mEax.source.lObstruction); - for (auto i = std::size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) { if(!mEaxActiveFxSlots[i]) continue; - if(has_source_occlusion) { + if(has_source_occlusion) + { const auto& fx_slot = mEaxAlContext->eaxGetFxSlot(i); const auto& fx_slot_eax = fx_slot.eax_get_eax_fx_slot(); const auto is_environmental_fx = ((fx_slot_eax.ulFlags & EAXFXSLOTFLAGS_ENVIRONMENT) != 0); const auto is_primary = (mEaxPrimaryFxSlotId.value_or(-1) == fx_slot.eax_get_index()); const auto is_listener_environment = (is_environmental_fx && is_primary); - if(is_listener_environment) { + if(is_listener_environment) + { gain_mb += eax_calculate_dst_occlusion_mb( mEax.source.lOcclusion, mEax.source.flOcclusionDirectRatio, @@ -4398,7 +3999,8 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept const auto& send = mEax.sends[i]; - if(send.lOcclusion != 0) { + if(send.lOcclusion != 0) + { gain_mb += eax_calculate_dst_occlusion_mb( send.lOcclusion, send.flOcclusionDirectRatio, @@ -4473,8 +4075,9 @@ void ALsource::eax_update_direct_filter() void ALsource::eax_update_room_filters() { - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { - if (!mEaxActiveFxSlots[i]) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) + { + if(!mEaxActiveFxSlots[i]) continue; auto& fx_slot = mEaxAlContext->eaxGetFxSlot(i); @@ -4486,7 +4089,7 @@ void ALsource::eax_update_room_filters() void ALsource::eax_set_efx_outer_gain_hf() { - OuterGainHF = clamp( + OuterGainHF = std::clamp( level_mb_to_gain(static_cast<float>(mEax.source.lOutsideVolumeHF)), AL_MIN_CONE_OUTER_GAINHF, AL_MAX_CONE_OUTER_GAINHF); @@ -5280,7 +4883,7 @@ void ALsource::eax_commit_active_fx_slots() // Deactivate EFX auxiliary effect slots for inactive slots. Active slots // will be updated with the room filters. - for(auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) { if(!mEaxActiveFxSlots[i]) eax_set_al_source_send(nullptr, i, EaxAlLowPassParam{1.0f, 1.0f}); diff --git a/al/source.h b/al/source.h index ac97c8a7..c7694f83 100644 --- a/al/source.h +++ b/al/source.h @@ -4,9 +4,10 @@ #include <array> #include <atomic> #include <cstddef> +#include <deque> #include <iterator> #include <limits> -#include <deque> +#include <string_view> #include "AL/al.h" #include "AL/alc.h" @@ -14,7 +15,6 @@ #include "alc/alu.h" #include "alc/context.h" #include "alc/inprogext.h" -#include "aldeque.h" #include "almalloc.h" #include "alnumeric.h" #include "atomic.h" @@ -39,9 +39,9 @@ enum class SourceStereo : bool { #define DEFAULT_SENDS 2 -#define INVALID_VOICE_IDX static_cast<ALuint>(-1) +inline constexpr ALuint InvalidVoiceIndex{std::numeric_limits<ALuint>::max()}; -extern bool sBufferSubDataCompat; +inline bool sBufferSubDataCompat{false}; struct ALbufferQueueItem : public VoiceBufferItem { ALbuffer *mBuffer{nullptr}; @@ -138,14 +138,14 @@ struct ALsource { ALenum state{AL_INITIAL}; /** Source Buffer Queue head. */ - al::deque<ALbufferQueueItem> mQueue; + std::deque<ALbufferQueueItem> mQueue; bool mPropsDirty{true}; /* Index into the context's Voices array. Lazily updated, only checked and * reset when looking up the voice. */ - ALuint VoiceIdx{INVALID_VOICE_IDX}; + ALuint VoiceIdx{InvalidVoiceIndex}; /** Self ID */ ALuint id{0}; @@ -157,6 +157,8 @@ struct ALsource { ALsource(const ALsource&) = delete; ALsource& operator=(const ALsource&) = delete; + static void SetName(ALCcontext *context, ALuint id, std::string_view name); + DISABLE_ALLOC() #ifdef ALSOFT_EAX diff --git a/al/state.cpp b/al/state.cpp index 86d81b13..5131edd9 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -24,7 +24,9 @@ #include <atomic> #include <cmath> +#include <cstring> #include <mutex> +#include <optional> #include <stdexcept> #include <string> @@ -32,16 +34,18 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "al/debug.h" +#include "albit.h" #include "alc/alu.h" #include "alc/context.h" #include "alc/inprogext.h" #include "alnumeric.h" -#include "aloptional.h" #include "atomic.h" #include "core/context.h" #include "core/except.h" #include "core/mixer/defs.h" #include "core/voice.h" +#include "direct_defs.h" #include "intrusive_ptr.h" #include "opthelpers.h" #include "strutils.h" @@ -67,6 +71,8 @@ constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; constexpr ALchar alErrInvalidValue[] = "Invalid Value"; constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; +constexpr ALchar alStackOverflow[] = "Stack Overflow"; +constexpr ALchar alStackUnderflow[] = "Stack Underflow"; /* Resampler strings */ template<Resampler rtype> struct ResamplerName { }; @@ -103,7 +109,7 @@ const ALchar *GetResamplerName(const Resampler rtype) throw std::runtime_error{"Unexpected resampler index"}; } -al::optional<DistanceModel> DistanceModelFromALenum(ALenum model) +std::optional<DistanceModel> DistanceModelFromALenum(ALenum model) { switch(model) { @@ -115,7 +121,7 @@ al::optional<DistanceModel> DistanceModelFromALenum(ALenum model) case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent; case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped; } - return al::nullopt; + return std::nullopt; } ALenum ALenumFromDistanceModel(DistanceModel model) { @@ -132,626 +138,352 @@ ALenum ALenumFromDistanceModel(DistanceModel model) throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))}; } -} // namespace - -/* WARNING: Non-standard export! Not part of any extension, or exposed in the - * alcFunctions list. - */ -AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) -START_API_FUNC -{ - static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION"); - if(spoof) return spoof->c_str(); - return ALSOFT_VERSION; -} -END_API_FUNC - -#define DO_UPDATEPROPS() do { \ - if(!context->mDeferUpdates) \ - UpdateContextProps(context.get()); \ - else \ - context->mPropsDirty = true; \ -} while(0) - - -AL_API void AL_APIENTRY alEnable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - { - std::lock_guard<std::mutex> _{context->mPropLock}; - context->mSourceDistanceModel = true; - DO_UPDATEPROPS(); - } - break; - - case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: - context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported"); - break; - - default: - context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alDisable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - { - std::lock_guard<std::mutex> _{context->mPropLock}; - context->mSourceDistanceModel = false; - DO_UPDATEPROPS(); - } - break; - - case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: - context->mStopVoicesOnDisconnect = false; - break; - - default: - context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return AL_FALSE; - - std::lock_guard<std::mutex> _{context->mPropLock}; - ALboolean value{AL_FALSE}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE; - break; - - case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: - value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE; - break; - - default: - context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); - } - - return value; -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) -START_API_FUNC +enum PropertyValue : ALenum { + DopplerFactor = AL_DOPPLER_FACTOR, + DopplerVelocity = AL_DOPPLER_VELOCITY, + DistanceModel = AL_DISTANCE_MODEL, + SpeedOfSound = AL_SPEED_OF_SOUND, + DeferredUpdates = AL_DEFERRED_UPDATES_SOFT, + GainLimit = AL_GAIN_LIMIT_SOFT, + NumResamplers = AL_NUM_RESAMPLERS_SOFT, + DefaultResampler = AL_DEFAULT_RESAMPLER_SOFT, + DebugLoggedMessages = AL_DEBUG_LOGGED_MESSAGES_EXT, + DebugNextLoggedMessageLength = AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT, + MaxDebugMessageLength = AL_MAX_DEBUG_MESSAGE_LENGTH_EXT, + MaxDebugLoggedMessages = AL_MAX_DEBUG_LOGGED_MESSAGES_EXT, + MaxDebugGroupDepth = AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT, + MaxLabelLength = AL_MAX_LABEL_LENGTH_EXT, + ContextFlags = AL_CONTEXT_FLAGS_EXT, +#ifdef ALSOFT_EAX + EaxRamSize = AL_EAX_RAM_SIZE, + EaxRamFree = AL_EAX_RAM_FREE, +#endif +}; + +template<typename T> +struct PropertyCastType { + template<typename U> + constexpr auto operator()(U&& value) const noexcept + { return static_cast<T>(std::forward<U>(value)); } +}; +/* Special-case ALboolean to be an actual bool instead of a char type. */ +template<> +struct PropertyCastType<ALboolean> { + template<typename U> + constexpr ALboolean operator()(U&& value) const noexcept + { return static_cast<bool>(std::forward<U>(value)) ? AL_TRUE : AL_FALSE; } +}; + + +template<typename T> +void GetValue(ALCcontext *context, ALenum pname, T *values) { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return AL_FALSE; + auto cast_value = PropertyCastType<T>{}; - std::lock_guard<std::mutex> _{context->mPropLock}; - ALboolean value{AL_FALSE}; - switch(pname) + switch(static_cast<PropertyValue>(pname)) { case AL_DOPPLER_FACTOR: - if(context->mDopplerFactor != 0.0f) - value = AL_TRUE; - break; + *values = cast_value(context->mDopplerFactor); + return; case AL_DOPPLER_VELOCITY: - if(context->mDopplerVelocity != 0.0f) - value = AL_TRUE; - break; - - case AL_DISTANCE_MODEL: - if(context->mDistanceModel == DistanceModel::Default) - value = AL_TRUE; - break; + if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY + context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0, + DebugSeverity::Medium, + "AL_DOPPLER_VELOCITY is deprecated in AL 1.1, use AL_SPEED_OF_SOUND; " + "AL_DOPPLER_VELOCITY -> AL_SPEED_OF_SOUND / 343.3f"); + *values = cast_value(context->mDopplerVelocity); + return; case AL_SPEED_OF_SOUND: - if(context->mSpeedOfSound != 0.0f) - value = AL_TRUE; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->mDeferUpdates) - value = AL_TRUE; - break; + *values = cast_value(context->mSpeedOfSound); + return; case AL_GAIN_LIMIT_SOFT: - if(GainMixMax/context->mGainBoost != 0.0f) - value = AL_TRUE; - break; - - case AL_NUM_RESAMPLERS_SOFT: - /* Always non-0. */ - value = AL_TRUE; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE; - break; - - default: - context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return 0.0; - - std::lock_guard<std::mutex> _{context->mPropLock}; - ALdouble value{0.0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = context->mDopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = context->mDopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel)); - break; - - case AL_SPEED_OF_SOUND: - value = context->mSpeedOfSound; - break; + *values = cast_value(GainMixMax / context->mGainBoost); + return; case AL_DEFERRED_UPDATES_SOFT: - if(context->mDeferUpdates) - value = static_cast<ALdouble>(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = ALdouble{GainMixMax}/context->mGainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast<ALdouble>(Resampler::Max) + 1.0; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast<ALdouble>(ResamplerDefault); - break; - - default: - context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return 0.0f; - - std::lock_guard<std::mutex> _{context->mPropLock}; - ALfloat value{0.0f}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = context->mDopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = context->mDopplerVelocity; - break; + *values = cast_value(context->mDeferUpdates ? AL_TRUE : AL_FALSE); + return; case AL_DISTANCE_MODEL: - value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel)); - break; - - case AL_SPEED_OF_SOUND: - value = context->mSpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->mDeferUpdates) - value = static_cast<ALfloat>(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = GainMixMax/context->mGainBoost; - break; + *values = cast_value(ALenumFromDistanceModel(context->mDistanceModel)); + return; case AL_NUM_RESAMPLERS_SOFT: - value = static_cast<ALfloat>(Resampler::Max) + 1.0f; - break; + *values = cast_value(al::to_underlying(Resampler::Max) + 1); + return; case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast<ALfloat>(ResamplerDefault); - break; + *values = cast_value(al::to_underlying(ResamplerDefault)); + return; - default: - context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); + case AL_DEBUG_LOGGED_MESSAGES_EXT: + { + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + *values = cast_value(context->mDebugLog.size()); + return; } - return value; -} -END_API_FUNC - -AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return 0; - - std::lock_guard<std::mutex> _{context->mPropLock}; - ALint value{0}; - switch(pname) + case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT: { - case AL_DOPPLER_FACTOR: - value = static_cast<ALint>(context->mDopplerFactor); - break; + std::lock_guard<std::mutex> _{context->mDebugCbLock}; + *values = cast_value(context->mDebugLog.empty() ? 0_uz + : (context->mDebugLog.front().mMessage.size()+1)); + return; + } - case AL_DOPPLER_VELOCITY: - value = static_cast<ALint>(context->mDopplerVelocity); - break; + case AL_MAX_DEBUG_MESSAGE_LENGTH_EXT: + *values = cast_value(MaxDebugMessageLength); + return; - case AL_DISTANCE_MODEL: - value = ALenumFromDistanceModel(context->mDistanceModel); - break; + case AL_MAX_DEBUG_LOGGED_MESSAGES_EXT: + *values = cast_value(MaxDebugLoggedMessages); + return; - case AL_SPEED_OF_SOUND: - value = static_cast<ALint>(context->mSpeedOfSound); - break; + case AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT: + *values = cast_value(MaxDebugGroupDepth); + return; - case AL_DEFERRED_UPDATES_SOFT: - if(context->mDeferUpdates) - value = AL_TRUE; - break; + case AL_MAX_LABEL_LENGTH_EXT: + *values = cast_value(MaxObjectLabelLength); + return; - case AL_GAIN_LIMIT_SOFT: - value = static_cast<ALint>(GainMixMax/context->mGainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast<int>(Resampler::Max) + 1; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast<int>(ResamplerDefault); - break; + case AL_CONTEXT_FLAGS_EXT: + *values = cast_value(context->mContextFlags.to_ulong()); + return; #ifdef ALSOFT_EAX #define EAX_ERROR "[alGetInteger] EAX not enabled." case AL_EAX_RAM_SIZE: - if (eax_g_is_enabled) - { - value = eax_x_ram_max_size; - } - else + if(eax_g_is_enabled) { - context->setError(AL_INVALID_VALUE, EAX_ERROR); + *values = cast_value(eax_x_ram_max_size); + return; } - - break; + context->setError(AL_INVALID_ENUM, EAX_ERROR); + return; case AL_EAX_RAM_FREE: - if (eax_g_is_enabled) + if(eax_g_is_enabled) { auto device = context->mALDevice.get(); std::lock_guard<std::mutex> device_lock{device->BufferLock}; - - value = static_cast<ALint>(device->eax_x_ram_free_size); + *values = cast_value(device->eax_x_ram_free_size); + return; } - else - { - context->setError(AL_INVALID_VALUE, EAX_ERROR); - } - - break; + context->setError(AL_INVALID_ENUM, EAX_ERROR); + return; #undef EAX_ERROR #endif // ALSOFT_EAX - - default: - context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); } + context->setError(AL_INVALID_ENUM, "Invalid context property 0x%04x", pname); +} - return value; + +inline void UpdateProps(ALCcontext *context) +{ + if(!context->mDeferUpdates) + UpdateContextProps(context); + else + context->mPropsDirty = true; } -END_API_FUNC -AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) -START_API_FUNC +} // namespace + +/* WARNING: Non-standard export! Not part of any extension, or exposed in the + * alcFunctions list. + */ +AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return 0_i64; + static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION"); + if(spoof) return spoof->c_str(); + return ALSOFT_VERSION; +} - std::lock_guard<std::mutex> _{context->mPropLock}; - ALint64SOFT value{0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = static_cast<ALint64SOFT>(context->mDopplerFactor); - break; - case AL_DOPPLER_VELOCITY: - value = static_cast<ALint64SOFT>(context->mDopplerVelocity); +AL_API DECL_FUNC1(void, alEnable, ALenum) +FORCE_ALIGN void AL_APIENTRY alEnableDirect(ALCcontext *context, ALenum capability) noexcept +{ + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + { + std::lock_guard<std::mutex> _{context->mPropLock}; + context->mSourceDistanceModel = true; + UpdateProps(context); + } break; - case AL_DISTANCE_MODEL: - value = ALenumFromDistanceModel(context->mDistanceModel); + case AL_DEBUG_OUTPUT_EXT: + context->mDebugEnabled = true; break; - case AL_SPEED_OF_SOUND: - value = static_cast<ALint64SOFT>(context->mSpeedOfSound); + case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: + context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported"); break; - case AL_DEFERRED_UPDATES_SOFT: - if(context->mDeferUpdates) - value = AL_TRUE; - break; + default: + context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); + } +} - case AL_GAIN_LIMIT_SOFT: - value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost); +AL_API DECL_FUNC1(void, alDisable, ALenum) +FORCE_ALIGN void AL_APIENTRY alDisableDirect(ALCcontext *context, ALenum capability) noexcept +{ + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + { + std::lock_guard<std::mutex> _{context->mPropLock}; + context->mSourceDistanceModel = false; + UpdateProps(context); + } break; - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast<ALint64SOFT>(Resampler::Max) + 1; + case AL_DEBUG_OUTPUT_EXT: + context->mDebugEnabled = false; break; - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast<ALint64SOFT>(ResamplerDefault); + case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: + context->mStopVoicesOnDisconnect = false; break; default: - context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); } - - return value; } -END_API_FUNC -AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname) -START_API_FUNC +AL_API DECL_FUNC1(ALboolean, alIsEnabled, ALenum) +FORCE_ALIGN ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum capability) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return nullptr; - std::lock_guard<std::mutex> _{context->mPropLock}; - void *value{nullptr}; - switch(pname) + ALboolean value{AL_FALSE}; + switch(capability) { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = reinterpret_cast<void*>(context->mEventCb); + case AL_SOURCE_DISTANCE_MODEL: + value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE; break; - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->mEventParam; + case AL_DEBUG_OUTPUT_EXT: + value = context->mDebugEnabled ? AL_TRUE : AL_FALSE; + break; + + case AL_STOP_SOURCES_ON_DISCONNECT_SOFT: + value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE; break; default: - context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); } return value; } -END_API_FUNC -AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetBoolean(pname); - return; - } - } +#define DECL_GETFUNC(R, Name, Ext) \ +AL_API R AL_APIENTRY Name##Ext(ALenum pname) noexcept \ +{ \ + R value{}; \ + auto context = GetContextRef(); \ + if(!context) UNLIKELY return value; \ + Name##vDirect##Ext(GetContextRef().get(), pname, &value); \ + return value; \ +} \ +FORCE_ALIGN R AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept \ +{ \ + R value{}; \ + Name##vDirect##Ext(context, pname, &value); \ + return value; \ +} - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; +DECL_GETFUNC(ALboolean, alGetBoolean,) +DECL_GETFUNC(ALdouble, alGetDouble,) +DECL_GETFUNC(ALfloat, alGetFloat,) +DECL_GETFUNC(ALint, alGetInteger,) - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); - } -} -END_API_FUNC +DECL_GETFUNC(ALint64SOFT, alGetInteger64,SOFT) +DECL_GETFUNC(ALvoid*, alGetPointer,SOFT) -AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetDouble(pname); - return; - } - } +#undef DECL_GETFUNC - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); - } +AL_API DECL_FUNC2(void, alGetBooleanv, ALenum, ALboolean*) +FORCE_ALIGN void AL_APIENTRY alGetBooleanvDirect(ALCcontext *context, ALenum pname, ALboolean *values) noexcept +{ + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + GetValue(context, pname, values); } -END_API_FUNC -AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetDoublev, ALenum, ALdouble*) +FORCE_ALIGN void AL_APIENTRY alGetDoublevDirect(ALCcontext *context, ALenum pname, ALdouble *values) noexcept { - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetFloat(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); - } + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + GetValue(context, pname, values); } -END_API_FUNC -AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetFloatv, ALenum, ALfloat*) +FORCE_ALIGN void AL_APIENTRY alGetFloatvDirect(ALCcontext *context, ALenum pname, ALfloat *values) noexcept { - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); - } + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + GetValue(context, pname, values); } -END_API_FUNC -AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) -START_API_FUNC +AL_API DECL_FUNC2(void, alGetIntegerv, ALenum, ALint*) +FORCE_ALIGN void AL_APIENTRY alGetIntegervDirect(ALCcontext *context, ALenum pname, ALint *values) noexcept { - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger64SOFT(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + GetValue(context, pname, values); +} - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); - } +AL_API DECL_FUNCEXT2(void, alGetInteger64v,SOFT, ALenum, ALint64SOFT*) +FORCE_ALIGN void AL_APIENTRY alGetInteger64vDirectSOFT(ALCcontext *context, ALenum pname, ALint64SOFT *values) noexcept +{ + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + GetValue(context, pname, values); } -END_API_FUNC -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values) -START_API_FUNC +AL_API DECL_FUNCEXT2(void, alGetPointerv,SOFT, ALenum, ALvoid**) +FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum pname, ALvoid **values) noexcept { - if(values) + if(!values) UNLIKELY + return context->setError(AL_INVALID_VALUE, "NULL pointer"); + + switch(pname) { - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - values[0] = alGetPointerSOFT(pname); - return; - } - } + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + *values = al::bit_cast<void*>(context->mEventCb); + break; - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + *values = context->mEventParam; + break; + + case AL_DEBUG_CALLBACK_FUNCTION_EXT: + *values = al::bit_cast<void*>(context->mDebugCb); + break; + + case AL_DEBUG_CALLBACK_USER_PARAM_EXT: + *values = context->mDebugParam; + break; - if(!values) - context->setError(AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { default: - context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); + context->setError(AL_INVALID_ENUM, "Invalid context pointer property 0x%04x", pname); } } -END_API_FUNC -AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) -START_API_FUNC +AL_API DECL_FUNC1(const ALchar*, alGetString, ALenum) +FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringDirect(ALCcontext *context, ALenum pname) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return nullptr; - const ALchar *value{nullptr}; switch(pname) { @@ -768,7 +500,7 @@ START_API_FUNC break; case AL_EXTENSIONS: - value = context->mExtensionList; + value = context->mExtensionsString.c_str(); break; case AL_NO_ERROR: @@ -795,112 +527,79 @@ START_API_FUNC value = alErrOutOfMemory; break; + case AL_STACK_OVERFLOW_EXT: + value = alStackOverflow; + break; + + case AL_STACK_UNDERFLOW_EXT: + value = alStackUnderflow; + break; + default: context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); } return value; } -END_API_FUNC -AL_API void AL_APIENTRY alDopplerFactor(ALfloat value) -START_API_FUNC +AL_API DECL_FUNC1(void, alDopplerFactor, ALfloat) +FORCE_ALIGN void AL_APIENTRY alDopplerFactorDirect(ALCcontext *context, ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(!(value >= 0.0f && std::isfinite(value))) context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { std::lock_guard<std::mutex> _{context->mPropLock}; context->mDopplerFactor = value; - DO_UPDATEPROPS(); + UpdateProps(context); } } -END_API_FUNC -AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) -START_API_FUNC +AL_API DECL_FUNC1(void, alSpeedOfSound, ALfloat) +FORCE_ALIGN void AL_APIENTRY alSpeedOfSoundDirect(ALCcontext *context, ALfloat value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - if(!(value >= 0.0f && std::isfinite(value))) - context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value); - else - { - std::lock_guard<std::mutex> _{context->mPropLock}; - context->mDopplerVelocity = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(!(value > 0.0f && std::isfinite(value))) context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { std::lock_guard<std::mutex> _{context->mPropLock}; context->mSpeedOfSound = value; - DO_UPDATEPROPS(); + UpdateProps(context); } } -END_API_FUNC -AL_API void AL_APIENTRY alDistanceModel(ALenum value) -START_API_FUNC +AL_API DECL_FUNC1(void, alDistanceModel, ALenum) +FORCE_ALIGN void AL_APIENTRY alDistanceModelDirect(ALCcontext *context, ALenum value) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(auto model = DistanceModelFromALenum(value)) { std::lock_guard<std::mutex> _{context->mPropLock}; context->mDistanceModel = *model; if(!context->mSourceDistanceModel) - DO_UPDATEPROPS(); + UpdateProps(context); } else context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); } -END_API_FUNC -AL_API void AL_APIENTRY alDeferUpdatesSOFT(void) -START_API_FUNC +AL_API DECL_FUNCEXT(void, alDeferUpdates,SOFT) +FORCE_ALIGN void AL_APIENTRY alDeferUpdatesDirectSOFT(ALCcontext *context) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; context->deferUpdates(); } -END_API_FUNC -AL_API void AL_APIENTRY alProcessUpdatesSOFT(void) -START_API_FUNC +AL_API DECL_FUNCEXT(void, alProcessUpdates,SOFT) +FORCE_ALIGN void AL_APIENTRY alProcessUpdatesDirectSOFT(ALCcontext *context) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - std::lock_guard<std::mutex> _{context->mPropLock}; context->processUpdates(); } -END_API_FUNC -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) -START_API_FUNC +AL_API DECL_FUNCEXT2(const ALchar*, alGetStringi,SOFT, ALenum,ALsizei) +FORCE_ALIGN const ALchar* AL_APIENTRY alGetStringiDirectSOFT(ALCcontext *context, ALenum pname, ALsizei index) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return nullptr; - const ALchar *value{nullptr}; switch(pname) { @@ -916,7 +615,28 @@ START_API_FUNC } return value; } -END_API_FUNC + + +AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept +{ + ContextRef context{GetContextRef()}; + if(!context) UNLIKELY return; + + if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY + context->debugMessage(DebugSource::API, DebugType::DeprecatedBehavior, 0, + DebugSeverity::Medium, + "alDopplerVelocity is deprecated in AL 1.1, use alSpeedOfSound; " + "alDopplerVelocity(x) -> alSpeedOfSound(343.3f * x)"); + + if(!(value >= 0.0f && std::isfinite(value))) + context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value); + else + { + std::lock_guard<std::mutex> _{context->mPropLock}; + context->mDopplerVelocity = value; + UpdateProps(context.get()); + } +} void UpdateContextProps(ALCcontext *context) |