update openal-soft to 1.24.3

keeping the alt 87514151c4 (diff-73a8dc1ce58605f6c5ea53548454c3bae516ec5132a29c9d7ff7edf9730c75be)
This commit is contained in:
AzaezelX 2025-09-03 11:09:27 -05:00
parent 12db0500e8
commit ba32094b7b
276 changed files with 49304 additions and 8712 deletions

View file

@ -31,7 +31,6 @@
#include <mutex>
#include <numeric>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
@ -54,27 +53,27 @@
#include "buffer.h"
#include "core/buffer_storage.h"
#include "core/device.h"
#include "core/except.h"
#include "core/fpu_ctrl.h"
#include "core/logging.h"
#include "direct_defs.h"
#include "effect.h"
#include "error.h"
#include "flexarray.h"
#include "opthelpers.h"
#ifdef ALSOFT_EAX
#if ALSOFT_EAX
#include "eax/api.h"
#include "eax/call.h"
#include "eax/effect.h"
#include "eax/fx_slot_index.h"
#include "eax/utils.h"
#endif
namespace {
using SubListAllocator = al::allocator<std::array<ALeffectslot,64>>;
EffectStateFactory *getFactoryByType(EffectSlotType type)
[[nodiscard]]
auto getFactoryByType(EffectSlotType type) -> EffectStateFactory*
{
switch(type)
{
@ -98,6 +97,7 @@ EffectStateFactory *getFactoryByType(EffectSlotType type)
}
[[nodiscard]]
auto LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -> ALeffectslot*
{
const size_t lidx{(id-1) >> 6};
@ -111,7 +111,8 @@ auto LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -> ALeffectslot*
return al::to_address(sublist.EffectSlots->begin() + slidx);
}
inline auto LookupEffect(ALCdevice *device, ALuint id) noexcept -> ALeffect*
[[nodiscard]]
inline auto LookupEffect(al::Device *device, ALuint id) noexcept -> ALeffect*
{
const size_t lidx{(id-1) >> 6};
const ALuint slidx{(id-1) & 0x3f};
@ -124,7 +125,8 @@ inline auto LookupEffect(ALCdevice *device, ALuint id) noexcept -> ALeffect*
return al::to_address(sublist.Effects->begin() + slidx);
}
inline auto LookupBuffer(ALCdevice *device, ALuint id) noexcept -> ALbuffer*
[[nodiscard]]
inline auto LookupBuffer(al::Device *device, ALuint id) noexcept -> ALbuffer*
{
const size_t lidx{(id-1) >> 6};
const ALuint slidx{(id-1) & 0x3f};
@ -217,6 +219,7 @@ void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext
}
[[nodiscard]]
constexpr auto EffectSlotTypeFromEnum(ALenum type) noexcept -> EffectSlotType
{
switch(type)
@ -239,10 +242,11 @@ constexpr auto EffectSlotTypeFromEnum(ALenum type) noexcept -> EffectSlotType
case AL_EFFECT_DEDICATED_DIALOGUE: return EffectSlotType::Dedicated;
case AL_EFFECT_CONVOLUTION_SOFT: return EffectSlotType::Convolution;
}
ERR("Unhandled effect enum: 0x%04x\n", type);
ERR("Unhandled effect enum: {:#04x}", as_unsigned(type));
return EffectSlotType::None;
}
[[nodiscard]]
auto EnsureEffectSlots(ALCcontext *context, size_t needed) noexcept -> bool
try {
size_t count{std::accumulate(context->mEffectSlotList.cbegin(),
@ -267,7 +271,8 @@ catch(...) {
return false;
}
ALeffectslot *AllocEffectSlot(ALCcontext *context)
[[nodiscard]]
auto AllocEffectSlot(ALCcontext *context) -> ALeffectslot*
{
auto sublist = std::find_if(context->mEffectSlotList.begin(), context->mEffectSlotList.end(),
[](const EffectSlotSubList &entry) noexcept -> bool
@ -322,20 +327,21 @@ FORCE_ALIGN void AL_APIENTRY alGenAuxiliaryEffectSlotsDirect(ALCcontext *context
ALuint *effectslots) noexcept
try {
if(n < 0)
throw al::context_error{AL_INVALID_VALUE, "Generating %d effect slots", n};
context->throw_error(AL_INVALID_VALUE, "Generating {} effect slots", n);
if(n <= 0) UNLIKELY return;
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALCdevice *device{context->mALDevice.get()};
auto slotlock = std::lock_guard{context->mEffectSlotLock};
auto *device = context->mALDevice.get();
const al::span eids{effectslots, static_cast<ALuint>(n)};
if(eids.size() > device->AuxiliaryEffectSlotMax-context->mNumEffectSlots)
throw al::context_error{AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit (%u + %d)",
device->AuxiliaryEffectSlotMax, context->mNumEffectSlots, n};
if(context->mNumEffectSlots > device->AuxiliaryEffectSlotMax
|| eids.size() > device->AuxiliaryEffectSlotMax-context->mNumEffectSlots)
context->throw_error(AL_OUT_OF_MEMORY, "Exceeding {} effect slot limit ({} + {})",
device->AuxiliaryEffectSlotMax, context->mNumEffectSlots, n);
if(!EnsureEffectSlots(context, eids.size()))
throw al::context_error{AL_OUT_OF_MEMORY, "Failed to allocate %d effectslot%s", n,
(n == 1) ? "" : "s"};
context->throw_error(AL_OUT_OF_MEMORY, "Failed to allocate {} effectslot{}", n,
(n==1) ? "" : "s");
std::vector<ALeffectslot*> slots;
try {
@ -355,16 +361,18 @@ try {
}
}
catch(std::exception& e) {
ERR("Exception allocating effectslot %zu of %d: %s\n", slots.size()+1, n, e.what());
ERR("Exception allocating effectslot {} of {}: {}", slots.size()+1, n, e.what());
auto delete_effectslot = [context](ALeffectslot *slot) -> void
{ FreeEffectSlot(context, slot); };
std::for_each(slots.begin(), slots.end(), delete_effectslot);
throw al::context_error{AL_INVALID_OPERATION, "Exception allocating %d effectslots: %s", n,
e.what()};
context->throw_error(AL_INVALID_OPERATION, "Exception allocating {} effectslots: {}", n,
e.what());
}
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC2(void, alDeleteAuxiliaryEffectSlots, ALsizei,n, const ALuint*,effectslots)
@ -372,7 +380,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *cont
const ALuint *effectslots) noexcept
try {
if(n < 0) UNLIKELY
throw al::context_error{AL_INVALID_VALUE, "Deleting %d effect slots", n};
context->throw_error(AL_INVALID_VALUE, "Deleting {} effect slots", n);
if(n <= 0) UNLIKELY return;
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
@ -380,10 +388,10 @@ try {
{
ALeffectslot *slot{LookupEffectSlot(context, *effectslots)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", *effectslots};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", *effectslots);
if(slot->ref.load(std::memory_order_relaxed) != 0)
throw al::context_error{AL_INVALID_OPERATION, "Deleting in-use effect slot %u",
*effectslots};
context->throw_error(AL_INVALID_OPERATION, "Deleting in-use effect slot {}",
*effectslots);
RemoveActiveEffectSlots({&slot, 1u}, context);
FreeEffectSlot(context, slot);
@ -398,10 +406,9 @@ try {
{
ALeffectslot *slot{LookupEffectSlot(context, eid)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", eid};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", eid);
if(slot->ref.load(std::memory_order_relaxed) != 0)
throw al::context_error{AL_INVALID_OPERATION, "Deleting in-use effect slot %u",
eid};
context->throw_error(AL_INVALID_OPERATION, "Deleting in-use effect slot {}", eid);
return slot;
};
std::transform(eids.cbegin(), eids.cend(), std::back_inserter(slots), lookupslot);
@ -417,8 +424,10 @@ try {
std::for_each(eids.begin(), eids.end(), delete_effectslot);
}
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC1(ALboolean, alIsAuxiliaryEffectSlot, ALuint,effectslot)
@ -436,7 +445,6 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlaySOFT(ALuint) noexcept
{
ContextRef context{GetContextRef()};
if(!context) UNLIKELY return;
context->setError(AL_INVALID_OPERATION, "alAuxiliaryEffectSlotPlaySOFT not supported");
}
@ -444,7 +452,6 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotPlayvSOFT(ALsizei, const ALuint*) n
{
ContextRef context{GetContextRef()};
if(!context) UNLIKELY return;
context->setError(AL_INVALID_OPERATION, "alAuxiliaryEffectSlotPlayvSOFT not supported");
}
@ -452,7 +459,6 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopSOFT(ALuint) noexcept
{
ContextRef context{GetContextRef()};
if(!context) UNLIKELY return;
context->setError(AL_INVALID_OPERATION, "alAuxiliaryEffectSlotStopSOFT not supported");
}
@ -460,7 +466,6 @@ AL_API void AL_APIENTRY alAuxiliaryEffectSlotStopvSOFT(ALsizei, const ALuint*) n
{
ContextRef context{GetContextRef()};
if(!context) UNLIKELY return;
context->setError(AL_INVALID_OPERATION, "alAuxiliaryEffectSlotStopvSOFT not supported");
}
@ -474,7 +479,7 @@ try {
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot) UNLIKELY
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
ALeffectslot *target{};
ALenum err{};
@ -482,20 +487,20 @@ try {
{
case AL_EFFECTSLOT_EFFECT:
{
ALCdevice *device{context->mALDevice.get()};
std::lock_guard<std::mutex> effectlock{device->EffectLock};
ALeffect *effect{value ? LookupEffect(device, static_cast<ALuint>(value)) : nullptr};
auto *device = context->mALDevice.get();
auto effectlock = std::lock_guard{device->EffectLock};
auto *effect = value ? LookupEffect(device, static_cast<ALuint>(value)) : nullptr;
if(effect)
err = slot->initEffect(effect->id, effect->type, effect->Props, context);
else
{
if(value != 0)
throw al::context_error{AL_INVALID_VALUE, "Invalid effect ID %u", value};
context->throw_error(AL_INVALID_VALUE, "Invalid effect ID {}", value);
err = slot->initEffect(0, AL_EFFECT_NULL, EffectProps{}, context);
}
}
if(err != AL_NO_ERROR)
throw al::context_error{err, "Effect initialization failed"};
context->throw_error(err, "Effect initialization failed");
if(slot->mState == SlotState::Initial) UNLIKELY
{
@ -511,8 +516,7 @@ try {
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(!(value == AL_TRUE || value == AL_FALSE))
throw al::context_error{AL_INVALID_VALUE,
"Effect slot auxiliary send auto out of range"};
context->throw_error(AL_INVALID_VALUE, "Effect slot auxiliary send auto out of range");
if(!(slot->AuxSendAuto == !!value)) LIKELY
{
slot->AuxSendAuto = !!value;
@ -523,7 +527,7 @@ try {
case AL_EFFECTSLOT_TARGET_SOFT:
target = LookupEffectSlot(context, static_cast<ALuint>(value));
if(value && !target)
throw al::context_error{AL_INVALID_VALUE, "Invalid effect slot target ID"};
context->throw_error(AL_INVALID_VALUE, "Invalid effect slot target ID {}", value);
if(slot->Target == target) UNLIKELY
return;
if(target)
@ -532,9 +536,9 @@ try {
while(checker && checker != slot)
checker = checker->Target;
if(checker)
throw al::context_error{AL_INVALID_OPERATION,
"Setting target of effect slot ID %u to %u creates circular chain", slot->id,
target->id};
context->throw_error(AL_INVALID_OPERATION,
"Setting target of effect slot ID {} to {} creates circular chain", slot->id,
target->id);
}
if(ALeffectslot *oldtarget{slot->Target})
@ -569,17 +573,17 @@ try {
assert(factory);
al::intrusive_ptr<EffectState> state{factory->create()};
ALCdevice *device{context->mALDevice.get()};
auto *device = context->mALDevice.get();
auto bufferlock = std::unique_lock{device->BufferLock};
ALbuffer *buffer{};
if(value)
{
buffer = LookupBuffer(device, static_cast<ALuint>(value));
if(!buffer)
throw al::context_error{AL_INVALID_VALUE, "Invalid buffer ID %u", value};
context->throw_error(AL_INVALID_VALUE, "Invalid buffer ID {}", value);
if(buffer->mCallback)
throw al::context_error{AL_INVALID_OPERATION,
"Callback buffer not valid for effects"};
context->throw_error(AL_INVALID_OPERATION,
"Callback buffer not valid for effects");
IncrementRef(buffer->ref);
}
@ -605,17 +609,17 @@ try {
}
else
{
ALCdevice *device{context->mALDevice.get()};
auto *device = context->mALDevice.get();
auto bufferlock = std::unique_lock{device->BufferLock};
ALbuffer *buffer{};
if(value)
{
buffer = LookupBuffer(device, static_cast<ALuint>(value));
if(!buffer)
throw al::context_error{AL_INVALID_VALUE, "Invalid buffer ID %u", value};
context->throw_error(AL_INVALID_VALUE, "Invalid buffer ID {}", value);
if(buffer->mCallback)
throw al::context_error{AL_INVALID_OPERATION,
"Callback buffer not valid for effects"};
context->throw_error(AL_INVALID_OPERATION,
"Callback buffer not valid for effects");
IncrementRef(buffer->ref);
}
@ -633,13 +637,16 @@ try {
return;
case AL_EFFECTSLOT_STATE_SOFT:
throw al::context_error{AL_INVALID_OPERATION, "AL_EFFECTSLOT_STATE_SOFT is read-only"};
context->throw_error(AL_INVALID_OPERATION, "AL_EFFECTSLOT_STATE_SOFT is read-only");
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot integer property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotiv, ALuint,effectslot, ALenum,param, const ALint*,values)
@ -660,16 +667,15 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot integer-vector property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotf, ALuint,effectslot, ALenum,param, ALfloat,value)
@ -681,13 +687,13 @@ try {
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
if(!(value >= 0.0f && value <= 1.0f))
throw al::context_error{AL_INVALID_VALUE, "Effect slot gain out of range"};
context->throw_error(AL_INVALID_VALUE, "Effect slot gain {} out of range", value);
if(!(slot->Gain == value)) LIKELY
{
slot->Gain = value;
@ -696,10 +702,13 @@ try {
return;
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot float property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alAuxiliaryEffectSlotfv, ALuint,effectslot, ALenum,param, const ALfloat*,values)
@ -716,16 +725,15 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot float-vector property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
@ -736,7 +744,7 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
@ -767,10 +775,13 @@ try {
return;
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot integer property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotiv, ALuint,effectslot, ALenum,param, ALint*,values)
@ -791,16 +802,15 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot = LookupEffectSlot(context, effectslot);
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot integer-vector property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotf, ALuint,effectslot, ALenum,param, ALfloat*,value)
@ -810,19 +820,20 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
*value = slot->Gain;
return;
case AL_EFFECTSLOT_GAIN: *value = slot->Gain; return;
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot float property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
AL_API DECL_FUNC3(void, alGetAuxiliaryEffectSlotfv, ALuint,effectslot, ALenum,param, ALfloat*,values)
@ -839,16 +850,15 @@ try {
std::lock_guard<std::mutex> slotlock{context->mEffectSlotLock};
ALeffectslot *slot{LookupEffectSlot(context, effectslot)};
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", effectslot};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", effectslot);
switch(param)
{
}
throw al::context_error{AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param};
context->throw_error(AL_INVALID_ENUM, "Invalid effect slot float-vector property {:#04x}",
as_unsigned(param));
}
catch(al::context_error& e) {
context->setError(e.errorCode(), "%s", e.what());
catch(al::base_exception&) {
}
catch(std::exception &e) {
ERR("Caught exception: {}", e.what());
}
@ -890,12 +900,13 @@ ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const Effect
EffectStateFactory *factory{getFactoryByType(newtype)};
if(!factory)
{
ERR("Failed to find factory for effect slot type %d\n", static_cast<int>(newtype));
ERR("Failed to find factory for effect slot type {}",
int{al::to_underlying(newtype)});
return AL_INVALID_ENUM;
}
al::intrusive_ptr<EffectState> state{factory->create()};
ALCdevice *device{context->mALDevice.get()};
auto *device = context->mALDevice.get();
state->mOutTarget = device->Dry.Buffer;
{
FPUCtl mixer_mode{};
@ -964,7 +975,7 @@ void ALeffectslot::SetName(ALCcontext* context, ALuint id, std::string_view name
auto slot = LookupEffectSlot(context, id);
if(!slot)
throw al::context_error{AL_INVALID_NAME, "Invalid effect slot ID %u", id};
context->throw_error(AL_INVALID_NAME, "Invalid effect slot ID {}", id);
context->mEffectSlotNames.insert_or_assign(id, name);
}
@ -1004,51 +1015,51 @@ EffectSlotSubList::~EffectSlotSubList()
EffectSlots = nullptr;
}
#ifdef ALSOFT_EAX
#if ALSOFT_EAX
void ALeffectslot::eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index)
{
if(index >= EAX_MAX_FXSLOTS)
eax_fail("Index out of range.");
eax_al_context_ = &al_context;
eax_fx_slot_index_ = index;
mEaxALContext = &al_context;
mEaxFXSlotIndex = index;
eax_fx_slot_set_defaults();
eax_effect_ = std::make_unique<EaxEffect>();
if(index == 0) eax_effect_->init<EaxReverbCommitter>();
else if(index == 1) eax_effect_->init<EaxChorusCommitter>();
else eax_effect_->init<EaxNullCommitter>();
mEaxEffect = std::make_unique<EaxEffect>();
if(index == 0) mEaxEffect->init<EaxReverbCommitter>();
else if(index == 1) mEaxEffect->init<EaxChorusCommitter>();
else mEaxEffect->init<EaxNullCommitter>();
}
void ALeffectslot::eax_commit()
{
if(eax_df_ != EaxDirtyFlags{})
if(mEaxDf.any())
{
auto df = EaxDirtyFlags{};
switch(eax_version_)
auto df = std::bitset<eax_dirty_bit_count>{};
switch(mEaxVersion)
{
case 1:
case 2:
case 3:
eax5_fx_slot_commit(eax123_, df);
eax5_fx_slot_commit(mEax123, df);
break;
case 4:
eax4_fx_slot_commit(df);
break;
case 5:
eax5_fx_slot_commit(eax5_, df);
eax5_fx_slot_commit(mEax5, df);
break;
}
eax_df_ = EaxDirtyFlags{};
mEaxDf.reset();
if((df & eax_volume_dirty_bit) != EaxDirtyFlags{})
if(df.test(eax_volume_dirty_bit))
eax_fx_slot_set_volume();
if((df & eax_flags_dirty_bit) != EaxDirtyFlags{})
if(df.test(eax_flags_dirty_bit))
eax_fx_slot_set_flags();
}
if(eax_effect_->commit(eax_version_))
eax_set_efx_slot_effect(*eax_effect_);
if(mEaxEffect->commit(mEaxVersion))
eax_set_efx_slot_effect(*mEaxEffect);
}
[[noreturn]] void ALeffectslot::eax_fail(const char* message)
@ -1111,7 +1122,7 @@ ALenum ALeffectslot::eax_get_efx_effect_type(const GUID& guid)
const GUID& ALeffectslot::eax_get_eax_default_effect_guid() const noexcept
{
switch(eax_fx_slot_index_)
switch(mEaxFXSlotIndex)
{
case 0: return EAX_REVERB_EFFECT;
case 1: return EAX_CHORUS_EFFECT;
@ -1124,7 +1135,7 @@ long ALeffectslot::eax_get_eax_default_lock() const noexcept
return eax4_fx_slot_is_legacy() ? EAXFXSLOT_LOCKED : EAXFXSLOT_UNLOCKED;
}
void ALeffectslot::eax4_fx_slot_set_defaults(Eax4Props& props) noexcept
void ALeffectslot::eax4_fx_slot_set_defaults(EAX40FXSLOTPROPERTIES& props) noexcept
{
props.guidLoadEffect = eax_get_eax_default_effect_guid();
props.lVolume = EAXFXSLOT_DEFAULTVOLUME;
@ -1132,7 +1143,7 @@ void ALeffectslot::eax4_fx_slot_set_defaults(Eax4Props& props) noexcept
props.ulFlags = EAX40FXSLOT_DEFAULTFLAGS;
}
void ALeffectslot::eax5_fx_slot_set_defaults(Eax5Props& props) noexcept
void ALeffectslot::eax5_fx_slot_set_defaults(EAX50FXSLOTPROPERTIES& props) noexcept
{
props.guidLoadEffect = eax_get_eax_default_effect_guid();
props.lVolume = EAXFXSLOT_DEFAULTVOLUME;
@ -1144,14 +1155,14 @@ void ALeffectslot::eax5_fx_slot_set_defaults(Eax5Props& props) noexcept
void ALeffectslot::eax_fx_slot_set_defaults()
{
eax5_fx_slot_set_defaults(eax123_.i);
eax4_fx_slot_set_defaults(eax4_.i);
eax5_fx_slot_set_defaults(eax5_.i);
eax_ = eax5_.i;
eax_df_ = EaxDirtyFlags{};
eax5_fx_slot_set_defaults(mEax123.i);
eax4_fx_slot_set_defaults(mEax4.i);
eax5_fx_slot_set_defaults(mEax5.i);
mEax = mEax5.i;
mEaxDf.reset();
}
void ALeffectslot::eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props)
void ALeffectslot::eax4_fx_slot_get(const EaxCall& call, const EAX40FXSLOTPROPERTIES& props)
{
switch(call.get_property_id())
{
@ -1175,7 +1186,7 @@ void ALeffectslot::eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props)
}
}
void ALeffectslot::eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props)
void ALeffectslot::eax5_fx_slot_get(const EaxCall& call, const EAX50FXSLOTPROPERTIES& props)
{
switch(call.get_property_id())
{
@ -1209,8 +1220,8 @@ void ALeffectslot::eax_fx_slot_get(const EaxCall& call) const
{
switch(call.get_version())
{
case 4: eax4_fx_slot_get(call, eax4_.i); break;
case 5: eax5_fx_slot_get(call, eax5_.i); break;
case 4: eax4_fx_slot_get(call, mEax4.i); break;
case 5: eax5_fx_slot_get(call, mEax5.i); break;
default: eax_fail_unknown_version();
}
}
@ -1223,7 +1234,7 @@ bool ALeffectslot::eax_get(const EaxCall& call)
eax_fx_slot_get(call);
break;
case EaxCallPropertySetId::fx_slot_effect:
eax_effect_->get(call);
mEaxEffect->get(call);
break;
default:
eax_fail_unknown_property_id();
@ -1236,19 +1247,19 @@ void ALeffectslot::eax_fx_slot_load_effect(int version, ALenum altype)
{
if(!IsValidEffectType(altype))
altype = AL_EFFECT_NULL;
eax_effect_->set_defaults(version, altype);
mEaxEffect->set_defaults(version, altype);
}
void ALeffectslot::eax_fx_slot_set_volume()
{
const auto volume = std::clamp(eax_.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME);
const auto volume = std::clamp(mEax.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME);
const auto gain = level_mb_to_gain(static_cast<float>(volume));
eax_set_efx_slot_gain(gain);
}
void ALeffectslot::eax_fx_slot_set_environment_flag()
{
eax_set_efx_slot_send_auto((eax_.ulFlags & EAXFXSLOTFLAGS_ENVIRONMENT) != 0u);
eax_set_efx_slot_send_auto((mEax.ulFlags & EAXFXSLOTFLAGS_ENVIRONMENT) != 0u);
}
void ALeffectslot::eax_fx_slot_set_flags()
@ -1261,11 +1272,11 @@ void ALeffectslot::eax4_fx_slot_set_all(const EaxCall& call)
eax4_fx_slot_ensure_unlocked();
const auto& src = call.get_value<Exception, const EAX40FXSLOTPROPERTIES>();
Eax4AllValidator{}(src);
auto& dst = eax4_.i;
eax_df_ |= eax_load_effect_dirty_bit; // Always reset the effect.
eax_df_ |= (dst.lVolume != src.lVolume ? eax_volume_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.lLock != src.lLock ? eax_lock_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.ulFlags != src.ulFlags ? eax_flags_dirty_bit : EaxDirtyFlags{});
auto& dst = mEax4.i;
mEaxDf.set(eax_load_effect_dirty_bit); // Always reset the effect.
if(dst.lVolume != src.lVolume) mEaxDf.set(eax_volume_dirty_bit);
if(dst.lLock != src.lLock) mEaxDf.set(eax_lock_dirty_bit);
if(dst.ulFlags != src.ulFlags) mEaxDf.set(eax_flags_dirty_bit);
dst = src;
}
@ -1273,30 +1284,30 @@ void ALeffectslot::eax5_fx_slot_set_all(const EaxCall& call)
{
const auto& src = call.get_value<Exception, const EAX50FXSLOTPROPERTIES>();
Eax5AllValidator{}(src);
auto& dst = eax5_.i;
eax_df_ |= eax_load_effect_dirty_bit; // Always reset the effect.
eax_df_ |= (dst.lVolume != src.lVolume ? eax_volume_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.lLock != src.lLock ? eax_lock_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.ulFlags != src.ulFlags ? eax_flags_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.lOcclusion != src.lOcclusion ? eax_flags_dirty_bit : EaxDirtyFlags{});
eax_df_ |= (dst.flOcclusionLFRatio != src.flOcclusionLFRatio ? eax_flags_dirty_bit : EaxDirtyFlags{});
auto& dst = mEax5.i;
mEaxDf.set(eax_load_effect_dirty_bit); // Always reset the effect.
if(dst.lVolume != src.lVolume) mEaxDf.set(eax_volume_dirty_bit);
if(dst.lLock != src.lLock) mEaxDf.set(eax_lock_dirty_bit);
if(dst.ulFlags != src.ulFlags) mEaxDf.set(eax_flags_dirty_bit);
if(dst.lOcclusion != src.lOcclusion) mEaxDf.set(eax_flags_dirty_bit);
if(dst.flOcclusionLFRatio != src.flOcclusionLFRatio) mEaxDf.set(eax_flags_dirty_bit);
dst = src;
}
bool ALeffectslot::eax_fx_slot_should_update_sources() const noexcept
{
static constexpr auto dirty_bits =
eax_occlusion_dirty_bit |
eax_occlusion_lf_ratio_dirty_bit |
eax_flags_dirty_bit;
return (eax_df_ & dirty_bits) != EaxDirtyFlags{};
static constexpr auto dirty_bits = std::bitset<eax_dirty_bit_count>{
(1u << eax_occlusion_dirty_bit)
| (1u << eax_occlusion_lf_ratio_dirty_bit)
| (1u << eax_flags_dirty_bit)
};
return (mEaxDf & dirty_bits).any();
}
// Returns `true` if all sources should be updated, or `false` otherwise.
bool ALeffectslot::eax4_fx_slot_set(const EaxCall& call)
{
auto& dst = eax4_.i;
auto& dst = mEax4.i;
switch(call.get_property_id())
{
@ -1304,24 +1315,25 @@ bool ALeffectslot::eax4_fx_slot_set(const EaxCall& call)
break;
case EAXFXSLOT_ALLPARAMETERS:
eax4_fx_slot_set_all(call);
if((eax_df_ & eax_load_effect_dirty_bit))
if(mEaxDf.test(eax_load_effect_dirty_bit))
eax_fx_slot_load_effect(4, eax_get_efx_effect_type(dst.guidLoadEffect));
break;
case EAXFXSLOT_LOADEFFECT:
eax4_fx_slot_ensure_unlocked();
eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call, dst.guidLoadEffect, eax_df_);
if((eax_df_ & eax_load_effect_dirty_bit))
eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call,
dst.guidLoadEffect, mEaxDf);
if(mEaxDf.test(eax_load_effect_dirty_bit))
eax_fx_slot_load_effect(4, eax_get_efx_effect_type(dst.guidLoadEffect));
break;
case EAXFXSLOT_VOLUME:
eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, eax_df_);
eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, mEaxDf);
break;
case EAXFXSLOT_LOCK:
eax4_fx_slot_ensure_unlocked();
eax_fx_slot_set<Eax4LockValidator, eax_lock_dirty_bit>(call, dst.lLock, eax_df_);
eax_fx_slot_set<Eax4LockValidator, eax_lock_dirty_bit>(call, dst.lLock, mEaxDf);
break;
case EAXFXSLOT_FLAGS:
eax_fx_slot_set<Eax4FlagsValidator, eax_flags_dirty_bit>(call, dst.ulFlags, eax_df_);
eax_fx_slot_set<Eax4FlagsValidator, eax_flags_dirty_bit>(call, dst.ulFlags, mEaxDf);
break;
default:
eax_fail_unknown_property_id();
@ -1333,7 +1345,7 @@ bool ALeffectslot::eax4_fx_slot_set(const EaxCall& call)
// Returns `true` if all sources should be updated, or `false` otherwise.
bool ALeffectslot::eax5_fx_slot_set(const EaxCall& call)
{
auto& dst = eax5_.i;
auto& dst = mEax5.i;
switch(call.get_property_id())
{
@ -1341,28 +1353,31 @@ bool ALeffectslot::eax5_fx_slot_set(const EaxCall& call)
break;
case EAXFXSLOT_ALLPARAMETERS:
eax5_fx_slot_set_all(call);
if((eax_df_ & eax_load_effect_dirty_bit))
if(mEaxDf.test(eax_load_effect_dirty_bit))
eax_fx_slot_load_effect(5, eax_get_efx_effect_type(dst.guidLoadEffect));
break;
case EAXFXSLOT_LOADEFFECT:
eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call, dst.guidLoadEffect, eax_df_);
if((eax_df_ & eax_load_effect_dirty_bit))
eax_fx_slot_set_dirty<Eax4GuidLoadEffectValidator, eax_load_effect_dirty_bit>(call,
dst.guidLoadEffect, mEaxDf);
if(mEaxDf.test(eax_load_effect_dirty_bit))
eax_fx_slot_load_effect(5, eax_get_efx_effect_type(dst.guidLoadEffect));
break;
case EAXFXSLOT_VOLUME:
eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, eax_df_);
eax_fx_slot_set<Eax4VolumeValidator, eax_volume_dirty_bit>(call, dst.lVolume, mEaxDf);
break;
case EAXFXSLOT_LOCK:
eax_fx_slot_set<Eax4LockValidator, eax_lock_dirty_bit>(call, dst.lLock, eax_df_);
eax_fx_slot_set<Eax4LockValidator, eax_lock_dirty_bit>(call, dst.lLock, mEaxDf);
break;
case EAXFXSLOT_FLAGS:
eax_fx_slot_set<Eax5FlagsValidator, eax_flags_dirty_bit>(call, dst.ulFlags, eax_df_);
eax_fx_slot_set<Eax5FlagsValidator, eax_flags_dirty_bit>(call, dst.ulFlags, mEaxDf);
break;
case EAXFXSLOT_OCCLUSION:
eax_fx_slot_set<Eax5OcclusionValidator, eax_occlusion_dirty_bit>(call, dst.lOcclusion, eax_df_);
eax_fx_slot_set<Eax5OcclusionValidator, eax_occlusion_dirty_bit>(call, dst.lOcclusion,
mEaxDf);
break;
case EAXFXSLOT_OCCLUSIONLFRATIO:
eax_fx_slot_set<Eax5OcclusionLfRatioValidator, eax_occlusion_lf_ratio_dirty_bit>(call, dst.flOcclusionLFRatio, eax_df_);
eax_fx_slot_set<Eax5OcclusionLfRatioValidator, eax_occlusion_lf_ratio_dirty_bit>(call,
dst.flOcclusionLFRatio, mEaxDf);
break;
default:
eax_fail_unknown_property_id();
@ -1374,7 +1389,7 @@ bool ALeffectslot::eax5_fx_slot_set(const EaxCall& call)
// Returns `true` if all sources should be updated, or `false` otherwise.
bool ALeffectslot::eax_fx_slot_set(const EaxCall& call)
{
switch (call.get_version())
switch(call.get_version())
{
case 4: return eax4_fx_slot_set(call);
case 5: return eax5_fx_slot_set(call);
@ -1390,39 +1405,41 @@ bool ALeffectslot::eax_set(const EaxCall& call)
switch(call.get_property_set_id())
{
case EaxCallPropertySetId::fx_slot: ret = eax_fx_slot_set(call); break;
case EaxCallPropertySetId::fx_slot_effect: eax_effect_->set(call); break;
case EaxCallPropertySetId::fx_slot_effect: mEaxEffect->set(call); break;
default: eax_fail_unknown_property_id();
}
const auto version = call.get_version();
if(eax_version_ != version)
eax_df_ = ~EaxDirtyFlags{};
eax_version_ = version;
if(mEaxVersion != version)
mEaxDf.set();
mEaxVersion = version;
return ret;
}
void ALeffectslot::eax4_fx_slot_commit(EaxDirtyFlags& dst_df)
void ALeffectslot::eax4_fx_slot_commit(std::bitset<eax_dirty_bit_count>& dst_df)
{
eax_fx_slot_commit_property<eax_load_effect_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::guidLoadEffect);
eax_fx_slot_commit_property<eax_volume_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::lVolume);
eax_fx_slot_commit_property<eax_lock_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::lLock);
eax_fx_slot_commit_property<eax_flags_dirty_bit>(eax4_, dst_df, &EAX40FXSLOTPROPERTIES::ulFlags);
eax_fx_slot_commit_property<eax_load_effect_dirty_bit>(mEax4, dst_df, &EAX40FXSLOTPROPERTIES::guidLoadEffect);
eax_fx_slot_commit_property<eax_volume_dirty_bit>(mEax4, dst_df, &EAX40FXSLOTPROPERTIES::lVolume);
eax_fx_slot_commit_property<eax_lock_dirty_bit>(mEax4, dst_df, &EAX40FXSLOTPROPERTIES::lLock);
eax_fx_slot_commit_property<eax_flags_dirty_bit>(mEax4, dst_df, &EAX40FXSLOTPROPERTIES::ulFlags);
auto& dst_i = eax_;
auto& dst_i = mEax;
if(dst_i.lOcclusion != EAXFXSLOT_DEFAULTOCCLUSION) {
dst_df |= eax_occlusion_dirty_bit;
if(dst_i.lOcclusion != EAXFXSLOT_DEFAULTOCCLUSION)
{
dst_df.set(eax_occlusion_dirty_bit);
dst_i.lOcclusion = EAXFXSLOT_DEFAULTOCCLUSION;
}
if(dst_i.flOcclusionLFRatio != EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO) {
dst_df |= eax_occlusion_lf_ratio_dirty_bit;
if(dst_i.flOcclusionLFRatio != EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO)
{
dst_df.set(eax_occlusion_lf_ratio_dirty_bit);
dst_i.flOcclusionLFRatio = EAXFXSLOT_DEFAULTOCCLUSIONLFRATIO;
}
}
void ALeffectslot::eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df)
void ALeffectslot::eax5_fx_slot_commit(Eax5State& state, std::bitset<eax_dirty_bit_count>& dst_df)
{
eax_fx_slot_commit_property<eax_load_effect_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::guidLoadEffect);
eax_fx_slot_commit_property<eax_volume_dirty_bit>(state, dst_df, &EAX50FXSLOTPROPERTIES::lVolume);
@ -1437,18 +1454,19 @@ void ALeffectslot::eax_set_efx_slot_effect(EaxEffect &effect)
#define EAX_PREFIX "[EAX_SET_EFFECT_SLOT_EFFECT] "
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.");
mEaxALContext);
if(error != AL_NO_ERROR)
{
ERR(EAX_PREFIX "Failed to initialize an effect.");
return;
}
if(mState == SlotState::Initial) {
if(mState == SlotState::Initial)
{
mPropsDirty = false;
updateProps(eax_al_context_);
updateProps(mEaxALContext);
auto effect_slot_ptr = this;
AddActiveEffectSlots({&effect_slot_ptr, 1}, eax_al_context_);
AddActiveEffectSlots({&effect_slot_ptr, 1}, mEaxALContext);
mState = SlotState::Playing;
return;
}
@ -1474,7 +1492,7 @@ void ALeffectslot::eax_set_efx_slot_gain(ALfloat gain)
if(gain == Gain)
return;
if(gain < 0.0f || gain > 1.0f)
ERR(EAX_PREFIX "Gain out of range (%f)\n", gain);
ERR(EAX_PREFIX "Slot gain out of range ({:f})", gain);
Gain = std::clamp(gain, 0.0f, 1.0f);
mPropsDirty = true;
@ -1484,7 +1502,7 @@ void ALeffectslot::eax_set_efx_slot_gain(ALfloat gain)
void ALeffectslot::EaxDeleter::operator()(ALeffectslot* effect_slot)
{
eax_delete_al_effect_slot(*effect_slot->eax_al_context_, *effect_slot);
eax_delete_al_effect_slot(*effect_slot->mEaxALContext, *effect_slot);
}
EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context)
@ -1494,13 +1512,15 @@ EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context)
std::lock_guard<std::mutex> slotlock{context.mEffectSlotLock};
auto& device = *context.mALDevice;
if(context.mNumEffectSlots == device.AuxiliaryEffectSlotMax) {
ERR(EAX_PREFIX "%s\n", "Out of memory.");
if(context.mNumEffectSlots == device.AuxiliaryEffectSlotMax)
{
ERR(EAX_PREFIX "Out of memory.");
return nullptr;
}
if(!EnsureEffectSlots(&context, 1)) {
ERR(EAX_PREFIX "%s\n", "Failed to ensure.");
if(!EnsureEffectSlots(&context, 1))
{
ERR(EAX_PREFIX "Failed to ensure.");
return nullptr;
}
@ -1517,7 +1537,7 @@ void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot)
if(effect_slot.ref.load(std::memory_order_relaxed) != 0)
{
ERR(EAX_PREFIX "Deleting in-use effect slot %u.\n", effect_slot.id);
ERR(EAX_PREFIX "Deleting in-use effect slot {}.", effect_slot.id);
return;
}