259template <
typename SampleType =
float>
416 update_ratio_dependents();
417 update_coefficients();
418 update_transformer();
425 base_history_.fill(0.0);
426 os_history_.fill(0.0);
427 dry_delay_.fill(0.0);
434 transformer_.reset();
460 update_ratio_dependents();
461 update_coefficients();
469 update_coefficients();
475 update_coefficients();
483 update_ratio_dependents();
488 transformer_amount_ = std::clamp(
490 update_transformer();
525 const double w = knee_db_;
528 if (w > 0.0 && m > 0.0 && 2.0 * over <= w * (1.0 + m)) {
531 (w / m) * (std::sqrt(1.0 + (2.0 * m / w) * (over + 0.5 * w)) - 1.0);
544 double loop_slope()
const {
return 1.0 - 1.0 / ratio_value_; }
589 return g_min_ + std::clamp(
c, 0.0, 1.0) * (g_max_ - g_min_);
605 return trim_ / (1.0 + series_resistance_ *
613 return 1.0 + alpha_max_ * std::clamp(
c, 0.0, 1.0) * clamped;
628 if (!(db > 0.0))
return 0.0;
629 const double rest = 1.0 + series_resistance_ * g_min_;
630 const double target =
rest * std::pow(10.0, db / 20.0);
631 const double c = (target -
rest) / (series_resistance_ * (g_max_ - g_min_));
632 return std::clamp(
c, 0.0, 1.0);
644 return (g_max_ - g_min_) * (1.0 -
a) >
a * g_min_;
659 return (1.0 - mix_) + mix_ * wet;
675 if (!std::isfinite(
static_cast<double>(input))) {
677 return SampleType{0};
679 const double x =
static_cast<double>(input);
680 const double dry = push_dry(x);
681 const double driven = x * input_gain_;
684 base_history_[base_write_] = driven;
686 double decimated = 0.0;
688 const double v = interpolate_phase(phase);
697 requested > detector_db_
698 ? attack_coef_ * detector_db_ + (1.0 - attack_coef_) * requested
699 : release_coef_ * detector_db_ + (1.0 - release_coef_) * requested);
705 os_history_[os_write_] = y;
708 if (phase == 0) decimated = decimate();
711 base_write_ = base_write_ + 1 < kBaseHistory ? base_write_ + 1 : 0;
713 const double wet = transformer_.process(decimated * output_gain_);
714 return static_cast<SampleType
>(
snap_to_zero(dry + mix_ * (wet - dry)));
722 static constexpr int kBaseHistory =
727 void design_resampler() {
730 const double cutoff =
734 double decimation_l1 = 0.0;
736 decimation_[
static_cast<std::size_t
>(
i)] = prototype[
static_cast<std::size_t
>(
i)];
737 decimation_l1 += std::abs(prototype[
static_cast<std::size_t
>(
i)]);
742 double interpolation_l1 = 0.0;
745 double branch_l1 = 0.0;
747 const double coefficient =
749 interpolation_[
static_cast<std::size_t
>(phase)][
static_cast<std::size_t
>(count)] =
751 branch_l1 += std::abs(coefficient);
754 interpolation_length_[
static_cast<std::size_t
>(phase)] = count;
755 interpolation_l1 = std::max(interpolation_l1, branch_l1);
757 resampler_peak_bound_ = interpolation_l1 * decimation_l1;
761 double interpolate_phase(
int phase)
const {
762 const auto p =
static_cast<std::size_t
>(phase);
763 const int count = interpolation_length_[
p];
765 int index = base_write_;
766 for (
int k = 0;
k <
count; ++
k) {
767 sum += interpolation_[
p][
static_cast<std::size_t
>(
k)] *
768 base_history_[
static_cast<std::size_t
>(index)];
769 if (--index < 0)
index = kBaseHistory - 1;
775 double decimate()
const {
777 int index = os_write_;
779 sum += decimation_[
static_cast<std::size_t
>(
k)] *
780 os_history_[
static_cast<std::size_t
>(index)];
788 double push_dry(
double x) {
791 const double out = dry_delay_[
read];
792 dry_delay_[dry_write_] =
x;
793 dry_write_ = (dry_write_ + 1) % size;
803 void solve_divider() {
809 trim_ = 1.0 + series_resistance_ * g_min_;
812 void update_ratio_dependents() {
813 const bool abi = ratio_button_ == Ratio::all_buttons_in;
814 switch (ratio_button_) {
815 case Ratio::r4_1: ratio_value_ = 4.0;
break;
816 case Ratio::r8_1: ratio_value_ = 8.0;
break;
817 case Ratio::r12_1: ratio_value_ = 12.0;
break;
818 case Ratio::r20_1: ratio_value_ = 20.0;
break;
819 case Ratio::all_buttons_in: ratio_value_ =
kAbiRatio;
break;
828 void update_coefficients() {
829 const bool abi = ratio_button_ == Ratio::all_buttons_in;
830 const double attack_s =
832 const double release_s =
834 attack_coef_ = retain(attack_s);
835 release_coef_ = retain(release_s);
840 double retain(
double tau_seconds)
const {
844 void update_transformer() {
845 transformer_.set_coefficients(
852 double sample_rate_ = 44100.0;
856 double input_gain_db_ = 0.0;
857 double output_gain_db_ = 0.0;
858 double attack_us_ = 200.0;
859 double release_ms_ = 300.0;
860 double knee_request_db_ = 1.0;
861 double transformer_amount_ = 0.6;
863 Ratio ratio_button_ = Ratio::r4_1;
866 double input_gain_ = 1.0;
867 double output_gain_ = 1.0;
868 double ratio_value_ = 4.0;
869 double knee_db_ = 1.0;
870 double bias_shift_db_ = 0.0;
872 double attack_coef_ = 0.0;
873 double release_coef_ = 0.0;
878 double series_resistance_ = 0.0;
882 std::array<double, kResamplerTaps> decimation_{};
884 std::array<int, kOversamplingFactor> interpolation_length_{};
885 double resampler_peak_bound_ = 1.0;
888 std::array<double, kBaseHistory> base_history_{};
889 std::array<double, kResamplerTaps> os_history_{};
890 std::array<double, kLatencySamples + 1> dry_delay_{};
893 std::size_t dry_write_ = 0;
895 double detector_db_ = 0.0;
896 double control_ = 0.0;
897 double feedback_ = 0.0;
898 BiquadT<double> transformer_{};
@ low_shelf
Definition biquad.hpp:58
Feedback-topology FET compressor.
Definition fet_compressor.hpp:260
static constexpr int kOversamplingFactor
Definition fet_compressor.hpp:269
static constexpr double kOutputGainDbMax
Definition fet_compressor.hpp:394
void set_ratio(Ratio r)
Definition fet_compressor.hpp:458
Ratio ratio() const
Definition fet_compressor.hpp:464
static constexpr double kAttackUsMax
Definition fet_compressor.hpp:396
static constexpr double kGainReductionMaxDb
Definition fet_compressor.hpp:304
static constexpr double kDividerGainSupremum
Definition fet_compressor.hpp:640
bool divider_supremum_is_provable() const
Definition fet_compressor.hpp:642
void reset()
Zeroes every state buffer.
Definition fet_compressor.hpp:424
static constexpr double kColorationAlphaCeiling
Definition fet_compressor.hpp:318
double divider_conductance(double c) const
Shunt conductance at control voltage c — the quantity that is linear in control voltage,...
Definition fet_compressor.hpp:588
static constexpr double kResamplerKaiserBeta
Definition fet_compressor.hpp:279
static constexpr double kAbiAttackScale
Definition fet_compressor.hpp:350
static constexpr double kAttackUsMin
Definition fet_compressor.hpp:395
double sample_rate() const noexcept
Definition fet_compressor.hpp:504
double loop_slope() const
The static curve's slope in the detector's domain, B = 1 − 1/R — the loop's only remaining gain term ...
Definition fet_compressor.hpp:544
double measured_ratio() const
The measured input/output ratio: 1 + B = 2 − 1/R, never R.
Definition fet_compressor.hpp:547
static constexpr double kThresholdDbfs
Definition fet_compressor.hpp:381
static constexpr int kResamplerTaps
Definition fet_compressor.hpp:275
void process_block(SampleType *io, int n)
Definition fet_compressor.hpp:717
SampleType process(SampleType input)
One mono sample.
Definition fet_compressor.hpp:671
double control_for_reduction_db(double db) const
The exact inverse of divider_small_signal_gain in the dB domain: the control voltage that makes the d...
Definition fet_compressor.hpp:627
double coloration_depth() const
Coloration depth ceiling in force: α_max, or α_max·kAbiAlphaExtraMult clamped to kColorationAlphaCeil...
Definition fet_compressor.hpp:564
void set_release_ms(double ms)
Definition fet_compressor.hpp:472
static constexpr double kTransformerTiltDbMax
Definition fet_compressor.hpp:369
double divider_gain(double c, double v) const
Instantaneous divider gain, including the coloration term.
Definition fet_compressor.hpp:604
void set_mix(double pct01)
0..1 parallel blend.
Definition fet_compressor.hpp:495
void set_transformer_amount(double pct01)
0..1 depth of the output transformer's low-frequency tilt.
Definition fet_compressor.hpp:487
static constexpr double kAbiRatio
Definition fet_compressor.hpp:335
void set_knee_db(double db)
Soft-knee width around the fixed reference, in the DETECTOR's domain.
Definition fet_compressor.hpp:480
static constexpr double kTransformerGainSupremum
Definition fet_compressor.hpp:665
static constexpr double kAbiAlphaExtraMult
Definition fet_compressor.hpp:357
static constexpr int kLatencySamples
Definition fet_compressor.hpp:288
double nominal_ratio() const
The nominal ratio feeding the gain computer (20 in all-buttons-in).
Definition fet_compressor.hpp:554
double measured_knee_db() const
The knee width a user measures at the INPUT, in dB.
Definition fet_compressor.hpp:551
double static_curve_db(double level_db) const
The static characteristic's output for a level in dB, per Giannoulis et al.
Definition fet_compressor.hpp:511
static constexpr double kTransformerCornerHz
Definition fet_compressor.hpp:365
static constexpr double kFetOffResistance
Definition fet_compressor.hpp:299
static constexpr double kKneeDbMax
Definition fet_compressor.hpp:400
double divider_small_signal_gain(double c) const
Small-signal divider gain at fixed c: R_fet/(R_s + R_fet) with the rest-state trim folded in,...
Definition fet_compressor.hpp:597
static constexpr double kAbiKneeWidenMult
Definition fet_compressor.hpp:339
FetRatio Ratio
Definition fet_compressor.hpp:262
double control_voltage() const
The control voltage currently driving the divider, 0..1.
Definition fet_compressor.hpp:582
static constexpr double kReleaseMsMin
Definition fet_compressor.hpp:397
int latency_samples() const noexcept
Exact, parameter independent. See the file doc block.
Definition fet_compressor.hpp:502
static constexpr double kLevelEpsilon
Definition fet_compressor.hpp:386
GainReduction gain_reduction() const noexcept
Definition fet_compressor.hpp:577
double gain_reduction_db() const
Smoothed gain reduction in dB (≥ 0, a magnitude) as of the last oversampled step — the detector itsel...
Definition fet_compressor.hpp:576
double coloration_multiplier(double c, double v) const
1 + α(c)·v, the conductance multiplier.
Definition fet_compressor.hpp:611
static constexpr double kResamplerCutoffFraction
Definition fet_compressor.hpp:284
static constexpr double kInputGainDbMax
Definition fet_compressor.hpp:392
double measured_gain_reduction_db(double input_db) const
Measured gain reduction in dB (≥ 0) at a steady input level.
Definition fet_compressor.hpp:538
FetCompressorT()
Definition fet_compressor.hpp:404
double attack_coefficient() const
Detector retain coefficients, exp(−1/(τ·fs_os)).
Definition fet_compressor.hpp:569
static constexpr double kColorationHeadroomClamp
Definition fet_compressor.hpp:323
void set_input_gain_db(double db)
The only lever into gain reduction — there is no threshold control.
Definition fet_compressor.hpp:445
void set_output_gain_db(double db)
Makeup gain, applied after the divider and before the transformer.
Definition fet_compressor.hpp:452
static constexpr double kAbiReleaseScale
Definition fet_compressor.hpp:353
double worst_case_gain() const
Closed-form ℓ∞ bound on |y/x| for the whole block at the current settings (series law 8).
Definition fet_compressor.hpp:656
double release_coefficient() const
Definition fet_compressor.hpp:570
double gain_computer_db(double level_db) const
Gain reduction the static curve asks for, as a POSITIVE magnitude in dB.
Definition fet_compressor.hpp:516
double effective_knee_db() const
Knee width in force, after the all-buttons-in widening.
Definition fet_compressor.hpp:557
void prepare(double sample_rate)
Designs the resampler prototype, solves the divider's series resistance, and configures the transform...
Definition fet_compressor.hpp:410
static constexpr double kInputGainDbMin
Definition fet_compressor.hpp:391
static constexpr double kKneeDbMin
Definition fet_compressor.hpp:399
double bias_shift_db() const
Detector bias shift in force (non-zero only in all-buttons-in).
Definition fet_compressor.hpp:560
double resampler_peak_gain_bound() const
‖h_up‖₁ · ‖h_down‖₁ for the shipped taps — a true ℓ∞ bound on the resampling pair's peak gain for ANY...
Definition fet_compressor.hpp:651
double coloration_multiplier_bound() const
The bound on |1 + α(c)·v|.
Definition fet_compressor.hpp:619
static constexpr double kOutputGainDbMin
Definition fet_compressor.hpp:393
static constexpr double kTransformerQ
Definition fet_compressor.hpp:374
static constexpr double kAbiBiasShiftDb
Definition fet_compressor.hpp:346
double oversampled_rate() const noexcept
Definition fet_compressor.hpp:505
static constexpr double kReleaseMsMax
Definition fet_compressor.hpp:398
double measured_static_curve_db(double input_db) const
The static curve a user actually measures, input dB → output dB: the closed-loop fixed point ŷ = x̂ −...
Definition fet_compressor.hpp:523
static constexpr double kColorationAlphaMax
Definition fet_compressor.hpp:314
void set_attack_us(double us)
Definition fet_compressor.hpp:466
static constexpr double kFetOnResistance
Definition fet_compressor.hpp:295
Canonical gain-reduction meter value.
Definition dynamics_contract.hpp:27
static GainReduction from_magnitude_db(double magnitude_db) noexcept
Adapt an attenuation magnitude, where reduction is positive dB.
Definition dynamics_contract.hpp:37
Shared envelope and gain-reduction vocabulary for dynamics processors.
The published compressor equations, once.
@ count
sentinel: number of real capabilities (keep LAST)
Definition canvas_capability.hpp:38
@ index
Definition gpu_pass.hpp:140
double soft_knee_output_db(double input_db, double threshold_db, double knee_db, double ratio)
The characteristic in the OUTPUT-LEVEL domain: input dB → output dB.
Definition dynamics_core.hpp:193
double one_pole_retain(double tau_seconds, double sample_rate)
α = exp(−1/(τ·fs)) — the RETAIN coefficient (see the file doc block).
Definition dynamics_core.hpp:155
double retain_finite(double candidate, double current) noexcept
Control setters retain their last valid value when automation supplies a non-finite sample.
Definition dynamics_core.hpp:117
double amplitude_db(double amplitude, double epsilon)
An amplitude → dB, floored by an ADDEND rather than a max().
Definition dynamics_core.hpp:135
constexpr double kLevelEpsilon
Level-conversion floor, guarding log10(0).
Definition dynamics_core.hpp:125
@ size
Definition config.hpp:216
std::uint64_t read(std::span< const std::uint8_t > b, std::size_t p, unsigned n) noexcept
Definition spectral_frame_codec.hpp:111
T db_to_linear(T db)
Amplitude dB → linear gain. 0 dB → 1, −6.0206 dB → 0.5.
Definition units.hpp:71
Definition additive_bank.hpp:218
FetCompressorT< double > FetCompressor64
Definition fet_compressor.hpp:902
@ c
Definition spectrum_trace.hpp:35
@ rest
Low for the whole stage — silence with duration.
Definition stage_sequencer.hpp:29
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
FetCompressorT< float > FetCompressor
Definition fet_compressor.hpp:901
std::vector< double > design_windowed_sinc(std::size_t taps, double cutoff, double beta)
Definition windowed_sinc_design.hpp:58
FetRatio
The ratio buttons.
Definition fet_compressor.hpp:250
@ all_buttons_in
Definition fet_compressor.hpp:255
@ r12_1
Definition fet_compressor.hpp:253
@ r20_1
Definition fet_compressor.hpp:254
@ r8_1
Definition fet_compressor.hpp:252
@ r4_1
Definition fet_compressor.hpp:251
float sum(const float *data, std::size_t count) noexcept
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ x
Definition input_events.hpp:41
The real-unit vocabulary shared by every DSP block in the catalog.
Shared Kaiser-windowed-sinc FIR design helpers.