Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
vactrol.hpp
Go to the documentation of this file.
1#pragma once
2
41
43
44#include <algorithm>
45#include <cmath>
46
47namespace pulp::signal {
48
51template <typename SampleType = float>
53public:
56 static constexpr double kMinRiseMs = 0.1;
57 static constexpr double kMaxRiseMs = 50.0;
58 static constexpr double kDefaultRiseMs = 2.0;
59
63 static constexpr double kMinFallMs = 10.0;
64 static constexpr double kMaxFallMs = 2000.0;
65 static constexpr double kDefaultFallMs = 200.0;
66
67 VactrolConditionerT() { update(); }
68
69 void prepare(double sample_rate) {
70 sample_rate_ = sample_rate > 0.0 ? sample_rate : sample_rate_;
71 update();
72 }
73
74 void set_rise_ms(double ms) {
75 rise_ms_ = std::clamp(ms, kMinRiseMs, kMaxRiseMs);
76 update();
77 }
78
79 void set_fall_ms(double ms) {
80 fall_ms_ = std::clamp(ms, kMinFallMs, kMaxFallMs);
81 update();
82 }
83
84 double rise_ms() const { return rise_ms_; }
85 double fall_ms() const { return fall_ms_; }
86
87 void reset() { control_ = 0.0; }
88
90 double control() const { return control_; }
91
94 double process(double target) {
95 // Do not admit a non-finite control into the recursive photoresistor
96 // state: std::clamp intentionally passes NaN through because every
97 // comparison is false. Resetting makes the following finite sample
98 // recover deterministically instead of keeping NaN forever.
99 if (!std::isfinite(target)) {
100 reset();
101 return 0.0;
102 }
103 const double clamped = std::clamp(target, 0.0, 1.0);
104 const double coefficient = clamped > control_ ? rise_a_ : fall_a_;
105 control_ = snap_to_zero(control_ + coefficient * (clamped - control_));
106 return control_;
107 }
108
109private:
110 void update() {
111 // The `max` guards a zero-or-negative sample rate; the time floor above
112 // already guards the ms side. Deliberately spelled out rather than
113 // routed through `units::ms_to_onepole_coef` so that this stays
114 // bit-identical to the coefficient `LowpassGateT` has always used.
115 rise_a_ = 1.0 - std::exp(-1.0 / std::max(0.001 * rise_ms_ * sample_rate_, 1e-9));
116 fall_a_ = 1.0 - std::exp(-1.0 / std::max(0.001 * fall_ms_ * sample_rate_, 1e-9));
117 }
118
119 double sample_rate_ = 44100.0;
120 double rise_ms_ = kDefaultRiseMs;
121 double fall_ms_ = kDefaultFallMs;
122 double rise_a_ = 0.0;
123 double fall_a_ = 0.0;
124 double control_ = 0.0;
125};
126
129
130} // namespace pulp::signal
The asymmetric one-pole that lags a control signal the way a photoresistor lags its LED.
Definition vactrol.hpp:52
static constexpr double kMinFallMs
Definition vactrol.hpp:63
double rise_ms() const
Definition vactrol.hpp:84
void reset()
Definition vactrol.hpp:87
static constexpr double kMaxFallMs
Definition vactrol.hpp:64
double fall_ms() const
Definition vactrol.hpp:85
void set_fall_ms(double ms)
Definition vactrol.hpp:79
void set_rise_ms(double ms)
Definition vactrol.hpp:74
double process(double target)
Advances one sample toward target (clamped to [0, 1]) and returns the conditioned control.
Definition vactrol.hpp:94
static constexpr double kMaxRiseMs
Definition vactrol.hpp:57
static constexpr double kDefaultRiseMs
Definition vactrol.hpp:58
static constexpr double kDefaultFallMs
Definition vactrol.hpp:65
double control() const
Current conditioned control in [0, 1] without advancing.
Definition vactrol.hpp:90
static constexpr double kMinRiseMs
Definition vactrol.hpp:56
void prepare(double sample_rate)
Definition vactrol.hpp:69
VactrolConditionerT()
Definition vactrol.hpp:67
Definition additive_bank.hpp:218
VactrolConditionerT< double > VactrolConditioner64
Definition vactrol.hpp:128
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ e
Definition formant_filter_bank.hpp:20
VactrolConditionerT< float > VactrolConditioner
Definition vactrol.hpp:127