#ifndef ALCONTEXT_H #define ALCONTEXT_H #include #include #include #include #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "inprogext.h" #include "atomic.h" #include "vector.h" #include "threads.h" #include "almalloc.h" #include "alnumeric.h" #include "alListener.h" struct ALsource; struct ALeffectslot; struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; struct ALeffectslotProps; struct ALvoice; struct RingBuffer; enum class DistanceModel { InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED, Inverse = AL_INVERSE_DISTANCE, Linear = AL_LINEAR_DISTANCE, Exponent = AL_EXPONENT_DISTANCE, Disable = AL_NONE, Default = InverseClamped }; struct SourceSubList { uint64_t FreeMask{~0_u64}; ALsource *Sources{nullptr}; /* 64 */ SourceSubList() noexcept = default; SourceSubList(const SourceSubList&) = delete; SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources} { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; } ~SourceSubList(); SourceSubList& operator=(const SourceSubList&) = delete; SourceSubList& operator=(SourceSubList&& rhs) noexcept { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; } }; struct EffectSlotSubList { uint64_t FreeMask{~0_u64}; ALeffectslot *EffectSlots{nullptr}; /* 64 */ EffectSlotSubList() noexcept = default; EffectSlotSubList(const EffectSlotSubList&) = delete; EffectSlotSubList(EffectSlotSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots} { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; } ~EffectSlotSubList(); EffectSlotSubList& operator=(const EffectSlotSubList&) = delete; EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; } }; struct ALCcontext { RefCount ref{1u}; al::vector SourceList; ALuint NumSources{0}; std::mutex SourceLock; al::vector EffectSlotList; ALuint NumEffectSlots{0u}; std::mutex EffectSlotLock; std::atomic LastError{AL_NO_ERROR}; DistanceModel mDistanceModel{DistanceModel::Default}; ALboolean SourceDistanceModel{AL_FALSE}; ALfloat DopplerFactor{1.0f}; ALfloat DopplerVelocity{1.0f}; ALfloat SpeedOfSound{}; ALfloat MetersPerUnit{1.0f}; std::atomic_flag PropsClean; std::atomic DeferUpdates{false}; std::mutex PropLock; /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit * indicates if updates are currently happening). */ RefCount UpdateCount{0u}; std::atomic HoldUpdates{false}; ALfloat GainBoost{1.0f}; std::atomic Update{nullptr}; /* Linked lists of unused property containers, free to use for future * updates. */ std::atomic FreeContextProps{nullptr}; std::atomic FreeListenerProps{nullptr}; std::atomic FreeVoiceProps{nullptr}; std::atomic FreeEffectslotProps{nullptr}; ALvoice **Voices{nullptr}; std::atomic VoiceCount{0}; ALsizei MaxVoices{0}; using ALeffectslotArray = al::FlexArray; std::atomic ActiveAuxSlots{nullptr}; std::thread EventThread; al::semaphore EventSem; std::unique_ptr AsyncEvents; std::atomic EnabledEvts{0u}; std::mutex EventCbLock; ALEVENTPROCSOFT EventCb{}; void *EventParam{nullptr}; /* Default effect slot */ std::unique_ptr DefaultSlot; ALCdevice *const Device; const ALCchar *ExtensionList{nullptr}; std::atomic next{nullptr}; ALlistener Listener{}; ALCcontext(ALCdevice *device); ALCcontext(const ALCcontext&) = delete; ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); static constexpr inline const char *CurrentPrefix() noexcept { return "ALCcontext::"; } DEF_NEWDEL(ALCcontext) }; void ALCcontext_DecRef(ALCcontext *context); void UpdateContextProps(ALCcontext *context); void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); /* Simple RAII context reference. Takes the reference of the provided * ALCcontext, and decrements it when leaving scope. Movable (transfer * reference) but not copyable (no new references). */ class ContextRef { ALCcontext *mCtx{nullptr}; void reset() noexcept { if(mCtx) ALCcontext_DecRef(mCtx); mCtx = nullptr; } public: ContextRef() noexcept = default; ContextRef(ContextRef&& rhs) noexcept : mCtx{rhs.mCtx} { rhs.mCtx = nullptr; } explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } ~ContextRef() { reset(); } ContextRef& operator=(const ContextRef&) = delete; ContextRef& operator=(ContextRef&& rhs) noexcept { std::swap(mCtx, rhs.mCtx); return *this; } operator bool() const noexcept { return mCtx != nullptr; } ALCcontext* operator->() noexcept { return mCtx; } ALCcontext* get() noexcept { return mCtx; } ALCcontext* release() noexcept { ALCcontext *ret{mCtx}; mCtx = nullptr; return ret; } }; ContextRef GetContextRef(void); struct ALcontextProps { ALfloat DopplerFactor; ALfloat DopplerVelocity; ALfloat SpeedOfSound; ALboolean SourceDistanceModel; DistanceModel mDistanceModel; ALfloat MetersPerUnit; std::atomic next; }; #endif /* ALCONTEXT_H */