Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
freeverb.hpp
1// Reverb model declaration
2//
3// Written by Jezar at Dreampoint, June 2000
4// http://www.dreampoint.co.uk
5// This code is public domain
6
7/*
8 * Copyright © 2015-2023 Synthstrom Audible Limited
9 *
10 * This file is part of The Synthstrom Audible Deluge Firmware.
11 *
12 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
13 * terms of the GNU General Public License as published by the Free Software Foundation,
14 * either version 3 of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
17 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 * See the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along with this program.
21 * If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#pragma once
25
26#include "dsp/reverb/base.hpp"
27#include "dsp/reverb/freeverb/allpass.hpp"
28#include "dsp/reverb/freeverb/comb.hpp"
29#include "dsp/reverb/freeverb/tuning.h"
30#include <cstdint>
31#include <span>
32
33namespace deluge::dsp::reverb {
34class Freeverb : public Base {
35public:
36 Freeverb();
37 ~Freeverb() override = default;
38
39 void mute();
40
41 void setRoomSize(float value) override {
42 roomsize = (value * scaleroom) + offsetroom;
43 update();
44 }
45
46 [[nodiscard]] constexpr float getRoomSize() const override { return (roomsize - offsetroom) / scaleroom; }
47
48 void setDamping(float value) override {
49 damp = value * scaledamp;
50 update();
51 }
52
53 [[nodiscard]] constexpr float getDamping() const override { return damp / scaledamp; }
54
55 void setWet(float value) {
56 wet = value * scalewet;
57 update();
58 }
59
60 [[nodiscard]] constexpr float getWet() const { return wet / scalewet; }
61
62 void setDry(float value) { dry = value * scaledry; }
63
64 [[nodiscard]] constexpr float getDry() const { return dry / scaledry; }
65
66 void setWidth(float value) override {
67 width = value;
68 update();
69 }
70
71 [[nodiscard]] constexpr float getWidth() const override { return width; }
72
73 [[gnu::always_inline]] void ProcessOne(int32_t input, StereoSample& output_sample) {
74 int32_t out_l = 0;
75 int32_t out_r = 0;
76
77 // Accumulate comb filters in parallel
78 for (int32_t i = 0; i < numcombs; i++) {
79 out_l += combL[i].process(input);
80 out_r += combR[i].process(input);
81 }
82
83 // Feed through allpasses in series
84 for (int32_t i = 0; i < numallpasses; i++) {
85 out_l = allpassL[i].process(out_l);
86 out_r = allpassR[i].process(out_r);
87 }
88
89 // Calculate output
90 out_l = (out_l + multiply_32x32_rshift32_rounded(out_r, wet2)) << 1;
91 out_r = (out_r + multiply_32x32_rshift32_rounded(out_l, wet2)) << 1;
92
93 // Mix output
94 output_sample.l += multiply_32x32_rshift32_rounded(out_l, this->getPanLeft());
95 output_sample.r += multiply_32x32_rshift32_rounded(out_r, this->getPanRight());
96 }
97
98 [[gnu::always_inline]] void process(std::span<int32_t> input, std::span<StereoSample> output) override {
99 // HPF on reverb input, cos if it has DC offset, the reverb magnifies that, and the sound farts out
100 for (int32_t& reverb_sample : input) {
101 int32_t distance_to_go_l = reverb_sample - reverb_send_post_lpf_;
102 reverb_send_post_lpf_ += distance_to_go_l >> 11;
103 reverb_sample -= reverb_send_post_lpf_;
104 }
105
106 for (size_t frame = 0; frame < input.size(); frame++) {
107 ProcessOne(input[frame], output[frame]);
108 }
109 }
110
111private:
112 void update();
113
114 int32_t gain;
115 float roomsize;
116 float damp;
117 float wet;
118 float wet1;
119 int32_t wet2;
120 float dry;
121 float width;
122
123 // The following are all declared inline
124 // to remove the need for dynamic allocation
125 // with its subsequent error-checking messiness
126
127 // Comb filters
128 std::array<freeverb::Comb, numcombs> combL;
129 std::array<freeverb::Comb, numcombs> combR;
130
131 // Allpass filters
132 std::array<freeverb::Allpass, numallpasses> allpassL;
133 std::array<freeverb::Allpass, numallpasses> allpassR;
134
135 // Buffers for the combs
136 std::array<int32_t, combtuningL1> bufcombL1;
137 std::array<int32_t, combtuningR1> bufcombR1;
138 std::array<int32_t, combtuningL2> bufcombL2;
139 std::array<int32_t, combtuningR2> bufcombR2;
140 std::array<int32_t, combtuningL3> bufcombL3;
141 std::array<int32_t, combtuningR3> bufcombR3;
142 std::array<int32_t, combtuningL4> bufcombL4;
143 std::array<int32_t, combtuningR4> bufcombR4;
144 std::array<int32_t, combtuningL5> bufcombL5;
145 std::array<int32_t, combtuningR5> bufcombR5;
146 std::array<int32_t, combtuningL6> bufcombL6;
147 std::array<int32_t, combtuningR6> bufcombR6;
148 std::array<int32_t, combtuningL7> bufcombL7;
149 std::array<int32_t, combtuningR7> bufcombR7;
150 std::array<int32_t, combtuningL8> bufcombL8;
151 std::array<int32_t, combtuningR8> bufcombR8;
152
153 // Buffers for the allpasses
154 std::array<int32_t, allpasstuningL1> bufallpassL1;
155 std::array<int32_t, allpasstuningR1> bufallpassR1;
156 std::array<int32_t, allpasstuningL2> bufallpassL2;
157 std::array<int32_t, allpasstuningR2> bufallpassR2;
158 std::array<int32_t, allpasstuningL3> bufallpassL3;
159 std::array<int32_t, allpasstuningR3> bufallpassR3;
160 std::array<int32_t, allpasstuningL4> bufallpassL4;
161 std::array<int32_t, allpasstuningR4> bufallpassR4;
162
163 int32_t reverb_send_post_lpf_ = 0;
164};
165} // namespace deluge::dsp::reverb
Definition stereo_sample.h:25