42 double db() const noexcept {
54 return std::pow(10.0, -db_ / 20.0);
72template <
typename SampleType =
float>
91 void synchronize_detector_state(SampleType
state)
noexcept {
110 left_.prepare(sample_rate);
111 right_.prepare(sample_rate);
115 left_.set_attack_ms(ms);
116 right_.set_attack_ms(ms);
120 left_.set_release_ms(ms);
121 right_.set_release_ms(ms);
125 left_.set_mode(mode);
126 right_.set_mode(mode);
130 if (!std::isfinite(
static_cast<double>(amount)))
132 const SampleType next = std::clamp(amount, SampleType{0}, SampleType{1});
133 if (next == SampleType{1} && link_ != SampleType{1})
134 synchronize_linked_state();
138 SampleType
link() const noexcept {
143 if (link_ == SampleType{0})
144 return {left_.process(
left), right_.process(
right)};
146 if (!std::isfinite(
static_cast<double>(
left)) ||
147 !std::isfinite(
static_cast<double>(
right))) {
149 return {SampleType{0}, SampleType{0}};
152 const SampleType left_magnitude = std::abs(
left);
153 const SampleType right_magnitude = std::abs(
right);
154 const SampleType shared = std::max(left_magnitude, right_magnitude);
155 const SampleType left_detector = left_magnitude + link_ * (shared - left_magnitude);
156 const SampleType right_detector = right_magnitude + link_ * (shared - right_magnitude);
157 const SampleType left_envelope = left_.process(left_detector);
158 const SampleType right_envelope = right_.process(right_detector);
159 if (link_ == SampleType{1}) {
160 const SampleType linked_state =
161 std::max(left_.detector_state(), right_.detector_state());
162 left_.synchronize_detector_state(linked_state);
163 right_.synchronize_detector_state(linked_state);
164 const SampleType linked_envelope = std::max(left_envelope, right_envelope);
165 return {linked_envelope, linked_envelope};
167 return {left_envelope, right_envelope};
171 return {left_.current(), right_.current()};
180 void synchronize_linked_state() noexcept {
181 const SampleType linked_state =
182 std::max(left_.detector_state(), right_.detector_state());
183 left_.synchronize_detector_state(linked_state);
184 right_.synchronize_detector_state(linked_state);
187 EnvelopeFollowerT<SampleType> left_{};
188 EnvelopeFollowerT<SampleType> right_{};
189 SampleType link_ = SampleType{1};
Peak/RMS envelope follower with independent attack and release curves.
static SampleType exact_coefficient_for_time_ms(SampleType ms, SampleType sample_rate)
Definition ballistics_filter.hpp:146
BallisticsFilterT()=default
TimeConvention
Definition ballistics_filter.hpp:34
Mode
Definition ballistics_filter.hpp:33
float detector_state() const noexcept
Definition ballistics_filter.hpp:161
void synchronize_detector_state(SampleType state) noexcept
Definition ballistics_filter.hpp:165
Discoverable name for Pulp's established peak/RMS envelope follower.
Definition dynamics_contract.hpp:73
friend class StereoEnvelopeFollowerT
Definition dynamics_contract.hpp:85
static SampleType coefficient_for_time_ms(SampleType ms, SampleType sample_rate)
Definition dynamics_contract.hpp:80
EnvelopeFollowerT()
Definition dynamics_contract.hpp:78
BallisticsFilterT< SampleType > Base
Definition dynamics_contract.hpp:75
typename Base::Mode Mode
Definition dynamics_contract.hpp:76
double linear_gain() const noexcept
The equivalent linear amplitude multiplier in [0, 1]; infinite attenuation maps to zero.
Definition dynamics_contract.hpp:53
double signed_db() const noexcept
The equivalent gain value for addition in the dB domain.
Definition dynamics_contract.hpp:47
double db() const noexcept
Non-negative attenuation magnitude in decibels.
Definition dynamics_contract.hpp:42
static GainReduction from_signed_db(double signed_db) noexcept
Adapt a signed gain value, where attenuation is negative dB.
Definition dynamics_contract.hpp:32
GainReduction() noexcept=default
static GainReduction from_magnitude_db(double magnitude_db) noexcept
Adapt an attenuation magnitude, where reduction is positive dB.
Definition dynamics_contract.hpp:37
Two-channel envelope follower with a detector-domain stereo link.
Definition dynamics_contract.hpp:105
void reset()
Definition dynamics_contract.hpp:174
void set_mode(Mode mode)
Definition dynamics_contract.hpp:124
typename EnvelopeFollowerT< SampleType >::Mode Mode
Definition dynamics_contract.hpp:107
std::array< SampleType, 2 > current() const
Definition dynamics_contract.hpp:170
void set_release_ms(SampleType ms)
Definition dynamics_contract.hpp:119
SampleType link() const noexcept
Definition dynamics_contract.hpp:138
void set_attack_ms(SampleType ms)
Definition dynamics_contract.hpp:114
std::array< SampleType, 2 > process(SampleType left, SampleType right)
Definition dynamics_contract.hpp:142
void set_link(SampleType amount)
Definition dynamics_contract.hpp:129
void prepare(SampleType sample_rate)
Definition dynamics_contract.hpp:109
Definition additive_bank.hpp:218
StereoEnvelopeFollowerT< float > StereoEnvelopeFollower
Definition dynamics_contract.hpp:192
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
float magnitude_db(const BiquadT< SampleType > &filter, double freq_hz, double sample_rate)
Ask a live filter what it looks like: the magnitude, in dB, that this BiquadT is applying at freq_hz ...
Definition frequency_response.hpp:130
EnvelopeFollowerT< double > EnvelopeFollower64
Definition dynamics_contract.hpp:97
@ independent
X and Y advance only on their own clocks and never on each other's.
Definition cartesian_walk.hpp:20
EnvelopeFollowerT< float > EnvelopeFollower
Definition dynamics_contract.hpp:96
StereoEnvelopeFollowerT< double > StereoEnvelopeFollower64
Definition dynamics_contract.hpp:193
DynamicsStereoLink
Shared policy for dynamics processors with two detector channels.
Definition dynamics_contract.hpp:15
@ peak_linked
Definition dynamics_contract.hpp:15
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48