Line data Source code
1 : #include "audio/effects/delay_reverb/delay.h"
2 :
3 : #include "audio/effects/core/effect_factory.h"
4 :
5 : namespace Amplitron {
6 :
7 2 : static EffectRegistrar<Delay> reg("Delay");
8 :
9 164 : Delay::Delay() {
10 451 : params_ = {
11 123 : {"Time", 350.0f, 10.0f, 2000.0f, 350.0f, "ms",
12 41 : "Time interval between each echo. Sets the tempo of the delay repeats."},
13 41 : {"Feedback", 0.4f, 0.0f, 0.95f, 0.4f, "",
14 41 : "Amount of the delayed signal fed back into the input. Higher values create more "
15 : "repeats."},
16 41 : {"Tone", 0.7f, 0.0f, 1.0f, 0.7f, "",
17 41 : "High-frequency damping on the repeats. Lower values create darker, tape-like echoes."},
18 41 : {"Level", 0.5f, 0.0f, 1.0f, 0.5f, "",
19 41 : "Mix volume of the delay repeats added to your dry signal."},
20 451 : };
21 123 : set_sample_rate(DEFAULT_SAMPLE_RATE);
22 246 : }
23 :
24 264 : void Delay::set_sample_rate(int sample_rate) {
25 264 : Effect::set_sample_rate(sample_rate);
26 264 : max_delay_samples_ = static_cast<int>(sample_rate * 2.5f); // max 2.5s
27 264 : delay_buffer_.resize(max_delay_samples_, 0.0f);
28 264 : write_pos_ = 0;
29 264 : }
30 :
31 24 : void Delay::process(float* buffer, int num_samples) {
32 24 : if (!enabled_) return;
33 :
34 24 : const float alpha = 1.0f - std::exp(-1.0f / (sample_rate_ * 0.020f)); // 20 ms
35 24 : smoothed_time_ms_ += alpha * (params_[0].value - smoothed_time_ms_);
36 24 : smoothed_feedback_ += alpha * (params_[1].value - smoothed_feedback_);
37 24 : smoothed_tone_ += alpha * (params_[2].value - smoothed_tone_);
38 24 : smoothed_level_ += alpha * (params_[3].value - smoothed_level_);
39 :
40 24 : float time_ms = smoothed_time_ms_;
41 24 : float feedback = smoothed_feedback_;
42 24 : float tone = smoothed_tone_;
43 24 : float level = smoothed_level_;
44 :
45 24 : int delay_samples = static_cast<int>(time_ms * 0.001f * sample_rate_);
46 24 : delay_samples = std::min(delay_samples, max_delay_samples_ - 1);
47 24 : float lp_coeff = 0.1f + tone * 0.85f;
48 :
49 16920 : for (int i = 0; i < num_samples; ++i) {
50 16896 : float dry = buffer[i];
51 :
52 16896 : int read_pos = write_pos_ - delay_samples;
53 16896 : if (read_pos < 0) read_pos += max_delay_samples_;
54 :
55 16896 : float delayed = delay_buffer_[read_pos];
56 :
57 : // Tone filter on feedback path
58 16896 : float filtered = tone_lp_.lp(delayed, lp_coeff);
59 :
60 : // Write to delay buffer: input + filtered feedback
61 16896 : delay_buffer_[write_pos_] = buffer[i] + filtered * feedback;
62 :
63 16896 : write_pos_++;
64 16896 : if (write_pos_ >= max_delay_samples_) write_pos_ = 0;
65 :
66 16896 : buffer[i] = dry + delayed * level;
67 5632 : }
68 8 : }
69 :
70 144 : void Delay::reset() {
71 144 : std::fill(delay_buffer_.begin(), delay_buffer_.end(), 0.0f);
72 144 : write_pos_ = 0;
73 144 : tone_lp_.reset();
74 144 : }
75 :
76 3 : void Delay::set_transport_state(float bpm) {
77 3 : if (bpm <= 0.0f || !std::isfinite(bpm)) return;
78 3 : if (bpm == last_bpm_) return;
79 3 : last_bpm_ = bpm;
80 :
81 : // Quarter-note duration
82 3 : float quarter_note_ms = 60000.0f / bpm;
83 : // Check current knob
84 3 : float current_knob_time = params_[0].value;
85 : // Distance to nearest subdivisions
86 3 : float diff_quarter = std::fabs(current_knob_time - quarter_note_ms);
87 3 : float diff_eighth = std::fabs(current_knob_time - (quarter_note_ms * 0.5f));
88 3 : float diff_sixteenth = std::fabs(current_knob_time - (quarter_note_ms * 0.25f));
89 : // Check closest
90 3 : float target_time = quarter_note_ms; // default to 1/4 note
91 3 : if (diff_eighth < diff_quarter && diff_eighth < diff_sixteenth) {
92 0 : target_time = quarter_note_ms * 0.5f; // 1/8 note
93 3 : } else if (diff_sixteenth < diff_quarter && diff_sixteenth < diff_eighth) {
94 0 : target_time = quarter_note_ms * 0.25f; // 1/16 note
95 0 : }
96 :
97 : // Set knob
98 3 : params_[0].value = clamp(target_time, params_[0].min_val, params_[0].max_val);
99 1 : }
100 :
101 : } // namespace Amplitron
|