Combine some duplicate code to mix each channel
[openal-soft.git] / core / context.h
blob9723eac38c8b63b6d4511334ce5aa32e0474ad73
1 #ifndef CORE_CONTEXT_H
2 #define CORE_CONTEXT_H
4 #include <array>
5 #include <atomic>
6 #include <bitset>
7 #include <cstddef>
8 #include <memory>
9 #include <thread>
11 #include "almalloc.h"
12 #include "alspan.h"
13 #include "async_event.h"
14 #include "atomic.h"
15 #include "bufferline.h"
16 #include "threads.h"
17 #include "vecmat.h"
18 #include "vector.h"
20 struct DeviceBase;
21 struct EffectSlot;
22 struct EffectSlotProps;
23 struct RingBuffer;
24 struct Voice;
25 struct VoiceChange;
26 struct VoicePropsItem;
28 using uint = unsigned int;
31 constexpr float SpeedOfSoundMetersPerSec{343.3f};
33 constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
35 enum class DistanceModel : unsigned char {
36 Disable,
37 Inverse, InverseClamped,
38 Linear, LinearClamped,
39 Exponent, ExponentClamped,
41 Default = InverseClamped
45 struct ContextProps {
46 std::array<float,3> Position;
47 std::array<float,3> Velocity;
48 std::array<float,3> OrientAt;
49 std::array<float,3> OrientUp;
50 float Gain;
51 float MetersPerUnit;
52 float AirAbsorptionGainHF;
54 float DopplerFactor;
55 float DopplerVelocity;
56 float SpeedOfSound;
57 bool SourceDistanceModel;
58 DistanceModel mDistanceModel;
60 std::atomic<ContextProps*> next;
62 DEF_NEWDEL(ContextProps)
65 struct ContextParams {
66 /* Pointer to the most recent property values that are awaiting an update. */
67 std::atomic<ContextProps*> ContextUpdate{nullptr};
69 alu::Vector Position{};
70 alu::Matrix Matrix{alu::Matrix::Identity()};
71 alu::Vector Velocity{};
73 float Gain{1.0f};
74 float MetersPerUnit{1.0f};
75 float AirAbsorptionGainHF{AirAbsorbGainHF};
77 float DopplerFactor{1.0f};
78 float SpeedOfSound{SpeedOfSoundMetersPerSec}; /* in units per sec! */
80 bool SourceDistanceModel{false};
81 DistanceModel mDistanceModel{};
84 struct ContextBase {
85 DeviceBase *const mDevice;
87 /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
88 * indicates if updates are currently happening).
90 RefCount mUpdateCount{0u};
91 std::atomic<bool> mHoldUpdates{false};
92 std::atomic<bool> mStopVoicesOnDisconnect{true};
94 float mGainBoost{1.0f};
96 /* Linked lists of unused property containers, free to use for future
97 * updates.
99 std::atomic<ContextProps*> mFreeContextProps{nullptr};
100 std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
101 std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr};
103 /* The voice change tail is the beginning of the "free" elements, up to and
104 * *excluding* the current. If tail==current, there's no free elements and
105 * new ones need to be allocated. The current voice change is the element
106 * last processed, and any after are pending.
108 VoiceChange *mVoiceChangeTail{};
109 std::atomic<VoiceChange*> mCurrentVoiceChange{};
111 void allocVoiceChanges();
112 void allocVoiceProps();
115 ContextParams mParams;
117 using VoiceArray = al::FlexArray<Voice*>;
118 std::atomic<VoiceArray*> mVoices{};
119 std::atomic<size_t> mActiveVoiceCount{};
121 void allocVoices(size_t addcount);
122 al::span<Voice*> getVoicesSpan() const noexcept
124 return {mVoices.load(std::memory_order_relaxed)->data(),
125 mActiveVoiceCount.load(std::memory_order_relaxed)};
127 al::span<Voice*> getVoicesSpanAcquired() const noexcept
129 return {mVoices.load(std::memory_order_acquire)->data(),
130 mActiveVoiceCount.load(std::memory_order_acquire)};
134 using EffectSlotArray = al::FlexArray<EffectSlot*>;
135 std::atomic<EffectSlotArray*> mActiveAuxSlots{nullptr};
137 std::thread mEventThread;
138 al::semaphore mEventSem;
139 std::unique_ptr<RingBuffer> mAsyncEvents;
140 using AsyncEventBitset = std::bitset<AsyncEvent::UserEventCount>;
141 std::atomic<AsyncEventBitset> mEnabledEvts{0u};
143 /* Asynchronous voice change actions are processed as a linked list of
144 * VoiceChange objects by the mixer, which is atomically appended to.
145 * However, to avoid allocating each object individually, they're allocated
146 * in clusters that are stored in a vector for easy automatic cleanup.
148 using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
149 al::vector<VoiceChangeCluster> mVoiceChangeClusters;
151 using VoiceCluster = std::unique_ptr<Voice[]>;
152 al::vector<VoiceCluster> mVoiceClusters;
154 using VoicePropsCluster = std::unique_ptr<VoicePropsItem[]>;
155 al::vector<VoicePropsCluster> mVoicePropClusters;
158 static constexpr size_t EffectSlotClusterSize{4};
159 EffectSlot *getEffectSlot();
161 using EffectSlotCluster = std::unique_ptr<EffectSlot[]>;
162 al::vector<EffectSlotCluster> mEffectSlotClusters;
165 ContextBase(DeviceBase *device);
166 ContextBase(const ContextBase&) = delete;
167 ContextBase& operator=(const ContextBase&) = delete;
168 ~ContextBase();
171 #endif /* CORE_CONTEXT_H */