Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
digital.hpp
1/*
2 * Copyright © 2024 Katherine Whitlock
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "definitions_cxx.hpp"
18#include "mutable.hpp"
19
20namespace deluge::dsp::reverb {
21
24class Digital : public Mutable {
25 constexpr static float kRatio = 29761.f / kSampleRate; // Lexicon sample rate to Deluge sample rate
26
27 constexpr static size_t max_excursion = 16.f * kRatio;
28
29public:
30 void process(std::span<q31_t> in, std::span<StereoSample> output) override {
31 typename FxEngine::Context c;
32
33 typename FxEngine::AllPass ap1(142 * kRatio);
34 typename FxEngine::AllPass ap2(107 * kRatio);
35 typename FxEngine::AllPass ap3(379 * kRatio);
36 typename FxEngine::AllPass ap4(277 * kRatio);
37
38 typename FxEngine::AllPass dap1a((672 * kRatio) + max_excursion);
39 typename FxEngine::DelayLine del1a(4453 * kRatio);
40 typename FxEngine::AllPass dap1b(1800 * kRatio);
41 typename FxEngine::DelayLine del1b(3720 * kRatio);
42
43 typename FxEngine::AllPass dap2a((908 * kRatio) + max_excursion);
44 typename FxEngine::DelayLine del2a(4217 * kRatio);
45 typename FxEngine::AllPass dap2b(2656 * kRatio);
46 typename FxEngine::DelayLine del2b(3163 * kRatio);
47
48 FxEngine::ConstructTopology(engine_, {&ap1, &ap2, &ap3, &ap4, //<
49 &dap1a, &del1a, &dap1b, &del1b, //<
50 &dap2a, &del2a, &dap2b, &del2b});
51
52 const float kdecay = reverb_time_; // 0.5f
53 const float kid1 = 0.750f; // input diffusion 1
54 const float kid2 = 0.625f; // input diffusion 2
55 const float kdd1 = 0.70f; // decay diffusion 1
56 const float kdd2 = std::clamp(kdecay + 0.15f, 0.25f, 0.5f); // decay diffusion 2
57
58 const float kdamp = lp_; // 1.f - 0.0005f; // damping
59 const float kbandwidth = 0.9995f;
60
61 const float gain = input_gain_;
62
63 float lp_1 = lp_decay_1_;
64 float lp_2 = lp_decay_2_;
65 float lp_band = lp_band_;
66
67 for (size_t frame = 0; frame < in.size(); ++frame) {
68 engine_.Advance();
69
70 const float input_sample = in[frame] / static_cast<float>(std::numeric_limits<int32_t>::max());
71 c.Set(input_sample); // * gain);
72
73 c.Lp(lp_band, kbandwidth);
74
75 // Diffuse through 4 allpasses.
76 ap1.Process(c, kid1);
77 ap2.Process(c, kid1);
78 ap3.Process(c, kid2);
79 ap4.Process(c, kid2);
80 float apout = c.Get();
81
82 // Main reverb loop.
83 c.Set(apout);
84 dap1a.Interpolate(c, 672.0f * kRatio, LFO_2, max_excursion, -kdd1);
85 del1a.Process(c);
86 c.Lp(lp_1, kdamp); // damping
87 c.Multiply(kdecay);
88 dap1b.Process(c, kdd2);
89 del1b.Process(c);
90 c.Multiply(kdecay);
91 c.Add(apout);
92 dap2a.Write(c, kdd2);
93
94 c.Set(apout);
95 dap2a.Interpolate(c, 908.0f * kRatio, LFO_1, max_excursion, -kdd1);
96 del2a.Process(c);
97 c.Lp(lp_1, kdamp); // damping
98 c.Multiply(kdecay);
99 dap2b.Process(c, kdd2);
100 del2b.Process(c);
101 c.Multiply(kdecay);
102 c.Add(apout);
103 dap1a.Write(c, kdd1);
104
105 float left_sum = 0;
106 left_sum += 0.6f * del2a.at(266 * kRatio);
107 left_sum += 0.6f * del2a.at(2974 * kRatio);
108 left_sum -= 0.6f * dap2b.at(1913 * kRatio);
109 left_sum += 0.6f * del2b.at(1996 * kRatio);
110 left_sum -= 0.6f * del1a.at(1990 * kRatio);
111 left_sum -= 0.6f * dap1b.at(187 * kRatio);
112 left_sum -= 0.6f * del1b.at(1066 * kRatio);
113 left_sum = left_sum - dsp::OnePole(hp_l_, left_sum, hp_cutoff_);
114 left_sum = dsp::OnePole(lp_l_, left_sum, lp_cutoff_);
115
116 float right_sum = 0;
117 right_sum += 0.6f * del1a.at(353 * kRatio);
118 right_sum += 0.6f * del1a.at(3627 * kRatio);
119 right_sum -= 0.6f * dap1b.at(1228 * kRatio);
120 right_sum += 0.6f * del1b.at(2673 * kRatio);
121 right_sum -= 0.6f * del2a.at(2111 * kRatio);
122 right_sum -= 0.6f * dap2b.at(335 * kRatio);
123 right_sum -= 0.6f * del2b.at(121 * kRatio);
124 right_sum = right_sum - dsp::OnePole(hp_l_, right_sum, hp_cutoff_);
125 right_sum = dsp::OnePole(lp_l_, right_sum, lp_cutoff_);
126
127 q31_t output_left =
128 static_cast<int32_t>(left_sum * static_cast<float>(std::numeric_limits<uint32_t>::max()) * 0xF);
129
130 q31_t output_right =
131 static_cast<int32_t>(left_sum * static_cast<float>(std::numeric_limits<uint32_t>::max()) * 0xF);
132
133 // Mix
134 output[frame].l += multiply_32x32_rshift32_rounded(output_left, getPanLeft());
135 output[frame].r += multiply_32x32_rshift32_rounded(output_right, getPanRight());
136 }
137
138 lp_decay_1_ = lp_1;
139 lp_decay_2_ = lp_2;
140 lp_band_ = lp_band;
141 }
142
143private:
144 float lp_band_;
145};
146} // namespace deluge::dsp::reverb
The Griesinger topology model from Part 1 of Effect Design by John Dattorro, classically based on the...
Definition digital.hpp:24
Definition fx_engine.hpp:81
Definition fx_engine.hpp:142
float Interpolate(Context &c, float offset, float scale)
Can be used in place of any AllPass::Read calls.
Definition fx_engine.hpp:174
Definition fx_engine.hpp:99