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 CLOUDS_DSP_FX_REVERB_H_ 30 #define CLOUDS_DSP_FX_REVERB_H_ 31 32 #include "stmlib/stmlib.h" 33 34 #include "clouds/dsp/fx/fx_engine.h" 35 36 namespace clouds { 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(FloatFrame * in_out,size_t size)51 void Process(FloatFrame* in_out, 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<113, 57 E::Reserve<162, 58 E::Reserve<241, 59 E::Reserve<399, 60 E::Reserve<1653, 61 E::Reserve<2038, 62 E::Reserve<3411, 63 E::Reserve<1913, 64 E::Reserve<1663, 65 E::Reserve<4782> > > > > > > > > > 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, 60.0f, 1.0f); 94 c.Write(ap1, 100, 0.0f); 95 96 c.Read(in_out->l + in_out->r, 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, 4680.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 in_out->l += (wet - in_out->l) * 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 in_out->r += (wet - in_out->r) * amount; 134 135 ++in_out; 136 } 137 138 lp_decay_1_ = lp_1; 139 lp_decay_2_ = lp_2; 140 } 141 set_amount(float amount)142 inline void set_amount(float amount) { 143 amount_ = amount; 144 } 145 set_input_gain(float input_gain)146 inline void set_input_gain(float input_gain) { 147 input_gain_ = input_gain; 148 } 149 set_time(float reverb_time)150 inline void set_time(float reverb_time) { 151 reverb_time_ = reverb_time; 152 } 153 set_diffusion(float diffusion)154 inline void set_diffusion(float diffusion) { 155 diffusion_ = diffusion; 156 } 157 set_lp(float lp)158 inline void set_lp(float lp) { 159 lp_ = lp; 160 } 161 162 private: 163 typedef FxEngine<16384, FORMAT_12_BIT> E; 164 E engine_; 165 166 float amount_; 167 float input_gain_; 168 float reverb_time_; 169 float diffusion_; 170 float lp_; 171 172 float lp_decay_1_; 173 float lp_decay_2_; 174 175 DISALLOW_COPY_AND_ASSIGN(Reverb); 176 }; 177 178 } // namespace clouds 179 180 #endif // CLOUDS_DSP_FX_REVERB_H_ 181