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
41 #include "al/buffer.h"
43 #include "al/source.h"
47 #include "alcontext.h"
48 #include "alnumeric.h"
49 #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!");
70 /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */
71 static_assert(MAX_RESAMPLE_PADDING
>= 24, "MAX_RESAMPLE_PADDING must be at least 24!");
74 Resampler ResamplerDefault
= LinearResampler
;
76 MixerFunc MixSamples
= Mix_
<CTag
>;
77 RowMixerFunc MixRowSamples
= MixRow_
<CTag
>;
78 static HrtfMixerFunc MixHrtfSamples
= MixHrtf_
<CTag
>;
79 static HrtfMixerBlendFunc MixHrtfBlendSamples
= MixHrtfBlend_
<CTag
>;
81 static MixerFunc
SelectMixer()
84 if((CPUCapFlags
&CPU_CAP_NEON
))
88 if((CPUCapFlags
&CPU_CAP_SSE
))
94 static RowMixerFunc
SelectRowMixer()
97 if((CPUCapFlags
&CPU_CAP_NEON
))
98 return MixRow_
<NEONTag
>;
101 if((CPUCapFlags
&CPU_CAP_SSE
))
102 return MixRow_
<SSETag
>;
104 return MixRow_
<CTag
>;
107 static inline HrtfMixerFunc
SelectHrtfMixer()
110 if((CPUCapFlags
&CPU_CAP_NEON
))
111 return MixHrtf_
<NEONTag
>;
114 if((CPUCapFlags
&CPU_CAP_SSE
))
115 return MixHrtf_
<SSETag
>;
117 return MixHrtf_
<CTag
>;
120 static inline HrtfMixerBlendFunc
SelectHrtfBlendMixer()
123 if((CPUCapFlags
&CPU_CAP_NEON
))
124 return MixHrtfBlend_
<NEONTag
>;
127 if((CPUCapFlags
&CPU_CAP_SSE
))
128 return MixHrtfBlend_
<SSETag
>;
130 return MixHrtfBlend_
<CTag
>;
133 ResamplerFunc
SelectResampler(Resampler resampler
)
138 return Resample_
<PointTag
,CTag
>;
139 case LinearResampler
:
141 if((CPUCapFlags
&CPU_CAP_NEON
))
142 return Resample_
<LerpTag
,NEONTag
>;
145 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
146 return Resample_
<LerpTag
,SSE4Tag
>;
149 if((CPUCapFlags
&CPU_CAP_SSE2
))
150 return Resample_
<LerpTag
,SSE2Tag
>;
152 return Resample_
<LerpTag
,CTag
>;
154 return Resample_
<CubicTag
,CTag
>;
155 case BSinc12Resampler
:
156 case BSinc24Resampler
:
158 if((CPUCapFlags
&CPU_CAP_NEON
))
159 return Resample_
<BSincTag
,NEONTag
>;
162 if((CPUCapFlags
&CPU_CAP_SSE
))
163 return Resample_
<BSincTag
,SSETag
>;
165 return Resample_
<BSincTag
,CTag
>;
168 return Resample_
<PointTag
,CTag
>;
174 if(auto resopt
= ConfigValueStr(nullptr, nullptr, "resampler"))
176 const char *str
{resopt
->c_str()};
177 if(strcasecmp(str
, "point") == 0 || strcasecmp(str
, "none") == 0)
178 ResamplerDefault
= PointResampler
;
179 else if(strcasecmp(str
, "linear") == 0)
180 ResamplerDefault
= LinearResampler
;
181 else if(strcasecmp(str
, "cubic") == 0)
182 ResamplerDefault
= FIR4Resampler
;
183 else if(strcasecmp(str
, "bsinc12") == 0)
184 ResamplerDefault
= BSinc12Resampler
;
185 else if(strcasecmp(str
, "bsinc24") == 0)
186 ResamplerDefault
= BSinc24Resampler
;
187 else if(strcasecmp(str
, "bsinc") == 0)
189 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str
);
190 ResamplerDefault
= BSinc12Resampler
;
192 else if(strcasecmp(str
, "sinc4") == 0 || strcasecmp(str
, "sinc8") == 0)
194 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
195 ResamplerDefault
= FIR4Resampler
;
198 ERR("Invalid resampler: %s\n", str
);
201 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
202 MixHrtfSamples
= SelectHrtfMixer();
203 MixSamples
= SelectMixer();
204 MixRowSamples
= SelectRowMixer();
210 /* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
211 * signed 16-bit sample */
212 constexpr ALshort muLawDecompressionTable
[256] = {
213 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
214 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
215 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
216 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
217 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
218 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
219 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
220 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
221 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
222 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
223 -876, -844, -812, -780, -748, -716, -684, -652,
224 -620, -588, -556, -524, -492, -460, -428, -396,
225 -372, -356, -340, -324, -308, -292, -276, -260,
226 -244, -228, -212, -196, -180, -164, -148, -132,
227 -120, -112, -104, -96, -88, -80, -72, -64,
228 -56, -48, -40, -32, -24, -16, -8, 0,
229 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
230 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
231 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
232 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
233 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
234 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
235 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
236 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
237 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
238 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
239 876, 844, 812, 780, 748, 716, 684, 652,
240 620, 588, 556, 524, 492, 460, 428, 396,
241 372, 356, 340, 324, 308, 292, 276, 260,
242 244, 228, 212, 196, 180, 164, 148, 132,
243 120, 112, 104, 96, 88, 80, 72, 64,
244 56, 48, 40, 32, 24, 16, 8, 0
247 /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a
248 * signed 16-bit sample */
249 constexpr ALshort aLawDecompressionTable
[256] = {
250 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
251 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
252 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
253 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
254 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
255 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
256 -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
257 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
258 -344, -328, -376, -360, -280, -264, -312, -296,
259 -472, -456, -504, -488, -408, -392, -440, -424,
260 -88, -72, -120, -104, -24, -8, -56, -40,
261 -216, -200, -248, -232, -152, -136, -184, -168,
262 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
263 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
264 -688, -656, -752, -720, -560, -528, -624, -592,
265 -944, -912, -1008, -976, -816, -784, -880, -848,
266 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
267 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
268 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
269 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
270 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
271 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
272 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
273 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
274 344, 328, 376, 360, 280, 264, 312, 296,
275 472, 456, 504, 488, 408, 392, 440, 424,
276 88, 72, 120, 104, 24, 8, 56, 40,
277 216, 200, 248, 232, 152, 136, 184, 168,
278 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
279 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
280 688, 656, 752, 720, 560, 528, 624, 592,
281 944, 912, 1008, 976, 816, 784, 880, 848
285 struct FmtTypeTraits
{ };
288 struct FmtTypeTraits
<FmtUByte
> {
289 using Type
= ALubyte
;
290 static constexpr ALfloat
to_float(const Type val
) { return (val
-128) * (1.0f
/128.0f
); }
293 struct FmtTypeTraits
<FmtShort
> {
294 using Type
= ALshort
;
295 static constexpr ALfloat
to_float(const Type val
) { return val
* (1.0f
/32768.0f
); }
298 struct FmtTypeTraits
<FmtFloat
> {
299 using Type
= ALfloat
;
300 static constexpr ALfloat
to_float(const Type val
) { return val
; }
303 struct FmtTypeTraits
<FmtDouble
> {
304 using Type
= ALdouble
;
305 static constexpr ALfloat
to_float(const Type val
) { return static_cast<ALfloat
>(val
); }
308 struct FmtTypeTraits
<FmtMulaw
> {
309 using Type
= ALubyte
;
310 static constexpr ALfloat
to_float(const Type val
)
311 { return muLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
314 struct FmtTypeTraits
<FmtAlaw
> {
315 using Type
= ALubyte
;
316 static constexpr ALfloat
to_float(const Type val
)
317 { return aLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
321 void SendSourceStoppedEvent(ALCcontext
*context
, ALuint id
)
323 RingBuffer
*ring
{context
->mAsyncEvents
.get()};
324 auto evt_vec
= ring
->getWriteVector();
325 if(evt_vec
.first
.len
< 1) return;
327 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_SourceStateChange
}};
328 evt
->u
.srcstate
.id
= id
;
329 evt
->u
.srcstate
.state
= AL_STOPPED
;
331 ring
->writeAdvance(1);
332 context
->mEventSem
.post();
336 const ALfloat
*DoFilters(BiquadFilter
*lpfilter
, BiquadFilter
*hpfilter
, ALfloat
*dst
,
337 const ALfloat
*src
, const size_t numsamples
, int type
)
347 lpfilter
->process(dst
, src
, numsamples
);
352 hpfilter
->process(dst
, src
, numsamples
);
356 lpfilter
->process(dst
, src
, numsamples
);
357 hpfilter
->process(dst
, dst
, numsamples
);
365 inline void LoadSampleArray(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
,
366 const size_t samples
)
368 using SampleType
= typename FmtTypeTraits
<T
>::Type
;
370 const SampleType
*RESTRICT ssrc
{reinterpret_cast<const SampleType
*>(src
)};
371 for(size_t i
{0u};i
< samples
;i
++)
372 dst
[i
] = FmtTypeTraits
<T
>::to_float(ssrc
[i
*srcstep
]);
375 void LoadSamples(ALfloat
*RESTRICT dst
, const al::byte
*src
, const size_t srcstep
, FmtType srctype
,
376 const size_t samples
)
378 #define HANDLE_FMT(T) case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
381 HANDLE_FMT(FmtUByte
);
382 HANDLE_FMT(FmtShort
);
383 HANDLE_FMT(FmtFloat
);
384 HANDLE_FMT(FmtDouble
);
385 HANDLE_FMT(FmtMulaw
);
391 ALfloat
*LoadBufferStatic(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 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
396 const ALuint LoopStart
{Buffer
->LoopStart
};
397 const ALuint LoopEnd
{Buffer
->LoopEnd
};
398 ASSUME(LoopEnd
> LoopStart
);
400 /* If current pos is beyond the loop range, do not loop */
401 if(!BufferLoopItem
|| DataPosInt
>= LoopEnd
)
403 BufferLoopItem
= nullptr;
405 /* Load what's left to play from the buffer */
406 const size_t DataSize
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
408 const al::byte
*Data
{Buffer
->mData
.data()};
409 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
411 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
412 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
416 /* Load what's left of this loop iteration */
417 const size_t DataSize
{minz(SrcBuffer
.size(), LoopEnd
-DataPosInt
)};
419 const al::byte
*Data
{Buffer
->mData
.data()};
420 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
422 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
423 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
425 /* Load any repeats of the loop we can to fill the buffer. */
426 const auto LoopSize
= static_cast<size_t>(LoopEnd
- LoopStart
);
427 while(!SrcBuffer
.empty())
429 const size_t DataSize
{minz(SrcBuffer
.size(), LoopSize
)};
431 const al::byte
*Data
{Buffer
->mData
.data()};
432 Data
+= (LoopStart
*NumChannels
+ chan
)*SampleSize
;
434 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
435 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
438 return SrcBuffer
.begin();
441 ALfloat
*LoadBufferQueue(ALbufferlistitem
*BufferListItem
, ALbufferlistitem
*BufferLoopItem
,
442 const size_t NumChannels
, const size_t SampleSize
, const size_t chan
, size_t DataPosInt
,
443 al::span
<ALfloat
> SrcBuffer
)
445 /* Crawl the buffer queue to fill in the temp buffer */
446 while(BufferListItem
&& !SrcBuffer
.empty())
448 ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
449 if(!(Buffer
&& DataPosInt
< Buffer
->SampleLen
))
451 if(Buffer
) DataPosInt
-= Buffer
->SampleLen
;
452 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
453 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
457 const size_t DataSize
{minz(SrcBuffer
.size(), Buffer
->SampleLen
-DataPosInt
)};
459 const al::byte
*Data
{Buffer
->mData
.data()};
460 Data
+= (DataPosInt
*NumChannels
+ chan
)*SampleSize
;
462 LoadSamples(SrcBuffer
.data(), Data
, NumChannels
, Buffer
->mFmtType
, DataSize
);
463 SrcBuffer
= SrcBuffer
.subspan(DataSize
);
464 if(SrcBuffer
.empty()) break;
467 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_acquire
);
468 if(!BufferListItem
) BufferListItem
= BufferLoopItem
;
471 return SrcBuffer
.begin();
476 void ALvoice::mix(State vstate
, ALCcontext
*Context
, const ALuint SamplesToDo
)
478 static constexpr ALfloat SilentTarget
[MAX_OUTPUT_CHANNELS
]{};
480 ASSUME(SamplesToDo
> 0);
483 const bool isstatic
{(mFlags
&VOICE_IS_STATIC
) != 0};
484 ALuint DataPosInt
{mPosition
.load(std::memory_order_relaxed
)};
485 ALuint DataPosFrac
{mPositionFrac
.load(std::memory_order_relaxed
)};
486 ALbufferlistitem
*BufferListItem
{mCurrentBuffer
.load(std::memory_order_relaxed
)};
487 ALbufferlistitem
*BufferLoopItem
{mLoopBuffer
.load(std::memory_order_relaxed
)};
488 const ALuint NumChannels
{mNumChannels
};
489 const ALuint SampleSize
{mSampleSize
};
490 const ALuint increment
{mStep
};
491 if(increment
< 1) return;
493 ASSUME(NumChannels
> 0);
494 ASSUME(SampleSize
> 0);
495 ASSUME(increment
> 0);
497 ALCdevice
*Device
{Context
->mDevice
.get()};
498 const ALuint NumSends
{Device
->NumAuxSends
};
499 const ALuint IrSize
{Device
->mHrtf
? Device
->mHrtf
->irSize
: 0};
501 ResamplerFunc Resample
{(increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
502 Resample_
<CopyTag
,CTag
> : mResampler
};
504 ALuint Counter
{(mFlags
&VOICE_IS_FADING
) ? SamplesToDo
: 0};
507 /* No fading, just overwrite the old/current params. */
508 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
510 ChannelData
&chandata
= mChans
[chan
];
511 DirectParams
&parms
= chandata
.mDryParams
;
512 if(!(mFlags
&VOICE_HAS_HRTF
))
513 std::copy(std::begin(parms
.Gains
.Target
), std::end(parms
.Gains
.Target
),
514 std::begin(parms
.Gains
.Current
));
516 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
517 for(ALuint send
{0};send
< NumSends
;++send
)
519 if(mSend
[send
].Buffer
.empty())
522 SendParams
&parms
= chandata
.mWetParams
[send
];
523 std::copy(std::begin(parms
.Gains
.Target
), std::end(parms
.Gains
.Target
),
524 std::begin(parms
.Gains
.Current
));
528 else if((mFlags
&VOICE_HAS_HRTF
))
530 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
532 DirectParams
&parms
= mChans
[chan
].mDryParams
;
533 if(!(parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
535 /* The old HRTF params are silent, so overwrite the old
536 * coefficients with the new, and reset the old gain to 0. The
537 * future mix will then fade from silence.
539 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
540 parms
.Hrtf
.Old
.Gain
= 0.0f
;
545 ALuint buffers_done
{0u};
548 /* Figure out how many buffer samples will be needed */
549 ALuint DstBufferSize
{SamplesToDo
- OutPos
};
551 /* Calculate the last written dst sample pos. */
552 uint64_t DataSize64
{DstBufferSize
- 1};
553 /* Calculate the last read src sample pos. */
554 DataSize64
= (DataSize64
*increment
+ DataPosFrac
) >> FRACTIONBITS
;
555 /* +1 to get the src sample count, include padding. */
556 DataSize64
+= 1 + MAX_RESAMPLE_PADDING
*2;
558 auto SrcBufferSize
= static_cast<ALuint
>(
559 minu64(DataSize64
, BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2 + 1));
560 if(SrcBufferSize
> BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2)
562 SrcBufferSize
= BUFFERSIZE
+ MAX_RESAMPLE_PADDING
*2;
563 /* If the source buffer got saturated, we can't fill the desired
564 * dst size. Figure out how many samples we can actually mix from
567 DataSize64
= SrcBufferSize
- MAX_RESAMPLE_PADDING
*2;
568 DataSize64
= ((DataSize64
<<FRACTIONBITS
) - DataPosFrac
+ increment
-1) / increment
;
569 DstBufferSize
= static_cast<ALuint
>(minu64(DataSize64
, DstBufferSize
));
571 /* Some mixers like having a multiple of 4, so try to give that
572 * unless this is the last update.
574 if(DstBufferSize
< SamplesToDo
-OutPos
)
575 DstBufferSize
&= ~3u;
578 ASSUME(DstBufferSize
> 0);
579 for(ALuint chan
{0};chan
< NumChannels
;chan
++)
581 ChannelData
&chandata
= mChans
[chan
];
582 const al::span
<ALfloat
> SrcData
{Device
->SourceData
, SrcBufferSize
};
584 /* Load the previous samples into the source data first, then load
585 * what we can from the buffer queue.
587 auto srciter
= std::copy_n(chandata
.mPrevSamples
.begin(), MAX_RESAMPLE_PADDING
,
590 if UNLIKELY(!BufferListItem
)
591 srciter
= std::copy(chandata
.mPrevSamples
.begin()+MAX_RESAMPLE_PADDING
,
592 chandata
.mPrevSamples
.end(), srciter
);
594 srciter
= LoadBufferStatic(BufferListItem
, BufferLoopItem
, NumChannels
,
595 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
597 srciter
= LoadBufferQueue(BufferListItem
, BufferLoopItem
, NumChannels
,
598 SampleSize
, chan
, DataPosInt
, {srciter
, SrcData
.end()});
600 if UNLIKELY(srciter
!= SrcData
.end())
602 /* If the source buffer wasn't filled, copy the last sample for
603 * the remaining buffer. Ideally it should have ended with
604 * silence, but if not the gain fading should help avoid clicks
605 * from sudden amplitude changes.
607 const ALfloat sample
{*(srciter
-1)};
608 std::fill(srciter
, SrcData
.end(), sample
);
611 /* Store the last source samples used for next time. */
612 std::copy_n(&SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
613 chandata
.mPrevSamples
.size(), chandata
.mPrevSamples
.begin());
615 /* Resample, then apply ambisonic upsampling as needed. */
616 const ALfloat
*ResampledData
{Resample(&mResampleState
, &SrcData
[MAX_RESAMPLE_PADDING
],
617 DataPosFrac
, increment
, {Device
->ResampledData
, DstBufferSize
})};
618 if((mFlags
&VOICE_IS_AMBISONIC
))
620 const ALfloat hfscale
{chandata
.mAmbiScale
};
621 /* Beware the evil const_cast. It's safe since it's pointing to
622 * either SourceData or ResampledData (both non-const), but the
623 * resample method takes the source as const float* and may
624 * return it without copying to output, making it currently
627 chandata
.mAmbiSplitter
.applyHfScale(const_cast<ALfloat
*>(ResampledData
), hfscale
,
631 /* Now filter and mix to the appropriate outputs. */
632 ALfloat (&FilterBuf
)[BUFFERSIZE
] = Device
->FilteredData
;
634 DirectParams
&parms
= chandata
.mDryParams
;
635 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
636 ResampledData
, DstBufferSize
, mDirect
.FilterType
)};
638 if((mFlags
&VOICE_HAS_HRTF
))
640 const ALuint OutLIdx
{GetChannelIdxByName(Device
->RealOut
, FrontLeft
)};
641 const ALuint OutRIdx
{GetChannelIdxByName(Device
->RealOut
, FrontRight
)};
643 auto &HrtfSamples
= Device
->HrtfSourceData
;
644 auto &AccumSamples
= Device
->HrtfAccumData
;
645 const ALfloat TargetGain
{UNLIKELY(vstate
== ALvoice::Stopping
) ? 0.0f
:
646 parms
.Hrtf
.Target
.Gain
};
649 /* Copy the HRTF history and new input samples into a temp
652 auto src_iter
= std::copy(parms
.Hrtf
.State
.History
.begin(),
653 parms
.Hrtf
.State
.History
.end(), std::begin(HrtfSamples
));
654 std::copy_n(samples
, DstBufferSize
, src_iter
);
655 /* Copy the last used samples back into the history buffer
658 std::copy_n(std::begin(HrtfSamples
) + DstBufferSize
,
659 parms
.Hrtf
.State
.History
.size(), parms
.Hrtf
.State
.History
.begin());
661 /* Copy the current filtered values being accumulated into
664 auto accum_iter
= std::copy_n(parms
.Hrtf
.State
.Values
.begin(),
665 parms
.Hrtf
.State
.Values
.size(), std::begin(AccumSamples
));
667 /* Clear the accumulation buffer that will start getting
670 std::fill_n(accum_iter
, DstBufferSize
, float2
{});
672 /* If fading, the old gain is not silence, and this is the
673 * first mixing pass, fade between the IRs.
675 if(Counter
&& (parms
.Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
) && OutPos
== 0)
677 fademix
= minu(DstBufferSize
, 128);
679 ALfloat gain
{TargetGain
};
681 /* The new coefficients need to fade in completely
682 * since they're replacing the old ones. To keep the
683 * gain fading consistent, interpolate between the old
684 * and new target gains given how much of the fade time
687 if LIKELY(Counter
> fademix
)
689 const ALfloat a
{static_cast<ALfloat
>(fademix
) /
690 static_cast<ALfloat
>(Counter
)};
691 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
693 MixHrtfFilter hrtfparams
;
694 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
695 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
696 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
697 hrtfparams
.Gain
= 0.0f
;
698 hrtfparams
.GainStep
= gain
/ static_cast<ALfloat
>(fademix
);
700 MixHrtfBlendSamples(mDirect
.Buffer
[OutLIdx
], mDirect
.Buffer
[OutRIdx
],
701 HrtfSamples
, AccumSamples
, OutPos
, IrSize
, &parms
.Hrtf
.Old
,
702 &hrtfparams
, fademix
);
703 /* Update the old parameters with the result. */
704 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
705 if(fademix
< Counter
)
706 parms
.Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
708 parms
.Hrtf
.Old
.Gain
= TargetGain
;
711 if LIKELY(fademix
< DstBufferSize
)
713 const ALuint todo
{DstBufferSize
- fademix
};
714 ALfloat gain
{TargetGain
};
716 /* Interpolate the target gain if the gain fading lasts
717 * longer than this mix.
719 if(Counter
> DstBufferSize
)
721 const ALfloat a
{static_cast<ALfloat
>(todo
) /
722 static_cast<ALfloat
>(Counter
-fademix
)};
723 gain
= lerp(parms
.Hrtf
.Old
.Gain
, TargetGain
, a
);
726 MixHrtfFilter hrtfparams
;
727 hrtfparams
.Coeffs
= &parms
.Hrtf
.Target
.Coeffs
;
728 hrtfparams
.Delay
[0] = parms
.Hrtf
.Target
.Delay
[0];
729 hrtfparams
.Delay
[1] = parms
.Hrtf
.Target
.Delay
[1];
730 hrtfparams
.Gain
= parms
.Hrtf
.Old
.Gain
;
731 hrtfparams
.GainStep
= (gain
- parms
.Hrtf
.Old
.Gain
) /
732 static_cast<ALfloat
>(todo
);
733 MixHrtfSamples(mDirect
.Buffer
[OutLIdx
], mDirect
.Buffer
[OutRIdx
],
734 HrtfSamples
+fademix
, AccumSamples
+fademix
, OutPos
+fademix
, IrSize
,
736 /* Store the interpolated gain or the final target gain
737 * depending if the fade is done.
739 if(DstBufferSize
< Counter
)
740 parms
.Hrtf
.Old
.Gain
= gain
;
742 parms
.Hrtf
.Old
.Gain
= TargetGain
;
745 /* Copy the new in-progress accumulation values back for
748 std::copy_n(std::begin(AccumSamples
) + DstBufferSize
,
749 parms
.Hrtf
.State
.Values
.size(), parms
.Hrtf
.State
.Values
.begin());
751 else if((mFlags
&VOICE_HAS_NFC
))
753 const ALfloat
*TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
754 SilentTarget
: parms
.Gains
.Target
};
756 const size_t outcount
{Device
->NumChannelsPerOrder
[0]};
757 MixSamples({samples
, DstBufferSize
}, mDirect
.Buffer
.first(outcount
),
758 parms
.Gains
.Current
, TargetGains
, Counter
, OutPos
);
760 const al::span
<float> nfcsamples
{Device
->NfcSampleData
, DstBufferSize
};
761 size_t chanoffset
{outcount
};
762 using FilterProc
= void (NfcFilter::*)(float*,const float*,const size_t);
763 auto apply_nfc
= [this,&parms
,samples
,TargetGains
,Counter
,OutPos
,&chanoffset
,nfcsamples
](const FilterProc process
, const size_t outcount
) -> void
765 if(outcount
< 1) return;
766 (parms
.NFCtrlFilter
.*process
)(nfcsamples
.data(), samples
, nfcsamples
.size());
767 MixSamples(nfcsamples
, mDirect
.Buffer
.subspan(chanoffset
, outcount
),
768 parms
.Gains
.Current
+chanoffset
, TargetGains
+chanoffset
, Counter
,
770 chanoffset
+= outcount
;
772 apply_nfc(&NfcFilter::process1
, Device
->NumChannelsPerOrder
[1]);
773 apply_nfc(&NfcFilter::process2
, Device
->NumChannelsPerOrder
[2]);
774 apply_nfc(&NfcFilter::process3
, Device
->NumChannelsPerOrder
[3]);
778 const ALfloat
*TargetGains
{UNLIKELY(vstate
== ALvoice::Stopping
) ?
779 SilentTarget
: parms
.Gains
.Target
};
780 MixSamples({samples
, DstBufferSize
}, mDirect
.Buffer
, parms
.Gains
.Current
,
781 TargetGains
, Counter
, OutPos
);
785 for(ALuint send
{0};send
< NumSends
;++send
)
787 if(mSend
[send
].Buffer
.empty())
790 SendParams
&parms
= chandata
.mWetParams
[send
];
791 const ALfloat
*samples
{DoFilters(&parms
.LowPass
, &parms
.HighPass
, FilterBuf
,
792 ResampledData
, DstBufferSize
, mSend
[send
].FilterType
)};
794 const ALfloat
*TargetGains
{UNLIKELY(vstate
==ALvoice::Stopping
) ? SilentTarget
:
796 MixSamples({samples
, DstBufferSize
}, mSend
[send
].Buffer
, parms
.Gains
.Current
,
797 TargetGains
, Counter
, OutPos
);
800 /* Update positions */
801 DataPosFrac
+= increment
*DstBufferSize
;
802 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
803 DataPosFrac
&= FRACTIONMASK
;
805 OutPos
+= DstBufferSize
;
806 Counter
= maxu(DstBufferSize
, Counter
) - DstBufferSize
;
808 if UNLIKELY(!BufferListItem
)
810 /* Do nothing extra when there's no buffers. */
816 /* Handle looping static source */
817 const ALbuffer
*Buffer
{BufferListItem
->mBuffer
};
818 const ALuint LoopStart
{Buffer
->LoopStart
};
819 const ALuint LoopEnd
{Buffer
->LoopEnd
};
820 if(DataPosInt
>= LoopEnd
)
822 assert(LoopEnd
> LoopStart
);
823 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
828 /* Handle non-looping static source */
829 if(DataPosInt
>= BufferListItem
->mSampleLen
)
831 if LIKELY(vstate
== ALvoice::Playing
)
832 vstate
= ALvoice::Stopped
;
833 BufferListItem
= nullptr;
840 /* Handle streaming source */
841 if(BufferListItem
->mSampleLen
> DataPosInt
)
844 DataPosInt
-= BufferListItem
->mSampleLen
;
847 BufferListItem
= BufferListItem
->mNext
.load(std::memory_order_relaxed
);
848 if(!BufferListItem
&& !(BufferListItem
=BufferLoopItem
))
850 if LIKELY(vstate
== ALvoice::Playing
)
851 vstate
= ALvoice::Stopped
;
855 } while(OutPos
< SamplesToDo
);
857 mFlags
|= VOICE_IS_FADING
;
859 /* Don't update positions and buffers if we were stopping. */
860 if UNLIKELY(vstate
== ALvoice::Stopping
)
862 mPlayState
.store(ALvoice::Stopped
, std::memory_order_release
);
866 /* Capture the source ID in case it's reset for stopping. */
867 const ALuint SourceID
{mSourceID
.load(std::memory_order_relaxed
)};
869 /* Update voice info */
870 mPosition
.store(DataPosInt
, std::memory_order_relaxed
);
871 mPositionFrac
.store(DataPosFrac
, std::memory_order_relaxed
);
872 mCurrentBuffer
.store(BufferListItem
, std::memory_order_relaxed
);
873 if(vstate
== ALvoice::Stopped
)
875 mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
876 mSourceID
.store(0u, std::memory_order_relaxed
);
878 std::atomic_thread_fence(std::memory_order_release
);
880 /* Send any events now, after the position/buffer info was updated. */
881 const ALbitfieldSOFT enabledevt
{Context
->mEnabledEvts
.load(std::memory_order_acquire
)};
882 if(buffers_done
> 0 && (enabledevt
&EventType_BufferCompleted
))
884 RingBuffer
*ring
{Context
->mAsyncEvents
.get()};
885 auto evt_vec
= ring
->getWriteVector();
886 if(evt_vec
.first
.len
> 0)
888 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_BufferCompleted
}};
889 evt
->u
.bufcomp
.id
= SourceID
;
890 evt
->u
.bufcomp
.count
= buffers_done
;
891 ring
->writeAdvance(1);
892 Context
->mEventSem
.post();
896 if(vstate
== ALvoice::Stopped
)
898 /* If the voice just ended, set it to Stopping so the next render
899 * ensures any residual noise fades to 0 amplitude.
901 mPlayState
.store(ALvoice::Stopping
, std::memory_order_release
);
902 if((enabledevt
&EventType_SourceStateChange
))
903 SendSourceStoppedEvent(Context
, SourceID
);