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
40 #include "al/buffer.h"
42 #include "al/source.h"
46 #include "alcontext.h"
47 #include "alnumeric.h"
48 #include "aloptional.h"
53 #include "devformat.h"
54 #include "filters/biquad.h"
55 #include "filters/nfc.h"
56 #include "filters/splitter.h"
58 #include "inprogext.h"
60 #include "mixer/defs.h"
61 #include "opthelpers.h"
62 #include "ringbuffer.h"
67 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
68 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
71 Resampler ResamplerDefault
{Resampler::Linear
};
75 using HrtfMixerFunc
= void(*)(const ALfloat
*InSamples
, float2
*AccumSamples
, const ALuint IrSize
,
76 MixHrtfFilter
*hrtfparams
, const size_t BufferSize
);
77 using HrtfMixerBlendFunc
= void(*)(const ALfloat
*InSamples
, float2
*AccumSamples
,
78 const ALuint IrSize
, const HrtfFilter
*oldparams
, MixHrtfFilter
*newparams
,
79 const size_t BufferSize
);
81 HrtfMixerFunc MixHrtfSamples
= MixHrtf_
<CTag
>;
82 HrtfMixerBlendFunc MixHrtfBlendSamples
= MixHrtfBlend_
<CTag
>;
84 inline HrtfMixerFunc
SelectHrtfMixer()
87 if((CPUCapFlags
&CPU_CAP_NEON
))
88 return MixHrtf_
<NEONTag
>;
91 if((CPUCapFlags
&CPU_CAP_SSE
))
92 return MixHrtf_
<SSETag
>;
94 return MixHrtf_
<CTag
>;
97 inline HrtfMixerBlendFunc
SelectHrtfBlendMixer()
100 if((CPUCapFlags
&CPU_CAP_NEON
))
101 return MixHrtfBlend_
<NEONTag
>;
104 if((CPUCapFlags
&CPU_CAP_SSE
))
105 return MixHrtfBlend_
<SSETag
>;
107 return MixHrtfBlend_
<CTag
>;
115 if(auto resopt
= ConfigValueStr(nullptr, nullptr, "resampler"))
117 struct ResamplerEntry
{
119 const Resampler resampler
;
121 constexpr ResamplerEntry ResamplerList
[]{
122 { "none", Resampler::Point
},
123 { "point", Resampler::Point
},
124 { "cubic", Resampler::Cubic
},
125 { "bsinc12", Resampler::BSinc12
},
126 { "fast_bsinc12", Resampler::FastBSinc12
},
127 { "bsinc24", Resampler::BSinc24
},
128 { "fast_bsinc24", Resampler::FastBSinc24
},
131 const char *str
{resopt
->c_str()};
132 if(al::strcasecmp(str
, "bsinc") == 0)
134 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str
);
137 else if(al::strcasecmp(str
, "sinc4") == 0 || al::strcasecmp(str
, "sinc8") == 0)
139 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
143 auto iter
= std::find_if(std::begin(ResamplerList
), std::end(ResamplerList
),
144 [str
](const ResamplerEntry
&entry
) -> bool
145 { return al::strcasecmp(str
, entry
.name
) == 0; });
146 if(iter
== std::end(ResamplerList
))
147 ERR("Invalid resampler: %s\n", str
);
149 ResamplerDefault
= iter
->resampler
;
152 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
153 MixHrtfSamples
= SelectHrtfMixer();
159 /* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
160 * signed 16-bit sample */
161 constexpr ALshort muLawDecompressionTable
[256] = {
162 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
163 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
164 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
165 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
166 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
167 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
168 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
169 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
170 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
171 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
172 -876, -844, -812, -780, -748, -716, -684, -652,
173 -620, -588, -556, -524, -492, -460, -428, -396,
174 -372, -356, -340, -324, -308, -292, -276, -260,
175 -244, -228, -212, -196, -180, -164, -148, -132,
176 -120, -112, -104, -96, -88, -80, -72, -64,
177 -56, -48, -40, -32, -24, -16, -8, 0,
178 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
179 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
180 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
181 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
182 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
183 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
184 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
185 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
186 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
187 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
188 876, 844, 812, 780, 748, 716, 684, 652,
189 620, 588, 556, 524, 492, 460, 428, 396,
190 372, 356, 340, 324, 308, 292, 276, 260,
191 244, 228, 212, 196, 180, 164, 148, 132,
192 120, 112, 104, 96, 88, 80, 72, 64,
193 56, 48, 40, 32, 24, 16, 8, 0
196 /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a
197 * signed 16-bit sample */
198 constexpr ALshort aLawDecompressionTable
[256] = {
199 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
200 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
201 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
202 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
203 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
204 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
205 -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
206 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
207 -344, -328, -376, -360, -280, -264, -312, -296,
208 -472, -456, -504, -488, -408, -392, -440, -424,
209 -88, -72, -120, -104, -24, -8, -56, -40,
210 -216, -200, -248, -232, -152, -136, -184, -168,
211 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
212 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
213 -688, -656, -752, -720, -560, -528, -624, -592,
214 -944, -912, -1008, -976, -816, -784, -880, -848,
215 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
216 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
217 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
218 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
219 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
220 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
221 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
222 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
223 344, 328, 376, 360, 280, 264, 312, 296,
224 472, 456, 504, 488, 408, 392, 440, 424,
225 88, 72, 120, 104, 24, 8, 56, 40,
226 216, 200, 248, 232, 152, 136, 184, 168,
227 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
228 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
229 688, 656, 752, 720, 560, 528, 624, 592,
230 944, 912, 1008, 976, 816, 784, 880, 848
234 struct FmtTypeTraits
{ };
237 struct FmtTypeTraits
<FmtUByte
> {
238 using Type
= ALubyte
;
239 static constexpr inline float to_float(const Type val
) noexcept
240 { return val
*(1.0f
/128.0f
) - 1.0f
; }
243 struct FmtTypeTraits
<FmtShort
> {
244 using Type
= ALshort
;
245 static constexpr inline float to_float(const Type val
) noexcept
{ return val
*(1.0f
/32768.0f
); }
248 struct FmtTypeTraits
<FmtFloat
> {
249 using Type
= ALfloat
;
250 static constexpr inline float to_float(const Type val
) noexcept
{ return val
; }
253 struct FmtTypeTraits
<FmtDouble
> {
254 using Type
= ALdouble
;
255 static constexpr inline float to_float(const Type val
) noexcept
256 { return static_cast<ALfloat
>(val
); }
259 struct FmtTypeTraits
<FmtMulaw
> {
260 using Type
= ALubyte
;
261 static constexpr inline float to_float(const Type val
) noexcept
262 { return muLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
265 struct FmtTypeTraits
<FmtAlaw
> {
266 using Type
= ALubyte
;
267 static constexpr inline float to_float(const Type val
) noexcept
268 { return aLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
272 void SendSourceStoppedEvent(ALCcontext
*context
, ALuint id
)
274 RingBuffer
*ring
{context
->mAsyncEvents
.get()};
275 auto evt_vec
= ring
->getWriteVector();
276 if(evt_vec
.first
.len
< 1) return;
278 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_SourceStateChange
}};
279 evt
->u
.srcstate
.id
= id
;
280 evt
->u
.srcstate
.state
= AL_STOPPED
;
282 ring
->writeAdvance(1);
283 context
->mEventSem
.post();
287 const ALfloat
*DoFilters(BiquadFilter
*lpfilter
, BiquadFilter
*hpfilter
, ALfloat
*dst
,
288 const ALfloat
*src
, const size_t numsamples
, int type
)
298 lpfilter
->process(dst
, src
, numsamples
);
303 hpfilter
->process(dst
, src
, numsamples
);
307 lpfilter
->process(dst
, src
, numsamples
);
308 hpfilter
->process(dst
, dst
, numsamples
);
316 inline void LoadSampleArray(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
,
317 const size_t samples
) noexcept
319 using SampleType
= typename FmtTypeTraits
<T
>::Type
;
321 const SampleType
*RESTRICT ssrc
{reinterpret_cast<const SampleType
*>(src
)};
322 for(size_t i
{0u};i
< samples
;i
++)
323 dst
[i
] = FmtTypeTraits
<T
>::to_float(ssrc
[i
*srcstep
]);
326 void LoadSamples(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
, FmtType srctype
,
327 const size_t samples
) noexcept
329 #define HANDLE_FMT(T) case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
332 HANDLE_FMT(FmtUByte
);
333 HANDLE_FMT(FmtShort
);
334 HANDLE_FMT(FmtFloat
);
335 HANDLE_FMT(FmtDouble
);
336 HANDLE_FMT(FmtMulaw
);
342 ALfloat
*LoadBufferStatic(ALbufferlistitem
*BufferListItem
, ALbufferlistitem
*&BufferLoopItem
,
343 const size_t NumChannels
, const size_t SampleSize
, const size_t chan
, size_t DataPosInt
,
344 al::span
<ALfloat
> SrcBuffer
)
346 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
347 const ALuint LoopStart
{Buffer
->LoopStart
};
348 const ALuint LoopEnd
{Buffer
->LoopEnd
};
349 ASSUME(LoopEnd
> LoopStart
);
351 /* If current pos is beyond the loop range, do not loop */
352 if(!BufferLoopItem
|| DataPosInt
>= LoopEnd
)
354 BufferLoopItem
= nullptr;
356 /* Load what's left to play from the buffer */
357 const size_t DataRem
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
359 const al::byte
*Data
{Buffer
->mData
.data()};
360 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
362 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataRem
);
363 SrcBuffer
= SrcBuffer
.subspan(DataRem
);
367 /* Load what's left of this loop iteration */
368 const size_t DataRem
{minz(SrcBuffer
.size(), LoopEnd
-DataPosInt
)};
370 const al::byte
*Data
{Buffer
->mData
.data()};
371 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
373 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataRem
);
374 SrcBuffer
= SrcBuffer
.subspan(DataRem
);
376 /* Load any repeats of the loop we can to fill the buffer. */
377 const auto LoopSize
= static_cast<size_t>(LoopEnd
- LoopStart
);
378 while(!SrcBuffer
.empty())
380 const size_t DataSize
{minz(SrcBuffer
.size(), LoopSize
)};
382 Data
= Buffer
->mData
.data() + (LoopStart
*NumChannels
+ chan
)*SampleSize
;
384 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
385 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
388 return SrcBuffer
.begin();
391 ALfloat
*LoadBufferQueue(ALbufferlistitem
*BufferListItem
, ALbufferlistitem
*BufferLoopItem
,
392 const size_t NumChannels
, const size_t SampleSize
, const size_t chan
, size_t DataPosInt
,
393 al::span
<ALfloat
> SrcBuffer
)
395 /* Crawl the buffer queue to fill in the temp buffer */
396 while(BufferListItem
&& !SrcBuffer
.empty())
398 ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
399 if(!(Buffer
&& DataPosInt
< Buffer
->SampleLen
))
401 if(Buffer
) DataPosInt
-= Buffer
->SampleLen
;
402 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
403 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
407 const size_t DataSize
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
409 const al::byte
*Data
{Buffer
->mData
.data()};
410 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
412 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
413 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
414 if(SrcBuffer
.empty()) break;
417 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
418 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
421 return SrcBuffer
.begin();
425 void DoHrtfMix(const float TargetGain
, DirectParams
&parms
, const float *samples
,
426 const ALuint DstBufferSize
, const ALuint Counter
, ALuint OutPos
, const ALuint IrSize
,
429 auto &HrtfSamples
= Device
->HrtfSourceData
;
430 auto &AccumSamples
= Device
->HrtfAccumData
;
432 /* Copy the HRTF history and new input samples into a temp buffer. */
433 auto src_iter
= std::copy(parms
.Hrtf
.State
.History
.begin(), parms
.Hrtf
.State
.History
.end(),
434 std::begin(HrtfSamples
));
435 std::copy_n(samples
, DstBufferSize
, src_iter
);
436 /* Copy the last used samples back into the history buffer for later. */
437 std::copy_n(std::begin(HrtfSamples
) + DstBufferSize
, parms
.Hrtf
.State
.History
.size(),
438 parms
.Hrtf
.State
.History
.begin());
440 /* If fading, the old gain is not silence, and this is the first mixing
441 * pass, fade between the IRs.
444 if(Counter
&& parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
&& OutPos
== 0)
446 fademix
= minu(DstBufferSize
, 128);
448 float gain
{TargetGain
};
450 /* The new coefficients need to fade in completely since they're
451 * replacing the old ones. To keep the gain fading consistent,
452 * interpolate between the old and new target gains given how much of
453 * the fade time this mix handles.
455 if LIKELY(Counter
> fademix
)
457 const ALfloat a
{static_cast<float>(fademix
) / static_cast<float>(Counter
)};
458 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
460 MixHrtfFilter hrtfparams
;
461 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
462 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
463 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
464 hrtfparams
.Gain
= 0.0f
;
465 hrtfparams
.GainStep
= gain
/ static_cast<float>(fademix
);
467 MixHrtfBlendSamples(HrtfSamples
, AccumSamples
+OutPos
, IrSize
, &parms
.Hrtf
.Old
, &hrtfparams
,
469 /* Update the old parameters with the result. */
470 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
471 if(fademix
< Counter
)
472 parms
.Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
474 parms
.Hrtf
.Old
.Gain
= TargetGain
;
478 if LIKELY(fademix
< DstBufferSize
)
480 const ALuint todo
{DstBufferSize
- fademix
};
481 float gain
{TargetGain
};
483 /* Interpolate the target gain if the gain fading lasts longer than
486 if(Counter
> DstBufferSize
)
488 const float a
{static_cast<float>(todo
) / static_cast<float>(Counter
-fademix
)};
489 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
492 MixHrtfFilter hrtfparams
;
493 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
494 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
495 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
496 hrtfparams
.Gain
= parms
.Hrtf
.Old
.Gain
;
497 hrtfparams
.GainStep
= (gain
- parms
.Hrtf
.Old
.Gain
) / static_cast<float>(todo
);
498 MixHrtfSamples(HrtfSamples
+fademix
, AccumSamples
+OutPos
, IrSize
, &hrtfparams
, todo
);
499 /* Store the interpolated gain or the final target gain depending if
502 if(DstBufferSize
< Counter
)
503 parms
.Hrtf
.Old
.Gain
= gain
;
505 parms
.Hrtf
.Old
.Gain
= TargetGain
;
509 void DoNfcMix(ALvoice::TargetData
&Direct
, const float *TargetGains
, DirectParams
&parms
,
510 const float *samples
, const ALuint DstBufferSize
, const ALuint Counter
, const ALuint OutPos
,
513 const size_t outcount
{Device
->NumChannelsPerOrder
[0]};
514 MixSamples({samples
, DstBufferSize
}, Direct
.Buffer
.first(outcount
),
515 parms
.Gains
.Current
.data(), TargetGains
, Counter
, OutPos
);
517 const al::span
<float> nfcsamples
{Device
->NfcSampleData
, DstBufferSize
};
518 size_t chanoffset
{outcount
};
519 using FilterProc
= void (NfcFilter::*)(float*,const float*,const size_t);
520 auto apply_nfc
= [&Direct
,&parms
,samples
,TargetGains
,Counter
,OutPos
,&chanoffset
,nfcsamples
](
521 const FilterProc process
, const size_t chancount
) -> void
523 if(chancount
< 1) return;
524 (parms
.NFCtrlFilter
.*process
)(nfcsamples
.data(), samples
, nfcsamples
.size());
525 MixSamples(nfcsamples
, Direct
.Buffer
.subspan(chanoffset
, chancount
),
526 &parms
.Gains
.Current
[chanoffset
], &TargetGains
[chanoffset
], Counter
, OutPos
);
527 chanoffset
+= chancount
;
529 apply_nfc(&NfcFilter::process1
, Device
->NumChannelsPerOrder
[1]);
530 apply_nfc(&NfcFilter::process2
, Device
->NumChannelsPerOrder
[2]);
531 apply_nfc(&NfcFilter::process3
, Device
->NumChannelsPerOrder
[3]);
536 void ALvoice::mix(const State vstate
, ALCcontext
*Context
, const ALuint SamplesToDo
)
538 static constexpr std::array
<float,MAX_OUTPUT_CHANNELS
> SilentTarget
{};
540 ASSUME(SamplesToDo
> 0);
543 const bool isstatic
{(mFlags
&VOICE_IS_STATIC
) != 0};
544 ALuint DataPosInt
{mPosition
.load(std::memory_order_relaxed
)};
545 ALuint DataPosFrac
{mPositionFrac
.load(std::memory_order_relaxed
)};
546 ALbufferlistitem
*BufferListItem
{mCurrentBuffer
.load(std::memory_order_relaxed
)};
547 ALbufferlistitem
*BufferLoopItem
{mLoopBuffer
.load(std::memory_order_relaxed
)};
548 const ALuint NumChannels
{mNumChannels
};
549 const ALuint SampleSize
{mSampleSize
};
550 const ALuint increment
{mStep
};
551 if(increment
< 1) return;
553 ASSUME(NumChannels
> 0);
554 ASSUME(SampleSize
> 0);
555 ASSUME(increment
> 0);
557 ALCdevice
*Device
{Context
->mDevice
.get()};
558 const ALuint NumSends
{Device
->NumAuxSends
};
559 const ALuint IrSize
{Device
->mHrtf
? Device
->mHrtf
->irSize
: 0};
561 ResamplerFunc Resample
{(increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
562 Resample_
<CopyTag
,CTag
> : mResampler
};
564 ALuint Counter
{(mFlags
&VOICE_IS_FADING
) ? SamplesToDo
: 0};
567 /* No fading, just overwrite the old/current params. */
568 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
570 ChannelData
&chandata
= mChans
[chan
];
572 DirectParams
&parms
= chandata
.mDryParams
;
573 if(!(mFlags
&VOICE_HAS_HRTF
))
574 parms
.Gains
.Current
= parms
.Gains
.Target
;
576 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
578 for(ALuint send
{0};send
< NumSends
;++send
)
580 if(mSend
[send
].Buffer
.empty())
583 SendParams
&parms
= chandata
.mWetParams
[send
];
584 parms
.Gains
.Current
= parms
.Gains
.Target
;
588 else if((mFlags
&VOICE_HAS_HRTF
))
590 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
592 DirectParams
&parms
= mChans
[chan
].mDryParams
;
593 if(!(parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
595 /* The old HRTF params are silent, so overwrite the old
596 * coefficients with the new, and reset the old gain to 0. The
597 * future mix will then fade from silence.
599 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
600 parms
.Hrtf
.Old
.Gain
= 0.0f
;
605 ALuint buffers_done
{0u};
608 /* Figure out how many buffer samples will be needed */
609 ALuint DstBufferSize
{SamplesToDo
- OutPos
};
611 /* Calculate the last written dst sample pos. */
612 uint64_t DataSize64
{DstBufferSize
- 1};
613 /* Calculate the last read src sample pos. */
614 DataSize64
= (DataSize64
*increment
+ DataPosFrac
) >> FRACTIONBITS
;
615 /* +1 to get the src sample count, include padding. */
616 DataSize64
+= 1 + MAX_RESAMPLER_PADDING
;
618 auto SrcBufferSize
= static_cast<ALuint
>(
619 minu64(DataSize64
, BUFFERSIZE
+ MAX_RESAMPLER_PADDING
+ 1));
620 if(SrcBufferSize
> BUFFERSIZE
+ MAX_RESAMPLER_PADDING
)
622 SrcBufferSize
= BUFFERSIZE
+ MAX_RESAMPLER_PADDING
;
623 /* If the source buffer got saturated, we can't fill the desired
624 * dst size. Figure out how many samples we can actually mix from
627 DataSize64
= SrcBufferSize
- MAX_RESAMPLER_PADDING
;
628 DataSize64
= ((DataSize64
<<FRACTIONBITS
) - DataPosFrac
+ increment
-1) / increment
;
629 DstBufferSize
= static_cast<ALuint
>(minu64(DataSize64
, DstBufferSize
));
631 /* Some mixers like having a multiple of 4, so try to give that
632 * unless this is the last update.
634 if(DstBufferSize
< SamplesToDo
-OutPos
)
635 DstBufferSize
&= ~3u;
638 ASSUME(DstBufferSize
> 0);
639 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
641 ChannelData
&chandata
= mChans
[chan
];
642 const al::span
<ALfloat
> SrcData
{Device
->SourceData
, SrcBufferSize
};
644 /* Load the previous samples into the source data first, then load
645 * what we can from the buffer queue.
647 auto srciter
= std::copy_n(chandata
.mPrevSamples
.begin(), MAX_RESAMPLER_PADDING
>>1,
650 if UNLIKELY(!BufferListItem
)
651 srciter
= std::copy(chandata
.mPrevSamples
.begin()+(MAX_RESAMPLER_PADDING
>>1),
652 chandata
.mPrevSamples
.end(), srciter
);
654 srciter
= LoadBufferStatic(BufferListItem
, BufferLoopItem
, NumChannels
,
655 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
657 srciter
= LoadBufferQueue(BufferListItem
, BufferLoopItem
, NumChannels
,
658 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
660 if UNLIKELY(srciter
!= SrcData
.end())
662 /* If the source buffer wasn't filled, copy the last sample for
663 * the remaining buffer. Ideally it should have ended with
664 * silence, but if not the gain fading should help avoid clicks
665 * from sudden amplitude changes.
667 const ALfloat sample
{*(srciter
-1)};
668 std::fill(srciter
, SrcData
.end(), sample
);
671 /* Store the last source samples used for next time. */
672 std::copy_n(&SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
673 chandata
.mPrevSamples
.size(), chandata
.mPrevSamples
.begin());
675 /* Resample, then apply ambisonic upsampling as needed. */
676 const ALfloat
*ResampledData
{Resample(&mResampleState
,
677 &SrcData
[MAX_RESAMPLER_PADDING
>>1], DataPosFrac
, increment
,
678 {Device
->ResampledData
, DstBufferSize
})};
679 if((mFlags
&VOICE_IS_AMBISONIC
))
681 const ALfloat hfscale
{chandata
.mAmbiScale
};
682 /* Beware the evil const_cast. It's safe since it's pointing to
683 * either SourceData or ResampledData (both non-const), but the
684 * resample method takes the source as const float* and may
685 * return it without copying to output, making it currently
688 chandata
.mAmbiSplitter
.applyHfScale(const_cast<ALfloat
*>(ResampledData
), hfscale
,
692 /* Now filter and mix to the appropriate outputs. */
693 ALfloat (&FilterBuf
)[BUFFERSIZE
] = Device
->FilteredData
;
695 DirectParams
&parms
= chandata
.mDryParams
;
696 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
697 ResampledData
, DstBufferSize
, mDirect
.FilterType
)};
699 if((mFlags
&VOICE_HAS_HRTF
))
701 const ALfloat TargetGain
{UNLIKELY(vstate
== ALvoice::Stopping
) ? 0.0f
:
702 parms
.Hrtf
.Target
.Gain
};
703 DoHrtfMix(TargetGain
, parms
, samples
, DstBufferSize
, Counter
, OutPos
, IrSize
,
706 else if((mFlags
&VOICE_HAS_NFC
))
708 const float *TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
709 SilentTarget
.data() : parms
.Gains
.Target
.data()};
710 DoNfcMix(mDirect
, TargetGains
, parms
, samples
, DstBufferSize
, Counter
, OutPos
,
715 const float *TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
716 SilentTarget
.data() : parms
.Gains
.Target
.data()};
717 MixSamples({samples
, DstBufferSize
}, mDirect
.Buffer
,
718 parms
.Gains
.Current
.data(), TargetGains
, Counter
, OutPos
);
722 for(ALuint send
{0};send
< NumSends
;++send
)
724 if(mSend
[send
].Buffer
.empty())
727 SendParams
&parms
= chandata
.mWetParams
[send
];
728 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
729 ResampledData
, DstBufferSize
, mSend
[send
].FilterType
)};
731 const float *TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
732 SilentTarget
.data() : parms
.Gains
.Target
.data()};
733 MixSamples({samples
, DstBufferSize
}, mSend
[send
].Buffer
,
734 parms
.Gains
.Current
.data(), TargetGains
, Counter
, OutPos
);
737 /* Update positions */
738 DataPosFrac
+= increment
*DstBufferSize
;
739 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
740 DataPosFrac
&= FRACTIONMASK
;
742 OutPos
+= DstBufferSize
;
743 Counter
= maxu(DstBufferSize
, Counter
) - DstBufferSize
;
745 if UNLIKELY(!BufferListItem
)
747 /* Do nothing extra when there's no buffers. */
753 /* Handle looping static source */
754 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
755 const ALuint LoopStart
{Buffer
->LoopStart
};
756 const ALuint LoopEnd
{Buffer
->LoopEnd
};
757 if(DataPosInt
>= LoopEnd
)
759 assert(LoopEnd
> LoopStart
);
760 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
765 /* Handle non-looping static source */
766 if(DataPosInt
>= BufferListItem
->mSampleLen
)
768 BufferListItem
= nullptr;
775 /* Handle streaming source */
777 if(BufferListItem
->mSampleLen
> DataPosInt
)
780 DataPosInt
-= BufferListItem
->mSampleLen
;
783 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_relaxed
);
784 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
785 } while(BufferListItem
);
787 } while(OutPos
< SamplesToDo
);
789 mFlags
|= VOICE_IS_FADING
;
791 /* Don't update positions and buffers if we were stopping. */
792 if UNLIKELY(vstate
== ALvoice::Stopping
)
794 mPlayState
.store(ALvoice::Stopped
, std::memory_order_release
);
798 /* Capture the source ID in case it's reset for stopping. */
799 const ALuint SourceID
{mSourceID
.load(std::memory_order_relaxed
)};
801 /* Update voice info */
802 mPosition
.store(DataPosInt
, std::memory_order_relaxed
);
803 mPositionFrac
.store(DataPosFrac
, std::memory_order_relaxed
);
804 mCurrentBuffer
.store(BufferListItem
, std::memory_order_relaxed
);
807 mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
808 mSourceID
.store(0u, std::memory_order_relaxed
);
810 std::atomic_thread_fence(std::memory_order_release
);
812 /* Send any events now, after the position/buffer info was updated. */
813 const ALbitfieldSOFT enabledevt
{Context
->mEnabledEvts
.load(std::memory_order_acquire
)};
814 if(buffers_done
> 0 && (enabledevt
&EventType_BufferCompleted
))
816 RingBuffer
*ring
{Context
->mAsyncEvents
.get()};
817 auto evt_vec
= ring
->getWriteVector();
818 if(evt_vec
.first
.len
> 0)
820 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_BufferCompleted
}};
821 evt
->u
.bufcomp
.id
= SourceID
;
822 evt
->u
.bufcomp
.count
= buffers_done
;
823 ring
->writeAdvance(1);
824 Context
->mEventSem
.post();
830 /* If the voice just ended, set it to Stopping so the next render
831 * ensures any residual noise fades to 0 amplitude.
833 mPlayState
.store(ALvoice::Stopping
, std::memory_order_release
);
834 if((enabledevt
&EventType_SourceStateChange
))
835 SendSourceStoppedEvent(Context
, SourceID
);