Use pw_buffer::requested in newer PipeWire versions
[openal-soft.git] / core / voice.cpp
blobe269c4a9d986b2b72007a1afe3fe56509695c64f
2 #include "config.h"
4 #include "voice.h"
6 #include <algorithm>
7 #include <array>
8 #include <atomic>
9 #include <cassert>
10 #include <cstdint>
11 #include <iterator>
12 #include <memory>
13 #include <new>
14 #include <stdlib.h>
15 #include <utility>
16 #include <vector>
18 #include "albyte.h"
19 #include "alnumeric.h"
20 #include "aloptional.h"
21 #include "alspan.h"
22 #include "alstring.h"
23 #include "ambidefs.h"
24 #include "async_event.h"
25 #include "buffer_storage.h"
26 #include "context.h"
27 #include "cpu_caps.h"
28 #include "devformat.h"
29 #include "device.h"
30 #include "filters/biquad.h"
31 #include "filters/nfc.h"
32 #include "filters/splitter.h"
33 #include "fmt_traits.h"
34 #include "logging.h"
35 #include "mixer.h"
36 #include "mixer/defs.h"
37 #include "mixer/hrtfdefs.h"
38 #include "opthelpers.h"
39 #include "resampler_limits.h"
40 #include "ringbuffer.h"
41 #include "vector.h"
42 #include "voice_change.h"
44 struct CTag;
45 #ifdef HAVE_SSE
46 struct SSETag;
47 #endif
48 #ifdef HAVE_NEON
49 struct NEONTag;
50 #endif
51 struct CopyTag;
54 static_assert(!(sizeof(DeviceBase::MixerBufferLine)&15),
55 "DeviceBase::MixerBufferLine must be a multiple of 16 bytes");
56 static_assert(!(MaxResamplerEdge&3), "MaxResamplerEdge is not a multiple of 4");
58 Resampler ResamplerDefault{Resampler::Linear};
60 namespace {
62 using uint = unsigned int;
64 using HrtfMixerFunc = void(*)(const float *InSamples, float2 *AccumSamples, const uint IrSize,
65 const MixHrtfFilter *hrtfparams, const size_t BufferSize);
66 using HrtfMixerBlendFunc = void(*)(const float *InSamples, float2 *AccumSamples,
67 const uint IrSize, const HrtfFilter *oldparams, const MixHrtfFilter *newparams,
68 const size_t BufferSize);
70 HrtfMixerFunc MixHrtfSamples{MixHrtf_<CTag>};
71 HrtfMixerBlendFunc MixHrtfBlendSamples{MixHrtfBlend_<CTag>};
73 inline MixerFunc SelectMixer()
75 #ifdef HAVE_NEON
76 if((CPUCapFlags&CPU_CAP_NEON))
77 return Mix_<NEONTag>;
78 #endif
79 #ifdef HAVE_SSE
80 if((CPUCapFlags&CPU_CAP_SSE))
81 return Mix_<SSETag>;
82 #endif
83 return Mix_<CTag>;
86 inline HrtfMixerFunc SelectHrtfMixer()
88 #ifdef HAVE_NEON
89 if((CPUCapFlags&CPU_CAP_NEON))
90 return MixHrtf_<NEONTag>;
91 #endif
92 #ifdef HAVE_SSE
93 if((CPUCapFlags&CPU_CAP_SSE))
94 return MixHrtf_<SSETag>;
95 #endif
96 return MixHrtf_<CTag>;
99 inline HrtfMixerBlendFunc SelectHrtfBlendMixer()
101 #ifdef HAVE_NEON
102 if((CPUCapFlags&CPU_CAP_NEON))
103 return MixHrtfBlend_<NEONTag>;
104 #endif
105 #ifdef HAVE_SSE
106 if((CPUCapFlags&CPU_CAP_SSE))
107 return MixHrtfBlend_<SSETag>;
108 #endif
109 return MixHrtfBlend_<CTag>;
112 } // namespace
114 void Voice::InitMixer(al::optional<std::string> resampler)
116 if(resampler)
118 struct ResamplerEntry {
119 const char name[16];
120 const Resampler resampler;
122 constexpr ResamplerEntry ResamplerList[]{
123 { "none", Resampler::Point },
124 { "point", Resampler::Point },
125 { "linear", Resampler::Linear },
126 { "cubic", Resampler::Cubic },
127 { "bsinc12", Resampler::BSinc12 },
128 { "fast_bsinc12", Resampler::FastBSinc12 },
129 { "bsinc24", Resampler::BSinc24 },
130 { "fast_bsinc24", Resampler::FastBSinc24 },
133 const char *str{resampler->c_str()};
134 if(al::strcasecmp(str, "bsinc") == 0)
136 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str);
137 str = "bsinc12";
139 else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0)
141 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str);
142 str = "cubic";
145 auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList),
146 [str](const ResamplerEntry &entry) -> bool
147 { return al::strcasecmp(str, entry.name) == 0; });
148 if(iter == std::end(ResamplerList))
149 ERR("Invalid resampler: %s\n", str);
150 else
151 ResamplerDefault = iter->resampler;
154 MixSamples = SelectMixer();
155 MixHrtfBlendSamples = SelectHrtfBlendMixer();
156 MixHrtfSamples = SelectHrtfMixer();
160 namespace {
162 void SendSourceStoppedEvent(ContextBase *context, uint id)
164 RingBuffer *ring{context->mAsyncEvents.get()};
165 auto evt_vec = ring->getWriteVector();
166 if(evt_vec.first.len < 1) return;
168 AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
169 AsyncEvent::SourceStateChange)};
170 evt->u.srcstate.id = id;
171 evt->u.srcstate.state = AsyncEvent::SrcState::Stop;
173 ring->writeAdvance(1);
177 const float *DoFilters(BiquadFilter &lpfilter, BiquadFilter &hpfilter, float *dst,
178 const al::span<const float> src, int type)
180 switch(type)
182 case AF_None:
183 lpfilter.clear();
184 hpfilter.clear();
185 break;
187 case AF_LowPass:
188 lpfilter.process(src, dst);
189 hpfilter.clear();
190 return dst;
191 case AF_HighPass:
192 lpfilter.clear();
193 hpfilter.process(src, dst);
194 return dst;
196 case AF_BandPass:
197 DualBiquad{lpfilter, hpfilter}.process(src, dst);
198 return dst;
200 return src.data();
204 template<FmtType Type>
205 inline void LoadSamples(const al::span<float*> dstSamples, const size_t dstOffset,
206 const al::byte *src, const size_t srcOffset, const FmtChannels srcChans, const size_t srcStep,
207 const size_t samples) noexcept
209 constexpr size_t sampleSize{sizeof(typename al::FmtTypeTraits<Type>::Type)};
210 auto s = src + srcOffset*srcStep*sampleSize;
211 if(srcChans == FmtUHJ2 || srcChans == FmtSuperStereo)
213 al::LoadSampleArray<Type>(dstSamples[0]+dstOffset, s, srcStep, samples);
214 al::LoadSampleArray<Type>(dstSamples[1]+dstOffset, s+sampleSize, srcStep, samples);
215 std::fill_n(dstSamples[2]+dstOffset, samples, 0.0f);
217 else
219 for(auto *dst : dstSamples)
221 al::LoadSampleArray<Type>(dst+dstOffset, s, srcStep, samples);
222 s += sampleSize;
227 void LoadSamples(const al::span<float*> dstSamples, const size_t dstOffset, const al::byte *src,
228 const size_t srcOffset, const FmtType srcType, const FmtChannels srcChans,
229 const size_t srcStep, const size_t samples) noexcept
231 #define HANDLE_FMT(T) case T: \
232 LoadSamples<T>(dstSamples, dstOffset, src, srcOffset, srcChans, srcStep, \
233 samples); \
234 break
236 switch(srcType)
238 HANDLE_FMT(FmtUByte);
239 HANDLE_FMT(FmtShort);
240 HANDLE_FMT(FmtFloat);
241 HANDLE_FMT(FmtDouble);
242 HANDLE_FMT(FmtMulaw);
243 HANDLE_FMT(FmtAlaw);
245 #undef HANDLE_FMT
248 void LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem,
249 const size_t dataPosInt, const FmtType sampleType, const FmtChannels sampleChannels,
250 const size_t srcStep, const size_t samplesToLoad, const al::span<float*> voiceSamples)
252 const uint loopStart{buffer->mLoopStart};
253 const uint loopEnd{buffer->mLoopEnd};
254 ASSUME(loopEnd > loopStart);
256 /* If current pos is beyond the loop range, do not loop */
257 if(!bufferLoopItem || dataPosInt >= loopEnd)
259 /* Load what's left to play from the buffer */
260 const size_t remaining{minz(samplesToLoad, buffer->mSampleLen-dataPosInt)};
261 LoadSamples(voiceSamples, 0, buffer->mSamples, dataPosInt, sampleType, sampleChannels,
262 srcStep, remaining);
264 if(const size_t toFill{samplesToLoad - remaining})
266 for(auto *chanbuffer : voiceSamples)
268 auto srcsamples = chanbuffer + remaining - 1;
269 std::fill_n(srcsamples + 1, toFill, *srcsamples);
273 else
275 /* Load what's left of this loop iteration */
276 const size_t remaining{minz(samplesToLoad, loopEnd-dataPosInt)};
277 LoadSamples(voiceSamples, 0, buffer->mSamples, dataPosInt, sampleType, sampleChannels,
278 srcStep, remaining);
280 /* Load repeats of the loop to fill the buffer. */
281 const auto loopSize = static_cast<size_t>(loopEnd - loopStart);
282 size_t samplesLoaded{remaining};
283 while(const size_t toFill{minz(samplesToLoad - samplesLoaded, loopSize)})
285 LoadSamples(voiceSamples, samplesLoaded, buffer->mSamples, loopStart, sampleType,
286 sampleChannels, srcStep, toFill);
287 samplesLoaded += toFill;
292 void LoadBufferCallback(VoiceBufferItem *buffer, const size_t numCallbackSamples,
293 const FmtType sampleType, const FmtChannels sampleChannels, const size_t srcStep,
294 const size_t samplesToLoad, const al::span<float*> voiceSamples)
296 /* Load what's left to play from the buffer */
297 const size_t remaining{minz(samplesToLoad, numCallbackSamples)};
298 LoadSamples(voiceSamples, 0, buffer->mSamples, 0, sampleType, sampleChannels, srcStep,
299 remaining);
301 if(const size_t toFill{samplesToLoad - remaining})
303 for(auto *chanbuffer : voiceSamples)
305 auto srcsamples = chanbuffer + remaining - 1;
306 std::fill_n(srcsamples + 1, toFill, *srcsamples);
311 void LoadBufferQueue(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem,
312 size_t dataPosInt, const FmtType sampleType, const FmtChannels sampleChannels,
313 const size_t srcStep, const size_t samplesToLoad, const al::span<float*> voiceSamples)
315 /* Crawl the buffer queue to fill in the temp buffer */
316 size_t samplesLoaded{0};
317 while(buffer && samplesLoaded != samplesToLoad)
319 if(dataPosInt >= buffer->mSampleLen)
321 dataPosInt -= buffer->mSampleLen;
322 buffer = buffer->mNext.load(std::memory_order_acquire);
323 if(!buffer) buffer = bufferLoopItem;
324 continue;
327 const size_t remaining{minz(samplesToLoad-samplesLoaded, buffer->mSampleLen-dataPosInt)};
328 LoadSamples(voiceSamples, samplesLoaded, buffer->mSamples, dataPosInt, sampleType,
329 sampleChannels, srcStep, remaining);
331 samplesLoaded += remaining;
332 if(samplesLoaded == samplesToLoad)
333 break;
335 dataPosInt = 0;
336 buffer = buffer->mNext.load(std::memory_order_acquire);
337 if(!buffer) buffer = bufferLoopItem;
339 if(const size_t toFill{samplesToLoad - samplesLoaded})
341 size_t chanidx{0};
342 for(auto *chanbuffer : voiceSamples)
344 auto srcsamples = chanbuffer + samplesLoaded - 1;
345 std::fill_n(srcsamples + 1, toFill, *srcsamples);
346 ++chanidx;
352 void DoHrtfMix(const float *samples, const uint DstBufferSize, DirectParams &parms,
353 const float TargetGain, const uint Counter, uint OutPos, const bool IsPlaying,
354 DeviceBase *Device)
356 const uint IrSize{Device->mIrSize};
357 auto &HrtfSamples = Device->HrtfSourceData;
358 auto &AccumSamples = Device->HrtfAccumData;
360 /* Copy the HRTF history and new input samples into a temp buffer. */
361 auto src_iter = std::copy(parms.Hrtf.History.begin(), parms.Hrtf.History.end(),
362 std::begin(HrtfSamples));
363 std::copy_n(samples, DstBufferSize, src_iter);
364 /* Copy the last used samples back into the history buffer for later. */
365 if(likely(IsPlaying))
366 std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.History.size(),
367 parms.Hrtf.History.begin());
369 /* If fading and this is the first mixing pass, fade between the IRs. */
370 uint fademix{0u};
371 if(Counter && OutPos == 0)
373 fademix = minu(DstBufferSize, Counter);
375 float gain{TargetGain};
377 /* The new coefficients need to fade in completely since they're
378 * replacing the old ones. To keep the gain fading consistent,
379 * interpolate between the old and new target gains given how much of
380 * the fade time this mix handles.
382 if(Counter > fademix)
384 const float a{static_cast<float>(fademix) / static_cast<float>(Counter)};
385 gain = lerpf(parms.Hrtf.Old.Gain, TargetGain, a);
388 MixHrtfFilter hrtfparams{
389 parms.Hrtf.Target.Coeffs,
390 parms.Hrtf.Target.Delay,
391 0.0f, gain / static_cast<float>(fademix)};
392 MixHrtfBlendSamples(HrtfSamples, AccumSamples+OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams,
393 fademix);
395 /* Update the old parameters with the result. */
396 parms.Hrtf.Old = parms.Hrtf.Target;
397 parms.Hrtf.Old.Gain = gain;
398 OutPos += fademix;
401 if(fademix < DstBufferSize)
403 const uint todo{DstBufferSize - fademix};
404 float gain{TargetGain};
406 /* Interpolate the target gain if the gain fading lasts longer than
407 * this mix.
409 if(Counter > DstBufferSize)
411 const float a{static_cast<float>(todo) / static_cast<float>(Counter-fademix)};
412 gain = lerpf(parms.Hrtf.Old.Gain, TargetGain, a);
415 MixHrtfFilter hrtfparams{
416 parms.Hrtf.Target.Coeffs,
417 parms.Hrtf.Target.Delay,
418 parms.Hrtf.Old.Gain,
419 (gain - parms.Hrtf.Old.Gain) / static_cast<float>(todo)};
420 MixHrtfSamples(HrtfSamples+fademix, AccumSamples+OutPos, IrSize, &hrtfparams, todo);
422 /* Store the now-current gain for next time. */
423 parms.Hrtf.Old.Gain = gain;
427 void DoNfcMix(const al::span<const float> samples, FloatBufferLine *OutBuffer, DirectParams &parms,
428 const float *TargetGains, const uint Counter, const uint OutPos, DeviceBase *Device)
430 using FilterProc = void (NfcFilter::*)(const al::span<const float>, float*);
431 static constexpr FilterProc NfcProcess[MaxAmbiOrder+1]{
432 nullptr, &NfcFilter::process1, &NfcFilter::process2, &NfcFilter::process3};
434 float *CurrentGains{parms.Gains.Current.data()};
435 MixSamples(samples, {OutBuffer, 1u}, CurrentGains, TargetGains, Counter, OutPos);
436 ++OutBuffer;
437 ++CurrentGains;
438 ++TargetGains;
440 const al::span<float> nfcsamples{Device->NfcSampleData, samples.size()};
441 size_t order{1};
442 while(const size_t chancount{Device->NumChannelsPerOrder[order]})
444 (parms.NFCtrlFilter.*NfcProcess[order])(samples, nfcsamples.data());
445 MixSamples(nfcsamples, {OutBuffer, chancount}, CurrentGains, TargetGains, Counter, OutPos);
446 OutBuffer += chancount;
447 CurrentGains += chancount;
448 TargetGains += chancount;
449 if(++order == MaxAmbiOrder+1)
450 break;
454 } // namespace
456 void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo)
458 static constexpr std::array<float,MAX_OUTPUT_CHANNELS> SilentTarget{};
460 ASSUME(SamplesToDo > 0);
462 /* Get voice info */
463 uint DataPosInt{mPosition.load(std::memory_order_relaxed)};
464 uint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)};
465 VoiceBufferItem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)};
466 VoiceBufferItem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)};
467 const uint increment{mStep};
468 if UNLIKELY(increment < 1)
470 /* If the voice is supposed to be stopping but can't be mixed, just
471 * stop it before bailing.
473 if(vstate == Stopping)
474 mPlayState.store(Stopped, std::memory_order_release);
475 return;
478 DeviceBase *Device{Context->mDevice};
479 const uint NumSends{Device->NumAuxSends};
481 ResamplerFunc Resample{(increment == MixerFracOne && DataPosFrac == 0) ?
482 Resample_<CopyTag,CTag> : mResampler};
484 uint Counter{mFlags.test(VoiceIsFading) ? SamplesToDo : 0};
485 if(!Counter)
487 /* No fading, just overwrite the old/current params. */
488 for(auto &chandata : mChans)
491 DirectParams &parms = chandata.mDryParams;
492 if(!mFlags.test(VoiceHasHrtf))
493 parms.Gains.Current = parms.Gains.Target;
494 else
495 parms.Hrtf.Old = parms.Hrtf.Target;
497 for(uint send{0};send < NumSends;++send)
499 if(mSend[send].Buffer.empty())
500 continue;
502 SendParams &parms = chandata.mWetParams[send];
503 parms.Gains.Current = parms.Gains.Target;
507 else if UNLIKELY(!BufferListItem)
508 Counter = std::min(Counter, 64u);
510 std::array<float*,DeviceBase::MixerChannelsMax> SamplePointers;
511 const al::span<float*> MixingSamples{SamplePointers.data(), mChans.size()};
512 auto offset_bufferline = [](DeviceBase::MixerBufferLine &bufline) noexcept -> float*
513 { return bufline.data() + MaxResamplerEdge; };
514 std::transform(Device->mSampleData.end() - mChans.size(), Device->mSampleData.end(),
515 MixingSamples.begin(), offset_bufferline);
517 const uint PostPadding{MaxResamplerEdge +
518 (mDecoder ? uint{UhjDecoder::sFilterDelay} : 0u)};
519 uint buffers_done{0u};
520 uint OutPos{0u};
521 do {
522 /* Figure out how many buffer samples will be needed */
523 uint DstBufferSize{SamplesToDo - OutPos};
524 uint SrcBufferSize;
526 if(increment <= MixerFracOne)
528 /* Calculate the last written dst sample pos. */
529 uint64_t DataSize64{DstBufferSize - 1};
530 /* Calculate the last read src sample pos. */
531 DataSize64 = (DataSize64*increment + DataPosFrac) >> MixerFracBits;
532 /* +1 to get the src sample count, include padding. */
533 DataSize64 += 1 + PostPadding;
535 /* Result is guaranteed to be <= BufferLineSize+PostPadding since
536 * we won't use more src samples than dst samples+padding.
538 SrcBufferSize = static_cast<uint>(DataSize64);
540 else
542 uint64_t DataSize64{DstBufferSize};
543 /* Calculate the end src sample pos, include padding. */
544 DataSize64 = (DataSize64*increment + DataPosFrac) >> MixerFracBits;
545 DataSize64 += PostPadding;
547 if(DataSize64 <= DeviceBase::MixerLineSize - MaxResamplerEdge)
548 SrcBufferSize = static_cast<uint>(DataSize64);
549 else
551 /* If the source size got saturated, we can't fill the desired
552 * dst size. Figure out how many samples we can actually mix.
554 SrcBufferSize = DeviceBase::MixerLineSize - MaxResamplerEdge;
556 DataSize64 = SrcBufferSize - PostPadding;
557 DataSize64 = ((DataSize64<<MixerFracBits) - DataPosFrac) / increment;
558 if(DataSize64 < DstBufferSize)
560 /* Some mixers require being 16-byte aligned, so also limit
561 * to a multiple of 4 samples to maintain alignment.
563 DstBufferSize = static_cast<uint>(DataSize64) & ~3u;
564 /* If the voice is stopping, only one mixing iteration will
565 * be done, so ensure it fades out completely this mix.
567 if(unlikely(vstate == Stopping))
568 Counter = std::min(Counter, DstBufferSize);
570 ASSUME(DstBufferSize > 0);
574 if(unlikely(!BufferListItem))
576 const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits};
577 auto prevSamples = mPrevSamples.data();
578 SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge;
579 for(auto *chanbuffer : MixingSamples)
581 auto srcend = std::copy_n(prevSamples->data(), MaxResamplerPadding,
582 chanbuffer-MaxResamplerEdge);
584 /* When loading from a voice that ended prematurely, only take
585 * the samples that get closest to 0 amplitude. This helps
586 * certain sounds fade out better.
588 auto abs_lt = [](const float lhs, const float rhs) noexcept -> bool
589 { return std::abs(lhs) < std::abs(rhs); };
590 auto srciter = std::min_element(chanbuffer, srcend, abs_lt);
592 std::fill(srciter+1, chanbuffer + SrcBufferSize, *srciter);
594 std::copy_n(chanbuffer-MaxResamplerEdge+srcOffset, prevSamples->size(),
595 prevSamples->data());
596 ++prevSamples;
599 else
601 auto prevSamples = mPrevSamples.data();
602 for(auto *chanbuffer : MixingSamples)
604 std::copy_n(prevSamples->data(), MaxResamplerEdge, chanbuffer-MaxResamplerEdge);
605 ++prevSamples;
607 if(mFlags.test(VoiceIsStatic))
608 LoadBufferStatic(BufferListItem, BufferLoopItem, DataPosInt, mFmtType,
609 mFmtChannels, mFrameStep, SrcBufferSize, MixingSamples);
610 else if(mFlags.test(VoiceIsCallback))
612 if(!mFlags.test(VoiceCallbackStopped) && SrcBufferSize > mNumCallbackSamples)
614 const size_t byteOffset{mNumCallbackSamples*mFrameSize};
615 const size_t needBytes{SrcBufferSize*mFrameSize - byteOffset};
617 const int gotBytes{BufferListItem->mCallback(BufferListItem->mUserData,
618 &BufferListItem->mSamples[byteOffset], static_cast<int>(needBytes))};
619 if(gotBytes < 0)
620 mFlags.set(VoiceCallbackStopped);
621 else if(static_cast<uint>(gotBytes) < needBytes)
623 mFlags.set(VoiceCallbackStopped);
624 mNumCallbackSamples += static_cast<uint>(gotBytes) / mFrameSize;
626 else
627 mNumCallbackSamples = SrcBufferSize;
629 LoadBufferCallback(BufferListItem, mNumCallbackSamples, mFmtType, mFmtChannels,
630 mFrameStep, SrcBufferSize, MixingSamples);
632 else
633 LoadBufferQueue(BufferListItem, BufferLoopItem, DataPosInt, mFmtType, mFmtChannels,
634 mFrameStep, SrcBufferSize, MixingSamples);
636 const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits};
637 if(mDecoder)
639 SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge;
640 ((*mDecoder).*mDecoderFunc)(MixingSamples, SrcBufferSize,
641 srcOffset * likely(vstate == Playing));
643 /* Store the last source samples used for next time. */
644 if(likely(vstate == Playing))
646 prevSamples = mPrevSamples.data();
647 for(auto *chanbuffer : MixingSamples)
649 /* Store the last source samples used for next time. */
650 std::copy_n(chanbuffer-MaxResamplerEdge+srcOffset, prevSamples->size(),
651 prevSamples->data());
652 ++prevSamples;
657 auto voiceSamples = MixingSamples.begin();
658 for(auto &chandata : mChans)
660 /* Resample, then apply ambisonic upsampling as needed. */
661 float *ResampledData{Resample(&mResampleState, *voiceSamples, DataPosFrac, increment,
662 {Device->ResampledData, DstBufferSize})};
663 ++voiceSamples;
665 if(mFlags.test(VoiceIsAmbisonic))
666 chandata.mAmbiSplitter.processScale({ResampledData, DstBufferSize},
667 chandata.mAmbiHFScale, chandata.mAmbiLFScale);
669 /* Now filter and mix to the appropriate outputs. */
670 const al::span<float,BufferLineSize> FilterBuf{Device->FilteredData};
672 DirectParams &parms = chandata.mDryParams;
673 const float *samples{DoFilters(parms.LowPass, parms.HighPass, FilterBuf.data(),
674 {ResampledData, DstBufferSize}, mDirect.FilterType)};
676 if(mFlags.test(VoiceHasHrtf))
678 const float TargetGain{parms.Hrtf.Target.Gain * likely(vstate == Playing)};
679 DoHrtfMix(samples, DstBufferSize, parms, TargetGain, Counter, OutPos,
680 (vstate == Playing), Device);
682 else
684 const float *TargetGains{likely(vstate == Playing) ? parms.Gains.Target.data()
685 : SilentTarget.data()};
686 if(mFlags.test(VoiceHasNfc))
687 DoNfcMix({samples, DstBufferSize}, mDirect.Buffer.data(), parms,
688 TargetGains, Counter, OutPos, Device);
689 else
690 MixSamples({samples, DstBufferSize}, mDirect.Buffer,
691 parms.Gains.Current.data(), TargetGains, Counter, OutPos);
695 for(uint send{0};send < NumSends;++send)
697 if(mSend[send].Buffer.empty())
698 continue;
700 SendParams &parms = chandata.mWetParams[send];
701 const float *samples{DoFilters(parms.LowPass, parms.HighPass, FilterBuf.data(),
702 {ResampledData, DstBufferSize}, mSend[send].FilterType)};
704 const float *TargetGains{likely(vstate == Playing) ? parms.Gains.Target.data()
705 : SilentTarget.data()};
706 MixSamples({samples, DstBufferSize}, mSend[send].Buffer,
707 parms.Gains.Current.data(), TargetGains, Counter, OutPos);
710 /* If the voice is stopping, we're now done. */
711 if(unlikely(vstate == Stopping))
712 break;
714 /* Update positions */
715 DataPosFrac += increment*DstBufferSize;
716 const uint SrcSamplesDone{DataPosFrac>>MixerFracBits};
717 DataPosInt += SrcSamplesDone;
718 DataPosFrac &= MixerFracMask;
720 OutPos += DstBufferSize;
721 Counter = maxu(DstBufferSize, Counter) - DstBufferSize;
723 if(unlikely(!BufferListItem))
725 /* Do nothing extra when there's no buffers. */
727 else if(mFlags.test(VoiceIsStatic))
729 if(BufferLoopItem)
731 /* Handle looping static source */
732 const uint LoopStart{BufferListItem->mLoopStart};
733 const uint LoopEnd{BufferListItem->mLoopEnd};
734 if(DataPosInt >= LoopEnd)
736 assert(LoopEnd > LoopStart);
737 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
740 else
742 /* Handle non-looping static source */
743 if(DataPosInt >= BufferListItem->mSampleLen)
745 BufferListItem = nullptr;
746 break;
750 else if(mFlags.test(VoiceIsCallback))
752 /* Handle callback buffer source */
753 if(SrcSamplesDone < mNumCallbackSamples)
755 const size_t byteOffset{SrcSamplesDone*mFrameSize};
756 const size_t byteEnd{mNumCallbackSamples*mFrameSize};
757 al::byte *data{BufferListItem->mSamples};
758 std::copy(data+byteOffset, data+byteEnd, data);
759 mNumCallbackSamples -= SrcSamplesDone;
761 else
763 BufferListItem = nullptr;
764 mNumCallbackSamples = 0;
767 else
769 /* Handle streaming source */
770 do {
771 if(BufferListItem->mSampleLen > DataPosInt)
772 break;
774 DataPosInt -= BufferListItem->mSampleLen;
776 ++buffers_done;
777 BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed);
778 if(!BufferListItem) BufferListItem = BufferLoopItem;
779 } while(BufferListItem);
781 } while(OutPos < SamplesToDo);
783 mFlags.set(VoiceIsFading);
785 /* Don't update positions and buffers if we were stopping. */
786 if(unlikely(vstate == Stopping))
788 mPlayState.store(Stopped, std::memory_order_release);
789 return;
792 /* Capture the source ID in case it's reset for stopping. */
793 const uint SourceID{mSourceID.load(std::memory_order_relaxed)};
795 /* Update voice info */
796 mPosition.store(DataPosInt, std::memory_order_relaxed);
797 mPositionFrac.store(DataPosFrac, std::memory_order_relaxed);
798 mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed);
799 if(!BufferListItem)
801 mLoopBuffer.store(nullptr, std::memory_order_relaxed);
802 mSourceID.store(0u, std::memory_order_relaxed);
804 std::atomic_thread_fence(std::memory_order_release);
806 /* Send any events now, after the position/buffer info was updated. */
807 const uint enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)};
808 if(buffers_done > 0 && (enabledevt&AsyncEvent::BufferCompleted))
810 RingBuffer *ring{Context->mAsyncEvents.get()};
811 auto evt_vec = ring->getWriteVector();
812 if(evt_vec.first.len > 0)
814 AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
815 AsyncEvent::BufferCompleted)};
816 evt->u.bufcomp.id = SourceID;
817 evt->u.bufcomp.count = buffers_done;
818 ring->writeAdvance(1);
822 if(!BufferListItem)
824 /* If the voice just ended, set it to Stopping so the next render
825 * ensures any residual noise fades to 0 amplitude.
827 mPlayState.store(Stopping, std::memory_order_release);
828 if((enabledevt&AsyncEvent::SourceStateChange))
829 SendSourceStoppedEvent(Context, SourceID);
833 void Voice::prepare(DeviceBase *device)
835 /* Even if storing really high order ambisonics, we only mix channels for
836 * orders up to the device order. The rest are simply dropped.
838 uint num_channels{(mFmtChannels == FmtUHJ2 || mFmtChannels == FmtSuperStereo) ? 3 :
839 ChannelsFromFmt(mFmtChannels, minu(mAmbiOrder, device->mAmbiOrder))};
840 if(unlikely(num_channels > device->mSampleData.size()))
842 ERR("Unexpected channel count: %u (limit: %zu, %d:%d)\n", num_channels,
843 device->mSampleData.size(), mFmtChannels, mAmbiOrder);
844 num_channels = static_cast<uint>(device->mSampleData.size());
846 if(mChans.capacity() > 2 && num_channels < mChans.capacity())
848 decltype(mChans){}.swap(mChans);
849 decltype(mPrevSamples){}.swap(mPrevSamples);
851 mChans.reserve(maxu(2, num_channels));
852 mChans.resize(num_channels);
853 mPrevSamples.reserve(maxu(2, num_channels));
854 mPrevSamples.resize(num_channels);
856 if(IsUHJ(mFmtChannels))
858 mDecoder = std::make_unique<UhjDecoder>();
859 mDecoderFunc = (mFmtChannels == FmtSuperStereo) ? &UhjDecoder::decodeStereo
860 : &UhjDecoder::decode;
862 else
864 mDecoder = nullptr;
865 mDecoderFunc = nullptr;
868 /* Clear the stepping value explicitly so the mixer knows not to mix this
869 * until the update gets applied.
871 mStep = 0;
873 /* Make sure the sample history is cleared. */
874 std::fill(mPrevSamples.begin(), mPrevSamples.end(), HistoryLine{});
876 /* Don't need to set the VoiceIsAmbisonic flag if the device is not higher
877 * order than the voice. No HF scaling is necessary to mix it.
879 if(mAmbiOrder && device->mAmbiOrder > mAmbiOrder)
881 const uint8_t *OrderFromChan{Is2DAmbisonic(mFmtChannels) ?
882 AmbiIndex::OrderFrom2DChannel().data() : AmbiIndex::OrderFromChannel().data()};
883 const auto scales = AmbiScale::GetHFOrderScales(mAmbiOrder, device->mAmbiOrder);
885 const BandSplitter splitter{device->mXOverFreq / static_cast<float>(device->Frequency)};
886 for(auto &chandata : mChans)
888 chandata.mAmbiHFScale = scales[*(OrderFromChan++)];
889 chandata.mAmbiLFScale = 1.0f;
890 chandata.mAmbiSplitter = splitter;
891 chandata.mDryParams = DirectParams{};
892 chandata.mDryParams.NFCtrlFilter = device->mNFCtrlFilter;
893 std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
895 /* 2-channel UHJ needs different shelf filters. However, we can't just
896 * use different shelf filters after mixing it and with any old speaker
897 * setup the user has. To make this work, we apply the expected shelf
898 * filters for decoding UHJ2 to quad (only needs LF scaling), and act
899 * as if those 4 quad channels are encoded right back onto first-order
900 * B-Format, which then upsamples to higher order as normal (only needs
901 * HF scaling).
903 * This isn't perfect, but without an entirely separate and limited
904 * UHJ2 path, it's better than nothing.
906 if(mFmtChannels == FmtUHJ2)
908 mChans[0].mAmbiLFScale = 0.661f;
909 mChans[1].mAmbiLFScale = 1.293f;
910 mChans[2].mAmbiLFScale = 1.293f;
912 mFlags.set(VoiceIsAmbisonic);
914 else if(mFmtChannels == FmtUHJ2 && !device->mUhjEncoder)
916 /* 2-channel UHJ with first-order output also needs the shelf filter
917 * correction applied, except with UHJ output (UHJ2->B-Format->UHJ2 is
918 * identity, so don't mess with it).
920 const BandSplitter splitter{device->mXOverFreq / static_cast<float>(device->Frequency)};
921 for(auto &chandata : mChans)
923 chandata.mAmbiHFScale = 1.0f;
924 chandata.mAmbiLFScale = 1.0f;
925 chandata.mAmbiSplitter = splitter;
926 chandata.mDryParams = DirectParams{};
927 chandata.mDryParams.NFCtrlFilter = device->mNFCtrlFilter;
928 std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
930 mChans[0].mAmbiLFScale = 0.661f;
931 mChans[1].mAmbiLFScale = 1.293f;
932 mChans[2].mAmbiLFScale = 1.293f;
933 mFlags.set(VoiceIsAmbisonic);
935 else
937 for(auto &chandata : mChans)
939 chandata.mDryParams = DirectParams{};
940 chandata.mDryParams.NFCtrlFilter = device->mNFCtrlFilter;
941 std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
943 mFlags.reset(VoiceIsAmbisonic);