Avoid class templates for the POPCNT64/CTZ64 macros
[openal-soft.git] / alc / voice.h
blob29ca048434c88944e2c4fd7c659e417283d37500
1 #ifndef VOICE_H
2 #define VOICE_H
4 #include <array>
6 #include "AL/al.h"
7 #include "AL/alext.h"
9 #include "al/buffer.h"
10 #include "almalloc.h"
11 #include "alspan.h"
12 #include "alu.h"
13 #include "buffer_storage.h"
14 #include "devformat.h"
15 #include "filters/biquad.h"
16 #include "filters/nfc.h"
17 #include "filters/splitter.h"
18 #include "hrtf.h"
20 enum class DistanceModel;
23 enum class SpatializeMode : unsigned char {
24 Off = AL_FALSE,
25 On = AL_TRUE,
26 Auto = AL_AUTO_SOFT
29 enum class DirectMode : unsigned char {
30 Off = AL_FALSE,
31 DropMismatch = AL_DROP_UNMATCHED_SOFT,
32 RemixMismatch = AL_REMIX_UNMATCHED_SOFT
35 enum class Resampler {
36 Point,
37 Linear,
38 Cubic,
39 FastBSinc12,
40 BSinc12,
41 FastBSinc24,
42 BSinc24,
44 Max = BSinc24
46 extern Resampler ResamplerDefault;
49 /* Interpolator state. Kind of a misnomer since the interpolator itself is
50 * stateless. This just keeps it from having to recompute scale-related
51 * mappings for every sample.
53 struct BsincState {
54 float sf; /* Scale interpolation factor. */
55 ALuint m; /* Coefficient count. */
56 ALuint l; /* Left coefficient offset. */
57 /* Filter coefficients, followed by the phase, scale, and scale-phase
58 * delta coefficients. Starting at phase index 0, each subsequent phase
59 * index follows contiguously.
61 const float *filter;
64 union InterpState {
65 BsincState bsinc;
68 using ResamplerFunc = const float*(*)(const InterpState *state, const float *RESTRICT src,
69 ALuint frac, ALuint increment, const al::span<float> dst);
71 ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state);
74 enum {
75 AF_None = 0,
76 AF_LowPass = 1,
77 AF_HighPass = 2,
78 AF_BandPass = AF_LowPass | AF_HighPass
82 struct MixHrtfFilter {
83 const HrirArray *Coeffs;
84 std::array<ALuint,2> Delay;
85 float Gain;
86 float GainStep;
90 struct DirectParams {
91 BiquadFilter LowPass;
92 BiquadFilter HighPass;
94 NfcFilter NFCtrlFilter;
96 struct {
97 HrtfFilter Old;
98 HrtfFilter Target;
99 alignas(16) std::array<float,HRTF_HISTORY_LENGTH> History;
100 } Hrtf;
102 struct {
103 std::array<float,MAX_OUTPUT_CHANNELS> Current;
104 std::array<float,MAX_OUTPUT_CHANNELS> Target;
105 } Gains;
108 struct SendParams {
109 BiquadFilter LowPass;
110 BiquadFilter HighPass;
112 struct {
113 std::array<float,MAX_OUTPUT_CHANNELS> Current;
114 std::array<float,MAX_OUTPUT_CHANNELS> Target;
115 } Gains;
119 struct VoiceProps {
120 float Pitch;
121 float Gain;
122 float OuterGain;
123 float MinGain;
124 float MaxGain;
125 float InnerAngle;
126 float OuterAngle;
127 float RefDistance;
128 float MaxDistance;
129 float RolloffFactor;
130 std::array<float,3> Position;
131 std::array<float,3> Velocity;
132 std::array<float,3> Direction;
133 std::array<float,3> OrientAt;
134 std::array<float,3> OrientUp;
135 bool HeadRelative;
136 DistanceModel mDistanceModel;
137 Resampler mResampler;
138 DirectMode DirectChannels;
139 SpatializeMode mSpatializeMode;
141 bool DryGainHFAuto;
142 bool WetGainAuto;
143 bool WetGainHFAuto;
144 float OuterGainHF;
146 float AirAbsorptionFactor;
147 float RoomRolloffFactor;
148 float DopplerFactor;
150 std::array<float,2> StereoPan;
152 float Radius;
154 /** Direct filter and auxiliary send info. */
155 struct {
156 float Gain;
157 float GainHF;
158 float HFReference;
159 float GainLF;
160 float LFReference;
161 } Direct;
162 struct SendData {
163 ALeffectslot *Slot;
164 float Gain;
165 float GainHF;
166 float HFReference;
167 float GainLF;
168 float LFReference;
169 } Send[MAX_SENDS];
172 struct VoicePropsItem : public VoiceProps {
173 std::atomic<VoicePropsItem*> next{nullptr};
175 DEF_NEWDEL(VoicePropsItem)
178 #define VOICE_IS_STATIC (1u<<0)
179 #define VOICE_IS_CALLBACK (1u<<1)
180 #define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */
181 #define VOICE_CALLBACK_STOPPED (1u<<3)
182 #define VOICE_IS_FADING (1u<<4) /* Fading sources use gain stepping for smooth transitions. */
183 #define VOICE_HAS_HRTF (1u<<5)
184 #define VOICE_HAS_NFC (1u<<6)
186 #define VOICE_TYPE_MASK (VOICE_IS_STATIC | VOICE_IS_CALLBACK)
188 struct Voice {
189 enum State {
190 Stopped,
191 Playing,
192 Stopping,
193 Pending
196 std::atomic<VoicePropsItem*> mUpdate{nullptr};
198 VoiceProps mProps;
200 std::atomic<ALuint> mSourceID{0u};
201 std::atomic<State> mPlayState{Stopped};
202 std::atomic<bool> mPendingChange{false};
205 * Source offset in samples, relative to the currently playing buffer, NOT
206 * the whole queue.
208 std::atomic<ALuint> mPosition;
209 /** Fractional (fixed-point) offset to the next sample. */
210 std::atomic<ALuint> mPositionFrac;
212 /* Current buffer queue item being played. */
213 std::atomic<ALbufferlistitem*> mCurrentBuffer;
215 /* Buffer queue item to loop to at end of queue (will be NULL for non-
216 * looping voices).
218 std::atomic<ALbufferlistitem*> mLoopBuffer;
220 /* Properties for the attached buffer(s). */
221 FmtChannels mFmtChannels;
222 ALuint mFrequency;
223 ALuint mSampleSize;
224 AmbiLayout mAmbiLayout;
225 AmbiScaling mAmbiScaling;
226 ALuint mAmbiOrder;
228 /** Current target parameters used for mixing. */
229 ALuint mStep{0};
231 ResamplerFunc mResampler;
233 InterpState mResampleState;
235 ALuint mFlags{};
236 ALuint mNumCallbackSamples{0};
238 struct TargetData {
239 int FilterType;
240 al::span<FloatBufferLine> Buffer;
242 TargetData mDirect;
243 std::array<TargetData,MAX_SENDS> mSend;
245 struct ChannelData {
246 alignas(16) std::array<float,MAX_RESAMPLER_PADDING> mPrevSamples;
248 float mAmbiScale;
249 BandSplitter mAmbiSplitter;
251 DirectParams mDryParams;
252 std::array<SendParams,MAX_SENDS> mWetParams;
254 al::vector<ChannelData> mChans{2};
256 Voice() = default;
257 Voice(const Voice&) = delete;
258 ~Voice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); }
259 Voice& operator=(const Voice&) = delete;
261 void mix(const State vstate, ALCcontext *Context, const ALuint SamplesToDo);
263 DEF_NEWDEL(Voice)
266 #endif /* VOICE_H */