diff options
author | Chris Robinson <[email protected]> | 2021-04-27 08:04:09 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2021-04-27 08:04:09 -0700 |
commit | 99157f149f180cfcc2e4be6a3d2a54843411e87a (patch) | |
tree | a813425be6d0cc5ee217ece901bb0ab483c02acd /core | |
parent | 26c8c50c2605e377f74d7a73bae3bbbf4f7bad61 (diff) |
Move ContextBase and VoiceChange to core
Diffstat (limited to 'core')
-rw-r--r-- | core/context.cpp | 5 | ||||
-rw-r--r-- | core/context.h | 171 | ||||
-rw-r--r-- | core/voice_change.h | 31 |
3 files changed, 207 insertions, 0 deletions
diff --git a/core/context.cpp b/core/context.cpp new file mode 100644 index 00000000..f1c310aa --- /dev/null +++ b/core/context.cpp @@ -0,0 +1,5 @@ + +#include "config.h" + +#include "context.h" + diff --git a/core/context.h b/core/context.h new file mode 100644 index 00000000..bf439053 --- /dev/null +++ b/core/context.h @@ -0,0 +1,171 @@ +#ifndef CORE_CONTEXT_H +#define CORE_CONTEXT_H + +#include <array> +#include <atomic> +#include <cstddef> +#include <memory> +#include <thread> + +#include "almalloc.h" +#include "alspan.h" +#include "atomic.h" +#include "core/bufferline.h" +#include "threads.h" +#include "vecmat.h" +#include "vector.h" + +struct DeviceBase; +struct EffectSlot; +struct EffectSlotProps; +struct RingBuffer; +struct Voice; +struct VoiceChange; +struct VoicePropsItem; + +using uint = unsigned int; + + +constexpr float SpeedOfSoundMetersPerSec{343.3f}; + +enum class DistanceModel : unsigned char { + Disable, + Inverse, InverseClamped, + Linear, LinearClamped, + Exponent, ExponentClamped, + + Default = InverseClamped +}; + + +struct WetBuffer { + bool mInUse; + al::FlexArray<FloatBufferLine, 16> mBuffer; + + WetBuffer(size_t count) : mBuffer{count} { } + + DEF_FAM_NEWDEL(WetBuffer, mBuffer) +}; +using WetBufferPtr = std::unique_ptr<WetBuffer>; + + +struct ContextProps { + float DopplerFactor; + float DopplerVelocity; + float SpeedOfSound; + bool SourceDistanceModel; + DistanceModel mDistanceModel; + + std::atomic<ContextProps*> next; + + DEF_NEWDEL(ContextProps) +}; + +struct ListenerProps { + std::array<float,3> Position; + std::array<float,3> Velocity; + std::array<float,3> OrientAt; + std::array<float,3> OrientUp; + float Gain; + float MetersPerUnit; + + std::atomic<ListenerProps*> next; + + DEF_NEWDEL(ListenerProps) +}; + +struct ContextParams { + /* Pointer to the most recent property values that are awaiting an update. */ + std::atomic<ContextProps*> ContextUpdate{nullptr}; + std::atomic<ListenerProps*> ListenerUpdate{nullptr}; + + alu::Matrix Matrix{alu::Matrix::Identity()}; + alu::Vector Velocity{}; + + float Gain{1.0f}; + float MetersPerUnit{1.0f}; + + float DopplerFactor{1.0f}; + float SpeedOfSound{343.3f}; /* in units per sec! */ + + bool SourceDistanceModel{false}; + DistanceModel mDistanceModel{}; +}; + +struct ContextBase { + DeviceBase *const mDevice; + + /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit + * indicates if updates are currently happening). + */ + RefCount mUpdateCount{0u}; + std::atomic<bool> mHoldUpdates{false}; + std::atomic<bool> mStopVoicesOnDisconnect{true}; + + float mGainBoost{1.0f}; + + /* Linked lists of unused property containers, free to use for future + * updates. + */ + std::atomic<ContextProps*> mFreeContextProps{nullptr}; + std::atomic<ListenerProps*> mFreeListenerProps{nullptr}; + std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr}; + std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr}; + + /* The voice change tail is the beginning of the "free" elements, up to and + * *excluding* the current. If tail==current, there's no free elements and + * new ones need to be allocated. The current voice change is the element + * last processed, and any after are pending. + */ + VoiceChange *mVoiceChangeTail{}; + std::atomic<VoiceChange*> mCurrentVoiceChange{}; + + void allocVoiceChanges(size_t addcount); + + + ContextParams mParams; + + using VoiceArray = al::FlexArray<Voice*>; + std::atomic<VoiceArray*> mVoices{}; + std::atomic<size_t> mActiveVoiceCount{}; + + void allocVoices(size_t addcount); + al::span<Voice*> getVoicesSpan() const noexcept + { + return {mVoices.load(std::memory_order_relaxed)->data(), + mActiveVoiceCount.load(std::memory_order_relaxed)}; + } + al::span<Voice*> getVoicesSpanAcquired() const noexcept + { + return {mVoices.load(std::memory_order_acquire)->data(), + mActiveVoiceCount.load(std::memory_order_acquire)}; + } + + + using EffectSlotArray = al::FlexArray<EffectSlot*>; + std::atomic<EffectSlotArray*> mActiveAuxSlots{nullptr}; + + std::thread mEventThread; + al::semaphore mEventSem; + std::unique_ptr<RingBuffer> mAsyncEvents; + std::atomic<uint> mEnabledEvts{0u}; + + /* Asynchronous voice change actions are processed as a linked list of + * VoiceChange objects by the mixer, which is atomically appended to. + * However, to avoid allocating each object individually, they're allocated + * in clusters that are stored in a vector for easy automatic cleanup. + */ + using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>; + al::vector<VoiceChangeCluster> mVoiceChangeClusters; + + using VoiceCluster = std::unique_ptr<Voice[]>; + al::vector<VoiceCluster> mVoiceClusters; + + + ContextBase(DeviceBase *device); + ContextBase(const ContextBase&) = delete; + ContextBase& operator=(const ContextBase&) = delete; + ~ContextBase(); +}; + +#endif /* CORE_CONTEXT_H */ diff --git a/core/voice_change.h b/core/voice_change.h new file mode 100644 index 00000000..ddc6186f --- /dev/null +++ b/core/voice_change.h @@ -0,0 +1,31 @@ +#ifndef VOICE_CHANGE_H +#define VOICE_CHANGE_H + +#include <atomic> + +#include "almalloc.h" + +struct Voice; + +using uint = unsigned int; + + +enum class VChangeState { + Reset, + Stop, + Play, + Pause, + Restart +}; +struct VoiceChange { + Voice *mOldVoice{nullptr}; + Voice *mVoice{nullptr}; + uint mSourceID{0}; + VChangeState mState{}; + + std::atomic<VoiceChange*> mNext{nullptr}; + + DEF_NEWDEL(VoiceChange) +}; + +#endif /* VOICE_CHANGE_H */ |