Recogmize jack64 for finding the JACK library name
[openal-soft.git] / core / context.h
blobc2fcb1a479eb09dcc815dd034ae18f6acd2d3091
1 #ifndef CORE_CONTEXT_H
2 #define CORE_CONTEXT_H
4 #include "config.h"
6 #include <array>
7 #include <atomic>
8 #include <bitset>
9 #include <cstddef>
10 #include <memory>
11 #include <thread>
12 #include <vector>
14 #include "alsem.h"
15 #include "alspan.h"
16 #include "async_event.h"
17 #include "atomic.h"
18 #include "flexarray.h"
19 #include "opthelpers.h"
20 #include "vecmat.h"
22 struct DeviceBase;
23 struct EffectSlot;
24 struct EffectSlotProps;
25 struct RingBuffer;
26 struct Voice;
27 struct VoiceChange;
28 struct VoicePropsItem;
31 inline constexpr float SpeedOfSoundMetersPerSec{343.3f};
33 inline 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 #if ALSOFT_EAX
58 float DistanceFactor;
59 #endif
60 bool SourceDistanceModel;
61 DistanceModel mDistanceModel;
63 std::atomic<ContextProps*> next;
66 struct ContextParams {
67 /* Pointer to the most recent property values that are awaiting an update. */
68 std::atomic<ContextProps*> ContextUpdate{nullptr};
70 alu::Vector Position{};
71 alu::Matrix Matrix{alu::Matrix::Identity()};
72 alu::Vector Velocity{};
74 float Gain{1.0f};
75 float MetersPerUnit{1.0f};
76 float AirAbsorptionGainHF{AirAbsorbGainHF};
78 float DopplerFactor{1.0f};
79 float SpeedOfSound{SpeedOfSoundMetersPerSec}; /* in units per sec! */
81 bool SourceDistanceModel{false};
82 DistanceModel mDistanceModel{};
85 struct ContextBase {
86 DeviceBase *const mDevice;
88 /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
89 * indicates if updates are currently happening).
91 std::atomic<unsigned int> mUpdateCount{0u};
92 std::atomic<bool> mHoldUpdates{false};
93 std::atomic<bool> mStopVoicesOnDisconnect{true};
95 float mGainBoost{1.0f};
97 /* Linked lists of unused property containers, free to use for future
98 * updates.
100 std::atomic<ContextProps*> mFreeContextProps{nullptr};
101 std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
102 std::atomic<EffectSlotProps*> mFreeEffectSlotProps{nullptr};
104 /* The voice change tail is the beginning of the "free" elements, up to and
105 * *excluding* the current. If tail==current, there's no free elements and
106 * new ones need to be allocated. The current voice change is the element
107 * last processed, and any after are pending.
109 VoiceChange *mVoiceChangeTail{};
110 std::atomic<VoiceChange*> mCurrentVoiceChange{};
112 void allocVoiceChanges();
113 void allocVoiceProps();
114 void allocEffectSlotProps();
115 void allocContextProps();
117 ContextParams mParams;
119 using VoiceArray = al::FlexArray<Voice*>;
120 al::atomic_unique_ptr<VoiceArray> mVoices{};
121 std::atomic<size_t> mActiveVoiceCount{};
123 void allocVoices(size_t addcount);
124 [[nodiscard]] auto getVoicesSpan() const noexcept -> al::span<Voice*>
126 return {mVoices.load(std::memory_order_relaxed)->data(),
127 mActiveVoiceCount.load(std::memory_order_relaxed)};
129 [[nodiscard]] auto getVoicesSpanAcquired() const noexcept -> al::span<Voice*>
131 return {mVoices.load(std::memory_order_acquire)->data(),
132 mActiveVoiceCount.load(std::memory_order_acquire)};
136 using EffectSlotArray = al::FlexArray<EffectSlot*>;
137 /* This array is split in half. The front half is the list of activated
138 * effect slots as set by the app, and the back half is the same list but
139 * sorted to ensure later effect slots are fed by earlier ones.
141 al::atomic_unique_ptr<EffectSlotArray> mActiveAuxSlots;
143 std::thread mEventThread;
144 al::semaphore mEventSem;
145 std::unique_ptr<RingBuffer> mAsyncEvents;
146 using AsyncEventBitset = std::bitset<al::to_underlying(AsyncEnableBits::Count)>;
147 std::atomic<AsyncEventBitset> mEnabledEvts{0u};
149 /* Asynchronous voice change actions are processed as a linked list of
150 * VoiceChange objects by the mixer, which is atomically appended to.
151 * However, to avoid allocating each object individually, they're allocated
152 * in clusters that are stored in a vector for easy automatic cleanup.
154 using VoiceChangeCluster = std::unique_ptr<std::array<VoiceChange,128>>;
155 std::vector<VoiceChangeCluster> mVoiceChangeClusters;
157 using VoiceCluster = std::unique_ptr<std::array<Voice,32>>;
158 std::vector<VoiceCluster> mVoiceClusters;
160 using VoicePropsCluster = std::unique_ptr<std::array<VoicePropsItem,32>>;
161 std::vector<VoicePropsCluster> mVoicePropClusters;
164 EffectSlot *getEffectSlot();
166 using EffectSlotCluster = std::unique_ptr<std::array<EffectSlot,4>>;
167 std::vector<EffectSlotCluster> mEffectSlotClusters;
169 using EffectSlotPropsCluster = std::unique_ptr<std::array<EffectSlotProps,4>>;
170 std::vector<EffectSlotPropsCluster> mEffectSlotPropClusters;
172 /* This could be greater than 2, but there should be no way there can be
173 * more than two context property updates in use simultaneously.
175 using ContextPropsCluster = std::unique_ptr<std::array<ContextProps,2>>;
176 std::vector<ContextPropsCluster> mContextPropClusters;
179 ContextBase(DeviceBase *device);
180 ContextBase(const ContextBase&) = delete;
181 ContextBase& operator=(const ContextBase&) = delete;
182 virtual ~ContextBase();
185 #endif /* CORE_CONTEXT_H */