1 | /**************************************************************************/ |
2 | /* reverb_filter.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "reverb_filter.h" |
32 | |
33 | #include "core/math/math_funcs.h" |
34 | |
35 | #include <math.h> |
36 | |
37 | const float Reverb::comb_tunings[MAX_COMBS] = { |
38 | //freeverb comb tunings |
39 | 0.025306122448979593f, |
40 | 0.026938775510204082f, |
41 | 0.028956916099773241f, |
42 | 0.03074829931972789f, |
43 | 0.032244897959183672f, |
44 | 0.03380952380952381f, |
45 | 0.035306122448979592f, |
46 | 0.036666666666666667f |
47 | }; |
48 | |
49 | const float Reverb::allpass_tunings[MAX_ALLPASS] = { |
50 | //freeverb allpass tunings |
51 | 0.0051020408163265302f, |
52 | 0.007732426303854875f, |
53 | 0.01f, |
54 | 0.012607709750566893f |
55 | }; |
56 | |
57 | void Reverb::process(float *p_src, float *p_dst, int p_frames) { |
58 | if (p_frames > INPUT_BUFFER_MAX_SIZE) { |
59 | p_frames = INPUT_BUFFER_MAX_SIZE; |
60 | } |
61 | |
62 | int predelay_frames = lrint((params.predelay / 1000.0) * params.mix_rate); |
63 | if (predelay_frames < 10) { |
64 | predelay_frames = 10; |
65 | } |
66 | if (predelay_frames >= echo_buffer_size) { |
67 | predelay_frames = echo_buffer_size - 1; |
68 | } |
69 | |
70 | for (int i = 0; i < p_frames; i++) { |
71 | if (echo_buffer_pos >= echo_buffer_size) { |
72 | echo_buffer_pos = 0; |
73 | } |
74 | |
75 | int read_pos = echo_buffer_pos - predelay_frames; |
76 | while (read_pos < 0) { |
77 | read_pos += echo_buffer_size; |
78 | } |
79 | |
80 | float in = undenormalize(echo_buffer[read_pos] * params.predelay_fb + p_src[i]); |
81 | |
82 | echo_buffer[echo_buffer_pos] = in; |
83 | |
84 | input_buffer[i] = in; |
85 | |
86 | p_dst[i] = 0; //take the chance and clear this |
87 | |
88 | echo_buffer_pos++; |
89 | } |
90 | |
91 | if (params.hpf > 0) { |
92 | float hpaux = expf(-Math_TAU * params.hpf * 6000 / params.mix_rate); |
93 | float hp_a1 = (1.0 + hpaux) / 2.0; |
94 | float hp_a2 = -(1.0 + hpaux) / 2.0; |
95 | float hp_b1 = hpaux; |
96 | |
97 | for (int i = 0; i < p_frames; i++) { |
98 | float in = input_buffer[i]; |
99 | input_buffer[i] = in * hp_a1 + hpf_h1 * hp_a2 + hpf_h2 * hp_b1; |
100 | hpf_h2 = input_buffer[i]; |
101 | hpf_h1 = in; |
102 | } |
103 | } |
104 | |
105 | for (int i = 0; i < MAX_COMBS; i++) { |
106 | Comb &c = comb[i]; |
107 | |
108 | int size_limit = c.size - lrintf((float)c.extra_spread_frames * (1.0 - params.extra_spread)); |
109 | for (int j = 0; j < p_frames; j++) { |
110 | if (c.pos >= size_limit) { //reset this now just in case |
111 | c.pos = 0; |
112 | } |
113 | |
114 | float out = undenormalize(c.buffer[c.pos] * c.feedback); |
115 | out = out * (1.0 - c.damp) + c.damp_h * c.damp; //lowpass |
116 | c.damp_h = out; |
117 | c.buffer[c.pos] = input_buffer[j] + out; |
118 | p_dst[j] += out; |
119 | c.pos++; |
120 | } |
121 | } |
122 | |
123 | static const float allpass_feedback = 0.7; |
124 | /* this one works, but the other version is just nicer.... |
125 | int ap_size_limit[MAX_ALLPASS]; |
126 | |
127 | for (int i=0;i<MAX_ALLPASS;i++) { |
128 | AllPass &a=allpass[i]; |
129 | ap_size_limit[i]=a.size-lrintf((float)a.extra_spread_frames*(1.0-params.extra_spread)); |
130 | } |
131 | |
132 | for (int i=0;i<p_frames;i++) { |
133 | float sample=p_dst[i]; |
134 | float aux,in; |
135 | float AllPass*ap; |
136 | |
137 | #define PROCESS_ALLPASS(m_ap) \ |
138 | ap=&allpass[m_ap]; \ |
139 | if (ap->pos>=ap_size_limit[m_ap]) \ |
140 | ap->pos=0; \ |
141 | aux=undenormalize(ap->buffer[ap->pos]); \ |
142 | in=sample; \ |
143 | sample=-in+aux; \ |
144 | ap->pos++; |
145 | |
146 | |
147 | PROCESS_ALLPASS(0); |
148 | PROCESS_ALLPASS(1); |
149 | PROCESS_ALLPASS(2); |
150 | PROCESS_ALLPASS(3); |
151 | |
152 | p_dst[i]=sample; |
153 | } |
154 | */ |
155 | |
156 | for (int i = 0; i < MAX_ALLPASS; i++) { |
157 | AllPass &a = allpass[i]; |
158 | int size_limit = a.size - lrintf((float)a.extra_spread_frames * (1.0 - params.extra_spread)); |
159 | |
160 | for (int j = 0; j < p_frames; j++) { |
161 | if (a.pos >= size_limit) { |
162 | a.pos = 0; |
163 | } |
164 | |
165 | float aux = a.buffer[a.pos]; |
166 | a.buffer[a.pos] = undenormalize(allpass_feedback * aux + p_dst[j]); |
167 | p_dst[j] = aux - allpass_feedback * a.buffer[a.pos]; |
168 | a.pos++; |
169 | } |
170 | } |
171 | |
172 | static const float wet_scale = 0.6; |
173 | |
174 | for (int i = 0; i < p_frames; i++) { |
175 | p_dst[i] = p_dst[i] * params.wet * wet_scale + p_src[i] * params.dry; |
176 | } |
177 | } |
178 | |
179 | void Reverb::set_room_size(float p_size) { |
180 | params.room_size = p_size; |
181 | update_parameters(); |
182 | } |
183 | |
184 | void Reverb::set_damp(float p_damp) { |
185 | params.damp = p_damp; |
186 | update_parameters(); |
187 | } |
188 | |
189 | void Reverb::set_wet(float p_wet) { |
190 | params.wet = p_wet; |
191 | } |
192 | |
193 | void Reverb::set_dry(float p_dry) { |
194 | params.dry = p_dry; |
195 | } |
196 | |
197 | void Reverb::set_predelay(float p_predelay) { |
198 | params.predelay = p_predelay; |
199 | } |
200 | |
201 | void Reverb::set_predelay_feedback(float p_predelay_fb) { |
202 | params.predelay_fb = p_predelay_fb; |
203 | } |
204 | |
205 | void Reverb::set_highpass(float p_frq) { |
206 | if (p_frq > 1) { |
207 | p_frq = 1; |
208 | } |
209 | if (p_frq < 0) { |
210 | p_frq = 0; |
211 | } |
212 | params.hpf = p_frq; |
213 | } |
214 | |
215 | void Reverb::(float p_spread) { |
216 | params.extra_spread = p_spread; |
217 | } |
218 | |
219 | void Reverb::set_mix_rate(float p_mix_rate) { |
220 | params.mix_rate = p_mix_rate; |
221 | configure_buffers(); |
222 | } |
223 | |
224 | void Reverb::(float p_sec) { |
225 | params.extra_spread_base = p_sec; |
226 | configure_buffers(); |
227 | } |
228 | |
229 | void Reverb::configure_buffers() { |
230 | clear_buffers(); //clear if necessary |
231 | |
232 | for (int i = 0; i < MAX_COMBS; i++) { |
233 | Comb &c = comb[i]; |
234 | |
235 | c.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); |
236 | |
237 | int len = lrint(comb_tunings[i] * params.mix_rate) + c.extra_spread_frames; |
238 | if (len < 5) { |
239 | len = 5; //may this happen? |
240 | } |
241 | |
242 | c.buffer = memnew_arr(float, len); |
243 | c.pos = 0; |
244 | for (int j = 0; j < len; j++) { |
245 | c.buffer[j] = 0; |
246 | } |
247 | c.size = len; |
248 | } |
249 | |
250 | for (int i = 0; i < MAX_ALLPASS; i++) { |
251 | AllPass &a = allpass[i]; |
252 | |
253 | a.extra_spread_frames = lrint(params.extra_spread_base * params.mix_rate); |
254 | |
255 | int len = lrint(allpass_tunings[i] * params.mix_rate) + a.extra_spread_frames; |
256 | if (len < 5) { |
257 | len = 5; //may this happen? |
258 | } |
259 | |
260 | a.buffer = memnew_arr(float, len); |
261 | a.pos = 0; |
262 | for (int j = 0; j < len; j++) { |
263 | a.buffer[j] = 0; |
264 | } |
265 | a.size = len; |
266 | } |
267 | |
268 | echo_buffer_size = (int)(((float)MAX_ECHO_MS / 1000.0) * params.mix_rate + 1.0); |
269 | echo_buffer = memnew_arr(float, echo_buffer_size); |
270 | for (int i = 0; i < echo_buffer_size; i++) { |
271 | echo_buffer[i] = 0; |
272 | } |
273 | |
274 | echo_buffer_pos = 0; |
275 | } |
276 | |
277 | void Reverb::update_parameters() { |
278 | //more freeverb derived constants |
279 | static const float room_scale = 0.28f; |
280 | static const float room_offset = 0.7f; |
281 | |
282 | for (int i = 0; i < MAX_COMBS; i++) { |
283 | Comb &c = comb[i]; |
284 | c.feedback = room_offset + params.room_size * room_scale; |
285 | if (c.feedback < room_offset) { |
286 | c.feedback = room_offset; |
287 | } else if (c.feedback > (room_offset + room_scale)) { |
288 | c.feedback = (room_offset + room_scale); |
289 | } |
290 | |
291 | float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) |
292 | auxdmp *= auxdmp; |
293 | |
294 | c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz |
295 | } |
296 | } |
297 | |
298 | void Reverb::clear_buffers() { |
299 | if (echo_buffer) { |
300 | memdelete_arr(echo_buffer); |
301 | } |
302 | |
303 | for (int i = 0; i < MAX_COMBS; i++) { |
304 | if (comb[i].buffer) { |
305 | memdelete_arr(comb[i].buffer); |
306 | } |
307 | |
308 | comb[i].buffer = nullptr; |
309 | } |
310 | |
311 | for (int i = 0; i < MAX_ALLPASS; i++) { |
312 | if (allpass[i].buffer) { |
313 | memdelete_arr(allpass[i].buffer); |
314 | } |
315 | |
316 | allpass[i].buffer = nullptr; |
317 | } |
318 | } |
319 | |
320 | Reverb::Reverb() { |
321 | params.room_size = 0.8; |
322 | params.damp = 0.5; |
323 | params.dry = 1.0; |
324 | params.wet = 0.0; |
325 | params.mix_rate = 44100; |
326 | params.extra_spread_base = 0; |
327 | params.extra_spread = 1.0; |
328 | params.predelay = 150; |
329 | params.predelay_fb = 0.4; |
330 | params.hpf = 0; |
331 | |
332 | input_buffer = memnew_arr(float, INPUT_BUFFER_MAX_SIZE); |
333 | |
334 | configure_buffers(); |
335 | update_parameters(); |
336 | } |
337 | |
338 | Reverb::~Reverb() { |
339 | memdelete_arr(input_buffer); |
340 | clear_buffers(); |
341 | } |
342 | |