16 #include "async_event.h"
18 #include "flexarray.h"
19 #include "opthelpers.h"
24 struct EffectSlotProps
;
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 {
37 Inverse
, InverseClamped
,
38 Linear
, LinearClamped
,
39 Exponent
, ExponentClamped
,
41 Default
= InverseClamped
46 std::array
<float,3> Position
;
47 std::array
<float,3> Velocity
;
48 std::array
<float,3> OrientAt
;
49 std::array
<float,3> OrientUp
;
52 float AirAbsorptionGainHF
;
55 float DopplerVelocity
;
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
{};
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
{};
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
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 */