diff options
author | Chris Robinson <[email protected]> | 2023-05-06 11:12:42 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-05-06 11:12:42 -0700 |
commit | 7c7b80ee49b4d8279c88e024039b8ff39ee14950 (patch) | |
tree | af49f28f963ce356793fb89d0e5036a0386de249 /al/source.cpp | |
parent | 6be304497b4866d751993ee544b38c26fab1cc0f (diff) |
Combine multiple functions into reusable templates
Diffstat (limited to 'al/source.cpp')
-rw-r--r-- | al/source.cpp | 1953 |
1 files changed, 814 insertions, 1139 deletions
diff --git a/al/source.cpp b/al/source.cpp index c96e4652..4dc17779 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -758,56 +758,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); +}; -std::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 std::nullopt; -} +}; ALenum EnumFromStereoMode(SourceStereo mode) { switch(mode) @@ -818,7 +817,7 @@ ALenum EnumFromStereoMode(SourceStereo mode) throw std::runtime_error{"Invalid SourceStereo: "+std::to_string(int(mode))}; } -std::optional<SpatializeMode> SpatializeModeFromEnum(ALenum mode) +auto SpatializeModeFromEnum = [](auto mode) noexcept -> std::optional<SpatializeMode> { switch(mode) { @@ -826,9 +825,8 @@ std::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 std::nullopt; -} +}; ALenum EnumFromSpatializeMode(SpatializeMode mode) { switch(mode) @@ -840,7 +838,7 @@ ALenum EnumFromSpatializeMode(SpatializeMode mode) throw std::runtime_error{"Invalid SpatializeMode: "+std::to_string(int(mode))}; } -std::optional<DirectMode> DirectModeFromEnum(ALenum mode) +auto DirectModeFromEnum = [](auto mode) noexcept -> std::optional<DirectMode> { switch(mode) { @@ -848,9 +846,8 @@ std::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 std::nullopt; -} +}; ALenum EnumFromDirectMode(DirectMode mode) { switch(mode) @@ -862,7 +859,7 @@ ALenum EnumFromDirectMode(DirectMode mode) throw std::runtime_error{"Invalid DirectMode: "+std::to_string(int(mode))}; } -std::optional<DistanceModel> DistanceModelFromALenum(ALenum model) +auto DistanceModelFromALenum = [](auto model) noexcept -> std::optional<DistanceModel> { switch(model) { @@ -875,7 +872,7 @@ std::optional<DistanceModel> DistanceModelFromALenum(ALenum model) case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped; } return std::nullopt; -} +}; ALenum ALenumFromDistanceModel(DistanceModel model) { switch(model) @@ -973,8 +970,6 @@ enum SourceProp : ALenum { }; -constexpr size_t MaxValues{6u}; - constexpr ALuint IntValsByProp(ALenum prop) { switch(static_cast<SourceProp>(prop)) @@ -1276,10 +1271,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 +1318,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,16 +1377,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 { +template<typename T, size_t N> +void SetProperty(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, + const al::span<const T,N> values) try +{ auto&& [CheckSize, CheckValue] = GetCheckers(Context, prop, values); - int ival; + 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, @@ -1374,102 +1411,200 @@ 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); + } + al::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 */ + 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 + { + /* 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: @@ -1478,604 +1613,328 @@ try { 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])); + CheckValue(values[0] >= T{0} && std::isfinite(static_cast<float>(values[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])); + 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])); + 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] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = 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])); + 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] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = 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])); + 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] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = 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]; + 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&& [CheckSize, CheckValue] = GetCheckers(Context, prop, values); - 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"); - - if(SetVoiceOffset(voice, *vpos, Source, Context, device)) - return; - } - Source->OffsetType = prop; - Source->Offset = values[0]; - return; + CheckSize(1); + CheckValue(values[0] == AL_FALSE || values[0] == AL_TRUE); - 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])) - { - Source->mSpatialize = *mode; - return UpdateSourceProps(Source, Context); - } - Context->setError(AL_INVALID_VALUE, "Unsupported AL_SOURCE_SPATIALIZE_SOFT: 0x%04x\n", - values[0]); - return; - - 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])) + if constexpr(std::is_integral_v<T>) { - Source->mStereoMode = *mode; - return; - } - Context->setError(AL_INVALID_VALUE, "Unsupported AL_STEREO_MODE_SOFT: 0x%04x\n", - values[0]); - return; + CheckSize(1); + CheckValue(values[0] >= 0 && values[0] <= static_cast<int>(Resampler::Max)); - 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&& [CheckSize, CheckValue] = GetCheckers(Context, prop, values); - 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[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&) { } @@ -2093,245 +1952,306 @@ 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, size_t N> +[[nodiscard]] +bool GetProperty(ALsource *const Source, ALCcontext *const Context, const SourceProp prop, + const al::span<T,N> values) try +{ 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); + /* FIXME: If T==int64, this max limit rounds up to int64_max+1 as a + * double, exceeding the intended limit and wrap. It's very unlikely to + * happen in practice, but it should be fixed if possible without + * putting an undue burden on it. + */ + values[0] = static_cast<T>(mind(GetSourceOffset(Source, prop, Context), + double{std::numeric_limits<T>::max()})); 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); + const auto offset = GetSourceOffset(Source, AL_SAMPLE_OFFSET, Context); + /* FIXME: As with AL_SAMPLE_OFFSET, this doesn't properly limit + * the max for T==int64. + */ + values[0] = static_cast<int>(mind(offset, double{std::numeric_limits<T>::max()})); + /* 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); + const auto offset = GetSourceOffset(Source, AL_BYTE_OFFSET, Context); + /* FIXME: As with AL_BYTE_OFFSET, this doesn't properly limit + * the max for T==int64. + */ + values[0] = static_cast<int>(mind(offset, double{std::numeric_limits<T>::max()})); + /* 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); + /* FIXME: As with AL_*_OFFSET, this doesn't properly limit the max for + * T==int64. + */ + values[0] = static_cast<T>(mind(GetSourceLength(Source, prop), + double{std::numeric_limits<T>::max()})); 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. + */ + 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 + { + /* 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{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>) { - /* 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); + 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>) + { + 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; + 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] = static_cast<double>(clocktime.Latency.count()) / 1'000'000'000.0; + 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 nanoseconds diff{clocktime.ClockTime - srcclock}; + const nanoseconds latency{clocktime.Latency - std::min(clocktime.Latency, diff)}; + values[1] = static_cast<double>(latency.count()) / 1'000'000'000.0; + } + 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); + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = static_cast<double>(srcclock.count()) / 1'000'000'000.0; + 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 @@ -2349,377 +2269,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&) { @@ -3004,9 +2697,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), + al::span<const float,1>{&value, 1u}); } END_API_FUNC @@ -3020,12 +2714,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), al::span{fvals}); } END_API_FUNC @@ -3044,7 +2736,7 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), al::span{values, count}); } END_API_FUNC @@ -3059,12 +2751,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), + al::span<const double,1>{&value, 1}); } END_API_FUNC @@ -3078,13 +2768,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), al::span{dvals}); } END_API_FUNC @@ -3103,10 +2790,7 @@ START_API_FUNC return context->setError(AL_INVALID_VALUE, "NULL pointer"); const ALuint count{DoubleValsByProp(param)}; - float fvals[MaxValues]; - std::transform(values, values+count, fvals, - [](const double d) noexcept -> float { return static_cast<float>(d); }); - SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {fvals, count}); + SetProperty(Source, context.get(), static_cast<SourceProp>(param), al::span{values, count}); } END_API_FUNC @@ -3121,9 +2805,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), + al::span<const int,1>{&value, 1u}); } END_API_FUNC @@ -3137,12 +2822,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), al::span{ivals}); } END_API_FUNC @@ -3161,7 +2844,7 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), al::span{values, count}); } END_API_FUNC @@ -3176,9 +2859,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), + al::span<const int64_t,1>{&value, 1u}); } END_API_FUNC @@ -3192,12 +2876,10 @@ START_API_FUNC std::lock_guard<std::mutex> __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), static_cast<SourceProp>(param), al::span{i64vals}); } END_API_FUNC @@ -3216,7 +2898,7 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), al::span{values, count}); } END_API_FUNC @@ -3230,15 +2912,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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.get(), static_cast<SourceProp>(param), + al::span<float,1>{value, 1}); } END_API_FUNC @@ -3251,18 +2930,16 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), 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 @@ -3281,10 +2958,8 @@ START_API_FUNC 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::transform(dvals, dvals+count, values, - [](const double d) noexcept -> float { return static_cast<float>(d); }); + std::ignore = GetProperty(Source, context.get(), static_cast<SourceProp>(param), + al::span{values, count}); } END_API_FUNC @@ -3298,11 +2973,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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.get(), static_cast<SourceProp>(param), + al::span<double,1>{value, 1u}); } END_API_FUNC @@ -3315,18 +2991,16 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), 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 @@ -3345,7 +3019,8 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), + al::span{values, count}); } END_API_FUNC @@ -3359,11 +3034,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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.get(), static_cast<SourceProp>(param), + al::span{value, 1u}); } END_API_FUNC @@ -3376,18 +3052,16 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), 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 @@ -3406,7 +3080,8 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), + al::span{values, count}); } END_API_FUNC @@ -3420,11 +3095,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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.get(), static_cast<SourceProp>(param), + al::span{value, 1u}); } END_API_FUNC @@ -3437,18 +3113,16 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), 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(Source, context.get(), 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 @@ -3467,7 +3141,8 @@ START_API_FUNC 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.get(), static_cast<SourceProp>(param), + al::span{values, count}); } END_API_FUNC |