Use separate 32-bit second and nanosecond atomics for the clock
[openal-soft.git] / core / voice.h
blobfab573e45bca94856e58f1f638f25e2ee3afd2ba
1 #ifndef CORE_VOICE_H
2 #define CORE_VOICE_H
4 #include <array>
5 #include <atomic>
6 #include <bitset>
7 #include <chrono>
8 #include <cstddef>
9 #include <memory>
10 #include <optional>
11 #include <string>
13 #include "alspan.h"
14 #include "bufferline.h"
15 #include "buffer_storage.h"
16 #include "devformat.h"
17 #include "filters/biquad.h"
18 #include "filters/nfc.h"
19 #include "filters/splitter.h"
20 #include "mixer/defs.h"
21 #include "mixer/hrtfdefs.h"
22 #include "opthelpers.h"
23 #include "resampler_limits.h"
24 #include "uhjfilter.h"
25 #include "vector.h"
27 struct ContextBase;
28 struct DeviceBase;
29 struct EffectSlot;
30 enum class DistanceModel : unsigned char;
32 using uint = unsigned int;
35 inline constexpr size_t MaxSendCount{6};
38 enum class SpatializeMode : unsigned char {
39 Off,
40 On,
41 Auto
44 enum class DirectMode : unsigned char {
45 Off,
46 DropMismatch,
47 RemixMismatch
51 inline constexpr uint MaxPitch{10};
54 enum {
55 AF_None = 0,
56 AF_LowPass = 1,
57 AF_HighPass = 2,
58 AF_BandPass = AF_LowPass | AF_HighPass
62 struct DirectParams {
63 BiquadFilter LowPass;
64 BiquadFilter HighPass;
66 NfcFilter NFCtrlFilter;
68 struct HrtfParams {
69 HrtfFilter Old{};
70 HrtfFilter Target{};
71 alignas(16) std::array<float,HrtfHistoryLength> History{};
73 HrtfParams Hrtf;
75 struct GainParams {
76 std::array<float,MaxOutputChannels> Current{};
77 std::array<float,MaxOutputChannels> Target{};
79 GainParams Gains;
82 struct SendParams {
83 BiquadFilter LowPass;
84 BiquadFilter HighPass;
86 struct GainParams {
87 std::array<float,MaxAmbiChannels> Current{};
88 std::array<float,MaxAmbiChannels> Target{};
90 GainParams Gains;
94 struct VoiceBufferItem {
95 std::atomic<VoiceBufferItem*> mNext{nullptr};
97 CallbackType mCallback{nullptr};
98 void *mUserData{nullptr};
100 uint mBlockAlign{0u};
101 uint mSampleLen{0u};
102 uint mLoopStart{0u};
103 uint mLoopEnd{0u};
105 al::span<std::byte> mSamples{};
107 protected:
108 ~VoiceBufferItem() = default;
112 struct VoiceProps {
113 float Pitch;
114 float Gain;
115 float OuterGain;
116 float MinGain;
117 float MaxGain;
118 float InnerAngle;
119 float OuterAngle;
120 float RefDistance;
121 float MaxDistance;
122 float RolloffFactor;
123 std::array<float,3> Position;
124 std::array<float,3> Velocity;
125 std::array<float,3> Direction;
126 std::array<float,3> OrientAt;
127 std::array<float,3> OrientUp;
128 bool HeadRelative;
129 DistanceModel mDistanceModel;
130 Resampler mResampler;
131 DirectMode DirectChannels;
132 SpatializeMode mSpatializeMode;
134 bool DryGainHFAuto;
135 bool WetGainAuto;
136 bool WetGainHFAuto;
137 float OuterGainHF;
139 float AirAbsorptionFactor;
140 float RoomRolloffFactor;
141 float DopplerFactor;
143 std::array<float,2> StereoPan;
145 float Radius;
146 float EnhWidth;
147 float Panning;
149 /** Direct filter and auxiliary send info. */
150 struct DirectData {
151 float Gain;
152 float GainHF;
153 float HFReference;
154 float GainLF;
155 float LFReference;
157 DirectData Direct;
159 struct SendData {
160 EffectSlot *Slot;
161 float Gain;
162 float GainHF;
163 float HFReference;
164 float GainLF;
165 float LFReference;
167 std::array<SendData,MaxSendCount> Send;
170 struct VoicePropsItem : public VoiceProps {
171 std::atomic<VoicePropsItem*> next{nullptr};
174 enum : uint {
175 VoiceIsStatic,
176 VoiceIsCallback,
177 VoiceIsAmbisonic,
178 VoiceCallbackStopped,
179 VoiceIsFading,
180 VoiceHasHrtf,
181 VoiceHasNfc,
183 VoiceFlagCount
186 struct SIMDALIGN Voice {
187 enum State {
188 Stopped,
189 Playing,
190 Stopping,
191 Pending
194 std::atomic<VoicePropsItem*> mUpdate{nullptr};
196 VoiceProps mProps{};
198 std::atomic<uint> mSourceID{0u};
199 std::atomic<State> mPlayState{Stopped};
200 std::atomic<bool> mPendingChange{false};
203 * Source offset in samples, relative to the currently playing buffer, NOT
204 * the whole queue.
206 std::atomic<int> mPosition{};
207 /** Fractional (fixed-point) offset to the next sample. */
208 std::atomic<uint> mPositionFrac{};
210 /* Current buffer queue item being played. */
211 std::atomic<VoiceBufferItem*> mCurrentBuffer{};
213 /* Buffer queue item to loop to at end of queue (will be NULL for non-
214 * looping voices).
216 std::atomic<VoiceBufferItem*> mLoopBuffer{};
218 std::chrono::nanoseconds mStartTime{};
220 /* Properties for the attached buffer(s). */
221 FmtChannels mFmtChannels{};
222 FmtType mFmtType{};
223 uint mFrequency{};
224 uint mFrameStep{}; /**< In steps of the sample type size. */
225 uint mBytesPerBlock{}; /**< Or for PCM formats, BytesPerFrame. */
226 uint mSamplesPerBlock{}; /**< Always 1 for PCM formats. */
227 AmbiLayout mAmbiLayout{};
228 AmbiScaling mAmbiScaling{};
229 uint mAmbiOrder{};
231 std::unique_ptr<DecoderBase> mDecoder;
232 uint mDecoderPadding{};
234 /** Current target parameters used for mixing. */
235 uint mStep{0};
237 ResamplerFunc mResampler{};
239 InterpState mResampleState{};
241 std::bitset<VoiceFlagCount> mFlags{};
242 uint mNumCallbackBlocks{0};
243 uint mCallbackBlockBase{0};
245 struct TargetData {
246 int FilterType{};
247 al::span<FloatBufferLine> Buffer;
249 TargetData mDirect;
250 std::array<TargetData,MaxSendCount> mSend;
252 /* The first MaxResamplerPadding/2 elements are the sample history from the
253 * previous mix, with an additional MaxResamplerPadding/2 elements that are
254 * now current (which may be overwritten if the buffer data is still
255 * available).
257 using HistoryLine = std::array<float,MaxResamplerPadding>;
258 al::vector<HistoryLine,16> mPrevSamples{2};
260 struct ChannelData {
261 float mAmbiHFScale{}, mAmbiLFScale{};
262 BandSplitter mAmbiSplitter;
264 DirectParams mDryParams;
265 std::array<SendParams,MaxSendCount> mWetParams;
267 al::vector<ChannelData> mChans{2};
269 Voice() = default;
270 ~Voice() = default;
272 Voice(const Voice&) = delete;
273 Voice& operator=(const Voice&) = delete;
275 void mix(const State vstate, ContextBase *Context, const std::chrono::nanoseconds deviceTime,
276 const uint SamplesToDo);
278 void prepare(DeviceBase *device);
280 static void InitMixer(std::optional<std::string> resopt);
283 inline Resampler ResamplerDefault{Resampler::Gaussian};
285 #endif /* CORE_VOICE_H */