Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
chorus.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <algorithm>
5#include <cmath>
6
7namespace pulp::signal {
8
9// Stereo chorus effect using modulated delay lines.
10//
11// RT contract: `prepare()` allocates delay-line storage. After preparation,
12// setters, `process()`, and `reset()` allocate no memory.
13template <typename SampleType = float>
14class ChorusT {
15public:
16 void prepare(SampleType sample_rate) {
17 if (!std::isfinite(sample_rate) || sample_rate <= SampleType{0.0f})
18 sample_rate = SampleType{44100.0f};
19
20 sample_rate_ = sample_rate;
21 int max_delay =
22 std::max(1, static_cast<int>(
23 sample_rate * max_delay_ms * SampleType{0.001f}));
24 delay_l_.prepare(max_delay);
25 delay_r_.prepare(max_delay);
26 prepared_ = true;
27 }
28
29 void set_rate(SampleType hz) {
30 rate_ = std::isfinite(hz) ? std::max(SampleType{0.0f}, hz) : SampleType{0.0f};
31 } // LFO rate (0.1-5 Hz typical)
32 void set_depth(SampleType d) {
33 depth_ = std::isfinite(d)
34 ? std::clamp(d, SampleType{0.0f}, SampleType{1.0f})
35 : SampleType{0.0f};
36 } // Modulation depth (0-1)
37 void set_mix(SampleType m) {
38 mix_ = std::isfinite(m)
39 ? std::clamp(m, SampleType{0.0f}, SampleType{1.0f})
40 : SampleType{0.0f};
41 } // Dry/wet mix (0-1)
42 void set_delay_ms(SampleType ms) {
43 delay_ms_ = std::isfinite(ms)
44 ? std::clamp(ms, SampleType{0.0f}, max_delay_ms)
45 : SampleType{0.0f};
46 } // Center delay (5-30ms typical)
47
48 struct StereoSample { SampleType left, right; };
49
50 StereoSample process(SampleType input) {
51 if (!prepared_)
52 return {input, input};
53
54 SampleType lfo_l = std::sin(SampleType{2.0f} * pi * phase_);
55 SampleType lfo_r = std::sin(SampleType{2.0f} * pi * phase_ +
56 pi * SampleType{0.5f}); // 90° offset
57
58 SampleType delay_samples = delay_ms_ * sample_rate_ * SampleType{0.001f};
59 SampleType mod_l = delay_samples + lfo_l * depth_ * delay_samples *
60 SampleType{0.5f};
61 SampleType mod_r = delay_samples + lfo_r * depth_ * delay_samples *
62 SampleType{0.5f};
63
64 delay_l_.push(input);
65 delay_r_.push(input);
66
67 SampleType wet_l = delay_l_.read(mod_l);
68 SampleType wet_r = delay_r_.read(mod_r);
69
70 phase_ += rate_ / sample_rate_;
71 if (phase_ >= SampleType{1.0f})
72 phase_ = std::fmod(phase_, SampleType{1.0f});
73
74 SampleType dry = SampleType{1.0f} - mix_;
75 return {input * dry + wet_l * mix_,
76 input * dry + wet_r * mix_};
77 }
78
79 void reset() {
80 delay_l_.reset();
81 delay_r_.reset();
82 phase_ = 0;
83 }
84
85private:
86 static constexpr SampleType pi = SampleType{3.14159265358979323846f};
87 static constexpr SampleType max_delay_ms = SampleType{50.0f};
88 DelayLineT<SampleType> delay_l_, delay_r_;
89 SampleType sample_rate_ = SampleType{44100.0f};
90 SampleType rate_ = SampleType{1.0f};
91 SampleType depth_ = SampleType{0.5f};
92 SampleType mix_ = SampleType{0.5f};
93 SampleType delay_ms_ = SampleType{15.0f};
94 SampleType phase_ = 0;
95 bool prepared_ = false;
96};
97
100
101} // namespace pulp::signal
Definition chorus.hpp:14
void set_delay_ms(SampleType ms)
Definition chorus.hpp:42
StereoSample process(SampleType input)
Definition chorus.hpp:50
void set_mix(SampleType m)
Definition chorus.hpp:37
void set_rate(SampleType hz)
Definition chorus.hpp:29
void prepare(SampleType sample_rate)
Definition chorus.hpp:16
void set_depth(SampleType d)
Definition chorus.hpp:32
void reset()
Definition chorus.hpp:79
Definition additive_bank.hpp:218
ChorusT< float > Chorus
Definition chorus.hpp:98
ChorusT< double > Chorus64
Definition chorus.hpp:99
Definition chorus.hpp:48
SampleType right
Definition chorus.hpp:48
SampleType left
Definition chorus.hpp:48