diff options
author | Sven Gothel <[email protected]> | 2023-11-28 12:51:46 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-11-28 12:51:46 +0100 |
commit | 1aaf4f070011490bcece50394b9b32dfa593fd9e (patch) | |
tree | 17d68284e401a35eea3d3a574d986d446a60763a /al/source.cpp | |
parent | 6e7cee4fa9a8af03f28ca26cd89f8357390dfc90 (diff) | |
parent | 571b546f35eead77ce109f8d4dd6c3de3199d573 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'al/source.cpp')
-rw-r--r-- | al/source.cpp | 2631 |
1 files changed, 1117 insertions, 1514 deletions
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}); |