aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-04-27 08:04:09 -0700
committerChris Robinson <[email protected]>2021-04-27 08:04:09 -0700
commit99157f149f180cfcc2e4be6a3d2a54843411e87a (patch)
treea813425be6d0cc5ee217ece901bb0ab483c02acd /core
parent26c8c50c2605e377f74d7a73bae3bbbf4f7bad61 (diff)
Move ContextBase and VoiceChange to core
Diffstat (limited to 'core')
-rw-r--r--core/context.cpp5
-rw-r--r--core/context.h171
-rw-r--r--core/voice_change.h31
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 */