Line data Source code
1 : #include "audio/effects/delay_reverb/reverb.h"
2 :
3 : #include "audio/effects/core/effect_factory.h"
4 :
5 : namespace Amplitron {
6 :
7 2 : static EffectRegistrar<Reverb> reg("Reverb");
8 :
9 : // Comb filter delay lengths (in samples at 44100Hz, will be scaled)
10 : static const int COMB_LENGTHS[] = {1116, 1188, 1277, 1356};
11 : static const int ALLPASS_LENGTHS[] = {556, 441};
12 : // Right-channel lengths add a prime offset for decorrelation (classic Freeverb technique)
13 : static constexpr int STEREO_SPREAD = 23;
14 : static const int COMB_LENGTHS_R[] = {1116 + STEREO_SPREAD, 1188 + STEREO_SPREAD,
15 : 1277 + STEREO_SPREAD, 1356 + STEREO_SPREAD};
16 : static const int ALLPASS_LENGTHS_R[] = {556 + STEREO_SPREAD, 441 + STEREO_SPREAD};
17 :
18 196 : Reverb::Reverb() {
19 441 : params_ = {
20 98 : {"Decay", 0.6f, 0.1f, 0.99f, 0.6f, "",
21 49 : "Length of the reverb tail. Higher values simulate larger acoustic spaces like halls or "
22 : "caves."},
23 49 : {"Damp", 0.4f, 0.0f, 1.0f, 0.4f, "",
24 49 : "High-frequency damping. Higher values absorb treble faster, simulating softer room "
25 : "materials."},
26 49 : {"Level", 0.3f, 0.0f, 1.0f, 0.3f, "",
27 49 : "Mix volume of the reverb effect. Controls how wet or distant the overall sound feels."},
28 441 : };
29 147 : init_filters();
30 343 : }
31 :
32 165 : void Reverb::set_sample_rate(int sample_rate) {
33 165 : Effect::set_sample_rate(sample_rate);
34 165 : init_filters();
35 165 : }
36 :
37 312 : void Reverb::init_filters() {
38 312 : const float scale = static_cast<float>(sample_rate_) / 44100.0f;
39 :
40 1560 : for (int i = 0; i < NUM_COMBS; ++i) {
41 1248 : int len = static_cast<int>(COMB_LENGTHS[i] * scale);
42 1248 : combs_[i].buffer.assign(len, 0.0f);
43 1248 : combs_[i].write_pos = 0;
44 1248 : combs_[i].lp_state = 0.0f;
45 :
46 1248 : int len_r = static_cast<int>(COMB_LENGTHS_R[i] * scale);
47 1248 : combs_r_[i].buffer.assign(len_r, 0.0f);
48 1248 : combs_r_[i].write_pos = 0;
49 1248 : combs_r_[i].lp_state = 0.0f;
50 416 : }
51 :
52 936 : for (int i = 0; i < NUM_ALLPASS; ++i) {
53 624 : int len = static_cast<int>(ALLPASS_LENGTHS[i] * scale);
54 624 : allpasses_[i].buffer.assign(len, 0.0f);
55 624 : allpasses_[i].write_pos = 0;
56 624 : allpasses_[i].feedback = 0.5f;
57 :
58 624 : int len_r = static_cast<int>(ALLPASS_LENGTHS_R[i] * scale);
59 624 : allpasses_r_[i].buffer.assign(len_r, 0.0f);
60 624 : allpasses_r_[i].write_pos = 0;
61 624 : allpasses_r_[i].feedback = 0.5f;
62 208 : }
63 312 : }
64 :
65 99 : void Reverb::process(float* buffer, int num_samples) {
66 99 : if (!enabled_) return;
67 :
68 96 : float decay = params_[0].value;
69 96 : float damp = params_[1].value;
70 96 : float level = params_[2].value;
71 :
72 189408 : for (int i = 0; i < num_samples; ++i) {
73 189312 : float dry = buffer[i];
74 189312 : float input = buffer[i] * 0.2f;
75 189312 : float out = 0.0f;
76 :
77 : // Parallel comb filters
78 946560 : for (int c = 0; c < NUM_COMBS; ++c) {
79 757248 : auto& comb = combs_[c];
80 757248 : int buf_len = static_cast<int>(comb.buffer.size());
81 757248 : int read_pos = comb.write_pos;
82 :
83 757248 : float delayed = comb.buffer[read_pos];
84 :
85 : // Damping LP filter
86 757248 : comb.lp_state = delayed * (1.0f - damp) + comb.lp_state * damp;
87 757248 : float fb_sample = comb.lp_state * decay;
88 :
89 757248 : comb.buffer[comb.write_pos] = input + fb_sample;
90 757248 : comb.write_pos = (comb.write_pos + 1) % buf_len;
91 :
92 757248 : out += delayed;
93 252416 : }
94 :
95 : // Series allpass filters
96 567936 : for (int a = 0; a < NUM_ALLPASS; ++a) {
97 378624 : auto& ap = allpasses_[a];
98 378624 : int buf_len = static_cast<int>(ap.buffer.size());
99 :
100 378624 : float delayed = ap.buffer[ap.write_pos];
101 378624 : float temp = out + delayed * ap.feedback;
102 378624 : ap.buffer[ap.write_pos] = temp;
103 378624 : out = delayed - out * ap.feedback;
104 :
105 378624 : ap.write_pos = (ap.write_pos + 1) % buf_len;
106 126208 : }
107 :
108 189312 : buffer[i] = dry * (1.0f - level) + out * level;
109 63104 : }
110 33 : }
111 :
112 3 : void Reverb::process_stereo(float* left, float* right, int num_samples) {
113 3 : if (!enabled_) {
114 0 : return;
115 : }
116 :
117 3 : const float decay = params_[0].value;
118 3 : const float damp = params_[1].value;
119 3 : const float level = params_[2].value;
120 :
121 6147 : for (int i = 0; i < num_samples; ++i) {
122 6144 : const float input_l = left[i] * 0.2f;
123 6144 : const float input_r = right[i] * 0.2f;
124 6144 : float out_l = 0.0f;
125 6144 : float out_r = 0.0f;
126 :
127 : // Parallel comb filters — left
128 30720 : for (int c = 0; c < NUM_COMBS; ++c) {
129 24576 : auto& comb = combs_[c];
130 24576 : const int buf_len = static_cast<int>(comb.buffer.size());
131 24576 : float delayed = comb.buffer[comb.write_pos];
132 24576 : comb.lp_state = delayed * (1.0f - damp) + comb.lp_state * damp;
133 24576 : comb.buffer[comb.write_pos] = input_l + comb.lp_state * decay;
134 24576 : comb.write_pos = (comb.write_pos + 1) % buf_len;
135 24576 : out_l += delayed;
136 8192 : }
137 : // Parallel comb filters — right
138 30720 : for (int c = 0; c < NUM_COMBS; ++c) {
139 24576 : auto& comb = combs_r_[c];
140 24576 : const int buf_len = static_cast<int>(comb.buffer.size());
141 24576 : float delayed = comb.buffer[comb.write_pos];
142 24576 : comb.lp_state = delayed * (1.0f - damp) + comb.lp_state * damp;
143 24576 : comb.buffer[comb.write_pos] = input_r + comb.lp_state * decay;
144 24576 : comb.write_pos = (comb.write_pos + 1) % buf_len;
145 24576 : out_r += delayed;
146 8192 : }
147 :
148 : // Series allpass filters — left
149 18432 : for (int a = 0; a < NUM_ALLPASS; ++a) {
150 12288 : auto& ap = allpasses_[a];
151 12288 : const int buf_len = static_cast<int>(ap.buffer.size());
152 12288 : float delayed = ap.buffer[ap.write_pos];
153 12288 : float temp = out_l + delayed * ap.feedback;
154 12288 : ap.buffer[ap.write_pos] = temp;
155 12288 : out_l = delayed - out_l * ap.feedback;
156 12288 : ap.write_pos = (ap.write_pos + 1) % buf_len;
157 4096 : }
158 : // Series allpass filters — right
159 18432 : for (int a = 0; a < NUM_ALLPASS; ++a) {
160 12288 : auto& ap = allpasses_r_[a];
161 12288 : const int buf_len = static_cast<int>(ap.buffer.size());
162 12288 : float delayed = ap.buffer[ap.write_pos];
163 12288 : float temp = out_r + delayed * ap.feedback;
164 12288 : ap.buffer[ap.write_pos] = temp;
165 12288 : out_r = delayed - out_r * ap.feedback;
166 12288 : ap.write_pos = (ap.write_pos + 1) % buf_len;
167 4096 : }
168 :
169 6144 : left[i] = left[i] * (1.0f - level) + out_l * level;
170 6144 : right[i] = right[i] * (1.0f - level) + out_r * level;
171 2048 : }
172 1 : }
173 :
174 168 : void Reverb::reset() {
175 840 : for (auto& c : combs_) {
176 672 : std::fill(c.buffer.begin(), c.buffer.end(), 0.0f);
177 672 : c.write_pos = 0;
178 672 : c.lp_state = 0.0f;
179 : }
180 840 : for (auto& c : combs_r_) {
181 672 : std::fill(c.buffer.begin(), c.buffer.end(), 0.0f);
182 672 : c.write_pos = 0;
183 672 : c.lp_state = 0.0f;
184 : }
185 504 : for (auto& a : allpasses_) {
186 336 : std::fill(a.buffer.begin(), a.buffer.end(), 0.0f);
187 336 : a.write_pos = 0;
188 : }
189 504 : for (auto& a : allpasses_r_) {
190 336 : std::fill(a.buffer.begin(), a.buffer.end(), 0.0f);
191 336 : a.write_pos = 0;
192 : }
193 168 : }
194 :
195 : } // namespace Amplitron
|