Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
latency_aware_control_smoother.hpp
Go to the documentation of this file.
1#pragma once
2
23
24#include <cassert>
25#include <cmath>
26
27namespace pulp::signal {
28
30public:
33 enum class Domain { linear, semitone };
34
35 struct Config {
37 float attack_seconds = 0.05f; // toward larger values
38 float release_seconds = 0.05f; // toward smaller values
39 };
40
45 void prepare(double sample_rate, const Config& config) {
46 assert(sample_rate > 0.0);
47 config_ = config;
48 // Per-sample retention coefficients; tau == 0 snaps immediately.
49 attack_k_ = coefficient(config.attack_seconds, sample_rate);
50 release_k_ = coefficient(config.release_seconds, sample_rate);
51 current_ = 0.0;
52 target_ = 0.0;
53 }
54
56 void set_target(float value) { target_ = static_cast<double>(value); }
57
59 void set_immediate(float value) {
60 target_ = static_cast<double>(value);
61 current_ = target_;
62 }
63
64 float target() const { return static_cast<float>(target_); }
65 float current() const { return static_cast<float>(current_); }
66
70 float value_at(int offset) const {
71 return static_cast<float>(project(offset));
72 }
73
76 float ratio_at(int offset) const {
77 return std::exp2(static_cast<float>(project(offset)) / 12.0f);
78 }
79
81 float advance(int samples) {
82 current_ = project(samples);
83 return static_cast<float>(current_);
84 }
85
86 bool is_settled(float tolerance) const {
87 return std::abs(current_ - target_) <= static_cast<double>(tolerance);
88 }
89
90private:
91 static double coefficient(float seconds, double sample_rate) {
92 if (seconds <= 0.0f) return 0.0;
93 // Standard one-pole: value covers ~63% of the step per tau.
94 return std::exp(-1.0 / (static_cast<double>(seconds) * sample_rate));
95 }
96
97 double project(int offset) const {
98 const double k = target_ > current_ ? attack_k_ : release_k_;
99 if (k <= 0.0) return offset >= 0 ? target_ : current_;
100 return target_ + (current_ - target_) * std::pow(k, static_cast<double>(offset));
101 }
102
103 Config config_;
104 double attack_k_ = 0.0;
105 double release_k_ = 0.0;
106 double current_ = 0.0;
107 double target_ = 0.0;
108};
109
110} // namespace pulp::signal
Definition latency_aware_control_smoother.hpp:29
Domain
Value domain.
Definition latency_aware_control_smoother.hpp:33
@ linear
Definition latency_aware_control_smoother.hpp:33
@ semitone
Definition latency_aware_control_smoother.hpp:33
void set_immediate(float value)
Jump immediately (e.g. on reset/preset load).
Definition latency_aware_control_smoother.hpp:59
float target() const
Definition latency_aware_control_smoother.hpp:64
float ratio_at(int offset) const
value_at in the ratio domain: 2^(semitones / 12).
Definition latency_aware_control_smoother.hpp:76
float advance(int samples)
Advance the stream position by samples and return the new value.
Definition latency_aware_control_smoother.hpp:81
float value_at(int offset) const
Value offset samples ahead of (or, if negative, behind) the current position, without advancing state...
Definition latency_aware_control_smoother.hpp:70
bool is_settled(float tolerance) const
Definition latency_aware_control_smoother.hpp:86
void prepare(double sample_rate, const Config &config)
RT contract: fixed-state and allocation-free.
Definition latency_aware_control_smoother.hpp:45
float current() const
Definition latency_aware_control_smoother.hpp:65
void set_target(float value)
RT-safe; takes effect from the current stream position.
Definition latency_aware_control_smoother.hpp:56
Definition additive_bank.hpp:218
Definition latency_aware_control_smoother.hpp:35
float attack_seconds
Definition latency_aware_control_smoother.hpp:37
float release_seconds
Definition latency_aware_control_smoother.hpp:38
Domain domain
Definition latency_aware_control_smoother.hpp:36