Feedback-topology FET compressor. More...
#include <fet_compressor.hpp>
Public Types | |
| using | Ratio = FetRatio |
Public Member Functions | |
| FetCompressorT () | |
| void | prepare (double sample_rate) |
| Designs the resampler prototype, solves the divider's series resistance, and configures the transformer shelf. | |
| void | reset () |
| Zeroes every state buffer. | |
| void | set_input_gain_db (double db) |
| The only lever into gain reduction — there is no threshold control. | |
| void | set_output_gain_db (double db) |
| Makeup gain, applied after the divider and before the transformer. | |
| void | set_ratio (Ratio r) |
| Ratio | ratio () const |
| void | set_attack_us (double us) |
| void | set_release_ms (double ms) |
| void | set_knee_db (double db) |
| Soft-knee width around the fixed reference, in the DETECTOR's domain. | |
| void | set_transformer_amount (double pct01) |
| 0..1 depth of the output transformer's low-frequency tilt. | |
| void | set_mix (double pct01) |
| 0..1 parallel blend. | |
| int | latency_samples () const noexcept |
| Exact, parameter independent. See the file doc block. | |
| double | sample_rate () const noexcept |
| double | oversampled_rate () const noexcept |
| double | static_curve_db (double level_db) const |
| The static characteristic's output for a level in dB, per Giannoulis et al. | |
| double | gain_computer_db (double level_db) const |
| Gain reduction the static curve asks for, as a POSITIVE magnitude in dB. | |
| 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̂ − bias − D(ŷ), solved in closed form on each of the three branches. | |
| double | measured_gain_reduction_db (double input_db) const |
| Measured gain reduction in dB (≥ 0) at a steady input level. | |
| 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 once the divider law is inverted. | |
| double | measured_ratio () const |
| The measured input/output ratio: 1 + B = 2 − 1/R, never R. | |
| double | measured_knee_db () const |
| The knee width a user measures at the INPUT, in dB. | |
| double | nominal_ratio () const |
| The nominal ratio feeding the gain computer (20 in all-buttons-in). | |
| double | effective_knee_db () const |
| Knee width in force, after the all-buttons-in widening. | |
| double | bias_shift_db () const |
| Detector bias shift in force (non-zero only in all-buttons-in). | |
| double | coloration_depth () const |
| Coloration depth ceiling in force: α_max, or α_max·kAbiAlphaExtraMult clamped to kColorationAlphaCeiling in all-buttons-in. | |
| double | attack_coefficient () const |
| Detector retain coefficients, exp(−1/(τ·fs_os)). | |
| double | release_coefficient () const |
| double | gain_reduction_db () const |
| Smoothed gain reduction in dB (≥ 0, a magnitude) as of the last oversampled step — the detector itself, exposed for metering and so tests can measure it directly instead of inferring it from audio that crosses zero every half cycle. | |
| GainReduction | gain_reduction () const noexcept |
| double | control_voltage () const |
| The control voltage currently driving the divider, 0..1. | |
| double | divider_conductance (double c) const |
| Shunt conductance at control voltage c — the quantity that is linear in control voltage, per Shichman & Hodges. | |
| 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, so c = 0 is exactly unity and c = 1 is exactly −kGainReductionMaxDb. | |
| double | divider_gain (double c, double v) const |
| Instantaneous divider gain, including the coloration term. | |
| double | coloration_multiplier (double c, double v) const |
| 1 + α(c)·v, the conductance multiplier. | |
| double | coloration_multiplier_bound () const |
| The bound on |1 + α(c)·v|. | |
| 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 divider apply db dB of attenuation. | |
| bool | divider_supremum_is_provable () const |
| 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 bounded input, not a step-response measurement. | |
| double | worst_case_gain () const |
| Closed-form ℓ∞ bound on |y/x| for the whole block at the current settings (series law 8). | |
| SampleType | process (SampleType input) |
| One mono sample. | |
| void | process_block (SampleType *io, int n) |
Static Public Attributes | |
| static constexpr int | kOversamplingFactor = 4 |
| Oversampling factor. | |
| static constexpr int | kResamplerTaps = 65 |
| Prototype length. | |
| static constexpr double | kResamplerKaiserBeta = 8.0 |
| Kaiser shape parameter of the prototype. | |
| static constexpr double | kResamplerCutoffFraction = 0.96 |
| Prototype cutoff, as a fraction of the BASE rate's Nyquist. | |
| static constexpr int | kLatencySamples |
| The whole module's latency, in base-rate samples. | |
| static constexpr double | kFetOnResistance = 120.0 |
| FET fully on — the maximum gain reduction the divider can express. | |
| static constexpr double | kFetOffResistance = 1.0e6 |
| FET fully off — negligible gain reduction at rest. | |
| static constexpr double | kGainReductionMaxDb = 40.0 |
| The control-voltage span the divider law is normalised against: the attenuation the divider hits exactly at c = 1. | |
| static constexpr double | kColorationAlphaMax = 0.08 |
| Coloration depth ceiling. | |
| static constexpr double | kColorationAlphaCeiling = 0.16 |
| Hard ceiling on the effective coloration depth, whatever the ABI multiplier is re-tuned to. | |
| static constexpr double | kColorationHeadroomClamp = 1.2 |
| Headroom clamp on the instantaneous sample fed to the coloration term. | |
| static constexpr double | kAbiRatio = 20.0 |
| ABI reuses the 20:1 static curve rather than inventing a fifth ratio. | |
| static constexpr double | kAbiKneeWidenMult = 2.5 |
| Widened knee — the documented "curve chaos" softness. | |
| static constexpr double | kAbiBiasShiftDb = 1.5 |
| Detector bias-point shift, added directly to the gain-reduction magnitude before smoothing. | |
| static constexpr double | kAbiAttackScale = 0.6 |
| Documented faster reaction. | |
| static constexpr double | kAbiReleaseScale = 0.75 |
| [design parameter] default 0.75, range 0.5 .. 0.9. | |
| static constexpr double | kAbiAlphaExtraMult = 1.4 |
| Raises the coloration ceiling — the documented increased distortion. | |
| static constexpr double | kTransformerCornerHz = 60.0 |
| Corner of the output transformer's low-frequency shelf. | |
| static constexpr double | kTransformerTiltDbMax = 3.0 |
| Tilt depth at transformer_amount = 1. | |
| static constexpr double | kTransformerQ = 0.70710678118654752 |
| Butterworth-flat, the shape with no shelf overshoot — so the stage's supremum magnitude is exactly 1 and the gain bound stays clean. | |
| static constexpr double | kThresholdDbfs = -18.0 |
| The fixed internal reference. | |
| static constexpr double | kLevelEpsilon = dynamics::kLevelEpsilon |
| Level-conversion floor, guarding log10(0). | |
| static constexpr double | kInputGainDbMin = -20.0 |
| static constexpr double | kInputGainDbMax = 40.0 |
| static constexpr double | kOutputGainDbMin = -20.0 |
| static constexpr double | kOutputGainDbMax = 20.0 |
| static constexpr double | kAttackUsMin = 20.0 |
| static constexpr double | kAttackUsMax = 800.0 |
| static constexpr double | kReleaseMsMin = 50.0 |
| static constexpr double | kReleaseMsMax = 1100.0 |
| static constexpr double | kKneeDbMin = 0.0 |
| static constexpr double | kKneeDbMax = 6.0 |
| static constexpr double | kDividerGainSupremum = 1.0 |
| The divider's supremum gain over the whole (c, v) grid. | |
| static constexpr double | kTransformerGainSupremum = 1.0 |
| The transformer stage's supremum magnitude. | |
Feedback-topology FET compressor.
| using pulp::signal::FetCompressorT< SampleType >::Ratio = FetRatio |
|
inline |
|
inline |
Detector retain coefficients, exp(−1/(τ·fs_os)).
Exposed so a test can predict the closed-loop pole from the SHIPPED values rather than restating them.
|
inline |
Detector bias shift in force (non-zero only in all-buttons-in).
|
inline |
Coloration depth ceiling in force: α_max, or α_max·kAbiAlphaExtraMult clamped to kColorationAlphaCeiling in all-buttons-in.
|
inline |
1 + α(c)·v, the conductance multiplier.
Bounded by coloration_multiplier_bound().
|
inline |
The bound on |1 + α(c)·v|.
This is the quantity the source spec's registry row calls worst_case_gain; it is NOT one — see the file doc block. Bounds the divider's gain from BELOW.
|
inline |
The exact inverse of divider_small_signal_gain in the dB domain: the control voltage that makes the divider apply db dB of attenuation.
Closed form — one pow, no iteration, which is what makes the loop unity-compensated without an implicit solve in process().
|
inline |
The control voltage currently driving the divider, 0..1.
|
inline |
Shunt conductance at control voltage c — the quantity that is linear in control voltage, per Shichman & Hodges.
|
inline |
Instantaneous divider gain, including the coloration term.
v is the divider-referred audio sample; it is clamped to ±kColorationHeadroomClamp before use.
|
inline |
Small-signal divider gain at fixed c: R_fet/(R_s + R_fet) with the rest-state trim folded in, so c = 0 is exactly unity and c = 1 is exactly −kGainReductionMaxDb.
The coloration term is a DEVIATION from this, never folded into it, so the documented small-signal gain stays exact and auditable independent of drive level (series law 1).
|
inline |
|
inline |
Knee width in force, after the all-buttons-in widening.
|
inline |
Gain reduction the static curve asks for, as a POSITIVE magnitude in dB.
|
inlinenoexcept |
|
inline |
Smoothed gain reduction in dB (≥ 0, a magnitude) as of the last oversampled step — the detector itself, exposed for metering and so tests can measure it directly instead of inferring it from audio that crosses zero every half cycle.
|
inlinenoexcept |
Exact, parameter independent. See the file doc block.
|
inline |
The static curve's slope in the detector's domain, B = 1 − 1/R — the loop's only remaining gain term once the divider law is inverted.
|
inline |
Measured gain reduction in dB (≥ 0) at a steady input level.
|
inline |
The knee width a user measures at the INPUT, in dB.
Wider than the one they set, by the loop's own re-mapping.
|
inline |
The measured input/output ratio: 1 + B = 2 − 1/R, never R.
|
inline |
The static curve a user actually measures, input dB → output dB: the closed-loop fixed point ŷ = x̂ − bias − D(ŷ), solved in closed form on each of the three branches.
No iteration.
|
inline |
The nominal ratio feeding the gain computer (20 in all-buttons-in).
|
inlinenoexcept |
|
inline |
Designs the resampler prototype, solves the divider's series resistance, and configures the transformer shelf.
Allocates nothing (every buffer is a fixed-size array), but is the expensive call and belongs off the audio thread.
|
inline |
One mono sample.
Stereo composes two instances driven from a caller-computed shared detector signal.
|
inline |
|
inline |
|
inline |
|
inline |
‖h_up‖₁ · ‖h_down‖₁ for the shipped taps — a true ℓ∞ bound on the resampling pair's peak gain for ANY bounded input, not a step-response measurement.
Conservative by design: the measured overshoot on a full-scale step is 1.045.
|
inline |
Zeroes every state buffer.
Never allocates; a zero-initialised instance after prepare() is already in this state.
|
inlinenoexcept |
|
inline |
|
inline |
The only lever into gain reduction — there is no threshold control.
|
inline |
Soft-knee width around the fixed reference, in the DETECTOR's domain.
The width a user measures at the input is wider — measured_knee_db().
|
inline |
0..1 parallel blend.
The dry path is taken PRE input gain and delayed by latency_samples(), so the blend is not a comb filter.
|
inline |
Makeup gain, applied after the divider and before the transformer.
|
inline |
|
inline |
|
inline |
0..1 depth of the output transformer's low-frequency tilt.
|
inline |
The static characteristic's output for a level in dB, per Giannoulis et al.
— evaluated in the DETECTOR's domain, which for this topology is the compressor's own OUTPUT. This is NOT the input/output curve a user measures; measured_static_curve_db() is.
|
inline |
Closed-form ℓ∞ bound on |y/x| for the whole block at the current settings (series law 8).
Every factor is either exactly 1 with a proof (the divider, the cut-only transformer shelf) or a shipped gain.
|
staticconstexpr |
Raises the coloration ceiling — the documented increased distortion.
[design parameter] default 1.4, range 1.2 .. 2.0.
|
staticconstexpr |
Documented faster reaction.
[design parameter] default 0.6, range 0.4 .. 0.8.
|
staticconstexpr |
Detector bias-point shift, added directly to the gain-reduction magnitude before smoothing.
Note this is added unconditionally, so ABI carries a small standing reduction even below the reference — which is what a bias shift means and what the mode is documented to do. [design parameter] default 1.5 dB, range 0.5 .. 3.0 dB.
|
staticconstexpr |
Widened knee — the documented "curve chaos" softness.
[design parameter] default 2.5, range 1.5 .. 4.0.
|
staticconstexpr |
ABI reuses the 20:1 static curve rather than inventing a fifth ratio.
|
staticconstexpr |
[design parameter] default 0.75, range 0.5 .. 0.9.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Hard ceiling on the effective coloration depth, whatever the ABI multiplier is re-tuned to.
[design parameter] default 0.16, fixed.
|
staticconstexpr |
Coloration depth ceiling.
α(c) = kColorationAlphaMax · c, so the distortion scales with how hard the FET is being driven. Honest gap: no citable literature gives a coloration-depth constant for any historical unit — those numbers are measured and proprietary, not published. Original engineering, sized to sit inside the documented qualitative envelope. [design parameter] default 0.08, range 0.0 .. 0.2.
|
staticconstexpr |
Headroom clamp on the instantaneous sample fed to the coloration term.
Bounds the correction so it can neither invert nor blow up the divider law. [design parameter] default 1.2, range 1.0 .. 1.5.
|
staticconstexpr |
The divider's supremum gain over the whole (c, v) grid.
Exactly 1: the stage is a passive attenuator and the coloration term cannot lift it, because Δg·(1 − α·v_clamp) ≫ α·v_clamp·g_min at the shipped constants. divider_supremum_is_provable() checks that inequality numerically so a re-tune of the design parameters cannot silently break the claim.
|
staticconstexpr |
FET fully off — negligible gain reduction at rest.
[design parameter] default 1 MΩ, range 200 kΩ .. 5 MΩ.
|
staticconstexpr |
FET fully on — the maximum gain reduction the divider can express.
[design parameter] default 120 Ω, range 50 .. 500 Ω.
|
staticconstexpr |
The control-voltage span the divider law is normalised against: the attenuation the divider hits exactly at c = 1.
[design parameter] default 40 dB, range 20 .. 60 dB.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
The whole module's latency, in base-rate samples.
Exact, parameter independent, computed from the geometry above.
|
staticconstexpr |
Level-conversion floor, guarding log10(0).
Declared in dynamics_core.hpp alongside the conversions that consume it, and re-exported here so the call sites and the catalog keep reading one name.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Oversampling factor.
Chosen, not defaulted — see the file doc block. Fixed at build time because changing it changes latency_samples(). [design parameter] default 4, range {2, 4, 8}.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Prototype cutoff, as a fraction of the BASE rate's Nyquist.
Lower buys alias rejection and costs passband; 0.96 is the balance measured in the file doc block. [design parameter] default 0.96, range 0.85 .. 1.0.
|
staticconstexpr |
Kaiser shape parameter of the prototype.
House policy value. [design parameter] default 8.0, range 6.0 .. 12.0.
|
staticconstexpr |
Prototype length.
Odd, and (kResamplerTaps − 1)/2 is divisible by kOversamplingFactor, which is what makes the base-rate group delay an exact integer rather than something to round. [design parameter] default 65, range 33 .. 257 (of the form 8k+1).
|
staticconstexpr |
The fixed internal reference.
Configurable only here, never at runtime: the absence of a threshold control is the point of the design. [design parameter] default −18 dBFS, range −24 .. −12 dBFS.
|
staticconstexpr |
Corner of the output transformer's low-frequency shelf.
A transformer loses level below its primary-inductance corner, so the shelf CUTS — which is also what keeps it out of the worst-case gain bound. [design parameter] default 60 Hz, range 20 .. 200 Hz.
|
staticconstexpr |
The transformer stage's supremum magnitude.
A low shelf with a non-positive gain and Q ≤ 1/√2 is monotone, so its peak is its high-frequency asymptote, exactly 1.
|
staticconstexpr |
Butterworth-flat, the shape with no shelf overshoot — so the stage's supremum magnitude is exactly 1 and the gain bound stays clean.
[design parameter] default 0.70710678, range 0.3 .. 0.7071.
|
staticconstexpr |
Tilt depth at transformer_amount = 1.
[design parameter] default 3 dB, range 0 .. 6 dB.