Add "fast" variants for the bsinc resamplers
[openal-soft.git] / alc / mixvoice.cpp
blobe9e0d8df2b82b2f7dad1a26015eca046f988a6c8
1 /**
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
21 #include "config.h"
23 #include <algorithm>
24 #include <array>
25 #include <atomic>
26 #include <cassert>
27 #include <climits>
28 #include <cstddef>
29 #include <cstdint>
30 #include <iterator>
31 #include <memory>
32 #include <new>
33 #include <string>
34 #include <utility>
36 #include "AL/al.h"
37 #include "AL/alc.h"
39 #include "al/buffer.h"
40 #include "al/event.h"
41 #include "al/source.h"
42 #include "alcmain.h"
43 #include "albyte.h"
44 #include "alconfig.h"
45 #include "alcontext.h"
46 #include "alnumeric.h"
47 #include "aloptional.h"
48 #include "alspan.h"
49 #include "alstring.h"
50 #include "alu.h"
51 #include "cpu_caps.h"
52 #include "devformat.h"
53 #include "filters/biquad.h"
54 #include "filters/nfc.h"
55 #include "filters/splitter.h"
56 #include "hrtf.h"
57 #include "inprogext.h"
58 #include "logging.h"
59 #include "mixer/defs.h"
60 #include "opthelpers.h"
61 #include "ringbuffer.h"
62 #include "threads.h"
63 #include "vector.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>;
78 namespace {
80 HrtfMixerFunc MixHrtfSamples = MixHrtf_<CTag>;
81 HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_<CTag>;
83 inline MixerFunc SelectMixer()
85 #ifdef HAVE_NEON
86 if((CPUCapFlags&CPU_CAP_NEON))
87 return Mix_<NEONTag>;
88 #endif
89 #ifdef HAVE_SSE
90 if((CPUCapFlags&CPU_CAP_SSE))
91 return Mix_<SSETag>;
92 #endif
93 return Mix_<CTag>;
96 inline RowMixerFunc SelectRowMixer()
98 #ifdef HAVE_NEON
99 if((CPUCapFlags&CPU_CAP_NEON))
100 return MixRow_<NEONTag>;
101 #endif
102 #ifdef HAVE_SSE
103 if((CPUCapFlags&CPU_CAP_SSE))
104 return MixRow_<SSETag>;
105 #endif
106 return MixRow_<CTag>;
109 inline HrtfMixerFunc SelectHrtfMixer()
111 #ifdef HAVE_NEON
112 if((CPUCapFlags&CPU_CAP_NEON))
113 return MixHrtf_<NEONTag>;
114 #endif
115 #ifdef HAVE_SSE
116 if((CPUCapFlags&CPU_CAP_SSE))
117 return MixHrtf_<SSETag>;
118 #endif
119 return MixHrtf_<CTag>;
122 inline HrtfMixerBlendFunc SelectHrtfBlendMixer()
124 #ifdef HAVE_NEON
125 if((CPUCapFlags&CPU_CAP_NEON))
126 return MixHrtfBlend_<NEONTag>;
127 #endif
128 #ifdef HAVE_SSE
129 if((CPUCapFlags&CPU_CAP_SSE))
130 return MixHrtfBlend_<SSETag>;
131 #endif
132 return MixHrtfBlend_<CTag>;
135 } // namespace
138 ResamplerFunc SelectResampler(Resampler resampler, ALuint increment)
140 switch(resampler)
142 case Resampler::Point:
143 return Resample_<PointTag,CTag>;
144 case Resampler::Linear:
145 #ifdef HAVE_NEON
146 if((CPUCapFlags&CPU_CAP_NEON))
147 return Resample_<LerpTag,NEONTag>;
148 #endif
149 #ifdef HAVE_SSE4_1
150 if((CPUCapFlags&CPU_CAP_SSE4_1))
151 return Resample_<LerpTag,SSE4Tag>;
152 #endif
153 #ifdef HAVE_SSE2
154 if((CPUCapFlags&CPU_CAP_SSE2))
155 return Resample_<LerpTag,SSE2Tag>;
156 #endif
157 return Resample_<LerpTag,CTag>;
158 case Resampler::Cubic:
159 return Resample_<CubicTag,CTag>;
160 case Resampler::BSinc12:
161 case Resampler::BSinc24:
162 if(increment <= FRACTIONONE)
164 /* fall-through */
165 case Resampler::FastBSinc12:
166 case Resampler::FastBSinc24:
167 #ifdef HAVE_NEON
168 if((CPUCapFlags&CPU_CAP_NEON))
169 return Resample_<FastBSincTag,NEONTag>;
170 #endif
171 #ifdef HAVE_SSE
172 if((CPUCapFlags&CPU_CAP_SSE))
173 return Resample_<FastBSincTag,SSETag>;
174 #endif
175 return Resample_<FastBSincTag,CTag>;
177 #ifdef HAVE_NEON
178 if((CPUCapFlags&CPU_CAP_NEON))
179 return Resample_<BSincTag,NEONTag>;
180 #endif
181 #ifdef HAVE_SSE
182 if((CPUCapFlags&CPU_CAP_SSE))
183 return Resample_<BSincTag,SSETag>;
184 #endif
185 return Resample_<BSincTag,CTag>;
188 return Resample_<PointTag,CTag>;
192 void aluInitMixer()
194 if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler"))
196 struct ResamplerEntry {
197 const char name[16];
198 const Resampler resampler;
200 constexpr ResamplerEntry ResamplerList[]{
201 { "none", Resampler::Point },
202 { "point", Resampler::Point },
203 { "cubic", Resampler::Cubic },
204 { "bsinc12", Resampler::BSinc12 },
205 { "fast_bsinc12", Resampler::FastBSinc12 },
206 { "bsinc24", Resampler::BSinc24 },
207 { "fast_bsinc24", Resampler::FastBSinc24 },
210 const char *str{resopt->c_str()};
211 if(al::strcasecmp(str, "bsinc") == 0)
213 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str);
214 str = "bsinc12";
216 else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0)
218 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str);
219 str = "cubic";
222 auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList),
223 [str](const ResamplerEntry &entry) -> bool
224 { return al::strcasecmp(str, entry.name) == 0; });
225 if(iter == std::end(ResamplerList))
226 ERR("Invalid resampler: %s\n", str);
227 else
228 ResamplerDefault = iter->resampler;
231 MixHrtfBlendSamples = SelectHrtfBlendMixer();
232 MixHrtfSamples = SelectHrtfMixer();
233 MixSamples = SelectMixer();
234 MixRowSamples = SelectRowMixer();
238 namespace {
240 /* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
241 * signed 16-bit sample */
242 constexpr ALshort muLawDecompressionTable[256] = {
243 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
244 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
245 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
246 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
247 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
248 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
249 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
250 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
251 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
252 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
253 -876, -844, -812, -780, -748, -716, -684, -652,
254 -620, -588, -556, -524, -492, -460, -428, -396,
255 -372, -356, -340, -324, -308, -292, -276, -260,
256 -244, -228, -212, -196, -180, -164, -148, -132,
257 -120, -112, -104, -96, -88, -80, -72, -64,
258 -56, -48, -40, -32, -24, -16, -8, 0,
259 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
260 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
261 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
262 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
263 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
264 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
265 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
266 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
267 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
268 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
269 876, 844, 812, 780, 748, 716, 684, 652,
270 620, 588, 556, 524, 492, 460, 428, 396,
271 372, 356, 340, 324, 308, 292, 276, 260,
272 244, 228, 212, 196, 180, 164, 148, 132,
273 120, 112, 104, 96, 88, 80, 72, 64,
274 56, 48, 40, 32, 24, 16, 8, 0
277 /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a
278 * signed 16-bit sample */
279 constexpr ALshort aLawDecompressionTable[256] = {
280 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
281 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
282 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
283 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
284 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
285 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
286 -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
287 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
288 -344, -328, -376, -360, -280, -264, -312, -296,
289 -472, -456, -504, -488, -408, -392, -440, -424,
290 -88, -72, -120, -104, -24, -8, -56, -40,
291 -216, -200, -248, -232, -152, -136, -184, -168,
292 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
293 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
294 -688, -656, -752, -720, -560, -528, -624, -592,
295 -944, -912, -1008, -976, -816, -784, -880, -848,
296 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
297 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
298 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
299 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
300 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
301 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
302 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
303 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
304 344, 328, 376, 360, 280, 264, 312, 296,
305 472, 456, 504, 488, 408, 392, 440, 424,
306 88, 72, 120, 104, 24, 8, 56, 40,
307 216, 200, 248, 232, 152, 136, 184, 168,
308 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
309 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
310 688, 656, 752, 720, 560, 528, 624, 592,
311 944, 912, 1008, 976, 816, 784, 880, 848
314 template<FmtType T>
315 struct FmtTypeTraits { };
317 template<>
318 struct FmtTypeTraits<FmtUByte> {
319 using Type = ALubyte;
320 static constexpr inline float to_float(const Type val) noexcept
321 { return val*(1.0f/128.0f) - 1.0f; }
323 template<>
324 struct FmtTypeTraits<FmtShort> {
325 using Type = ALshort;
326 static constexpr inline float to_float(const Type val) noexcept { return val*(1.0f/32768.0f); }
328 template<>
329 struct FmtTypeTraits<FmtFloat> {
330 using Type = ALfloat;
331 static constexpr inline float to_float(const Type val) noexcept { return val; }
333 template<>
334 struct FmtTypeTraits<FmtDouble> {
335 using Type = ALdouble;
336 static constexpr inline float to_float(const Type val) noexcept
337 { return static_cast<ALfloat>(val); }
339 template<>
340 struct FmtTypeTraits<FmtMulaw> {
341 using Type = ALubyte;
342 static constexpr inline float to_float(const Type val) noexcept
343 { return muLawDecompressionTable[val] * (1.0f/32768.0f); }
345 template<>
346 struct FmtTypeTraits<FmtAlaw> {
347 using Type = ALubyte;
348 static constexpr inline float to_float(const Type val) noexcept
349 { return aLawDecompressionTable[val] * (1.0f/32768.0f); }
353 void SendSourceStoppedEvent(ALCcontext *context, ALuint id)
355 RingBuffer *ring{context->mAsyncEvents.get()};
356 auto evt_vec = ring->getWriteVector();
357 if(evt_vec.first.len < 1) return;
359 AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}};
360 evt->u.srcstate.id = id;
361 evt->u.srcstate.state = AL_STOPPED;
363 ring->writeAdvance(1);
364 context->mEventSem.post();
368 const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst,
369 const ALfloat *src, const size_t numsamples, int type)
371 switch(type)
373 case AF_None:
374 lpfilter->clear();
375 hpfilter->clear();
376 break;
378 case AF_LowPass:
379 lpfilter->process(dst, src, numsamples);
380 hpfilter->clear();
381 return dst;
382 case AF_HighPass:
383 lpfilter->clear();
384 hpfilter->process(dst, src, numsamples);
385 return dst;
387 case AF_BandPass:
388 lpfilter->process(dst, src, numsamples);
389 hpfilter->process(dst, dst, numsamples);
390 return dst;
392 return src;
396 template<FmtType T>
397 inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep,
398 const size_t samples) noexcept
400 using SampleType = typename FmtTypeTraits<T>::Type;
402 const SampleType *RESTRICT ssrc{reinterpret_cast<const SampleType*>(src)};
403 for(size_t i{0u};i < samples;i++)
404 dst[i] = FmtTypeTraits<T>::to_float(ssrc[i*srcstep]);
407 void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype,
408 const size_t samples) noexcept
410 #define HANDLE_FMT(T) case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
411 switch(srctype)
413 HANDLE_FMT(FmtUByte);
414 HANDLE_FMT(FmtShort);
415 HANDLE_FMT(FmtFloat);
416 HANDLE_FMT(FmtDouble);
417 HANDLE_FMT(FmtMulaw);
418 HANDLE_FMT(FmtAlaw);
420 #undef HANDLE_FMT
423 ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem,
424 const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt,
425 al::span<ALfloat> SrcBuffer)
427 const ALbuffer *Buffer{BufferListItem->mBuffer};
428 const ALuint LoopStart{Buffer->LoopStart};
429 const ALuint LoopEnd{Buffer->LoopEnd};
430 ASSUME(LoopEnd > LoopStart);
432 /* If current pos is beyond the loop range, do not loop */
433 if(!BufferLoopItem || DataPosInt >= LoopEnd)
435 BufferLoopItem = nullptr;
437 /* Load what's left to play from the buffer */
438 const size_t DataRem{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)};
440 const al::byte *Data{Buffer->mData.data()};
441 Data += (DataPosInt*NumChannels + chan)*SampleSize;
443 LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem);
444 SrcBuffer = SrcBuffer.subspan(DataRem);
446 else
448 /* Load what's left of this loop iteration */
449 const size_t DataRem{minz(SrcBuffer.size(), LoopEnd-DataPosInt)};
451 const al::byte *Data{Buffer->mData.data()};
452 Data += (DataPosInt*NumChannels + chan)*SampleSize;
454 LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem);
455 SrcBuffer = SrcBuffer.subspan(DataRem);
457 /* Load any repeats of the loop we can to fill the buffer. */
458 const auto LoopSize = static_cast<size_t>(LoopEnd - LoopStart);
459 while(!SrcBuffer.empty())
461 const size_t DataSize{minz(SrcBuffer.size(), LoopSize)};
463 Data = Buffer->mData.data() + (LoopStart*NumChannels + chan)*SampleSize;
465 LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize);
466 SrcBuffer = SrcBuffer.subspan(DataSize);
469 return SrcBuffer.begin();
472 ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem,
473 const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt,
474 al::span<ALfloat> SrcBuffer)
476 /* Crawl the buffer queue to fill in the temp buffer */
477 while(BufferListItem && !SrcBuffer.empty())
479 ALbuffer *Buffer{BufferListItem->mBuffer};
480 if(!(Buffer && DataPosInt < Buffer->SampleLen))
482 if(Buffer) DataPosInt -= Buffer->SampleLen;
483 BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire);
484 if(!BufferListItem) BufferListItem = BufferLoopItem;
485 continue;
488 const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)};
490 const al::byte *Data{Buffer->mData.data()};
491 Data += (DataPosInt*NumChannels + chan)*SampleSize;
493 LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize);
494 SrcBuffer = SrcBuffer.subspan(DataSize);
495 if(SrcBuffer.empty()) break;
497 DataPosInt = 0;
498 BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire);
499 if(!BufferListItem) BufferListItem = BufferLoopItem;
502 return SrcBuffer.begin();
506 void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams &parms,
507 const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos,
508 const ALuint IrSize, ALCdevice *Device)
510 const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)};
511 const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)};
512 auto &HrtfSamples = Device->HrtfSourceData;
513 auto &AccumSamples = Device->HrtfAccumData;
515 /* Copy the HRTF history and new input samples into a temp buffer. */
516 auto src_iter = std::copy(parms.Hrtf.State.History.begin(), parms.Hrtf.State.History.end(),
517 std::begin(HrtfSamples));
518 std::copy_n(samples, DstBufferSize, src_iter);
519 /* Copy the last used samples back into the history buffer for later. */
520 std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(),
521 parms.Hrtf.State.History.begin());
523 /* Copy the current filtered values being accumulated into the temp buffer. */
524 auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(),
525 std::begin(AccumSamples));
526 /* Clear the accumulation buffer that will start getting filled in. */
527 std::fill_n(accum_iter, DstBufferSize, float2{});
529 /* If fading, the old gain is not silence, and this is the first mixing
530 * pass, fade between the IRs.
532 ALuint fademix{0u};
533 if(Counter && parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD && OutPos == 0)
535 fademix = minu(DstBufferSize, 128);
537 float gain{TargetGain};
539 /* The new coefficients need to fade in completely since they're
540 * replacing the old ones. To keep the gain fading consistent,
541 * interpolate between the old and new target gains given how much of
542 * the fade time this mix handles.
544 if LIKELY(Counter > fademix)
546 const ALfloat a{static_cast<float>(fademix) / static_cast<float>(Counter)};
547 gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a);
549 MixHrtfFilter hrtfparams;
550 hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs;
551 hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0];
552 hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1];
553 hrtfparams.Gain = 0.0f;
554 hrtfparams.GainStep = gain / static_cast<float>(fademix);
556 MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples,
557 AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix);
558 /* Update the old parameters with the result. */
559 parms.Hrtf.Old = parms.Hrtf.Target;
560 if(fademix < Counter)
561 parms.Hrtf.Old.Gain = hrtfparams.Gain;
562 else
563 parms.Hrtf.Old.Gain = TargetGain;
566 if LIKELY(fademix < DstBufferSize)
568 const ALuint todo{DstBufferSize - fademix};
569 float gain{TargetGain};
571 /* Interpolate the target gain if the gain fading lasts longer than
572 * this mix.
574 if(Counter > DstBufferSize)
576 const float a{static_cast<float>(todo) / static_cast<float>(Counter-fademix)};
577 gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a);
580 MixHrtfFilter hrtfparams;
581 hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs;
582 hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0];
583 hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1];
584 hrtfparams.Gain = parms.Hrtf.Old.Gain;
585 hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast<float>(todo);
586 MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix,
587 AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo);
588 /* Store the interpolated gain or the final target gain depending if
589 * the fade is done.
591 if(DstBufferSize < Counter)
592 parms.Hrtf.Old.Gain = gain;
593 else
594 parms.Hrtf.Old.Gain = TargetGain;
597 /* Copy the new in-progress accumulation values back for the next mix. */
598 std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(),
599 parms.Hrtf.State.Values.begin());
602 void DoNfcMix(ALvoice::DirectData &Direct, const float *TargetGains, DirectParams &parms,
603 const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos,
604 ALCdevice *Device)
606 const size_t outcount{Device->NumChannelsPerOrder[0]};
607 MixSamples({samples, DstBufferSize}, Direct.Buffer.first(outcount),
608 parms.Gains.Current, TargetGains, Counter, OutPos);
610 const al::span<float> nfcsamples{Device->NfcSampleData, DstBufferSize};
611 size_t chanoffset{outcount};
612 using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t);
613 auto apply_nfc = [&Direct,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](
614 const FilterProc process, const size_t chancount) -> void
616 if(chancount < 1) return;
617 (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size());
618 MixSamples(nfcsamples, Direct.Buffer.subspan(chanoffset, chancount),
619 parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos);
620 chanoffset += chancount;
622 apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]);
623 apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]);
624 apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]);
627 } // namespace
629 void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo)
631 static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{};
633 ASSUME(SamplesToDo > 0);
635 /* Get voice info */
636 const bool isstatic{(mFlags&VOICE_IS_STATIC) != 0};
637 ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)};
638 ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)};
639 ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)};
640 ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)};
641 const ALuint NumChannels{mNumChannels};
642 const ALuint SampleSize{mSampleSize};
643 const ALuint increment{mStep};
644 if(increment < 1) return;
646 ASSUME(NumChannels > 0);
647 ASSUME(SampleSize > 0);
648 ASSUME(increment > 0);
650 ALCdevice *Device{Context->mDevice.get()};
651 const ALuint NumSends{Device->NumAuxSends};
652 const ALuint IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0};
654 ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ?
655 Resample_<CopyTag,CTag> : mResampler};
657 ALuint Counter{(mFlags&VOICE_IS_FADING) ? SamplesToDo : 0};
658 if(!Counter)
660 /* No fading, just overwrite the old/current params. */
661 for(ALuint chan{0};chan < NumChannels;chan++)
663 ChannelData &chandata = mChans[chan];
665 DirectParams &parms = chandata.mDryParams;
666 if(!(mFlags&VOICE_HAS_HRTF))
667 std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target),
668 std::begin(parms.Gains.Current));
669 else
670 parms.Hrtf.Old = parms.Hrtf.Target;
672 for(ALuint send{0};send < NumSends;++send)
674 if(mSend[send].Buffer.empty())
675 continue;
677 SendParams &parms = chandata.mWetParams[send];
678 std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target),
679 std::begin(parms.Gains.Current));
683 else if((mFlags&VOICE_HAS_HRTF))
685 for(ALuint chan{0};chan < NumChannels;chan++)
687 DirectParams &parms = mChans[chan].mDryParams;
688 if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
690 /* The old HRTF params are silent, so overwrite the old
691 * coefficients with the new, and reset the old gain to 0. The
692 * future mix will then fade from silence.
694 parms.Hrtf.Old = parms.Hrtf.Target;
695 parms.Hrtf.Old.Gain = 0.0f;
700 ALuint buffers_done{0u};
701 ALuint OutPos{0u};
702 do {
703 /* Figure out how many buffer samples will be needed */
704 ALuint DstBufferSize{SamplesToDo - OutPos};
706 /* Calculate the last written dst sample pos. */
707 uint64_t DataSize64{DstBufferSize - 1};
708 /* Calculate the last read src sample pos. */
709 DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS;
710 /* +1 to get the src sample count, include padding. */
711 DataSize64 += 1 + MAX_RESAMPLE_PADDING*2;
713 auto SrcBufferSize = static_cast<ALuint>(
714 minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1));
715 if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2)
717 SrcBufferSize = BUFFERSIZE + MAX_RESAMPLE_PADDING*2;
718 /* If the source buffer got saturated, we can't fill the desired
719 * dst size. Figure out how many samples we can actually mix from
720 * this.
722 DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2;
723 DataSize64 = ((DataSize64<<FRACTIONBITS) - DataPosFrac + increment-1) / increment;
724 DstBufferSize = static_cast<ALuint>(minu64(DataSize64, DstBufferSize));
726 /* Some mixers like having a multiple of 4, so try to give that
727 * unless this is the last update.
729 if(DstBufferSize < SamplesToDo-OutPos)
730 DstBufferSize &= ~3u;
733 ASSUME(DstBufferSize > 0);
734 for(ALuint chan{0};chan < NumChannels;chan++)
736 ChannelData &chandata = mChans[chan];
737 const al::span<ALfloat> SrcData{Device->SourceData, SrcBufferSize};
739 /* Load the previous samples into the source data first, then load
740 * what we can from the buffer queue.
742 auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING,
743 SrcData.begin());
745 if UNLIKELY(!BufferListItem)
746 srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING,
747 chandata.mPrevSamples.end(), srciter);
748 else if(isstatic)
749 srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels,
750 SampleSize, chan, DataPosInt, {srciter, SrcData.end()});
751 else
752 srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels,
753 SampleSize, chan, DataPosInt, {srciter, SrcData.end()});
755 if UNLIKELY(srciter != SrcData.end())
757 /* If the source buffer wasn't filled, copy the last sample for
758 * the remaining buffer. Ideally it should have ended with
759 * silence, but if not the gain fading should help avoid clicks
760 * from sudden amplitude changes.
762 const ALfloat sample{*(srciter-1)};
763 std::fill(srciter, SrcData.end(), sample);
766 /* Store the last source samples used for next time. */
767 std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
768 chandata.mPrevSamples.size(), chandata.mPrevSamples.begin());
770 /* Resample, then apply ambisonic upsampling as needed. */
771 const ALfloat *ResampledData{Resample(&mResampleState, &SrcData[MAX_RESAMPLE_PADDING],
772 DataPosFrac, increment, {Device->ResampledData, DstBufferSize})};
773 if((mFlags&VOICE_IS_AMBISONIC))
775 const ALfloat hfscale{chandata.mAmbiScale};
776 /* Beware the evil const_cast. It's safe since it's pointing to
777 * either SourceData or ResampledData (both non-const), but the
778 * resample method takes the source as const float* and may
779 * return it without copying to output, making it currently
780 * unavoidable.
782 chandata.mAmbiSplitter.applyHfScale(const_cast<ALfloat*>(ResampledData), hfscale,
783 DstBufferSize);
786 /* Now filter and mix to the appropriate outputs. */
787 ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData;
789 DirectParams &parms = chandata.mDryParams;
790 const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
791 ResampledData, DstBufferSize, mDirect.FilterType)};
793 if((mFlags&VOICE_HAS_HRTF))
795 const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f :
796 parms.Hrtf.Target.Gain};
797 DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos,
798 IrSize, Device);
800 else if((mFlags&VOICE_HAS_NFC))
802 const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
803 SilentTarget : parms.Gains.Target};
804 DoNfcMix(mDirect, TargetGains, parms, samples, DstBufferSize, Counter, OutPos,
805 Device);
807 else
809 const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
810 SilentTarget : parms.Gains.Target};
811 MixSamples({samples, DstBufferSize}, mDirect.Buffer, parms.Gains.Current,
812 TargetGains, Counter, OutPos);
816 for(ALuint send{0};send < NumSends;++send)
818 if(mSend[send].Buffer.empty())
819 continue;
821 SendParams &parms = chandata.mWetParams[send];
822 const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf,
823 ResampledData, DstBufferSize, mSend[send].FilterType)};
825 const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget :
826 parms.Gains.Target};
827 MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current,
828 TargetGains, Counter, OutPos);
831 /* Update positions */
832 DataPosFrac += increment*DstBufferSize;
833 DataPosInt += DataPosFrac>>FRACTIONBITS;
834 DataPosFrac &= FRACTIONMASK;
836 OutPos += DstBufferSize;
837 Counter = maxu(DstBufferSize, Counter) - DstBufferSize;
839 if UNLIKELY(!BufferListItem)
841 /* Do nothing extra when there's no buffers. */
843 else if(isstatic)
845 if(BufferLoopItem)
847 /* Handle looping static source */
848 const ALbuffer *Buffer{BufferListItem->mBuffer};
849 const ALuint LoopStart{Buffer->LoopStart};
850 const ALuint LoopEnd{Buffer->LoopEnd};
851 if(DataPosInt >= LoopEnd)
853 assert(LoopEnd > LoopStart);
854 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
857 else
859 /* Handle non-looping static source */
860 if(DataPosInt >= BufferListItem->mSampleLen)
862 if LIKELY(vstate == ALvoice::Playing)
863 vstate = ALvoice::Stopped;
864 BufferListItem = nullptr;
865 break;
869 else while(1)
871 /* Handle streaming source */
872 if(BufferListItem->mSampleLen > DataPosInt)
873 break;
875 DataPosInt -= BufferListItem->mSampleLen;
877 ++buffers_done;
878 BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed);
879 if(!BufferListItem && !(BufferListItem=BufferLoopItem))
881 if LIKELY(vstate == ALvoice::Playing)
882 vstate = ALvoice::Stopped;
883 break;
886 } while(OutPos < SamplesToDo);
888 mFlags |= VOICE_IS_FADING;
890 /* Don't update positions and buffers if we were stopping. */
891 if UNLIKELY(vstate == ALvoice::Stopping)
893 mPlayState.store(ALvoice::Stopped, std::memory_order_release);
894 return;
897 /* Capture the source ID in case it's reset for stopping. */
898 const ALuint SourceID{mSourceID.load(std::memory_order_relaxed)};
900 /* Update voice info */
901 mPosition.store(DataPosInt, std::memory_order_relaxed);
902 mPositionFrac.store(DataPosFrac, std::memory_order_relaxed);
903 mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed);
904 if(vstate == ALvoice::Stopped)
906 mLoopBuffer.store(nullptr, std::memory_order_relaxed);
907 mSourceID.store(0u, std::memory_order_relaxed);
909 std::atomic_thread_fence(std::memory_order_release);
911 /* Send any events now, after the position/buffer info was updated. */
912 const ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)};
913 if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted))
915 RingBuffer *ring{Context->mAsyncEvents.get()};
916 auto evt_vec = ring->getWriteVector();
917 if(evt_vec.first.len > 0)
919 AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}};
920 evt->u.bufcomp.id = SourceID;
921 evt->u.bufcomp.count = buffers_done;
922 ring->writeAdvance(1);
923 Context->mEventSem.post();
927 if(vstate == ALvoice::Stopped)
929 /* If the voice just ended, set it to Stopping so the next render
930 * ensures any residual noise fades to 0 amplitude.
932 mPlayState.store(ALvoice::Stopping, std::memory_order_release);
933 if((enabledevt&EventType_SourceStateChange))
934 SendSourceStoppedEvent(Context, SourceID);