72 if (!validSpec(spec))
return;
74 const int newFftSize = sanitizeFftSize(fftSize);
75 const int newHopSize = sanitizeHopSize(newFftSize, hopSize);
76 const int newBins = newFftSize / 2 + 1;
83 nextProcessor.
prepare(spec, newFftSize, newHopSize);
85 const std::size_t channelBins = checkedProduct(
86 static_cast<std::size_t
>(channels),
static_cast<std::size_t
>(newBins));
87 const std::size_t complexChannelBins = checkedProduct(channelBins, 2u);
89 std::vector<T> nextScratch(checkedProduct(
90 static_cast<std::size_t
>(channels),
92 std::vector<T> nextRaw(checkedProduct(complexChannelBins, 3u), T(0));
93 std::vector<T> nextMagnitude(channelBins, T(0));
94 std::vector<T> nextCapturedPhase(channelBins, T(0));
95 std::vector<T> nextFrozenPhase(channelBins, T(0));
96 std::vector<T> nextPower(
static_cast<std::size_t
>(newBins), T(0));
97 std::vector<T> nextOmega(
static_cast<std::size_t
>(newBins), T(0));
98 std::vector<T> nextOmegaImag(
static_cast<std::size_t
>(newBins), T(0));
99 std::vector<std::uint32_t> nextActive(
100 static_cast<std::size_t
>(newBins), 0u);
101 std::vector<std::uint32_t> nextPeak(
102 static_cast<std::size_t
>(newBins), 0u);
103 std::vector<std::uint32_t> nextRegion(
104 static_cast<std::size_t
>(newBins), 0u);
106 processor_ = std::move(nextProcessor);
107 scratch_ = std::move(nextScratch);
108 rawSpectra_ = std::move(nextRaw);
109 capturedMagnitude_ = std::move(nextMagnitude);
110 capturedPhase_ = std::move(nextCapturedPhase);
111 frozenPhase_ = std::move(nextFrozenPhase);
112 binPower_ = std::move(nextPower);
113 omega_ = std::move(nextOmega);
114 omegaImag_ = std::move(nextOmegaImag);
115 active_ = std::move(nextActive);
116 peak_ = std::move(nextPeak);
117 regionPeak_ = std::move(nextRegion);
120 fftSize_ = newFftSize;
121 hopSize_ = newHopSize;
124 rebuildScratchPointers();
125 clearStreamState(
false);
134 if (!prepared_)
return;
135 clearStreamState(
true);
142 requested_.fetch_or(kFrozenBit, std::memory_order_relaxed);
144 requested_.fetch_and(~kFrozenBit, std::memory_order_relaxed);
150 return (requested_.load(std::memory_order_relaxed) & kFrozenBit) != 0u;
160 requested_.fetch_or(kDiffuseBit, std::memory_order_relaxed);
162 requested_.fetch_and(~kDiffuseBit, std::memory_order_relaxed);
168 return (requested_.load(std::memory_order_relaxed) & kDiffuseBit) != 0u
176 [[nodiscard]] std::vector<uint8_t>
getState()
const
199 return prepared_ ? fftSize_ : 0;
205 return prepared_ ? fftSize_ : 0;
211 return prepared_ ? hopSize_ : 0;
217 return prepared_ ? fftSize_ : 0;
229 if (!prepared_ || buffer.getNumSamples() <= 0)
return;
231 const int runtimeChannels = buffer.getNumChannels();
232 const int processedChannels = std::min(runtimeChannels, spec_.
numChannels);
233 const int totalSamples = buffer.getNumSamples();
236 while (offset < totalSamples)
238 const int block = std::min(spec_.
maxBlockSize, totalSamples - offset);
242 T*
const work = scratchChannels_[
static_cast<std::size_t
>(ch)];
243 if (ch < processedChannels && buffer.getChannel(ch) !=
nullptr)
245 const T*
const source = buffer.getChannel(ch) + offset;
246 for (
int i = 0; i < block; ++i)
247 work[i] = std::isfinite(source[i]) ? source[i] : T(0);
251 std::fill_n(work, block, T(0));
257 auto callback = [
this](T* spectrum,
int bins)
noexcept {
258 processSpectrum(spectrum, bins);
260 processor_.processBlock(workView, callback);
262 for (
int ch = 0; ch < processedChannels; ++ch)
264 T*
const destination = buffer.getChannel(ch);
265 if (destination ==
nullptr)
continue;
266 const T*
const work = scratchChannels_[
static_cast<std::size_t
>(ch)];
267 for (
int i = 0; i < block; ++i)
268 destination[offset + i] = std::isfinite(work[i]) ? work[i] : T(0);
276 static constexpr std::uint32_t kFrozenBit = 1u;
277 static constexpr std::uint32_t kDiffuseBit = 2u;
278 static constexpr int kMinFftSize = 256;
279 static constexpr int kMaxFftSize = 32768;
280 static constexpr int kMaxBlockSize = 65536;
281 static constexpr int kMaxChannels = 16;
282 static_assert(std::atomic<std::uint32_t>::is_always_lock_free);
284 [[nodiscard]]
static bool validSpec(
const AudioSpec& spec)
noexcept
286 return std::isfinite(spec.sampleRate) && spec.sampleRate > 0.0
287 && spec.maxBlockSize >= 1 && spec.maxBlockSize <= kMaxBlockSize
288 && spec.numChannels >= 1 && spec.numChannels <= kMaxChannels;
291 [[nodiscard]]
static int sanitizeFftSize(
int requested)
noexcept
293 requested = std::clamp(requested, kMinFftSize, kMaxFftSize);
294 int result = kMinFftSize;
295 while (result < requested) result <<= 1;
299 [[nodiscard]]
static int sanitizeHopSize(
int fftSize,
int requested)
noexcept
301 if (requested == fftSize / 8 || requested == fftSize / 4
302 || requested == fftSize / 2)
307 [[nodiscard]]
static std::size_t checkedProduct(std::size_t a,
312 if (a != 0u && b > std::numeric_limits<std::size_t>::max() / a)
314#if defined(DSPARK_NO_EXCEPTIONS)
317 throw std::length_error(
"SpectralFreeze allocation size overflow");
323 void rebuildScratchPointers() noexcept
325 scratchChannels_.fill(
nullptr);
328 scratchChannels_[
static_cast<std::size_t
>(ch)] = scratch_.data()
329 +
static_cast<std::size_t
>(ch)
334 void clearStreamState(
bool resetProcessor)
noexcept
336 if (resetProcessor) processor_.reset();
337 std::fill(scratch_.begin(), scratch_.end(), T(0));
338 std::fill(rawSpectra_.begin(), rawSpectra_.end(), T(0));
339 std::fill(capturedMagnitude_.begin(), capturedMagnitude_.end(), T(0));
340 std::fill(capturedPhase_.begin(), capturedPhase_.end(), T(0));
341 std::fill(frozenPhase_.begin(), frozenPhase_.end(), T(0));
342 std::fill(binPower_.begin(), binPower_.end(), T(0));
343 std::fill(omega_.begin(), omega_.end(), T(0));
344 std::fill(omegaImag_.begin(), omegaImag_.end(), T(0));
345 std::fill(active_.begin(), active_.end(), 0u);
346 std::fill(peak_.begin(), peak_.end(), 0u);
347 std::fill(regionPeak_.begin(), regionPeak_.end(), 0u);
352 completedFrames_ = 0;
353 callbackChannel_ = 0;
356 frameRequestWord_ = 0u;
359 magnitudeFloor_ = T(0);
360 nextDiffuseGeneration_ = 0u;
361 diffuseGeneration_ = 0u;
363 tonalAdvanceCount_ = 0u;
366 [[nodiscard]] std::size_t rawOffset(
int bank,
int channel)
const noexcept
368 return (
static_cast<std::size_t
>(bank)
370 +
static_cast<std::size_t
>(channel))
371 *
static_cast<std::size_t
>(numBins_ * 2);
374 [[nodiscard]] std::size_t channelBinOffset(
int channel)
const noexcept
376 return static_cast<std::size_t
>(channel)
377 *
static_cast<std::size_t
>(numBins_);
380 [[nodiscard]]
static T principalArgument(T phase)
noexcept
382 constexpr T p = std::numbers::pi_v<T>;
383 constexpr T tau = T(2) * p;
384 T wrapped = std::fmod(phase + p, tau);
385 if (wrapped < T(0)) wrapped += tau;
389 [[nodiscard]]
static T phaseOf(T real, T imag)
noexcept
391 return std::atan2(imag, real);
394 [[nodiscard]]
static T safeMagnitude(T real, T imag)
noexcept
396 return std::hypot(real, imag);
399 void processSpectrum(T* spectrum,
int bins)
noexcept
401 if (callbackChannel_ == 0) beginFrame();
403 const int channel = callbackChannel_;
404 T*
const raw = rawSpectra_.data() + rawOffset(currentBank_, channel);
405 const int usableBins = std::min(bins, numBins_);
406 for (
int k = 0; k < usableBins; ++k)
408 T real = spectrum[2 * k];
409 T imag = spectrum[2 * k + 1];
410 if (!std::isfinite(real) || !std::isfinite(imag))
414 spectrum[2 * k] = T(0);
415 spectrum[2 * k + 1] = T(0);
418 raw[2 * k + 1] = imag;
421 if (frameQ_ > 0 && captured_)
422 blendFrozenSpectrum(spectrum, channel);
427 callbackChannel_ = 0;
432 void beginFrame() noexcept
436 frameRequestWord_ = requested_.load(std::memory_order_relaxed);
440 if ((frameRequestWord_ & kFrozenBit) == 0u)
444 else if (!captured_ && completedFrames_ >= 2)
446 capturedMode_ = (frameRequestWord_ & kDiffuseBit) != 0u
449 captureLatestFrame();
460 if (frameQ_ > 0 && captured_
462 prepareDiffuseFrame();
465 void completeFrame() noexcept
467 const int recycled = olderBank_;
468 olderBank_ = latestBank_;
469 latestBank_ = currentBank_;
470 currentBank_ = recycled;
471 completedFrames_ = std::min(2, completedFrames_ + 1);
473 if (!captured_)
return;
475 if ((frameRequestWord_ & kFrozenBit) != 0u)
477 if (q_ < fftSize_ / hopSize_) ++q_;
484 if (q_ == 0 && (frameRequestWord_ & kFrozenBit) == 0u)
492 else if (frameQ_ > 0)
496 void captureLatestFrame() noexcept
498 std::fill(active_.begin(), active_.end(), 0u);
499 std::fill(peak_.begin(), peak_.end(), 0u);
500 std::fill(regionPeak_.begin(), regionPeak_.end(), 0u);
501 std::fill(binPower_.begin(), binPower_.end(), T(0));
502 std::fill(omega_.begin(), omega_.end(), T(0));
504 long double globalScale = 0.0L;
507 const T*
const latest = rawSpectra_.data() + rawOffset(latestBank_, ch);
508 for (
int k = 0; k < numBins_; ++k)
510 globalScale = std::max(globalScale,
511 std::abs(
static_cast<long double>(latest[2 * k])));
512 globalScale = std::max(globalScale,
513 std::abs(
static_cast<long double>(latest[2 * k + 1])));
517 long double maxPower = 0.0L;
518 if (globalScale > 0.0L)
520 for (
int k = 0; k < numBins_; ++k)
522 long double power = 0.0L;
525 const T*
const latest = rawSpectra_.data()
526 + rawOffset(latestBank_, ch);
527 const long double real =
528 static_cast<long double>(latest[2 * k]) / globalScale;
529 const long double imag =
530 static_cast<long double>(latest[2 * k + 1]) / globalScale;
531 power += real * real + imag * imag;
533 binPower_[
static_cast<std::size_t
>(k)] =
static_cast<T
>(power);
534 maxPower = std::max(maxPower, power);
538 const long double epsilon =
539 static_cast<long double>(std::numeric_limits<T>::epsilon());
540 const long double minimumNormal =
541 static_cast<long double>(std::numeric_limits<T>::min());
542 const long double minimumMagnitude = std::sqrt(minimumNormal);
543 long double normalizedPowerFloor = 0.0L;
544 if (globalScale > 0.0L)
546 normalizedPowerFloor = 64.0L * epsilon * maxPower;
547 const long double relativeMagnitudeFloor = globalScale
548 * std::sqrt(normalizedPowerFloor);
549 magnitudeFloor_ =
static_cast<T
>(std::max(
550 relativeMagnitudeFloor, minimumMagnitude));
554 magnitudeFloor_ =
static_cast<T
>(minimumMagnitude);
557 const long double normalizedMagnitudeFloor =
558 std::sqrt(normalizedPowerFloor);
559 for (
int k = 1; k < numBins_ - 1; ++k)
561 const long double normalizedMagnitude = std::sqrt(
562 static_cast<long double>(binPower_[
static_cast<std::size_t
>(k)]));
563 const long double rawMagnitude = globalScale * normalizedMagnitude;
564 active_[
static_cast<std::size_t
>(k)] =
565 normalizedMagnitude > normalizedMagnitudeFloor
566 && rawMagnitude > minimumMagnitude
573 const T*
const latest = rawSpectra_.data() + rawOffset(latestBank_, ch);
574 const std::size_t base = channelBinOffset(ch);
575 capturedMagnitude_[base] = latest[0];
576 capturedPhase_[base] = T(1);
577 frozenPhase_[base] = T(0);
578 const int nyquist = numBins_ - 1;
579 capturedMagnitude_[base +
static_cast<std::size_t
>(nyquist)] =
581 capturedPhase_[base +
static_cast<std::size_t
>(nyquist)] = T(1);
582 frozenPhase_[base +
static_cast<std::size_t
>(nyquist)] = T(0);
584 for (
int k = 1; k < nyquist; ++k)
586 const std::size_t index = base +
static_cast<std::size_t
>(k);
587 const T magnitude = active_[
static_cast<std::size_t
>(k)] != 0u
588 ? safeMagnitude(latest[2 * k], latest[2 * k + 1])
590 capturedMagnitude_[index] = magnitude;
591 if (magnitude > T(0))
593 capturedPhase_[index] = latest[2 * k] / magnitude;
594 frozenPhase_[index] = latest[2 * k + 1] / magnitude;
598 capturedPhase_[index] = T(1);
599 frozenPhase_[index] = T(0);
607 diffuseGeneration_ = nextDiffuseGeneration_++;
609 tonalAdvanceCount_ = 0u;
612 void buildTonalRegions() noexcept
615 for (
int k = 1; k < numBins_ - 1; ++k)
617 const std::size_t index =
static_cast<std::size_t
>(k);
618 if (active_[index] != 0u
619 && binPower_[index] > binPower_[index - 1u]
620 && binPower_[index] >= binPower_[index + 1u])
629 for (
int k = 1; k < numBins_ - 1; ++k)
631 const std::size_t index =
static_cast<std::size_t
>(k);
632 if (active_[index] != 0u)
635 regionPeak_[index] =
static_cast<std::uint32_t
>(k);
641 int currentPeak = -1;
643 for (
int k = 1; k < numBins_ - 1; ++k)
645 if (peak_[
static_cast<std::size_t
>(k)] != 0u)
651 for (
int k = currentPeak + 1; k < numBins_ - 1; ++k)
653 if (peak_[
static_cast<std::size_t
>(k)] != 0u)
660 for (
int k = 1; k < numBins_ - 1; ++k)
662 if (active_[
static_cast<std::size_t
>(k)] == 0u)
continue;
663 while (nextPeak >= 0 && k > (currentPeak + nextPeak) / 2)
665 currentPeak = nextPeak;
667 for (
int p = currentPeak + 1; p < numBins_ - 1; ++p)
669 if (peak_[
static_cast<std::size_t
>(p)] != 0u)
676 regionPeak_[
static_cast<std::size_t
>(k)] =
677 static_cast<std::uint32_t
>(currentPeak);
681 for (
int p = 1; p < numBins_ - 1; ++p)
683 if (peak_[
static_cast<std::size_t
>(p)] == 0u)
continue;
685 long double binScale = 0.0L;
688 const T*
const latest = rawSpectra_.data()
689 + rawOffset(latestBank_, ch);
690 binScale = std::max(binScale,
691 std::abs(
static_cast<long double>(latest[2 * p])));
692 binScale = std::max(binScale,
693 std::abs(
static_cast<long double>(latest[2 * p + 1])));
696 long double sumWeight = 0.0L;
697 long double realResidual = 0.0L;
698 long double imagResidual = 0.0L;
699 const long double nominal = 2.0L * std::numbers::pi_v<long double>
700 *
static_cast<long double>(p) *
static_cast<long double>(hopSize_)
701 /
static_cast<long double>(fftSize_);
707 const T*
const latest = rawSpectra_.data()
708 + rawOffset(latestBank_, ch);
709 const T*
const older = rawSpectra_.data()
710 + rawOffset(olderBank_, ch);
711 const long double real =
712 static_cast<long double>(latest[2 * p]) / binScale;
713 const long double imag =
714 static_cast<long double>(latest[2 * p + 1]) / binScale;
715 const long double weight = real * real + imag * imag;
716 const long double latestPhase = std::atan2(
717 static_cast<long double>(latest[2 * p + 1]),
718 static_cast<long double>(latest[2 * p]));
719 const long double olderPhase = std::atan2(
720 static_cast<long double>(older[2 * p + 1]),
721 static_cast<long double>(older[2 * p]));
722 const T residual = principalArgument(
static_cast<T
>(
723 latestPhase - olderPhase - nominal));
724 realResidual += weight
725 * std::cos(
static_cast<long double>(residual));
726 imagResidual += weight
727 * std::sin(
static_cast<long double>(residual));
732 long double rho = 0.0L;
733 const long double residualMagnitude =
734 std::hypot(realResidual, imagResidual);
735 if (residualMagnitude > 64.0L
736 *
static_cast<long double>(std::numeric_limits<T>::epsilon())
738 rho = std::atan2(imagResidual, realResidual);
740 const T advance = principalArgument(
static_cast<T
>(nominal + rho));
741 omega_[
static_cast<std::size_t
>(p)] = std::cos(advance);
742 omegaImag_[
static_cast<std::size_t
>(p)] = std::sin(advance);
751 const std::size_t base = channelBinOffset(ch);
752 for (
int k = 1; k < numBins_ - 1; ++k)
754 if (active_[
static_cast<std::size_t
>(k)] == 0u
755 || peak_[
static_cast<std::size_t
>(k)] != 0u)
757 const std::size_t index = base +
static_cast<std::size_t
>(k);
758 const std::size_t peakIndex = base + regionPeak_[
759 static_cast<std::size_t
>(k)];
760 const T real = capturedPhase_[index];
761 const T imag = frozenPhase_[index];
762 const T peakReal = capturedPhase_[peakIndex];
763 const T peakImag = frozenPhase_[peakIndex];
764 capturedPhase_[index] = real * peakReal + imag * peakImag;
765 frozenPhase_[index] = imag * peakReal - real * peakImag;
770 void advanceTonalPhase() noexcept
772 ++tonalAdvanceCount_;
773 const bool renormalize = (tonalAdvanceCount_ & 255u) == 0u;
776 const std::size_t base = channelBinOffset(ch);
777 for (
int p = 1; p < numBins_ - 1; ++p)
779 if (peak_[
static_cast<std::size_t
>(p)] == 0u)
continue;
780 const std::size_t index = base +
static_cast<std::size_t
>(p);
781 const T real = capturedPhase_[index];
782 const T imag = frozenPhase_[index];
783 const T advanceReal = omega_[
static_cast<std::size_t
>(p)];
784 const T advanceImag = omegaImag_[
static_cast<std::size_t
>(p)];
785 T nextReal = real * advanceReal - imag * advanceImag;
786 T nextImag = real * advanceImag + imag * advanceReal;
789 const T length = std::hypot(nextReal, nextImag);
790 if (length > T(0) && std::isfinite(length))
801 capturedPhase_[index] = nextReal;
802 frozenPhase_[index] = nextImag;
807 [[nodiscard]]
static T diffuseAngle(std::uint64_t generation,
809 std::uint64_t bin)
noexcept
811 std::uint64_t x = UINT64_C(0xD1B54A32D192ED03)
812 ^ (generation * UINT64_C(0x9E3779B97F4A7C15))
813 ^ (frame * UINT64_C(0xBF58476D1CE4E5B9))
814 ^ (bin * UINT64_C(0x94D049BB133111EB));
815 x += UINT64_C(0x9E3779B97F4A7C15);
816 x = (x ^ (x >> 30u)) * UINT64_C(0xBF58476D1CE4E5B9);
817 x = (x ^ (x >> 27u)) * UINT64_C(0x94D049BB133111EB);
819 const double uniform =
static_cast<double>(x >> 11u) * 0x1.0p-53;
820 return static_cast<T
>(2.0 * std::numbers::pi_v<double> * uniform);
823 void prepareDiffuseFrame() noexcept
825 for (
int k = 1; k < numBins_ - 1; ++k)
827 const T angle = diffuseAngle(diffuseGeneration_, diffuseFrame_,
828 static_cast<std::uint64_t
>(k));
829 omega_[
static_cast<std::size_t
>(k)] = std::cos(angle);
830 omegaImag_[
static_cast<std::size_t
>(k)] = std::sin(angle);
834 void targetPhasor(
int channel,
int bin, T& real, T& imag)
const noexcept
836 const std::size_t base = channelBinOffset(channel);
837 const std::size_t index = base +
static_cast<std::size_t
>(bin);
840 const T capturedReal = capturedPhase_[index];
841 const T capturedImag = frozenPhase_[index];
842 const T randomReal = omega_[
static_cast<std::size_t
>(bin)];
843 const T randomImag = omegaImag_[
static_cast<std::size_t
>(bin)];
844 real = capturedReal * randomReal - capturedImag * randomImag;
845 imag = capturedReal * randomImag + capturedImag * randomReal;
849 if (peak_[
static_cast<std::size_t
>(bin)] != 0u)
851 real = capturedPhase_[index];
852 imag = frozenPhase_[index];
856 const std::size_t peakIndex = base
857 + regionPeak_[
static_cast<std::size_t
>(bin)];
858 const T peakReal = capturedPhase_[peakIndex];
859 const T peakImag = frozenPhase_[peakIndex];
860 const T relativeReal = capturedPhase_[index];
861 const T relativeImag = frozenPhase_[index];
862 real = peakReal * relativeReal - peakImag * relativeImag;
863 imag = peakReal * relativeImag + peakImag * relativeReal;
866 void blendFrozenSpectrum(T* spectrum,
int channel)
noexcept
868 const int transitionSteps = fftSize_ / hopSize_;
869 const std::size_t base = channelBinOffset(channel);
870 const int nyquist = numBins_ - 1;
872 if (frameQ_ == transitionSteps)
874 spectrum[0] = capturedMagnitude_[base];
876 spectrum[2 * nyquist] =
877 capturedMagnitude_[base +
static_cast<std::size_t
>(nyquist)];
878 spectrum[2 * nyquist + 1] = T(0);
879 for (
int k = 1; k < nyquist; ++k)
881 const std::size_t index = base +
static_cast<std::size_t
>(k);
882 const T liveMagnitude = safeMagnitude(spectrum[2 * k],
883 spectrum[2 * k + 1]);
884 const T frozenMagnitude = capturedMagnitude_[index];
885 const bool liveActive = liveMagnitude >= magnitudeFloor_;
886 const bool frozenActive = frozenMagnitude >= magnitudeFloor_;
887 if (!liveActive && !frozenActive)
889 spectrum[2 * k] = T(0);
890 spectrum[2 * k + 1] = T(0);
895 const T scale = frozenMagnitude / liveMagnitude;
896 spectrum[2 * k] *= scale;
897 spectrum[2 * k + 1] *= scale;
902 targetPhasor(channel, k, targetReal, targetImag);
903 spectrum[2 * k] = frozenMagnitude * targetReal;
904 spectrum[2 * k + 1] = frozenMagnitude * targetImag;
909 const T phase = std::numbers::pi_v<T> *
static_cast<T
>(frameQ_)
910 /
static_cast<T
>(transitionSteps);
911 const T alpha = T(0.5) - T(0.5) * std::cos(phase);
912 const T oneMinusAlpha = T(1) - alpha;
913 spectrum[0] = oneMinusAlpha * spectrum[0]
914 + alpha * capturedMagnitude_[base];
916 spectrum[2 * nyquist] = oneMinusAlpha * spectrum[2 * nyquist]
917 + alpha * capturedMagnitude_[base +
static_cast<std::size_t
>(nyquist)];
918 spectrum[2 * nyquist + 1] = T(0);
920 for (
int k = 1; k < nyquist; ++k)
922 const std::size_t index = base +
static_cast<std::size_t
>(k);
923 const T liveMagnitude = safeMagnitude(spectrum[2 * k],
924 spectrum[2 * k + 1]);
925 const T frozenMagnitude = capturedMagnitude_[index];
926 const bool liveActive = liveMagnitude >= magnitudeFloor_;
927 const bool frozenActive = frozenMagnitude >= magnitudeFloor_;
928 if (!liveActive && !frozenActive)
930 spectrum[2 * k] = T(0);
931 spectrum[2 * k + 1] = T(0);
937 targetPhasor(channel, k, targetReal, targetImag);
938 T livePhase = phaseOf(spectrum[2 * k], spectrum[2 * k + 1]);
939 T targetPhase = phaseOf(targetReal, targetImag);
940 if (!liveActive) livePhase = targetPhase;
941 if (!frozenActive) targetPhase = livePhase;
943 const T magnitude = oneMinusAlpha * liveMagnitude
944 + alpha * frozenMagnitude;
945 const T outputPhase = principalArgument(livePhase
946 + alpha * principalArgument(targetPhase - livePhase));
947 spectrum[2 * k] = magnitude * std::cos(outputPhase);
948 spectrum[2 * k + 1] = magnitude * std::sin(outputPhase);
949 if (!std::isfinite(spectrum[2 * k])
950 || !std::isfinite(spectrum[2 * k + 1]))
952 spectrum[2 * k] = T(0);
953 spectrum[2 * k + 1] = T(0);
959 bool prepared_ =
false;
964 SpectralProcessor<T> processor_;
965 std::vector<T> scratch_;
966 std::array<T*, kMaxChannels> scratchChannels_ {};
970 std::vector<T> rawSpectra_;
973 int currentBank_ = 2;
974 int completedFrames_ = 0;
975 int callbackChannel_ = 0;
977 std::vector<T> capturedMagnitude_;
978 std::vector<T> capturedPhase_;
979 std::vector<T> frozenPhase_;
980 std::vector<T> binPower_;
981 std::vector<T> omega_;
982 std::vector<T> omegaImag_;
983 std::vector<std::uint32_t> active_;
984 std::vector<std::uint32_t> peak_;
985 std::vector<std::uint32_t> regionPeak_;
989 std::uint32_t frameRequestWord_ = 0u;
990 bool captured_ =
false;
992 T magnitudeFloor_ = T(0);
993 std::uint64_t nextDiffuseGeneration_ = 0u;
994 std::uint64_t diffuseGeneration_ = 0u;
995 std::uint64_t diffuseFrame_ = 0u;
996 std::uint32_t tonalAdvanceCount_ = 0u;
998 std::atomic<std::uint32_t> requested_ { 0u };