|
3 | 3 | // SPDX-FileCopyrightText: Copyright (c) 2025 Mark Komus |
4 | 4 | // |
5 | 5 | // SPDX-License-Identifier: MIT |
| 6 | +// |
| 7 | +// Based on FreeVerb - https://github.com/sinshu/freeverb/tree/main |
| 8 | +// Fixed point ideas from - Paul Stoffregen in the Teensy audio library https://github.com/PaulStoffregen/Audio/blob/master/effect_freeverb.cpp |
| 9 | +// |
6 | 10 | #include "shared-bindings/audiodelays/Reverb.h" |
7 | 11 |
|
8 | 12 | #include <stdint.h> |
@@ -278,69 +282,62 @@ audioio_get_buffer_result_t audiodelays_reverb_get_buffer(audiodelays_reverb_obj |
278 | 282 | mp_float_t roomsize = synthio_block_slot_get_limited(&self->roomsize, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); |
279 | 283 | int16_t feedback = audiodelays_reverb_get_roomsize_fixedpoint(roomsize); |
280 | 284 |
|
281 | | - // If we have no sample keep the reverb reverbing |
282 | | - if (self->sample == NULL) { |
283 | | - // Since we have no sample we can just iterate over the our entire remaining buffer and finish |
284 | | - for (uint32_t i = 0; i < n; i++) { |
285 | | - int16_t word = 0; |
286 | | - word_buffer[i] = word; |
| 285 | + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; |
| 286 | + |
| 287 | + for (uint32_t i = 0; i < n; i++) { |
| 288 | + int32_t sample_word = 0; |
| 289 | + if (self->sample != NULL) { |
| 290 | + sample_word = sample_src[i]; |
287 | 291 | } |
288 | | - } else { |
289 | | - // we have a sample to play |
290 | | - int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; |
291 | | - |
292 | | - for (uint32_t i = 0; i < n; i++) { |
293 | | - int32_t sample_word = sample_src[i]; |
294 | | - |
295 | | - int32_t word, sum; |
296 | | - int16_t input, bufout, output; |
297 | | - uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; |
298 | | - |
299 | | - input = sat16(sample_word * 8738, 17); |
300 | | - sum = 0; |
301 | | - |
302 | | - for (uint32_t j = 0 + channel_comb_offset; j < 8 + channel_comb_offset; j++) { |
303 | | - bufout = self->combbuffers[j][self->combbufferindex[j]]; |
304 | | - sum += bufout; |
305 | | - self->combfitlers[j] = sat16(bufout * damp2 + self->combfitlers[j] * damp1, 15); |
306 | | - self->combbuffers[j][self->combbufferindex[j]] = sat16(input + sat16(self->combfitlers[j] * feedback, 15), 0); |
307 | | - if (++self->combbufferindex[j] >= self->combbuffersizes[j]) { |
308 | | - self->combbufferindex[j] = 0; |
309 | | - } |
310 | | - } |
311 | 292 |
|
312 | | - output = sat16(sum * 31457, 17); // 31457 = 0.96f |
| 293 | + int32_t word, sum; |
| 294 | + int16_t input, bufout, output; |
| 295 | + uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; |
313 | 296 |
|
314 | | - for (uint32_t j = 0 + channel_allpass_offset; j < 4 + channel_allpass_offset; j++) { |
315 | | - bufout = self->allpassbuffers[j][self->allpassbufferindex[j]]; |
316 | | - self->allpassbuffers[j][self->allpassbufferindex[j]] = output + (bufout >> 1); // bufout >> 1 same as bufout*0.5f |
317 | | - output = sat16(bufout - output, 1); |
318 | | - if (++self->allpassbufferindex[j] >= self->allpassbuffersizes[j]) { |
319 | | - self->allpassbufferindex[j] = 0; |
320 | | - } |
321 | | - } |
| 297 | + input = sat16(sample_word * 8738, 17); |
| 298 | + sum = 0; |
322 | 299 |
|
323 | | - word = output * 30; |
| 300 | + for (uint32_t j = 0 + channel_comb_offset; j < 8 + channel_comb_offset; j++) { |
| 301 | + bufout = self->combbuffers[j][self->combbufferindex[j]]; |
| 302 | + sum += bufout; |
| 303 | + self->combfitlers[j] = sat16(bufout * damp2 + self->combfitlers[j] * damp1, 15); |
| 304 | + self->combbuffers[j][self->combbufferindex[j]] = sat16(input + sat16(self->combfitlers[j] * feedback, 15), 0); |
| 305 | + if (++self->combbufferindex[j] >= self->combbuffersizes[j]) { |
| 306 | + self->combbufferindex[j] = 0; |
| 307 | + } |
| 308 | + } |
324 | 309 |
|
325 | | - word = (sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix); |
326 | | - word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); |
327 | | - word_buffer[i] = (int16_t)word; |
| 310 | + output = sat16(sum * 31457, 17); // 31457 = 0.96f |
328 | 311 |
|
329 | | - if ((self->base.channel_count == 2) && (channel_comb_offset == 0)) { |
330 | | - channel_comb_offset = 8; |
331 | | - channel_allpass_offset = 4; |
332 | | - } else { |
333 | | - channel_comb_offset = 0; |
334 | | - channel_allpass_offset = 0; |
| 312 | + for (uint32_t j = 0 + channel_allpass_offset; j < 4 + channel_allpass_offset; j++) { |
| 313 | + bufout = self->allpassbuffers[j][self->allpassbufferindex[j]]; |
| 314 | + self->allpassbuffers[j][self->allpassbufferindex[j]] = output + (bufout >> 1); // bufout >> 1 same as bufout*0.5f |
| 315 | + output = sat16(bufout - output, 1); |
| 316 | + if (++self->allpassbufferindex[j] >= self->allpassbuffersizes[j]) { |
| 317 | + self->allpassbufferindex[j] = 0; |
335 | 318 | } |
336 | 319 | } |
337 | 320 |
|
338 | | - // Update the remaining length and the buffer positions based on how much we wrote into our buffer |
339 | | - length -= n; |
340 | | - word_buffer += n; |
341 | | - self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); |
342 | | - self->sample_buffer_length -= n; |
| 321 | + word = output * 30; |
| 322 | + |
| 323 | + word = (sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix); |
| 324 | + word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); |
| 325 | + word_buffer[i] = (int16_t)word; |
| 326 | + |
| 327 | + if ((self->base.channel_count == 2) && (channel_comb_offset == 0)) { |
| 328 | + channel_comb_offset = 8; |
| 329 | + channel_allpass_offset = 4; |
| 330 | + } else { |
| 331 | + channel_comb_offset = 0; |
| 332 | + channel_allpass_offset = 0; |
| 333 | + } |
343 | 334 | } |
| 335 | + |
| 336 | + // Update the remaining length and the buffer positions based on how much we wrote into our buffer |
| 337 | + length -= n; |
| 338 | + word_buffer += n; |
| 339 | + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); |
| 340 | + self->sample_buffer_length -= n; |
344 | 341 | } |
345 | 342 |
|
346 | 343 | // Finally pass our buffer and length to the calling audio function |
|
0 commit comments