2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
39 #include "al/buffer.h"
41 #include "al/source.h"
45 #include "alcontext.h"
46 #include "alnumeric.h"
47 #include "aloptional.h"
52 #include "devformat.h"
53 #include "filters/biquad.h"
54 #include "filters/nfc.h"
55 #include "filters/splitter.h"
57 #include "inprogext.h"
59 #include "mixer/defs.h"
60 #include "opthelpers.h"
61 #include "ringbuffer.h"
66 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
67 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
69 /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */
70 static_assert(MAX_RESAMPLE_PADDING
>= 24, "MAX_RESAMPLE_PADDING must be at least 24!");
73 Resampler ResamplerDefault
{Resampler::Linear
};
75 MixerFunc MixSamples
= Mix_
<CTag
>;
76 RowMixerFunc MixRowSamples
= MixRow_
<CTag
>;
80 HrtfMixerFunc MixHrtfSamples
= MixHrtf_
<CTag
>;
81 HrtfMixerBlendFunc MixHrtfBlendSamples
= MixHrtfBlend_
<CTag
>;
83 inline MixerFunc
SelectMixer()
86 if((CPUCapFlags
&CPU_CAP_NEON
))
90 if((CPUCapFlags
&CPU_CAP_SSE
))
96 inline RowMixerFunc
SelectRowMixer()
99 if((CPUCapFlags
&CPU_CAP_NEON
))
100 return MixRow_
<NEONTag
>;
103 if((CPUCapFlags
&CPU_CAP_SSE
))
104 return MixRow_
<SSETag
>;
106 return MixRow_
<CTag
>;
109 inline HrtfMixerFunc
SelectHrtfMixer()
112 if((CPUCapFlags
&CPU_CAP_NEON
))
113 return MixHrtf_
<NEONTag
>;
116 if((CPUCapFlags
&CPU_CAP_SSE
))
117 return MixHrtf_
<SSETag
>;
119 return MixHrtf_
<CTag
>;
122 inline HrtfMixerBlendFunc
SelectHrtfBlendMixer()
125 if((CPUCapFlags
&CPU_CAP_NEON
))
126 return MixHrtfBlend_
<NEONTag
>;
129 if((CPUCapFlags
&CPU_CAP_SSE
))
130 return MixHrtfBlend_
<SSETag
>;
132 return MixHrtfBlend_
<CTag
>;
138 ResamplerFunc
SelectResampler(Resampler resampler
)
142 case Resampler::Point
:
143 return Resample_
<PointTag
,CTag
>;
144 case Resampler::Linear
:
146 if((CPUCapFlags
&CPU_CAP_NEON
))
147 return Resample_
<LerpTag
,NEONTag
>;
150 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
151 return Resample_
<LerpTag
,SSE4Tag
>;
154 if((CPUCapFlags
&CPU_CAP_SSE2
))
155 return Resample_
<LerpTag
,SSE2Tag
>;
157 return Resample_
<LerpTag
,CTag
>;
158 case Resampler::Cubic
:
159 return Resample_
<CubicTag
,CTag
>;
160 case Resampler::BSinc12
:
161 case Resampler::BSinc24
:
163 if((CPUCapFlags
&CPU_CAP_NEON
))
164 return Resample_
<BSincTag
,NEONTag
>;
167 if((CPUCapFlags
&CPU_CAP_SSE
))
168 return Resample_
<BSincTag
,SSETag
>;
170 return Resample_
<BSincTag
,CTag
>;
173 return Resample_
<PointTag
,CTag
>;
179 if(auto resopt
= ConfigValueStr(nullptr, nullptr, "resampler"))
181 struct ResamplerEntry
{
183 const Resampler resampler
;
185 constexpr ResamplerEntry ResamplerList
[]{
186 { "none", Resampler::Point
},
187 { "point", Resampler::Point
},
188 { "cubic", Resampler::Cubic
},
189 { "bsinc12", Resampler::BSinc12
},
190 { "bsinc24", Resampler::BSinc24
},
193 const char *str
{resopt
->c_str()};
194 if(al::strcasecmp(str
, "bsinc") == 0)
196 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str
);
199 else if(al::strcasecmp(str
, "sinc4") == 0 || al::strcasecmp(str
, "sinc8") == 0)
201 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
205 auto iter
= std::find_if(std::begin(ResamplerList
), std::end(ResamplerList
),
206 [str
](const ResamplerEntry
&entry
) -> bool
207 { return al::strcasecmp(str
, entry
.name
) == 0; });
208 if(iter
== std::end(ResamplerList
))
209 ERR("Invalid resampler: %s\n", str
);
211 ResamplerDefault
= iter
->resampler
;
214 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
215 MixHrtfSamples
= SelectHrtfMixer();
216 MixSamples
= SelectMixer();
217 MixRowSamples
= SelectRowMixer();
223 /* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
224 * signed 16-bit sample */
225 constexpr ALshort muLawDecompressionTable
[256] = {
226 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
227 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
228 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
229 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
230 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
231 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
232 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
233 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
234 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
235 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
236 -876, -844, -812, -780, -748, -716, -684, -652,
237 -620, -588, -556, -524, -492, -460, -428, -396,
238 -372, -356, -340, -324, -308, -292, -276, -260,
239 -244, -228, -212, -196, -180, -164, -148, -132,
240 -120, -112, -104, -96, -88, -80, -72, -64,
241 -56, -48, -40, -32, -24, -16, -8, 0,
242 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
243 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
244 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
245 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
246 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
247 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
248 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
249 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
250 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
251 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
252 876, 844, 812, 780, 748, 716, 684, 652,
253 620, 588, 556, 524, 492, 460, 428, 396,
254 372, 356, 340, 324, 308, 292, 276, 260,
255 244, 228, 212, 196, 180, 164, 148, 132,
256 120, 112, 104, 96, 88, 80, 72, 64,
257 56, 48, 40, 32, 24, 16, 8, 0
260 /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a
261 * signed 16-bit sample */
262 constexpr ALshort aLawDecompressionTable
[256] = {
263 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
264 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
265 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
266 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
267 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
268 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
269 -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
270 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
271 -344, -328, -376, -360, -280, -264, -312, -296,
272 -472, -456, -504, -488, -408, -392, -440, -424,
273 -88, -72, -120, -104, -24, -8, -56, -40,
274 -216, -200, -248, -232, -152, -136, -184, -168,
275 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
276 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
277 -688, -656, -752, -720, -560, -528, -624, -592,
278 -944, -912, -1008, -976, -816, -784, -880, -848,
279 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
280 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
281 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
282 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
283 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
284 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
285 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
286 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
287 344, 328, 376, 360, 280, 264, 312, 296,
288 472, 456, 504, 488, 408, 392, 440, 424,
289 88, 72, 120, 104, 24, 8, 56, 40,
290 216, 200, 248, 232, 152, 136, 184, 168,
291 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
292 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
293 688, 656, 752, 720, 560, 528, 624, 592,
294 944, 912, 1008, 976, 816, 784, 880, 848
298 struct FmtTypeTraits
{ };
301 struct FmtTypeTraits
<FmtUByte
> {
302 using Type
= ALubyte
;
303 static constexpr inline float to_float(const Type val
) noexcept
304 { return val
*(1.0f
/128.0f
) - 128.0f
; }
307 struct FmtTypeTraits
<FmtShort
> {
308 using Type
= ALshort
;
309 static constexpr inline float to_float(const Type val
) noexcept
{ return val
*(1.0f
/32768.0f
); }
312 struct FmtTypeTraits
<FmtFloat
> {
313 using Type
= ALfloat
;
314 static constexpr inline float to_float(const Type val
) noexcept
{ return val
; }
317 struct FmtTypeTraits
<FmtDouble
> {
318 using Type
= ALdouble
;
319 static constexpr inline float to_float(const Type val
) noexcept
320 { return static_cast<ALfloat
>(val
); }
323 struct FmtTypeTraits
<FmtMulaw
> {
324 using Type
= ALubyte
;
325 static constexpr inline float to_float(const Type val
) noexcept
326 { return muLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
329 struct FmtTypeTraits
<FmtAlaw
> {
330 using Type
= ALubyte
;
331 static constexpr inline float to_float(const Type val
) noexcept
332 { return aLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
336 void SendSourceStoppedEvent(ALCcontext
*context
, ALuint id
)
338 RingBuffer
*ring
{context
->mAsyncEvents
.get()};
339 auto evt_vec
= ring
->getWriteVector();
340 if(evt_vec
.first
.len
< 1) return;
342 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_SourceStateChange
}};
343 evt
->u
.srcstate
.id
= id
;
344 evt
->u
.srcstate
.state
= AL_STOPPED
;
346 ring
->writeAdvance(1);
347 context
->mEventSem
.post();
351 const ALfloat
*DoFilters(BiquadFilter
*lpfilter
, BiquadFilter
*hpfilter
, ALfloat
*dst
,
352 const ALfloat
*src
, const size_t numsamples
, int type
)
362 lpfilter
->process(dst
, src
, numsamples
);
367 hpfilter
->process(dst
, src
, numsamples
);
371 lpfilter
->process(dst
, src
, numsamples
);
372 hpfilter
->process(dst
, dst
, numsamples
);
380 inline void LoadSampleArray(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
,
381 const size_t samples
) noexcept
383 using SampleType
= typename FmtTypeTraits
<T
>::Type
;
385 const SampleType
*RESTRICT ssrc
{reinterpret_cast<const SampleType
*>(src
)};
386 for(size_t i
{0u};i
< samples
;i
++)
387 dst
[i
] = FmtTypeTraits
<T
>::to_float(ssrc
[i
*srcstep
]);
390 void LoadSamples(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
, FmtType srctype
,
391 const size_t samples
) noexcept
393 #define HANDLE_FMT(T) case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
396 HANDLE_FMT(FmtUByte
);
397 HANDLE_FMT(FmtShort
);
398 HANDLE_FMT(FmtFloat
);
399 HANDLE_FMT(FmtDouble
);
400 HANDLE_FMT(FmtMulaw
);
406 ALfloat
*LoadBufferStatic(ALbufferlistitem
*BufferListItem
, ALbufferlistitem
*&BufferLoopItem
,
407 const size_t NumChannels
, const size_t SampleSize
, const size_t chan
, size_t DataPosInt
,
408 al::span
<ALfloat
> SrcBuffer
)
410 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
411 const ALuint LoopStart
{Buffer
->LoopStart
};
412 const ALuint LoopEnd
{Buffer
->LoopEnd
};
413 ASSUME(LoopEnd
> LoopStart
);
415 /* If current pos is beyond the loop range, do not loop */
416 if(!BufferLoopItem
|| DataPosInt
>= LoopEnd
)
418 BufferLoopItem
= nullptr;
420 /* Load what's left to play from the buffer */
421 const size_t DataRem
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
423 const al::byte
*Data
{Buffer
->mData
.data()};
424 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
426 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataRem
);
427 SrcBuffer
= SrcBuffer
.subspan(DataRem
);
431 /* Load what's left of this loop iteration */
432 const size_t DataRem
{minz(SrcBuffer
.size(), LoopEnd
-DataPosInt
)};
434 const al::byte
*Data
{Buffer
->mData
.data()};
435 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
437 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataRem
);
438 SrcBuffer
= SrcBuffer
.subspan(DataRem
);
440 /* Load any repeats of the loop we can to fill the buffer. */
441 const auto LoopSize
= static_cast<size_t>(LoopEnd
- LoopStart
);
442 while(!SrcBuffer
.empty())
444 const size_t DataSize
{minz(SrcBuffer
.size(), LoopSize
)};
446 Data
= Buffer
->mData
.data() + (LoopStart
*NumChannels
+ chan
)*SampleSize
;
448 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
449 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
452 return SrcBuffer
.begin();
455 ALfloat
*LoadBufferQueue(ALbufferlistitem
*BufferListItem
, ALbufferlistitem
*BufferLoopItem
,
456 const size_t NumChannels
, const size_t SampleSize
, const size_t chan
, size_t DataPosInt
,
457 al::span
<ALfloat
> SrcBuffer
)
459 /* Crawl the buffer queue to fill in the temp buffer */
460 while(BufferListItem
&& !SrcBuffer
.empty())
462 ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
463 if(!(Buffer
&& DataPosInt
< Buffer
->SampleLen
))
465 if(Buffer
) DataPosInt
-= Buffer
->SampleLen
;
466 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
467 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
471 const size_t DataSize
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
473 const al::byte
*Data
{Buffer
->mData
.data()};
474 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
476 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
477 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
478 if(SrcBuffer
.empty()) break;
481 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
482 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
485 return SrcBuffer
.begin();
489 void DoHrtfMix(ALvoice::DirectData
&Direct
, const float TargetGain
, DirectParams
&parms
,
490 const float *samples
, const ALuint DstBufferSize
, const ALuint Counter
, const ALuint OutPos
,
491 const ALuint IrSize
, ALCdevice
*Device
)
493 const ALuint OutLIdx
{GetChannelIdxByName(Device
->RealOut
, FrontLeft
)};
494 const ALuint OutRIdx
{GetChannelIdxByName(Device
->RealOut
, FrontRight
)};
495 auto &HrtfSamples
= Device
->HrtfSourceData
;
496 auto &AccumSamples
= Device
->HrtfAccumData
;
498 /* Copy the HRTF history and new input samples into a temp buffer. */
499 auto src_iter
= std::copy(parms
.Hrtf
.State
.History
.begin(), parms
.Hrtf
.State
.History
.end(),
500 std::begin(HrtfSamples
));
501 std::copy_n(samples
, DstBufferSize
, src_iter
);
502 /* Copy the last used samples back into the history buffer for later. */
503 std::copy_n(std::begin(HrtfSamples
) + DstBufferSize
, parms
.Hrtf
.State
.History
.size(),
504 parms
.Hrtf
.State
.History
.begin());
506 /* Copy the current filtered values being accumulated into the temp buffer. */
507 auto accum_iter
= std::copy_n(parms
.Hrtf
.State
.Values
.begin(), parms
.Hrtf
.State
.Values
.size(),
508 std::begin(AccumSamples
));
509 /* Clear the accumulation buffer that will start getting filled in. */
510 std::fill_n(accum_iter
, DstBufferSize
, float2
{});
512 /* If fading, the old gain is not silence, and this is the first mixing
513 * pass, fade between the IRs.
516 if(Counter
&& parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
&& OutPos
== 0)
518 fademix
= minu(DstBufferSize
, 128);
520 float gain
{TargetGain
};
522 /* The new coefficients need to fade in completely since they're
523 * replacing the old ones. To keep the gain fading consistent,
524 * interpolate between the old and new target gains given how much of
525 * the fade time this mix handles.
527 if LIKELY(Counter
> fademix
)
529 const ALfloat a
{static_cast<float>(fademix
) / static_cast<float>(Counter
)};
530 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
532 MixHrtfFilter hrtfparams
;
533 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
534 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
535 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
536 hrtfparams
.Gain
= 0.0f
;
537 hrtfparams
.GainStep
= gain
/ static_cast<float>(fademix
);
539 MixHrtfBlendSamples(Direct
.Buffer
[OutLIdx
], Direct
.Buffer
[OutRIdx
], HrtfSamples
,
540 AccumSamples
, OutPos
, IrSize
, &parms
.Hrtf
.Old
, &hrtfparams
, fademix
);
541 /* Update the old parameters with the result. */
542 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
543 if(fademix
< Counter
)
544 parms
.Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
546 parms
.Hrtf
.Old
.Gain
= TargetGain
;
549 if LIKELY(fademix
< DstBufferSize
)
551 const ALuint todo
{DstBufferSize
- fademix
};
552 float gain
{TargetGain
};
554 /* Interpolate the target gain if the gain fading lasts longer than
557 if(Counter
> DstBufferSize
)
559 const float a
{static_cast<float>(todo
) / static_cast<float>(Counter
-fademix
)};
560 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
563 MixHrtfFilter hrtfparams
;
564 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
565 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
566 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
567 hrtfparams
.Gain
= parms
.Hrtf
.Old
.Gain
;
568 hrtfparams
.GainStep
= (gain
- parms
.Hrtf
.Old
.Gain
) / static_cast<float>(todo
);
569 MixHrtfSamples(Direct
.Buffer
[OutLIdx
], Direct
.Buffer
[OutRIdx
], HrtfSamples
+fademix
,
570 AccumSamples
+fademix
, OutPos
+fademix
, IrSize
, &hrtfparams
, todo
);
571 /* Store the interpolated gain or the final target gain depending if
574 if(DstBufferSize
< Counter
)
575 parms
.Hrtf
.Old
.Gain
= gain
;
577 parms
.Hrtf
.Old
.Gain
= TargetGain
;
580 /* Copy the new in-progress accumulation values back for the next mix. */
581 std::copy_n(std::begin(AccumSamples
) + DstBufferSize
, parms
.Hrtf
.State
.Values
.size(),
582 parms
.Hrtf
.State
.Values
.begin());
585 void DoNfcMix(ALvoice::DirectData
&Direct
, const float *TargetGains
, DirectParams
&parms
,
586 const float *samples
, const ALuint DstBufferSize
, const ALuint Counter
, const ALuint OutPos
,
589 const size_t outcount
{Device
->NumChannelsPerOrder
[0]};
590 MixSamples({samples
, DstBufferSize
}, Direct
.Buffer
.first(outcount
),
591 parms
.Gains
.Current
, TargetGains
, Counter
, OutPos
);
593 const al::span
<float> nfcsamples
{Device
->NfcSampleData
, DstBufferSize
};
594 size_t chanoffset
{outcount
};
595 using FilterProc
= void (NfcFilter::*)(float*,const float*,const size_t);
596 auto apply_nfc
= [&Direct
,&parms
,samples
,TargetGains
,Counter
,OutPos
,&chanoffset
,nfcsamples
](
597 const FilterProc process
, const size_t chancount
) -> void
599 if(chancount
< 1) return;
600 (parms
.NFCtrlFilter
.*process
)(nfcsamples
.data(), samples
, nfcsamples
.size());
601 MixSamples(nfcsamples
, Direct
.Buffer
.subspan(chanoffset
, chancount
),
602 parms
.Gains
.Current
+chanoffset
, TargetGains
+chanoffset
, Counter
, OutPos
);
603 chanoffset
+= chancount
;
605 apply_nfc(&NfcFilter::process1
, Device
->NumChannelsPerOrder
[1]);
606 apply_nfc(&NfcFilter::process2
, Device
->NumChannelsPerOrder
[2]);
607 apply_nfc(&NfcFilter::process3
, Device
->NumChannelsPerOrder
[3]);
612 void ALvoice::mix(State vstate
, ALCcontext
*Context
, const ALuint SamplesToDo
)
614 static constexpr ALfloat SilentTarget
[MAX_OUTPUT_CHANNELS
]{};
616 ASSUME(SamplesToDo
> 0);
619 const bool isstatic
{(mFlags
&VOICE_IS_STATIC
) != 0};
620 ALuint DataPosInt
{mPosition
.load(std::memory_order_relaxed
)};
621 ALuint DataPosFrac
{mPositionFrac
.load(std::memory_order_relaxed
)};
622 ALbufferlistitem
*BufferListItem
{mCurrentBuffer
.load(std::memory_order_relaxed
)};
623 ALbufferlistitem
*BufferLoopItem
{mLoopBuffer
.load(std::memory_order_relaxed
)};
624 const ALuint NumChannels
{mNumChannels
};
625 const ALuint SampleSize
{mSampleSize
};
626 const ALuint increment
{mStep
};
627 if(increment
< 1) return;
629 ASSUME(NumChannels
> 0);
630 ASSUME(SampleSize
> 0);
631 ASSUME(increment
> 0);
633 ALCdevice
*Device
{Context
->mDevice
.get()};
634 const ALuint NumSends
{Device
->NumAuxSends
};
635 const ALuint IrSize
{Device
->mHrtf
? Device
->mHrtf
->irSize
: 0};
637 ResamplerFunc Resample
{(increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
638 Resample_
<CopyTag
,CTag
> : mResampler
};
640 ALuint Counter
{(mFlags
&VOICE_IS_FADING
) ? SamplesToDo
: 0};
643 /* No fading, just overwrite the old/current params. */
644 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
646 ChannelData
&chandata
= mChans
[chan
];
648 DirectParams
&parms
= chandata
.mDryParams
;
649 if(!(mFlags
&VOICE_HAS_HRTF
))
650 std::copy(std::begin(parms
.Gains
.Target
), std::end(parms
.Gains
.Target
),
651 std::begin(parms
.Gains
.Current
));
653 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
655 for(ALuint send
{0};send
< NumSends
;++send
)
657 if(mSend
[send
].Buffer
.empty())
660 SendParams
&parms
= chandata
.mWetParams
[send
];
661 std::copy(std::begin(parms
.Gains
.Target
), std::end(parms
.Gains
.Target
),
662 std::begin(parms
.Gains
.Current
));
666 else if((mFlags
&VOICE_HAS_HRTF
))
668 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
670 DirectParams
&parms
= mChans
[chan
].mDryParams
;
671 if(!(parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
673 /* The old HRTF params are silent, so overwrite the old
674 * coefficients with the new, and reset the old gain to 0. The
675 * future mix will then fade from silence.
677 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
678 parms
.Hrtf
.Old
.Gain
= 0.0f
;
683 ALuint buffers_done
{0u};
686 /* Figure out how many buffer samples will be needed */
687 ALuint DstBufferSize
{SamplesToDo
- OutPos
};
689 /* Calculate the last written dst sample pos. */
690 uint64_t DataSize64
{DstBufferSize
- 1};
691 /* Calculate the last read src sample pos. */
692 DataSize64
= (DataSize64
*increment
+ DataPosFrac
) >> FRACTIONBITS
;
693 /* +1 to get the src sample count, include padding. */
694 DataSize64
+= 1 + MAX_RESAMPLE_PADDING
*2;
696 auto SrcBufferSize
= static_cast<ALuint
>(
697 minu64(DataSize64
, BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2 + 1));
698 if(SrcBufferSize
> BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2)
700 SrcBufferSize
= BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2;
701 /* If the source buffer got saturated, we can't fill the desired
702 * dst size. Figure out how many samples we can actually mix from
705 DataSize64
= SrcBufferSize
- MAX_RESAMPLE_PADDING
*2;
706 DataSize64
= ((DataSize64
<<FRACTIONBITS
) - DataPosFrac
+ increment
-1) / increment
;
707 DstBufferSize
= static_cast<ALuint
>(minu64(DataSize64
, DstBufferSize
));
709 /* Some mixers like having a multiple of 4, so try to give that
710 * unless this is the last update.
712 if(DstBufferSize
< SamplesToDo
-OutPos
)
713 DstBufferSize
&= ~3u;
716 ASSUME(DstBufferSize
> 0);
717 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
719 ChannelData
&chandata
= mChans
[chan
];
720 const al::span
<ALfloat
> SrcData
{Device
->SourceData
, SrcBufferSize
};
722 /* Load the previous samples into the source data first, then load
723 * what we can from the buffer queue.
725 auto srciter
= std::copy_n(chandata
.mPrevSamples
.begin(), MAX_RESAMPLE_PADDING
,
728 if UNLIKELY(!BufferListItem
)
729 srciter
= std::copy(chandata
.mPrevSamples
.begin()+MAX_RESAMPLE_PADDING
,
730 chandata
.mPrevSamples
.end(), srciter
);
732 srciter
= LoadBufferStatic(BufferListItem
, BufferLoopItem
, NumChannels
,
733 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
735 srciter
= LoadBufferQueue(BufferListItem
, BufferLoopItem
, NumChannels
,
736 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
738 if UNLIKELY(srciter
!= SrcData
.end())
740 /* If the source buffer wasn't filled, copy the last sample for
741 * the remaining buffer. Ideally it should have ended with
742 * silence, but if not the gain fading should help avoid clicks
743 * from sudden amplitude changes.
745 const ALfloat sample
{*(srciter
-1)};
746 std::fill(srciter
, SrcData
.end(), sample
);
749 /* Store the last source samples used for next time. */
750 std::copy_n(&SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
751 chandata
.mPrevSamples
.size(), chandata
.mPrevSamples
.begin());
753 /* Resample, then apply ambisonic upsampling as needed. */
754 const ALfloat
*ResampledData
{Resample(&mResampleState
, &SrcData
[MAX_RESAMPLE_PADDING
],
755 DataPosFrac
, increment
, {Device
->ResampledData
, DstBufferSize
})};
756 if((mFlags
&VOICE_IS_AMBISONIC
))
758 const ALfloat hfscale
{chandata
.mAmbiScale
};
759 /* Beware the evil const_cast. It's safe since it's pointing to
760 * either SourceData or ResampledData (both non-const), but the
761 * resample method takes the source as const float* and may
762 * return it without copying to output, making it currently
765 chandata
.mAmbiSplitter
.applyHfScale(const_cast<ALfloat
*>(ResampledData
), hfscale
,
769 /* Now filter and mix to the appropriate outputs. */
770 ALfloat (&FilterBuf
)[BUFFERSIZE
] = Device
->FilteredData
;
772 DirectParams
&parms
= chandata
.mDryParams
;
773 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
774 ResampledData
, DstBufferSize
, mDirect
.FilterType
)};
776 if((mFlags
&VOICE_HAS_HRTF
))
778 const ALfloat TargetGain
{UNLIKELY(vstate
== ALvoice::Stopping
) ? 0.0f
:
779 parms
.Hrtf
.Target
.Gain
};
780 DoHrtfMix(mDirect
, TargetGain
, parms
, samples
, DstBufferSize
, Counter
, OutPos
,
783 else if((mFlags
&VOICE_HAS_NFC
))
785 const ALfloat
*TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
786 SilentTarget
: parms
.Gains
.Target
};
787 DoNfcMix(mDirect
, TargetGains
, parms
, samples
, DstBufferSize
, Counter
, OutPos
,
792 const ALfloat
*TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
793 SilentTarget
: parms
.Gains
.Target
};
794 MixSamples({samples
, DstBufferSize
}, mDirect
.Buffer
, parms
.Gains
.Current
,
795 TargetGains
, Counter
, OutPos
);
799 for(ALuint send
{0};send
< NumSends
;++send
)
801 if(mSend
[send
].Buffer
.empty())
804 SendParams
&parms
= chandata
.mWetParams
[send
];
805 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
806 ResampledData
, DstBufferSize
, mSend
[send
].FilterType
)};
808 const ALfloat
*TargetGains
{UNLIKELY(vstate
==ALvoice::Stopping
) ? SilentTarget
:
810 MixSamples({samples
, DstBufferSize
}, mSend
[send
].Buffer
, parms
.Gains
.Current
,
811 TargetGains
, Counter
, OutPos
);
814 /* Update positions */
815 DataPosFrac
+= increment
*DstBufferSize
;
816 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
817 DataPosFrac
&= FRACTIONMASK
;
819 OutPos
+= DstBufferSize
;
820 Counter
= maxu(DstBufferSize
, Counter
) - DstBufferSize
;
822 if UNLIKELY(!BufferListItem
)
824 /* Do nothing extra when there's no buffers. */
830 /* Handle looping static source */
831 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
832 const ALuint LoopStart
{Buffer
->LoopStart
};
833 const ALuint LoopEnd
{Buffer
->LoopEnd
};
834 if(DataPosInt
>= LoopEnd
)
836 assert(LoopEnd
> LoopStart
);
837 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
842 /* Handle non-looping static source */
843 if(DataPosInt
>= BufferListItem
->mSampleLen
)
845 if LIKELY(vstate
== ALvoice::Playing
)
846 vstate
= ALvoice::Stopped
;
847 BufferListItem
= nullptr;
854 /* Handle streaming source */
855 if(BufferListItem
->mSampleLen
> DataPosInt
)
858 DataPosInt
-= BufferListItem
->mSampleLen
;
861 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_relaxed
);
862 if(!BufferListItem
&& !(BufferListItem
=BufferLoopItem
))
864 if LIKELY(vstate
== ALvoice::Playing
)
865 vstate
= ALvoice::Stopped
;
869 } while(OutPos
< SamplesToDo
);
871 mFlags
|= VOICE_IS_FADING
;
873 /* Don't update positions and buffers if we were stopping. */
874 if UNLIKELY(vstate
== ALvoice::Stopping
)
876 mPlayState
.store(ALvoice::Stopped
, std::memory_order_release
);
880 /* Capture the source ID in case it's reset for stopping. */
881 const ALuint SourceID
{mSourceID
.load(std::memory_order_relaxed
)};
883 /* Update voice info */
884 mPosition
.store(DataPosInt
, std::memory_order_relaxed
);
885 mPositionFrac
.store(DataPosFrac
, std::memory_order_relaxed
);
886 mCurrentBuffer
.store(BufferListItem
, std::memory_order_relaxed
);
887 if(vstate
== ALvoice::Stopped
)
889 mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
890 mSourceID
.store(0u, std::memory_order_relaxed
);
892 std::atomic_thread_fence(std::memory_order_release
);
894 /* Send any events now, after the position/buffer info was updated. */
895 const ALbitfieldSOFT enabledevt
{Context
->mEnabledEvts
.load(std::memory_order_acquire
)};
896 if(buffers_done
> 0 && (enabledevt
&EventType_BufferCompleted
))
898 RingBuffer
*ring
{Context
->mAsyncEvents
.get()};
899 auto evt_vec
= ring
->getWriteVector();
900 if(evt_vec
.first
.len
> 0)
902 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_BufferCompleted
}};
903 evt
->u
.bufcomp
.id
= SourceID
;
904 evt
->u
.bufcomp
.count
= buffers_done
;
905 ring
->writeAdvance(1);
906 Context
->mEventSem
.post();
910 if(vstate
== ALvoice::Stopped
)
912 /* If the voice just ended, set it to Stopping so the next render
913 * ensures any residual noise fades to 0 amplitude.
915 mPlayState
.store(ALvoice::Stopping
, std::memory_order_release
);
916 if((enabledevt
&EventType_SourceStateChange
))
917 SendSourceStoppedEvent(Context
, SourceID
);