81 if (
length <= 0)
return 1.0f;
82 return static_cast<float>(
pos) /
static_cast<float>(
length);
89 return static_cast<long long>(std::lround(std::max(0.0, ms) * 0.001 * sample_rate));
99template <
typename SampleType =
float>
107 sample_rate_ = sample_rate > 0.0 ? sample_rate : 1.0;
112 void set_delay_ms(
double ms) { delay_ms_ = std::max(0.0, ms); update_lengths_(); }
113 void set_attack_ms(
double ms) { attack_ms_ = std::max(0.0, ms); update_lengths_(); }
114 void set_hold_ms(
double ms) { hold_ms_ = std::max(0.0, ms); update_lengths_(); }
115 void set_decay_ms(
double ms) { decay_ms_ = std::max(0.0, ms); update_lengths_(); }
116 void set_release_ms(
double ms) { release_ms_ = std::max(0.0, ms); update_lengths_(); }
123 sustain_ = std::clamp(level, SampleType{0}, SampleType{1});
131 loop_count_ = std::clamp(count, 0,
kMaxLoops);
135 stage_ = Stage::idle;
136 level_ = SampleType{0};
137 peak_ = SampleType{1};
138 start_ = SampleType{0};
139 release_start_ = SampleType{0};
145 peak_ = std::clamp(velocity, SampleType{0}, SampleType{1});
151 if (!gate_driven_ || stage_ == Stage::idle || stage_ == Stage::release)
return;
152 release_start_ = level_;
153 stage_ = Stage::release;
154 clock_.restart(release_samples_);
155 if (release_samples_ <= 0) {
159 stage_ = Stage::idle;
160 level_ = SampleType{0};
166 level_ = level_at_();
173 bool active()
const {
return stage_ != Stage::idle; }
177 void update_lengths_() {
185 long long shape_length_()
const {
186 return delay_samples_ + attack_samples_ + hold_samples_ + decay_samples_;
189 SampleType sustain_level_()
const {
190 return has_sustain_ ? sustain_ * peak_ : SampleType{0};
193 void begin_shape_() {
198 void enter_delay_() {
199 if (delay_samples_ <= 0) {
203 stage_ = Stage::delay;
204 clock_.restart(delay_samples_);
207 void enter_attack_() {
208 if (attack_samples_ <= 0) {
213 stage_ = Stage::attack;
214 clock_.restart(attack_samples_);
218 if (hold_samples_ <= 0) {
222 stage_ = Stage::hold;
223 clock_.restart(hold_samples_);
226 void enter_decay_() {
227 if (decay_samples_ <= 0) {
228 level_ = sustain_level_();
229 enter_after_decay_();
232 stage_ = Stage::decay;
233 clock_.restart(decay_samples_);
236 void enter_after_decay_() {
239 if (has_sustain_ && !loop_) {
240 stage_ = Stage::sustain;
250 if (loop_ && shape_length_() > 0) {
252 if (loop_count_ == 0 || loops_done_ < loop_count_) {
258 stage_ = Stage::idle;
259 level_ = SampleType{0};
263 SampleType level_at_()
const {
264 const float p = clock_.progress();
274 return start_ + (peak_ - start_)
275 *
static_cast<SampleType
>(
curve_rise(p, attack_curve_));
279 const SampleType floor_level = sustain_level_();
280 return floor_level + (peak_ - floor_level)
281 *
static_cast<SampleType
>(
curve_fall(p, decay_curve_));
284 return sustain_level_();
286 return release_start_ *
static_cast<SampleType
>(
curve_fall(p, release_curve_));
289 return SampleType{0};
296 if (clock_.advance()) enter_attack_();
299 if (clock_.advance()) enter_hold_();
302 if (clock_.advance()) enter_decay_();
305 if (clock_.advance()) enter_after_decay_();
308 if (clock_.advance()) {
309 stage_ = Stage::idle;
310 level_ = SampleType{0};
321 EnvelopeStageClock clock_{};
322 double sample_rate_ = 48000.0;
323 double delay_ms_ = 0.0;
324 double attack_ms_ = 10.0;
325 double hold_ms_ = 0.0;
326 double decay_ms_ = 100.0;
327 double release_ms_ = 200.0;
328 long long delay_samples_ = 0;
329 long long attack_samples_ = 480;
330 long long hold_samples_ = 0;
331 long long decay_samples_ = 4800;
332 long long release_samples_ = 9600;
333 SampleType level_ = SampleType{0};
334 SampleType peak_ = SampleType{1};
335 SampleType start_ = SampleType{0};
336 SampleType release_start_ = SampleType{0};
337 SampleType sustain_ = SampleType{0.7};
338 float attack_curve_ = 0.0f;
339 float decay_curve_ = 0.0f;
340 float release_curve_ = 0.0f;
343 Stage stage_ = Stage::idle;
344 bool has_sustain_ =
true;
345 bool gate_driven_ =
true;
359template <
typename SampleType =
float>
363 engine_.set_has_sustain(
true);
364 engine_.set_sustain(SampleType{1});
365 engine_.set_gate_driven(
true);
366 engine_.set_hold_ms(0.0);
367 engine_.set_decay_ms(0.0);
368 engine_.prepare(sample_rate);
380 const float curve =
static_cast<float>(std::clamp(
c, 0.0, 1.0));
381 engine_.set_attack_curve(-curve);
382 engine_.set_release_curve(curve);
388 if (on == gate_)
return;
390 if (on) engine_.trigger(SampleType{1});
391 else engine_.release();
404 SampleType
next() {
return engine_.next(); }
405 SampleType
current()
const {
return engine_.current(); }
407 bool active()
const {
return engine_.active(); }
425template <
typename SampleType =
float>
429 engine_.set_has_sustain(
false);
430 engine_.set_gate_driven(
false);
431 engine_.set_hold_ms(0.0);
432 engine_.prepare(sample_rate);
441 const float curve =
static_cast<float>(std::clamp(
c, 0.0, 1.0));
442 engine_.set_attack_curve(-curve);
443 engine_.set_decay_curve(curve);
447 void set_loop(
bool on,
int count = 0) { engine_.set_loop(on, count); }
449 void trigger(SampleType velocity = SampleType{1}) { engine_.trigger(velocity); }
454 SampleType
next() {
return engine_.next(); }
455 SampleType
current()
const {
return engine_.current(); }
457 bool active()
const {
return engine_.active(); }
475template <
typename SampleType =
float>
479 engine_.set_has_sustain(
false);
480 engine_.set_gate_driven(
false);
481 engine_.prepare(sample_rate);
490 const float curve =
static_cast<float>(std::clamp(
c, 0.0, 1.0));
491 engine_.set_attack_curve(-curve);
492 engine_.set_decay_curve(curve);
494 void set_loop(
bool on,
int count = 0) { engine_.set_loop(on, count); }
496 void trigger(SampleType velocity = SampleType{1}) { engine_.trigger(velocity); }
501 SampleType
next() {
return engine_.next(); }
502 SampleType
current()
const {
return engine_.current(); }
504 bool active()
const {
return engine_.active(); }
528template <
typename SampleType =
float>
532 engine_.set_has_sustain(
true);
533 engine_.set_gate_driven(
true);
534 engine_.prepare(sample_rate);
541 void set_sustain(SampleType level) { engine_.set_sustain(level); }
549 const float curve =
static_cast<float>(std::clamp(
c, 0.0, 1.0));
550 engine_.set_attack_curve(-curve);
551 engine_.set_decay_curve(curve);
552 engine_.set_release_curve(curve);
555 void set_loop(
bool on,
int count = 0) { engine_.set_loop(on, count); }
557 void note_on(SampleType velocity = SampleType{1}) { engine_.trigger(velocity); }
563 SampleType
next() {
return engine_.next(); }
564 SampleType
current()
const {
return engine_.current(); }
566 bool active()
const {
return engine_.active(); }
585template <
typename SampleType =
float>
589 engine_.set_has_sustain(
false);
590 engine_.set_gate_driven(
false);
591 engine_.prepare(sample_rate);
599 void set_sustain(SampleType level) { engine_.set_sustain(level); }
603 const float curve =
static_cast<float>(std::clamp(
c, 0.0, 1.0));
604 engine_.set_attack_curve(-curve);
605 engine_.set_decay_curve(curve);
606 engine_.set_release_curve(curve);
608 void set_loop(
bool on,
int count = 0) { engine_.set_loop(on, count); }
611 void set_depth(SampleType d) { depth_ = std::clamp(d, SampleType{-1}, SampleType{1}); }
613 void trigger(SampleType velocity = SampleType{1}) {
614 legacy_scaled_next_ =
false;
615 engine_.set_has_sustain(
false);
616 engine_.set_gate_driven(
false);
617 engine_.trigger(velocity);
620 legacy_scaled_next_ =
true;
621 engine_.set_has_sustain(
true);
622 engine_.set_gate_driven(
true);
623 engine_.trigger(SampleType{1});
630 const SampleType level = engine_.next();
631 return legacy_scaled_next_ ? level * depth_ : level;
636 SampleType
modulation()
const {
return engine_.current() * depth_; }
638 SampleType
current()
const {
return engine_.current(); }
640 return legacy_scaled_next_ ? engine_.current() * depth_ : engine_.current();
642 bool active()
const {
return engine_.active(); }
647 SampleType depth_ = SampleType{1};
648 bool legacy_scaled_next_ =
false;
670template <
typename SampleType =
float>
685 fast_.prepare(sample_rate);
686 slow_.prepare(sample_rate);
691 fast_ms_ = std::max(SampleType{0.01}, ms);
696 slow_ms_ = std::max(SampleType{0.01}, ms);
706 const SampleType magnitude = std::abs(input);
707 const SampleType f = fast_.process(magnitude);
708 const SampleType s = slow_.process(magnitude);
712 const SampleType denominator = std::max(s, SampleType{1
e-9});
713 return std::max(SampleType{0}, (f - s) / denominator);
717 void apply_times_() {
727 BallisticsFilterT<SampleType> fast_{};
728 BallisticsFilterT<SampleType> slow_{};
Peak/RMS envelope follower with independent attack and release curves.
Attack-Decay one-shot, trigger-driven.
Definition envelope.hpp:426
SampleType value() const
Definition envelope.hpp:456
bool active() const
Definition envelope.hpp:457
SampleType next()
Definition envelope.hpp:454
void set_attack_ms(double ms)
Definition envelope.hpp:435
void set_curve(double c)
Definition envelope.hpp:440
void set_attack_curve(float c)
Definition envelope.hpp:437
void gate_on()
Definition envelope.hpp:450
void set_decay_ms(double ms)
Definition envelope.hpp:436
void trigger(SampleType velocity=SampleType{1})
Definition envelope.hpp:449
void reset()
Definition envelope.hpp:452
int loops_completed() const
Definition envelope.hpp:458
EnvelopeStage stage() const
Definition envelope.hpp:459
void set_loop(bool on, int count=0)
Definition envelope.hpp:447
SampleType current() const
Definition envelope.hpp:455
void set_decay_curve(float c)
Definition envelope.hpp:438
void prepare(double sample_rate)
Definition envelope.hpp:428
void gate_off()
Definition envelope.hpp:451
Attack-Hold-Decay one-shot, trigger-driven.
Definition envelope.hpp:476
SampleType current() const
Definition envelope.hpp:502
void reset()
Definition envelope.hpp:499
void set_curve(double c)
Definition envelope.hpp:489
void prepare(double sample_rate)
Definition envelope.hpp:478
void gate_off()
Definition envelope.hpp:498
void set_attack_curve(float c)
Definition envelope.hpp:487
void set_attack_ms(double ms)
Definition envelope.hpp:484
void gate_on()
Definition envelope.hpp:497
bool active() const
Definition envelope.hpp:504
SampleType next()
Definition envelope.hpp:501
void trigger(SampleType velocity=SampleType{1})
Definition envelope.hpp:496
SampleType value() const
Definition envelope.hpp:503
void set_loop(bool on, int count=0)
Definition envelope.hpp:494
EnvelopeStage stage() const
Definition envelope.hpp:506
void set_hold_ms(double ms)
Definition envelope.hpp:485
int loops_completed() const
Definition envelope.hpp:505
void set_decay_curve(float c)
Definition envelope.hpp:488
void set_decay_ms(double ms)
Definition envelope.hpp:486
Attack-Release, gate-driven.
Definition envelope.hpp:360
void set_attack_ms(double ms)
Definition envelope.hpp:371
void gate_on()
Convenience spelling with exactly the same level-before-advance sample ordering as gate(true).
Definition envelope.hpp:396
bool active() const
Definition envelope.hpp:407
void set_release_ms(double ms)
Definition envelope.hpp:372
SampleType next()
Definition envelope.hpp:404
SampleType current() const
Definition envelope.hpp:405
void reset()
Definition envelope.hpp:399
SampleType value() const
Definition envelope.hpp:406
void gate_off()
Definition envelope.hpp:397
EnvelopeStage stage() const
Definition envelope.hpp:408
void gate(bool on)
Gate edges drive the envelope; repeated calls with the same state are no-ops, so this can be called e...
Definition envelope.hpp:387
void prepare(double sample_rate)
Definition envelope.hpp:362
void set_release_curve(float c)
Definition envelope.hpp:374
void set_curve(double c)
Round-2 compatibility curve: 0 is linear and 1 is the strongest capacitor-like attack/release pair.
Definition envelope.hpp:379
void set_attack_curve(float c)
Definition envelope.hpp:373
void set_attack_ms(SampleType ms)
Definition ballistics_filter.hpp:46
void set_release_ms(SampleType ms)
Definition ballistics_filter.hpp:53
@ rms
Definition ballistics_filter.hpp:33
Delay-Attack-Hold-Decay-Sustain-Release with per-stage curves and velocity.
Definition envelope.hpp:529
void set_release_curve(float c)
Definition envelope.hpp:546
void set_decay_curve(float c)
Definition envelope.hpp:545
void gate_on()
Definition envelope.hpp:559
void reset()
Definition envelope.hpp:561
void set_hold_ms(double ms)
Definition envelope.hpp:539
EnvelopeStage stage() const
Definition envelope.hpp:568
void set_attack_ms(double ms)
Definition envelope.hpp:538
void set_sustain(SampleType level)
Definition envelope.hpp:541
void set_delay_ms(double ms)
Definition envelope.hpp:537
SampleType current() const
Definition envelope.hpp:564
void set_decay_ms(double ms)
Definition envelope.hpp:540
void set_release_ms(double ms)
Definition envelope.hpp:542
SampleType next()
Definition envelope.hpp:563
bool active() const
Definition envelope.hpp:566
void set_attack_curve(float c)
Definition envelope.hpp:544
void note_off()
Definition envelope.hpp:558
void prepare(double sample_rate)
Definition envelope.hpp:531
void set_curve(double c)
Definition envelope.hpp:548
int loops_completed() const
Definition envelope.hpp:567
void set_loop(bool on, int count=0)
Definition envelope.hpp:555
void gate_off()
Definition envelope.hpp:560
void note_on(SampleType velocity=SampleType{1})
Definition envelope.hpp:557
SampleType value() const
Definition envelope.hpp:565
Delay-Attack-Hold-Decay modulation envelope with a signed depth.
Definition envelope.hpp:586
void reset()
Definition envelope.hpp:626
void set_curve(double c)
Definition envelope.hpp:602
void set_depth(SampleType d)
Signed, -1..+1. Applied by modulation(), not by next().
Definition envelope.hpp:611
void set_decay_ms(double ms)
Definition envelope.hpp:597
void set_release_ms(double ms)
Definition envelope.hpp:598
void set_attack_ms(double ms)
Definition envelope.hpp:595
SampleType next()
Raw unipolar level, 0..1.
Definition envelope.hpp:629
SampleType modulation() const
The last next() scaled by the signed depth — the value to hand a modulation destination.
Definition envelope.hpp:636
bool active() const
Definition envelope.hpp:642
void set_loop(bool on, int count=0)
Definition envelope.hpp:608
void set_attack_curve(float c)
Definition envelope.hpp:600
void set_delay_ms(double ms)
Definition envelope.hpp:594
void set_sustain(SampleType level)
Definition envelope.hpp:599
void gate_on()
Definition envelope.hpp:619
SampleType value() const
Definition envelope.hpp:639
SampleType current() const
Definition envelope.hpp:638
void prepare(double sample_rate)
Definition envelope.hpp:588
void set_hold_ms(double ms)
Definition envelope.hpp:596
EnvelopeStage stage() const
Definition envelope.hpp:643
void set_decay_curve(float c)
Definition envelope.hpp:601
void gate_off()
Definition envelope.hpp:625
void trigger(SampleType velocity=SampleType{1})
Definition envelope.hpp:613
Level-independent transient detector: the normalized excess of a fast envelope follower over a slow o...
Definition envelope.hpp:671
static constexpr float kDefaultSlowMs
Definition envelope.hpp:676
void set_fast_ms(SampleType ms)
Definition envelope.hpp:690
void set_slow_ms(SampleType ms)
Definition envelope.hpp:695
void reset()
Definition envelope.hpp:700
static constexpr float kDefaultFastMs
Definition envelope.hpp:674
void prepare(SampleType sample_rate)
Definition envelope.hpp:678
SampleType process(SampleType input)
Definition envelope.hpp:705
The DAHDSR superset state machine.
Definition envelope.hpp:100
void set_attack_curve(float c)
Definition envelope.hpp:118
void set_hold_ms(double ms)
Definition envelope.hpp:114
int loops_completed() const
Definition envelope.hpp:174
void set_loop(bool on, int count)
Definition envelope.hpp:129
void set_delay_ms(double ms)
Definition envelope.hpp:112
Stage stage() const
Definition envelope.hpp:172
SampleType current() const
Definition envelope.hpp:171
void trigger(SampleType velocity)
Definition envelope.hpp:144
void set_release_ms(double ms)
Definition envelope.hpp:116
void set_has_sustain(bool on)
Definition envelope.hpp:126
void set_release_curve(float c)
Definition envelope.hpp:120
static constexpr int kMaxLoops
Definition envelope.hpp:104
EnvelopeStage Stage
Definition envelope.hpp:102
void set_decay_ms(double ms)
Definition envelope.hpp:115
void release()
Definition envelope.hpp:150
void set_gate_driven(bool on)
Definition envelope.hpp:127
SampleType next()
Definition envelope.hpp:165
void set_sustain(SampleType level)
Definition envelope.hpp:122
void prepare(double sample_rate)
Definition envelope.hpp:106
void set_decay_curve(float c)
Definition envelope.hpp:119
bool active() const
Definition envelope.hpp:173
void reset()
Definition envelope.hpp:134
void set_attack_ms(double ms)
Definition envelope.hpp:113
long long envelope_ms_to_samples(double ms, double sample_rate)
Definition envelope.hpp:88
Definition additive_bank.hpp:218
float curve_fall(float p, float curve)
Shape a falling stage: 1 -> 0 over p.
Definition mod_tools.hpp:70
ModEnvT< float > ModEnv
Definition envelope.hpp:651
@ c
Definition spectrum_trace.hpp:35
EnvelopeStage
Stage of any envelope in this header.
Definition envelope.hpp:55
@ sustain
Definition envelope.hpp:61
@ release
Definition envelope.hpp:62
@ decay
Definition envelope.hpp:60
@ delay
Definition envelope.hpp:57
@ hold
Definition envelope.hpp:59
@ idle
Definition envelope.hpp:56
@ attack
Definition envelope.hpp:58
AdT< double > Ad64
Definition envelope.hpp:466
ModEnvT< double > ModEnv64
Definition envelope.hpp:652
AhdT< float > Ahd
Definition envelope.hpp:512
DahdsrT< double > Dahdsr64
Definition envelope.hpp:575
float curve_rise(float p, float curve)
Shape a rising stage: 0 -> 1 over p, with curve in [-1, +1].
Definition mod_tools.hpp:65
@ e
Definition formant_filter_bank.hpp:20
ArT< double > Ar64
Definition envelope.hpp:416
AhdT< double > Ahd64
Definition envelope.hpp:513
TransientDetectorT< float > TransientDetector
Definition envelope.hpp:733
AdT< float > Ad
Definition envelope.hpp:465
TransientDetectorT< double > TransientDetector64
Definition envelope.hpp:734
ArT< float > Ar
Definition envelope.hpp:415
DahdsrT< float > Dahdsr
Definition envelope.hpp:574
@ p
Definition input_events.hpp:40
Sample counter for one envelope stage.
Definition envelope.hpp:71
bool advance()
Definition envelope.hpp:85
float progress() const
Definition envelope.hpp:80
long long pos
Definition envelope.hpp:72
long long length
Definition envelope.hpp:73
void restart(long long len)
Definition envelope.hpp:75