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