19 #include "alnumeric.h"
20 #include "aloptional.h"
24 #include "async_event.h"
25 #include "buffer_storage.h"
28 #include "devformat.h"
30 #include "filters/biquad.h"
31 #include "filters/nfc.h"
32 #include "filters/splitter.h"
33 #include "fmt_traits.h"
36 #include "mixer/defs.h"
37 #include "mixer/hrtfdefs.h"
38 #include "opthelpers.h"
39 #include "resampler_limits.h"
40 #include "ringbuffer.h"
42 #include "voice_change.h"
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
};
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()
76 if((CPUCapFlags
&CPU_CAP_NEON
))
80 if((CPUCapFlags
&CPU_CAP_SSE
))
86 inline HrtfMixerFunc
SelectHrtfMixer()
89 if((CPUCapFlags
&CPU_CAP_NEON
))
90 return MixHrtf_
<NEONTag
>;
93 if((CPUCapFlags
&CPU_CAP_SSE
))
94 return MixHrtf_
<SSETag
>;
96 return MixHrtf_
<CTag
>;
99 inline HrtfMixerBlendFunc
SelectHrtfBlendMixer()
102 if((CPUCapFlags
&CPU_CAP_NEON
))
103 return MixHrtfBlend_
<NEONTag
>;
106 if((CPUCapFlags
&CPU_CAP_SSE
))
107 return MixHrtfBlend_
<SSETag
>;
109 return MixHrtfBlend_
<CTag
>;
114 void Voice::InitMixer(al::optional
<std::string
> resampler
)
118 struct ResamplerEntry
{
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
);
139 else if(al::strcasecmp(str
, "sinc4") == 0 || al::strcasecmp(str
, "sinc8") == 0)
141 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
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
);
151 ResamplerDefault
= iter
->resampler
;
154 MixSamples
= SelectMixer();
155 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
156 MixHrtfSamples
= SelectHrtfMixer();
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
)
188 lpfilter
.process(src
, dst
);
193 hpfilter
.process(src
, dst
);
197 DualBiquad
{lpfilter
, hpfilter
}.process(src
, dst
);
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
);
219 for(auto *dst
: dstSamples
)
221 al::LoadSampleArray
<Type
>(dst
+dstOffset
, s
, srcStep
, samples
);
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, \
238 HANDLE_FMT(FmtUByte
);
239 HANDLE_FMT(FmtShort
);
240 HANDLE_FMT(FmtFloat
);
241 HANDLE_FMT(FmtDouble
);
242 HANDLE_FMT(FmtMulaw
);
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
,
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
);
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
,
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
,
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
;
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
)
336 buffer
= buffer
->mNext
.load(std::memory_order_acquire
);
337 if(!buffer
) buffer
= bufferLoopItem
;
339 if(const size_t toFill
{samplesToLoad
- samplesLoaded
})
342 for(auto *chanbuffer
: voiceSamples
)
344 auto srcsamples
= chanbuffer
+ samplesLoaded
- 1;
345 std::fill_n(srcsamples
+ 1, toFill
, *srcsamples
);
352 void DoHrtfMix(const float *samples
, const uint DstBufferSize
, DirectParams
&parms
,
353 const float TargetGain
, const uint Counter
, uint OutPos
, const bool IsPlaying
,
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. */
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
,
395 /* Update the old parameters with the result. */
396 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
397 parms
.Hrtf
.Old
.Gain
= gain
;
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
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
,
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
);
440 const al::span
<float> nfcsamples
{Device
->NfcSampleData
, samples
.size()};
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)
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);
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
);
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};
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
;
495 parms
.Hrtf
.Old
= parms
.Hrtf
.Target
;
497 for(uint send
{0};send
< NumSends
;++send
)
499 if(mSend
[send
].Buffer
.empty())
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};
522 /* Figure out how many buffer samples will be needed */
523 uint DstBufferSize
{SamplesToDo
- OutPos
};
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
);
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
);
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());
601 auto prevSamples
= mPrevSamples
.data();
602 for(auto *chanbuffer
: MixingSamples
)
604 std::copy_n(prevSamples
->data(), MaxResamplerEdge
, chanbuffer
-MaxResamplerEdge
);
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
))};
620 mFlags
.set(VoiceCallbackStopped
);
621 else if(static_cast<uint
>(gotBytes
) < needBytes
)
623 mFlags
.set(VoiceCallbackStopped
);
624 mNumCallbackSamples
+= static_cast<uint
>(gotBytes
) / mFrameSize
;
627 mNumCallbackSamples
= SrcBufferSize
;
629 LoadBufferCallback(BufferListItem
, mNumCallbackSamples
, mFmtType
, mFmtChannels
,
630 mFrameStep
, SrcBufferSize
, MixingSamples
);
633 LoadBufferQueue(BufferListItem
, BufferLoopItem
, DataPosInt
, mFmtType
, mFmtChannels
,
634 mFrameStep
, SrcBufferSize
, MixingSamples
);
636 const size_t srcOffset
{(increment
*DstBufferSize
+ DataPosFrac
)>>MixerFracBits
};
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());
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
})};
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
);
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
);
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())
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
))
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
))
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
;
742 /* Handle non-looping static source */
743 if(DataPosInt
>= BufferListItem
->mSampleLen
)
745 BufferListItem
= nullptr;
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
;
763 BufferListItem
= nullptr;
764 mNumCallbackSamples
= 0;
769 /* Handle streaming source */
771 if(BufferListItem
->mSampleLen
> DataPosInt
)
774 DataPosInt
-= BufferListItem
->mSampleLen
;
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
);
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
);
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);
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
;
865 mDecoderFunc
= nullptr;
868 /* Clear the stepping value explicitly so the mixer knows not to mix this
869 * until the update gets applied.
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
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
);
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
);