Two transformer brackets around one diode bridge, with a feedback sidechain. More...
#include <diode_bridge_compressor.hpp>
Public Member Functions | |
| void | prepare (double sample_rate) |
| Never allocates — every member is fixed-size POD. | |
| void | reset () |
| void | set_threshold_db (double db) |
| void | set_ratio (double r) |
| void | set_knee_db (double w) |
| void | set_attack_ms (double ms) |
| void | set_release_ms (double ms) |
| void | set_makeup_db (double db) |
| void | set_character (double character01) |
| 0..1 colour depth — the one macro. | |
| void | set_mix_percent (double percent) |
| Parallel dry/wet as a percentage, matching the catalog table's units. | |
| void | set_sc_hpf_hz (double hz) |
| void | set_auto_release (bool on) |
| Program-dependent dual-slope release. | |
| void | set_feedback (bool on) |
| On is the authentic topology: the detector senses the output. | |
| void | set_adaa (bool on) |
| int | latency_samples () const noexcept |
| Zero. | |
| double | gain_reduction_db () const |
| Smoothed gain reduction in dB (≤ 0) as of the last processed sample. | |
| GainReduction | gain_reduction () const noexcept |
| double | control_drive () const |
| The control drive x currently applied to the bridge. | |
| double | static_curve_db (double input_db) const |
| The static characteristic's gain reduction (≤ 0) for an input level in dB, ignoring the loop and the detector. | |
| double | static_curve_feedback_db (double input_db) const |
| The gain reduction the FEEDBACK loop settles at for a given input level — the fixed point of GR = static_curve(L_in + GR), solved by iteration because the soft knee makes the closed form piecewise. | |
| SampleType | process (SampleType input) |
| void | process_block (SampleType *io, int n) |
Static Public Member Functions | |
| static double | worst_case_gain () |
| The bound the Forge registry cites (series law 8): makeup ceiling times both brackets' peak gain. | |
Static Public Attributes | |
| static constexpr double | kThresholdDbMin = -40.0 |
| static constexpr double | kThresholdDbMax = 6.0 |
| static constexpr double | kRatioMin = 1.5 |
| static constexpr double | kRatioMax = 20.0 |
| static constexpr double | kAttackMsMin = 0.5 |
| static constexpr double | kAttackMsMax = 100.0 |
| static constexpr double | kReleaseMsMin = 50.0 |
| static constexpr double | kReleaseMsMax = 2000.0 |
| static constexpr double | kKneeDbMin = 0.0 |
| static constexpr double | kKneeDbMax = 18.0 |
| static constexpr double | kMakeupDbMax = 24.0 |
| static constexpr double | kScHpfHzMin = 20.0 |
| static constexpr double | kScHpfHzMax = 400.0 |
| static constexpr double | kLimitRatio = 20.0 |
| Ratio at or above which the limit (infinite-ratio) region engages. | |
| static constexpr double | kCtrlSmoothMs = 1.0 |
| Control-signal smoothing. | |
| static constexpr double | kAutoSlowFactor = 6.0 |
| Slow/fast release ratio of the auto (program-dependent) mode. | |
| static constexpr double | kSustainTauMs = 200.0 |
| Time constant of the "has compression been sustained" detector that blends the two auto-release slopes. | |
| static constexpr double | kSustainThresholdDb = 3.0 |
| How much gain reduction counts as sustained, for that blend. | |
| static constexpr double | kEnvelopeEpsilon = 1e-9 |
| Envelope-to-dB log guard. | |
Two transformer brackets around one diode bridge, with a feedback sidechain.
With feedback on, the detector senses the OUTPUT, so the gain computer's argument already contains the reduction it is about to apply. In the hard region that is a fixed point:
At L_in − thr = 6 dB and ρ = 4 the feed-forward answer is −4.5 dB and the feedback answer is −2.57 dB: less reduction, and an EFFECTIVE ratio of 1.75:1 rather than 4:1. That program-dependent softening is the documented signature of this lineage, not a calibration error — the manual ratio control reads "aggressive" only relative to a far gentler realised curve. static_curve_feedback_db() states the closed form so a caller can see the curve it is actually getting.
The loop closes through a ONE-SAMPLE delay in the control path only. The audio path is strictly feed-forward — gain multiply, two memoryless shapers, one-pole filters — so latency_samples() is 0 and the impulse response starts at n = 0.
The bridge can only attenuate (g ∈ (0, 1]), each bracket has peak gain exactly 1, and the only element that can boost is the makeup control. So
bounds the ratio of output peak to input peak at every setting and every input. The suite asserts it directly; it is not an estimate.
A true per-sample diode ODE solve (the distortion.hpp treatment) is overkill for a bridge whose operating region is near-linear by design; the closed-form divider plus a mild ADAA'd cubic captures the audible behaviour at a fraction of the cost. Transformer hysteresis (Jiles-Atherton) belongs to the tape tier — a line-level bracket runs far below a tape head's flux. Vari-mu (Fairchild 670 lineage) is a different gain element entirely, grid bias rather than diode current, and a separate catalog entry. Mid/side and true stereo linking are graph concerns; this class is mono, and a linked pair sums detectors at the graph layer.
|
inline |
The control drive x currently applied to the bridge.
|
inlinenoexcept |
|
inline |
Smoothed gain reduction in dB (≤ 0) as of the last processed sample.
|
inlinenoexcept |
Zero.
The audio path is a gain multiply, two memoryless ADAA shapers and one-pole filters; ADAA's half-sample group delay is sub-sample colouration and the one-poles add phase, not delay (series law 5).
|
inline |
Never allocates — every member is fixed-size POD.
Kept as prepare() rather than folded into the setters because the filters and followers need the sample rate before any of them is meaningful.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
Program-dependent dual-slope release.
|
inline |
0..1 colour depth — the one macro.
Drives the bridge's internal operating amplitude and both brackets' saturation depth together, which is what makes it one knob rather than three.
|
inline |
On is the authentic topology: the detector senses the output.
|
inline |
|
inline |
|
inline |
Parallel dry/wet as a percentage, matching the catalog table's units.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
The static characteristic's gain reduction (≤ 0) for an input level in dB, ignoring the loop and the detector.
Exposed so a caller or a test can plot the curve without running audio through it. This lineage's ratio control maps its top of range onto a true limiter, so the resolved slope — not the ratio — is what goes to the shared equation: 1/ρ normally, exactly 0 at and above kLimitRatio.
|
inline |
The gain reduction the FEEDBACK loop settles at for a given input level — the fixed point of GR = static_curve(L_in + GR), solved by iteration because the soft knee makes the closed form piecewise.
The iteration is AVERAGED (gr ← ½(gr + f(gr))), and that is not a refinement — the plain iteration does not converge at the top of the ratio control. f's slope is 1/ρ − 1, which is −0.95 at ρ = 20 and exactly −1 in the limit region, so plain iteration either crawls or oscillates forever between two values without ever narrowing. Averaging maps that slope to (1/ρ)/2 ∈ [0, ½], so the worst case is now the GENTLEST ratio rather than the harshest, and the limit region converges in a single step. Not an RT path — this is a curve query.
|
inlinestatic |
The bound the Forge registry cites (series law 8): makeup ceiling times both brackets' peak gain.
The bridge contributes at most 1.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Slow/fast release ratio of the auto (program-dependent) mode.
[design parameter] default 6.0, range 3.0 .. 10.0.
|
staticconstexpr |
Control-signal smoothing.
Short: its job is to keep β(x) continuous per sample so the memoryless-ADAA assumption holds, not to shape the ballistics — those are the detector's. [design parameter] default 1.0 ms, range 0.2 .. 5.0 ms.
|
staticconstexpr |
Envelope-to-dB log guard.
Far below the quietest envelope anyone measures (−180 dB) and far above float epsilon. [design parameter] default 1e-9, range 1e-12 .. 1e-6.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Ratio at or above which the limit (infinite-ratio) region engages.
Must be at or below kRatioMax for the control's top position to reach it. [design parameter] default 20, range 15 .. 25.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |
Time constant of the "has compression been sustained" detector that blends the two auto-release slopes.
[design parameter] default 200 ms, range 50 .. 1000 ms.
|
staticconstexpr |
How much gain reduction counts as sustained, for that blend.
[design parameter] default 3 dB, range 1 .. 12 dB.
|
staticconstexpr |
|
staticconstexpr |