138 prepared_.store(
false, std::memory_order_relaxed);
148 const double osRate = sampleRate_ *
static_cast<double>(osFactor_);
151 oversampler_ = std::make_unique<Oversampling<T>>(
153 oversampler_->prepare(spec);
157 oversampler_.reset();
164 hysteresis_.assign(
static_cast<size_t>(numChannels_), {});
165 hysteresisN_.assign(
static_cast<size_t>(numChannels_), {});
166 for (
auto& h : hysteresis_)
169 h.setParameters(3.5e5, 2.2e4, 1.6e-3, 2.7e4, 0.17);
171 for (
auto& h : hysteresisN_)
174 h.setParameters(3.5e5, 2.2e4, 1.6e-3, 2.7e4, 0.17);
177 recordHF_.assign(
static_cast<size_t>(numChannels_), {});
178 recordLF_.assign(
static_cast<size_t>(numChannels_), {});
179 playHF_.assign(
static_cast<size_t>(numChannels_), {});
180 playLF_.assign(
static_cast<size_t>(numChannels_), {});
181 headBump_.assign(
static_cast<size_t>(numChannels_), {});
182 overBiasLp_.assign(
static_cast<size_t>(numChannels_), 0.0);
186 outHp_.assign(
static_cast<size_t>(numChannels_), {});
189 for (
auto& h : outHp_)
190 h = PeakSection { hc.b0, hc.b1, hc.b2, hc.a1, hc.a2, 0.0, 0.0 };
193 firState_.assign(
static_cast<size_t>(numChannels_),
194 std::vector<T>(
static_cast<size_t>(kFirRing), T(0)));
196 firTaps_.assign(
static_cast<size_t>(kFirLen), T(0));
200 delayCenter_ = std::max(96,
static_cast<int>(96.0 * sampleRate_ / 48000.0));
202 while (dsz < 2 * delayCenter_ + 8) dsz <<= 1;
203 delayMask_ = dsz - 1;
204 delayRing_.assign(
static_cast<size_t>(numChannels_),
205 std::vector<T>(
static_cast<size_t>(dsz), T(0)));
209 const double dt = 1.0 / sampleRate_;
210 driftA_ = std::exp(-2.0 * std::numbers::pi * 0.10 * dt);
211 scrapeA1_ = std::exp(-2.0 * std::numbers::pi * 90.0 * dt);
212 scrapeA2_ = std::exp(-2.0 * std::numbers::pi * 40.0 * dt);
214 latency_ = (oversampler_ ? oversampler_->getLatency() : 0) + kFirCenter + delayCenter_;
216 while (drySize_ < latency_ + maxBlock_ + 1) drySize_ <<= 1;
217 dryRing_.assign(
static_cast<size_t>(numChannels_),
218 std::vector<T>(
static_cast<size_t>(drySize_), T(0)));
221 prepared_.store(
true, std::memory_order_relaxed);
222 dirty_.store(
true, std::memory_order_release);
229 if (!prepared_.load(std::memory_order_relaxed))
return;
230 for (
auto& h : hysteresis_) h.reset();
231 for (
auto& h : hysteresisN_) h.reset();
232 for (
auto& f : firState_) std::fill(f.begin(), f.end(), T(0));
233 for (
auto& d : delayRing_) std::fill(d.begin(), d.end(), T(0));
234 for (
auto& d : dryRing_) std::fill(d.begin(), d.end(), T(0));
235 for (
auto& s : recordHF_) s.clear();
236 for (
auto& s : recordLF_) s.clear();
237 for (
auto& s : playHF_) s.clear();
238 for (
auto& s : playLF_) s.clear();
239 for (
auto& v : overBiasLp_) v = 0.0;
242 for (
auto& b : headBump_) b.clear();
243 for (
auto& h : outHp_) h.clear();
250 modPhaseFlut2_ = 0.0;
252 scrapeLp1_ = scrapeLp2_ = 0.0;
254 rngNoise_ = 0x2468beefu;
255 if (oversampler_) oversampler_->reset();
264 if (!std::isfinite(driveDb))
return;
265 driveDb_.store(std::clamp(driveDb, T(-12), T(24)), std::memory_order_relaxed);
266 dirty_.store(
true, std::memory_order_release);
277 if (!std::isfinite(bias))
return;
278 bias_.store(std::clamp(bias, T(0), T(1)), std::memory_order_relaxed);
279 dirty_.store(
true, std::memory_order_release);
297 if (factor < 1 || factor > 16 || (factor & (factor - 1)) != 0)
return;
298 if (factor == osFactor_)
return;
300 if (prepared_.load(std::memory_order_relaxed))
311 const int v = std::clamp(
static_cast<int>(s),
314 speed_.store(v, std::memory_order_relaxed);
315 dirty_.store(
true, std::memory_order_release);
322 const int v = std::clamp(
static_cast<int>(s),
325 standard_.store(v, std::memory_order_relaxed);
326 dirty_.store(
true, std::memory_order_release);
333 if (!std::isfinite(amount))
return;
334 loss_.store(std::clamp(amount, T(0), T(1)), std::memory_order_relaxed);
335 dirty_.store(
true, std::memory_order_release);
342 if (!std::isfinite(amount))
return;
343 headBumpAmt_.store(std::clamp(amount, T(0), T(1)), std::memory_order_relaxed);
344 dirty_.store(
true, std::memory_order_release);
351 if (!std::isfinite(amount))
return;
352 wowFlutter_.store(std::clamp(amount, T(0), T(1)), std::memory_order_relaxed);
359 if (!std::isfinite(dbfs))
return;
360 noiseDb_.store(std::clamp(dbfs, T(-200), T(-20)), std::memory_order_relaxed);
367 if (!std::isfinite(mix))
return;
368 mix_.store(std::clamp(mix, T(0), T(1)), std::memory_order_relaxed);
371 [[nodiscard]] T
getDrive() const noexcept {
return driveDb_.load(std::memory_order_relaxed); }
372 [[nodiscard]] T
getBias() const noexcept {
return bias_.load(std::memory_order_relaxed); }
375 return static_cast<Speed>(speed_.load(std::memory_order_relaxed));
379 return static_cast<Standard>(standard_.load(std::memory_order_relaxed));
381 [[nodiscard]] T
getLossEffects() const noexcept {
return loss_.load(std::memory_order_relaxed); }
382 [[nodiscard]] T
getHeadBump() const noexcept {
return headBumpAmt_.load(std::memory_order_relaxed); }
383 [[nodiscard]] T
getWowFlutter() const noexcept {
return wowFlutter_.load(std::memory_order_relaxed); }
384 [[nodiscard]] T
getNoise() const noexcept {
return noiseDb_.load(std::memory_order_relaxed); }
385 [[nodiscard]] T
getMix() const noexcept {
return mix_.load(std::memory_order_relaxed); }
389 [[nodiscard]]
int getLatency() const noexcept {
return latency_; }
396 [[nodiscard]] std::vector<uint8_t>
getState()
const
401 w.
write(
"drive",
static_cast<float>(driveDb_.load(std::memory_order_relaxed)));
402 w.
write(
"bias",
static_cast<float>(bias_.load(std::memory_order_relaxed)));
403 w.
write(
"speed", speed_.load(std::memory_order_relaxed));
404 w.
write(
"standard", standard_.load(std::memory_order_relaxed));
405 w.
write(
"loss",
static_cast<float>(loss_.load(std::memory_order_relaxed)));
406 w.
write(
"headBump",
static_cast<float>(headBumpAmt_.load(std::memory_order_relaxed)));
407 w.
write(
"wowFlutter",
static_cast<float>(wowFlutter_.load(std::memory_order_relaxed)));
408 w.
write(
"noise",
static_cast<float>(noiseDb_.load(std::memory_order_relaxed)));
409 w.
write(
"mix",
static_cast<float>(mix_.load(std::memory_order_relaxed)));
410 w.
write(
"oversampling", osFactor_);
438 if (!prepared_.load(std::memory_order_relaxed))
return;
441 const int nCh = std::min(buffer.getNumChannels(), numChannels_);
442 const int nS = buffer.getNumSamples();
443 if (nCh == 0 || nS == 0)
return;
452 for (
int ch = 0; ch < nCh; ++ch)
454 T* d = buffer.getChannel(ch);
455 for (
int i = 0; i < nS; ++i)
456 if (!std::isfinite(d[i])) d[i] = T(0);
461 if (dirty_.load(std::memory_order_relaxed)
462 && dirty_.exchange(
false, std::memory_order_acquire))
465 const T mixVal = mix_.load(std::memory_order_relaxed);
466 const double noiseAmp = std::pow(10.0,
static_cast<double>(
467 noiseDb_.load(std::memory_order_relaxed)) / 20.0);
468 const bool noiseOn = noiseDb_.load(std::memory_order_relaxed) > T(-120);
469 const double wfDepth =
static_cast<double>(wowFlutter_.load(std::memory_order_relaxed));
472 for (
int ch = 0; ch < nCh; ++ch)
474 const T* in = buffer.getChannel(ch);
475 auto& dry = dryRing_[
static_cast<size_t>(ch)];
477 for (
int i = 0; i < nS; ++i)
479 dry[
static_cast<size_t>(dp)] = in[i];
480 dp = (dp + 1) & (drySize_ - 1);
485 for (
int ch = 0; ch < nCh; ++ch)
487 T* d = buffer.getChannel(ch);
488 auto& hf = recordHF_[
static_cast<size_t>(ch)];
489 auto& lf = recordLF_[
static_cast<size_t>(ch)];
490 for (
int i = 0; i < nS; ++i)
491 d[i] =
static_cast<T
>(hf.process(lf.process(
static_cast<double>(d[i]))));
500 const bool osOn = (oversampler_ !=
nullptr);
501 auto osView = osOn ? oversampler_->upsample(buffer) : buffer;
502 const int osN = osView.getNumSamples();
503 const int phaseStart = biasPhase_;
504 for (
int ch = 0; ch < nCh; ++ch)
506 T* d = osView.getChannel(ch);
507 auto& hp = hysteresis_[
static_cast<size_t>(ch)];
508 auto& hn = hysteresisN_[
static_cast<size_t>(ch)];
509 const double inScale = hScale_;
510 const double outScale = mScale_ * 0.5;
511 const double B = biasAmp_;
512 int phase = phaseStart;
513 for (
int i = 0; i < osN; ++i)
515 const double x = inScale *
static_cast<double>(d[i]);
516 const double c = B * kBiasTable[
static_cast<size_t>(phase)];
517 phase = (phase + 1) & 7;
518 const double mp =
static_cast<double>(hp.processSample(
static_cast<T
>(x + c)));
519 const double mn =
static_cast<double>(hn.processSample(
static_cast<T
>(x - c)));
520 d[i] =
static_cast<T
>(outScale * (mp + mn));
523 biasPhase_ = (phaseStart + osN) & 7;
524 if (osOn) oversampler_->downsample(buffer);
528 for (
int i = 0; i < nS; ++i)
532 const double mod = nextTransportMod(wfDepth);
533 const double readPos =
static_cast<double>(delayCenter_) + mod;
534 const auto readInt =
static_cast<int>(std::floor(readPos));
535 const T frac =
static_cast<T
>(readPos - readInt);
537 for (
int ch = 0; ch < nCh; ++ch)
539 T* d = buffer.getChannel(ch);
542 auto& fir = firState_[
static_cast<size_t>(ch)];
543 fir[
static_cast<size_t>(firPos_)] = d[i];
544 fir[
static_cast<size_t>(firPos_ + kFirRing / 2)] = d[i];
545 const T* win = &fir[
static_cast<size_t>(firPos_ + kFirRing / 2 - (kFirLen - 1))];
549 y = headBump_[
static_cast<size_t>(ch)].process(y);
554 auto& dl = delayRing_[
static_cast<size_t>(ch)];
555 dl[
static_cast<size_t>(delayPos_)] = y;
556 const int base = delayPos_ - readInt;
557 const int dm = delayMask_;
558 const T p0 = dl[
static_cast<size_t>((base + 1) & dm)];
559 const T p1 = dl[
static_cast<size_t>(base & dm)];
560 const T p2 = dl[
static_cast<size_t>((base - 1) & dm)];
561 const T p3 = dl[
static_cast<size_t>((base - 2) & dm)];
562 T w = p1 + T(0.5) * frac * (p2 - p0
563 + frac * (T(2) * p0 - T(5) * p1 + T(4) * p2 - p3
564 + frac * (T(3) * (p1 - p2) + p3 - p0)));
567 w =
static_cast<T
>(playLF_[
static_cast<size_t>(ch)].process(
568 playHF_[
static_cast<size_t>(ch)].process(
static_cast<double>(w))));
573 if (overBiasA_ > 0.0)
575 auto& lp = overBiasLp_[
static_cast<size_t>(ch)];
576 lp += overBiasA_ * (
static_cast<double>(w) - lp);
577 w =
static_cast<T
>(lp);
582 w = outHp_[
static_cast<size_t>(ch)].process(w);
588 rngNoise_ = rngNoise_ * 1664525u + 1013904223u;
589 const double n1 =
static_cast<double>(rngNoise_ >> 8) / 8388608.0 - 1.0;
590 w +=
static_cast<T
>(noiseAmp * n1 * 0.35);
594 const auto& dry = dryRing_[
static_cast<size_t>(ch)];
595 const int dryIdx = (dryPos_ + i - latency_) & (drySize_ - 1);
596 const T drySample = dry[
static_cast<size_t>(dryIdx)];
597 d[i] = drySample + (w - drySample) * mixVal;
600 firPos_ = (firPos_ + 1) & (kFirRing / 2 - 1);
601 delayPos_ = (delayPos_ + 1) & delayMask_;
603 dryPos_ = (dryPos_ + nS) & (drySize_ - 1);
612 double b0 = 1.0, b1 = 0.0, a1 = 0.0;
613 double x1 = 0.0, y1 = 0.0;
615 void clear() noexcept { x1 = 0.0; y1 = 0.0; }
616 [[nodiscard]]
double process(
double x)
noexcept
618 const double y = b0 * x + b1 * x1 - a1 * y1;
628 double b0 = 1.0, b1 = 0.0, b2 = 0.0, a1 = 0.0, a2 = 0.0;
629 double z1 = 0.0, z2 = 0.0;
631 void clear() noexcept { z1 = 0.0; z2 = 0.0; }
632 [[nodiscard]] T process(T x)
noexcept
634 const double in =
static_cast<double>(x);
635 const double y = b0 * in + z1;
636 z1 = b1 * in - a1 * y + z2;
637 z2 = b2 * in - a2 * y;
638 return static_cast<T
>(y);
644 static ShelfSection makeHFShelf(
double t,
double kHi,
double fs,
bool inverse)
noexcept
646 const double kt = 2.0 * fs * t;
647 double n0 = kHi * kt + 1.0, n1 = 1.0 - kHi * kt;
648 double d0 = kt + 1.0, d1 = 1.0 - kt;
649 if (inverse) { std::swap(n0, d0); std::swap(n1, d1); }
650 return { n0 / d0, n1 / d0, d1 / d0, 0.0, 0.0 };
653 static ShelfSection makeLFShelf(
double t,
double kLo,
double fs,
bool inverse)
noexcept
655 const double kt = 2.0 * fs * t;
656 double n0 = kt + kLo, n1 = kLo - kt;
657 double d0 = kt + 1.0, d1 = 1.0 - kt;
658 if (inverse) { std::swap(n0, d0); std::swap(n1, d1); }
659 return { n0 / d0, n1 / d0, d1 / d0, 0.0, 0.0 };
663 void recompute() noexcept
665 const double driveDbV =
static_cast<double>(driveDb_.load(std::memory_order_relaxed));
666 const double drive = std::pow(10.0, driveDbV / 20.0);
667 const double bias =
static_cast<double>(bias_.load(std::memory_order_relaxed));
668 const auto speed =
static_cast<Speed>(speed_.load(std::memory_order_relaxed));
669 const auto standard =
static_cast<Standard>(standard_.load(std::memory_order_relaxed));
670 const double lossAmt =
static_cast<double>(loss_.load(std::memory_order_relaxed));
671 const double bumpAmt =
static_cast<double>(headBumpAmt_.load(std::memory_order_relaxed));
683 const double biasB = std::min(6.0, 3.0 * std::pow(9.0, bias - 0.5));
684 biasAmp_ = biasB * 2.2e4;
689 const double fc = 22000.0 * (3.5 / biasB);
690 overBiasA_ = 1.0 - std::exp(-2.0 * std::numbers::pi * fc / sampleRate_);
712 constexpr double kHiCap = 4.0;
713 constexpr double kLoBoost = 2.0;
714 const double tLo = 3180e-6;
724 hScale_ = drive * 1.2 * 2.2e4;
732 const double w1 = 2.0 * std::numbers::pi * 1000.0 * t2;
733 const double emph1k = std::sqrt((1.0 + kHiCap * kHiCap * w1 * w1)
735 const double kCalAmp = 0.25 * emph1k;
737 const double fs4 = sampleRate_ *
static_cast<double>(osFactor_);
740 const int calN =
static_cast<int>(0.024 * fs4);
741 const int calFrom = (calN * 2) / 3;
743 calib_.setParameters(3.5e5, 2.2e4, 1.6e-3, 2.7e4, 0.17);
744 calib2_.prepare(fs4);
745 calib2_.setParameters(3.5e5, 2.2e4, 1.6e-3, 2.7e4, 0.17);
750 const double wCal = 2.0 * std::numbers::pi * 1000.0 / fs4;
751 double outRe = 0.0, outIm = 0.0;
753 for (
int i = 0; i < calN; ++i)
755 const double s = std::sin(wCal * i);
756 const double x = hScale_ * kCalAmp * s;
757 const double c = biasAmp_ * kBiasTable[
static_cast<size_t>(i & 7)];
759 * (
static_cast<double>(calib_.processSample(
static_cast<T
>(x + c)))
760 +
static_cast<double>(calib2_.processSample(
static_cast<T
>(x - c))));
763 outRe += m * std::cos(wCal * i);
764 outIm += m * std::sin(wCal * i);
768 const double fund = 2.0 * std::sqrt(outRe * outRe + outIm * outIm)
770 mScale_ = (fund > 0.0) ? kCalAmp / fund : 1.0;
778 mScale_ *= std::pow(drive, 0.25);
781 for (
int ch = 0; ch < numChannels_; ++ch)
783 auto& rhf = recordHF_[
static_cast<size_t>(ch)];
784 auto& rlf = recordLF_[
static_cast<size_t>(ch)];
785 auto& phf = playHF_[
static_cast<size_t>(ch)];
786 auto& plf = playLF_[
static_cast<size_t>(ch)];
788 const double sx1 = rhf.x1, sy1 = rhf.y1;
789 rhf = makeHFShelf(t2, kHiCap, sampleRate_,
false);
790 rhf.x1 = sx1; rhf.y1 = sy1;
792 const double lx1 = rlf.x1, ly1 = rlf.y1;
793 rlf = useLF ? makeLFShelf(tLo, kLoBoost, sampleRate_,
false) : ShelfSection {};
794 rlf.x1 = lx1; rlf.y1 = ly1;
796 const double px1 = phf.x1, py1 = phf.y1;
797 phf = makeHFShelf(t2, kHiCap, sampleRate_,
true);
798 phf.x1 = px1; phf.y1 = py1;
800 const double qx1 = plf.x1, qy1 = plf.y1;
801 plf = useLF ? makeLFShelf(tLo, kLoBoost, sampleRate_,
true) : ShelfSection {};
802 plf.x1 = qx1; plf.y1 = qy1;
808 const double v = ips * 0.0254;
809 constexpr double gap = 3.0e-6;
810 constexpr double spacing = 0.5e-6;
811 constexpr double thickness = 1.0e-6;
813 constexpr int kGrid = kFirLen + 1;
814 double mags[kGrid / 2 + 1];
815 for (
int kBin = 0; kBin <= kGrid / 2; ++kBin)
817 const double f = kBin * sampleRate_ / kGrid;
821 const double lambda = v / f;
822 const double spacingLoss = std::pow(10.0, -54.6 * (spacing / lambda) / 20.0);
823 const double gx = std::numbers::pi * gap / lambda;
824 const double gapLoss = (gx < 1e-9) ? 1.0
825 : std::abs(std::sin(gx) / gx);
826 const double tx = 4.0 * std::numbers::pi * thickness / lambda;
827 const double thickLoss = (tx < 1e-9) ? 1.0 : (1.0 - std::exp(-tx)) / tx;
828 mag = spacingLoss * gapLoss * thickLoss;
830 mags[kBin] = (1.0 - lossAmt) + lossAmt * mag;
839 else if (f > 19500.0)
840 mags[kBin] *= 0.5 + 0.5 * std::cos(std::numbers::pi * (f - 19500.0) / 2000.0);
842 double taps[kFirLen];
843 for (
int n = 0; n < kFirLen; ++n)
845 double acc = mags[0];
846 for (
int kBin = 1; kBin < kGrid / 2; ++kBin)
847 acc += 2.0 * mags[kBin]
848 * std::cos(2.0 * std::numbers::pi * kBin * (n - kFirCenter)
849 /
static_cast<double>(kGrid));
850 acc += mags[kGrid / 2] * std::cos(std::numbers::pi * (n - kFirCenter));
851 const double hann = 0.5 - 0.5 * std::cos(2.0 * std::numbers::pi * (n + 1)
853 taps[n] = acc * hann / kGrid;
858 const double w1k = 2.0 * std::numbers::pi * 1000.0 / sampleRate_;
859 double re = 0.0, im = 0.0;
860 for (
int n = 0; n < kFirLen; ++n)
862 re += taps[n] * std::cos(w1k * n);
863 im -= taps[n] * std::sin(w1k * n);
865 const double g = std::sqrt(re * re + im * im);
866 const double norm = (g > 1e-9) ? 1.0 / g : 1.0;
867 for (
int n = 0; n < kFirLen; ++n) taps[n] *= norm;
869 for (
int n = 0; n < kFirLen; ++n)
870 firTaps_[
static_cast<size_t>(kFirLen - 1 - n)] =
871 static_cast<T
>(taps[n]);
876 const double bumpDb = 2.5 * bumpAmt;
878 for (
auto& b : headBump_)
880 const double pz1 = b.z1, pz2 = b.z2;
881 b = PeakSection { bc.b0, bc.b1, bc.b2, bc.a1, bc.a2, 0.0, 0.0 };
888 [[nodiscard]]
double nextTransportMod(
double depth)
noexcept
892 const double dt = 1.0 / sampleRate_;
893 modPhaseWow_ += 0.55 * dt;
894 if (modPhaseWow_ >= 1.0) modPhaseWow_ -= 1.0;
895 modPhaseFlut_ += 8.3 * dt;
896 if (modPhaseFlut_ >= 1.0) modPhaseFlut_ -= 1.0;
897 modPhaseFlut2_ += 23.0 * dt;
898 if (modPhaseFlut2_ >= 1.0) modPhaseFlut2_ -= 1.0;
900 rng_ = rng_ * 1664525u + 1013904223u;
901 const double n =
static_cast<double>(rng_ >> 8) / 8388608.0 - 1.0;
904 driftState_ = driftA_ * driftState_ + (1.0 - driftA_) * n * 600.0;
905 const double drift = std::clamp(driftState_, -18.0, 18.0);
908 scrapeLp1_ = scrapeA1_ * scrapeLp1_ + (1.0 - scrapeA1_) * n;
909 scrapeLp2_ = scrapeA2_ * scrapeLp2_ + (1.0 - scrapeA2_) * n;
910 const double scrape = (scrapeLp1_ - scrapeLp2_) * 0.6;
915 const double twoPi = 2.0 * std::numbers::pi;
920 const double rateScale = sampleRate_ / 48000.0;
921 const double wow = 27.8 * std::sin(
twoPi * modPhaseWow_);
922 const double flut = 0.55 * std::sin(
twoPi * modPhaseFlut_);
923 const double flut2 = 0.066 * std::sin(
twoPi * modPhaseFlut2_);
925 return 0.4 * depth * rateScale * (drift + wow + flut + flut2 + scrape);
929 static constexpr int kFirLen = 63;
930 static constexpr int kFirCenter = 31;
931 static constexpr int kFirRing = 128;
934 double sampleRate_ = 48000.0;
935 int numChannels_ = 0;
937 std::atomic<bool> prepared_ {
false };
942 std::unique_ptr<Oversampling<T>> oversampler_;
943 std::vector<Hysteresis<T>> hysteresis_;
944 std::vector<Hysteresis<T>> hysteresisN_;
945 Hysteresis<T> calib_;
946 Hysteresis<T> calib2_;
951 static constexpr double kBiasTable[8] = {
952 0.0, 0.70710678118654752, -1.0, 0.70710678118654752,
953 0.0, -0.70710678118654752, 1.0, -0.70710678118654752
956 std::vector<ShelfSection> recordHF_, recordLF_, playHF_, playLF_;
957 std::vector<PeakSection> headBump_;
958 std::vector<PeakSection> outHp_;
959 std::vector<double> overBiasLp_;
961 std::vector<T> firTaps_;
962 std::vector<std::vector<T>> firState_;
965 std::vector<std::vector<T>> delayRing_;
967 int delayCenter_ = 96;
968 int delayMask_ = 255;
969 double driftA_ = 0.0, scrapeA1_ = 0.0, scrapeA2_ = 0.0;
971 std::vector<std::vector<T>> dryRing_;
974 double hScale_ = 1.0, mScale_ = 1.0;
975 double biasAmp_ = 3.0 * 2.2e4;
976 double overBiasA_ = 0.0;
979 double modPhaseWow_ = 0.0, modPhaseFlut_ = 0.0, modPhaseFlut2_ = 0.0;
980 double driftState_ = 0.0, scrapeLp1_ = 0.0, scrapeLp2_ = 0.0;
981 uint32_t rng_ = 0x1357feedu;
982 uint32_t rngNoise_ = 0x2468beefu;
984 std::atomic<T> driveDb_ { T(0) };
985 std::atomic<T> bias_ { T(0.5) };
987 std::atomic<int> standard_ {
static_cast<int>(
Standard::NAB) };
988 std::atomic<T> loss_ { T(0.5) };
989 std::atomic<T> headBumpAmt_ { T(0.5) };
990 std::atomic<T> wowFlutter_ { T(0.15) };
991 std::atomic<T> noiseDb_ { T(-200) };
992 std::atomic<T> mix_ { T(1) };
993 std::atomic<bool> dirty_ {
true };