1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Reverb.
28 
29 #ifndef ELEMENTS_DSP_FX_REVERB_H_
30 #define ELEMENTS_DSP_FX_REVERB_H_
31 
32 #include "stmlib/stmlib.h"
33 
34 #include "elements/dsp/fx/fx_engine.h"
35 
36 namespace elements {
37 
38 class Reverb {
39  public:
Reverb()40   Reverb() { }
~Reverb()41   ~Reverb() { }
42 
Init(uint16_t * buffer)43   void Init(uint16_t* buffer) {
44     engine_.Init(buffer);
45     engine_.SetLFOFrequency(LFO_1, 0.5f / 32000.0f);
46     engine_.SetLFOFrequency(LFO_2, 0.3f / 32000.0f);
47     lp_ = 0.7f;
48     diffusion_ = 0.625f;
49   }
50 
Process(float * left,float * right,size_t size)51   void Process(float* left, float* right, size_t size) {
52     // This is the Griesinger topology described in the Dattorro paper
53     // (4 AP diffusers on the input, then a loop of 2x 2AP+1Delay).
54     // Modulation is applied in the loop of the first diffuser AP for additional
55     // smearing; and to the two long delays for a slow shimmer/chorus effect.
56     typedef E::Reserve<150,
57       E::Reserve<214,
58       E::Reserve<319,
59       E::Reserve<527,
60       E::Reserve<2182,
61       E::Reserve<2690,
62       E::Reserve<4501,
63       E::Reserve<2525,
64       E::Reserve<2197,
65       E::Reserve<6312> > > > > > > > > > Memory;
66     E::DelayLine<Memory, 0> ap1;
67     E::DelayLine<Memory, 1> ap2;
68     E::DelayLine<Memory, 2> ap3;
69     E::DelayLine<Memory, 3> ap4;
70     E::DelayLine<Memory, 4> dap1a;
71     E::DelayLine<Memory, 5> dap1b;
72     E::DelayLine<Memory, 6> del1;
73     E::DelayLine<Memory, 7> dap2a;
74     E::DelayLine<Memory, 8> dap2b;
75     E::DelayLine<Memory, 9> del2;
76     E::Context c;
77 
78     const float kap = diffusion_;
79     const float klp = lp_;
80     const float krt = reverb_time_;
81     const float amount = amount_;
82     const float gain = input_gain_;
83 
84     float lp_1 = lp_decay_1_;
85     float lp_2 = lp_decay_2_;
86 
87     while (size--) {
88       float wet;
89       float apout = 0.0f;
90       engine_.Start(&c);
91 
92       // Smear AP1 inside the loop.
93       c.Interpolate(ap1, 10.0f, LFO_1, 80.0f, 1.0f);
94       c.Write(ap1, 100, 0.0f);
95 
96       c.Read(*left + *right, gain);
97 
98       // Diffuse through 4 allpasses.
99       c.Read(ap1 TAIL, kap);
100       c.WriteAllPass(ap1, -kap);
101       c.Read(ap2 TAIL, kap);
102       c.WriteAllPass(ap2, -kap);
103       c.Read(ap3 TAIL, kap);
104       c.WriteAllPass(ap3, -kap);
105       c.Read(ap4 TAIL, kap);
106       c.WriteAllPass(ap4, -kap);
107       c.Write(apout);
108 
109       // Main reverb loop.
110       c.Load(apout);
111       c.Interpolate(del2, 6211.0f, LFO_2, 100.0f, krt);
112       c.Lp(lp_1, klp);
113       c.Read(dap1a TAIL, -kap);
114       c.WriteAllPass(dap1a, kap);
115       c.Read(dap1b TAIL, kap);
116       c.WriteAllPass(dap1b, -kap);
117       c.Write(del1, 2.0f);
118       c.Write(wet, 0.0f);
119 
120       *left += (wet - *left) * amount;
121 
122       c.Load(apout);
123       // c.Interpolate(del1, 4450.0f, LFO_1, 50.0f, krt);
124       c.Read(del1 TAIL, krt);
125       c.Lp(lp_2, klp);
126       c.Read(dap2a TAIL, kap);
127       c.WriteAllPass(dap2a, -kap);
128       c.Read(dap2b TAIL, -kap);
129       c.WriteAllPass(dap2b, kap);
130       c.Write(del2, 2.0f);
131       c.Write(wet, 0.0f);
132 
133       *right += (wet - *right) * amount;
134 
135       ++left;
136       ++right;
137     }
138 
139     lp_decay_1_ = lp_1;
140     lp_decay_2_ = lp_2;
141   }
142 
set_amount(float amount)143   inline void set_amount(float amount) {
144     amount_ = amount;
145   }
146 
set_input_gain(float input_gain)147   inline void set_input_gain(float input_gain) {
148     input_gain_ = input_gain;
149   }
150 
set_time(float reverb_time)151   inline void set_time(float reverb_time) {
152     reverb_time_ = reverb_time;
153   }
154 
set_diffusion(float diffusion)155   inline void set_diffusion(float diffusion) {
156     diffusion_ = diffusion;
157   }
158 
set_lp(float lp)159   inline void set_lp(float lp) {
160     lp_ = lp;
161   }
162 
163  private:
164   typedef FxEngine<32768, FORMAT_16_BIT> E;
165   E engine_;
166 
167   float amount_;
168   float input_gain_;
169   float reverb_time_;
170   float diffusion_;
171   float lp_;
172 
173   float lp_decay_1_;
174   float lp_decay_2_;
175 
176   DISALLOW_COPY_AND_ASSIGN(Reverb);
177 };
178 
179 }  // namespace elements
180 
181 #endif  // ELEMENTS_DSP_FX_REVERB_H_
182