13 #include "al/buffer.h"
18 #include "devformat.h"
19 #include "filters/biquad.h"
20 #include "filters/nfc.h"
21 #include "filters/splitter.h"
25 struct ALbufferlistitem
;
30 enum class DistanceModel
;
36 #define DITHER_RNG_SEED 22222
40 SpatializeOff
= AL_FALSE
,
41 SpatializeOn
= AL_TRUE
,
42 SpatializeAuto
= AL_AUTO_SOFT
45 enum class Resampler
{
56 extern Resampler ResamplerDefault
;
58 /* The number of distinct scale and phase intervals within the bsinc filter
61 #define BSINC_SCALE_BITS 4
62 #define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
63 #define BSINC_PHASE_BITS 4
64 #define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
66 /* Interpolator state. Kind of a misnomer since the interpolator itself is
67 * stateless. This just keeps it from having to recompute scale-related
68 * mappings for every sample.
71 ALfloat sf
; /* Scale interpolation factor. */
72 ALuint m
; /* Coefficient count. */
73 ALuint l
; /* Left coefficient offset. */
74 /* Filter coefficients, followed by the scale, phase, and scale-phase
75 * delta coefficients. Starting at phase index 0, each subsequent phase
76 * index follows contiguously.
78 const ALfloat
*filter
;
85 using ResamplerFunc
= const ALfloat
*(*)(const InterpState
*state
, const ALfloat
*RESTRICT src
,
86 ALuint frac
, ALuint increment
, const al::span
<float> dst
);
88 void BsincPrepare(const ALuint increment
, BsincState
*state
, const BSincTable
*table
);
90 extern const BSincTable bsinc12
;
91 extern const BSincTable bsinc24
;
98 AF_BandPass
= AF_LowPass
| AF_HighPass
102 struct MixHrtfFilter
{
103 const HrirArray
*Coeffs
;
110 struct DirectParams
{
111 BiquadFilter LowPass
;
112 BiquadFilter HighPass
;
114 NfcFilter NFCtrlFilter
;
123 ALfloat Current
[MAX_OUTPUT_CHANNELS
];
124 ALfloat Target
[MAX_OUTPUT_CHANNELS
];
129 BiquadFilter LowPass
;
130 BiquadFilter HighPass
;
133 ALfloat Current
[MAX_OUTPUT_CHANNELS
];
134 ALfloat Target
[MAX_OUTPUT_CHANNELS
];
139 struct ALvoicePropsBase
{
149 ALfloat RolloffFactor
;
150 std::array
<ALfloat
,3> Position
;
151 std::array
<ALfloat
,3> Velocity
;
152 std::array
<ALfloat
,3> Direction
;
153 std::array
<ALfloat
,3> OrientAt
;
154 std::array
<ALfloat
,3> OrientUp
;
155 ALboolean HeadRelative
;
156 DistanceModel mDistanceModel
;
157 Resampler mResampler
;
158 ALboolean DirectChannels
;
159 SpatializeMode mSpatializeMode
;
161 ALboolean DryGainHFAuto
;
162 ALboolean WetGainAuto
;
163 ALboolean WetGainHFAuto
;
166 ALfloat AirAbsorptionFactor
;
167 ALfloat RoomRolloffFactor
;
168 ALfloat DopplerFactor
;
170 std::array
<ALfloat
,2> StereoPan
;
174 /** Direct filter and auxiliary send info. */
192 struct ALvoiceProps
: public ALvoicePropsBase
{
193 std::atomic
<ALvoiceProps
*> next
{nullptr};
195 DEF_NEWDEL(ALvoiceProps
)
198 #define VOICE_IS_STATIC (1u<<0)
199 #define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */
200 #define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */
201 #define VOICE_HAS_HRTF (1u<<3)
202 #define VOICE_HAS_NFC (1u<<4)
211 std::atomic
<ALvoiceProps
*> mUpdate
{nullptr};
213 std::atomic
<ALuint
> mSourceID
{0u};
214 std::atomic
<State
> mPlayState
{Stopped
};
216 ALvoicePropsBase mProps
;
219 * Source offset in samples, relative to the currently playing buffer, NOT
222 std::atomic
<ALuint
> mPosition
;
223 /** Fractional (fixed-point) offset to the next sample. */
224 std::atomic
<ALuint
> mPositionFrac
;
226 /* Current buffer queue item being played. */
227 std::atomic
<ALbufferlistitem
*> mCurrentBuffer
;
229 /* Buffer queue item to loop to at end of queue (will be NULL for non-
232 std::atomic
<ALbufferlistitem
*> mLoopBuffer
;
234 /* Properties for the attached buffer(s). */
235 FmtChannels mFmtChannels
;
240 /** Current target parameters used for mixing. */
243 ResamplerFunc mResampler
;
245 InterpState mResampleState
;
251 al::span
<FloatBufferLine
> Buffer
;
257 al::span
<FloatBufferLine
> Buffer
;
259 std::array
<SendData
,MAX_SENDS
> mSend
;
262 alignas(16) std::array
<ALfloat
,MAX_RESAMPLE_PADDING
*2> mPrevSamples
;
265 BandSplitter mAmbiSplitter
;
267 DirectParams mDryParams
;
268 std::array
<SendParams
,MAX_SENDS
> mWetParams
;
270 std::array
<ChannelData
,MAX_INPUT_CHANNELS
> mChans
;
273 ALvoice(const ALvoice
&) = delete;
274 ALvoice(ALvoice
&& rhs
) noexcept
{ *this = std::move(rhs
); }
275 ~ALvoice() { delete mUpdate
.exchange(nullptr, std::memory_order_acq_rel
); }
276 ALvoice
& operator=(const ALvoice
&) = delete;
277 ALvoice
& operator=(ALvoice
&& rhs
) noexcept
279 ALvoiceProps
*old_update
{mUpdate
.load(std::memory_order_relaxed
)};
280 mUpdate
.store(rhs
.mUpdate
.exchange(old_update
, std::memory_order_relaxed
),
281 std::memory_order_relaxed
);
283 mSourceID
.store(rhs
.mSourceID
.load(std::memory_order_relaxed
), std::memory_order_relaxed
);
284 mPlayState
.store(rhs
.mPlayState
.load(std::memory_order_relaxed
),
285 std::memory_order_relaxed
);
289 mPosition
.store(rhs
.mPosition
.load(std::memory_order_relaxed
), std::memory_order_relaxed
);
290 mPositionFrac
.store(rhs
.mPositionFrac
.load(std::memory_order_relaxed
),
291 std::memory_order_relaxed
);
293 mCurrentBuffer
.store(rhs
.mCurrentBuffer
.load(std::memory_order_relaxed
),
294 std::memory_order_relaxed
);
295 mLoopBuffer
.store(rhs
.mLoopBuffer
.load(std::memory_order_relaxed
),
296 std::memory_order_relaxed
);
298 mFmtChannels
= rhs
.mFmtChannels
;
299 mFrequency
= rhs
.mFrequency
;
300 mNumChannels
= rhs
.mNumChannels
;
301 mSampleSize
= rhs
.mSampleSize
;
304 mResampler
= rhs
.mResampler
;
306 mResampleState
= rhs
.mResampleState
;
310 mDirect
= rhs
.mDirect
;
317 void mix(ALvoice::State vstate
, ALCcontext
*Context
, const ALuint SamplesToDo
);
321 using MixerFunc
= void(*)(const al::span
<const float> InSamples
,
322 const al::span
<FloatBufferLine
> OutBuffer
, float *CurrentGains
, const float *TargetGains
,
323 const size_t Counter
, const size_t OutPos
);
324 using RowMixerFunc
= void(*)(const al::span
<float> OutBuffer
, const al::span
<const float> Gains
,
325 const float *InSamples
, const size_t InStride
);
326 using HrtfMixerFunc
= void(*)(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
327 const ALfloat
*InSamples
, float2
*AccumSamples
, const size_t OutPos
, const ALuint IrSize
,
328 MixHrtfFilter
*hrtfparams
, const size_t BufferSize
);
329 using HrtfMixerBlendFunc
= void(*)(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
330 const ALfloat
*InSamples
, float2
*AccumSamples
, const size_t OutPos
, const ALuint IrSize
,
331 const HrtfFilter
*oldparams
, MixHrtfFilter
*newparams
, const size_t BufferSize
);
332 using HrtfDirectMixerFunc
= void(*)(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
333 const al::span
<const FloatBufferLine
> InSamples
, float2
*AccumSamples
, DirectHrtfState
*State
,
334 const size_t BufferSize
);
337 #define GAIN_MIX_MAX (1000.0f) /* +60dB */
339 #define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */
341 #define SPEEDOFSOUNDMETRESPERSEC (343.3f)
342 #define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
344 /* Target gain for the reverb decay feedback reaching the decay time. */
345 #define REVERB_DECAY_GAIN (0.001f) /* -60 dB */
347 #define FRACTIONBITS (12)
348 #define FRACTIONONE (1<<FRACTIONBITS)
349 #define FRACTIONMASK (FRACTIONONE-1)
352 inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
) noexcept
353 { return val1
+ (val2
-val1
)*mu
; }
354 inline ALfloat
cubic(ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat val4
, ALfloat mu
) noexcept
356 ALfloat mu2
= mu
*mu
, mu3
= mu2
*mu
;
357 ALfloat a0
= -0.5f
*mu3
+ mu2
+ -0.5f
*mu
;
358 ALfloat a1
= 1.5f
*mu3
+ -2.5f
*mu2
+ 1.0f
;
359 ALfloat a2
= -1.5f
*mu3
+ 2.0f
*mu2
+ 0.5f
*mu
;
360 ALfloat a3
= 0.5f
*mu3
+ -0.5f
*mu2
;
361 return val1
*a0
+ val2
*a1
+ val3
*a2
+ val4
*a3
;
365 enum HrtfRequestMode
{
373 void aluInitMixer(void);
375 ResamplerFunc
SelectResampler(Resampler resampler
, ALuint increment
);
379 * Set up the appropriate panning method and mixing method given the device
382 void aluInitRenderer(ALCdevice
*device
, ALint hrtf_id
, HrtfRequestMode hrtf_appreq
, HrtfRequestMode hrtf_userreq
);
384 void aluInitEffectPanning(ALeffectslot
*slot
, ALCdevice
*device
);
387 * Calculates ambisonic encoder coefficients using the X, Y, and Z direction
388 * components, which must represent a normalized (unit length) vector, and the
389 * spread is the angular width of the sound (0...tau).
391 * NOTE: The components use ambisonic coordinates. As a result:
393 * Ambisonic Y = OpenAL -X
394 * Ambisonic Z = OpenAL Y
395 * Ambisonic X = OpenAL -Z
397 * The components are ordered such that OpenAL's X, Y, and Z are the first,
398 * second, and third parameters respectively -- simply negate X and Z.
400 void CalcAmbiCoeffs(const ALfloat y
, const ALfloat z
, const ALfloat x
, const ALfloat spread
,
401 ALfloat (&coeffs
)[MAX_AMBI_CHANNELS
]);
404 * CalcDirectionCoeffs
406 * Calculates ambisonic coefficients based on an OpenAL direction vector. The
407 * vector must be normalized (unit length), and the spread is the angular width
408 * of the sound (0...tau).
410 inline void CalcDirectionCoeffs(const ALfloat (&dir
)[3], ALfloat spread
, ALfloat (&coeffs
)[MAX_AMBI_CHANNELS
])
412 /* Convert from OpenAL coords to Ambisonics. */
413 CalcAmbiCoeffs(-dir
[0], dir
[1], -dir
[2], spread
, coeffs
);
419 * Calculates ambisonic coefficients based on azimuth and elevation. The
420 * azimuth and elevation parameters are in radians, going right and up
423 inline void CalcAngleCoeffs(ALfloat azimuth
, ALfloat elevation
, ALfloat spread
, ALfloat (&coeffs
)[MAX_AMBI_CHANNELS
])
425 ALfloat x
= -std::sin(azimuth
) * std::cos(elevation
);
426 ALfloat y
= std::sin(elevation
);
427 ALfloat z
= std::cos(azimuth
) * std::cos(elevation
);
429 CalcAmbiCoeffs(x
, y
, z
, spread
, coeffs
);
436 * Computes panning gains using the given channel decoder coefficients and the
437 * pre-calculated direction or angle coefficients. For B-Format sources, the
438 * coeffs are a 'slice' of a transform matrix for the input channel, used to
439 * scale and orient the sound samples.
441 void ComputePanGains(const MixParams
*mix
, const ALfloat
*RESTRICT coeffs
, ALfloat ingain
, ALfloat (&gains
)[MAX_OUTPUT_CHANNELS
]);
444 inline std::array
<ALfloat
,MAX_AMBI_CHANNELS
> GetAmbiIdentityRow(size_t i
) noexcept
446 std::array
<ALfloat
,MAX_AMBI_CHANNELS
> ret
{};
452 void aluMixData(ALCdevice
*device
, ALvoid
*OutBuffer
, const ALuint NumSamples
);
453 /* Caller must lock the device state, and the mixer must not be running. */
454 void aluHandleDisconnect(ALCdevice
*device
, const char *msg
, ...) DECL_FORMAT(printf
, 2, 3);
456 extern MixerFunc MixSamples
;
457 extern RowMixerFunc MixRowSamples
;
459 extern const ALfloat ConeScale
;
460 extern const ALfloat ZScale
;