1 // synthv1_reverb.h 2 // 3 /**************************************************************************** 4 Copyright (C) 2012-2021, rncbc aka Rui Nuno Capela. All rights reserved. 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License 8 as published by the Free Software Foundation; either version 2 9 of the License, or (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. main()15 16 You should have received a copy of the GNU General Public License along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 20 *****************************************************************************/ 21 22 #ifndef __synthv1_reverb_h 23 #define __synthv1_reverb_h 24 25 #include <cstdint> 26 #include <cstring> 27 28 29 //------------------------------------------------------------------------- 30 // synthv1_reverb 31 // 32 // -- borrowed, stirred and refactored from original FreeVerb -- 33 // by Jezar at Dreampoint, June 2000 (public domain) 34 // 35 36 class synthv1_reverb 37 { 38 public: 39 40 synthv1_reverb (float srate = 44100.0f) 41 : m_srate(srate), m_room(0.5f), m_damp(0.5f), m_feedb(0.5f) 42 { reset(); } 43 44 void setSampleRate(float srate) 45 { m_srate = srate; } 46 float sampleRate() const 47 { return m_srate; } 48 49 void reset() 50 { 51 static const uint32_t s_comb[NUM_COMBS] 52 = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617, 1685, 1748 }; 53 static const uint32_t s_allpass[NUM_ALLPASSES] 54 = { 556, 441, 341, 225, 180, 153 }; 55 56 const float sr = m_srate / 44100.0f; 57 58 uint32_t j; 59 60 for (j = 0; j < NUM_ALLPASSES; ++j) { 61 m_allpass0[j].resize(uint32_t(s_allpass[j] * sr)); 62 m_allpass0[j].reset(); 63 m_allpass1[j].resize(uint32_t((s_allpass[j] + STEREO_SPREAD) * sr)); 64 m_allpass1[j].reset(); 65 } 66 67 for (j = 0; j < NUM_COMBS; ++j) { 68 m_comb0[j].resize(uint32_t(s_comb[j] * sr)); 69 m_comb0[j].reset(); 70 m_comb1[j].resize(uint32_t((s_comb[j] + STEREO_SPREAD) * sr)); 71 m_comb1[j].reset(); 72 } 73 74 reset_feedb(); 75 reset_room(); 76 reset_damp(); 77 } 78 79 void process(float *in0, float *in1, uint32_t nframes, 80 float wet, float feedb, float room, float damp, float width) 81 { 82 if (wet < 1E-9f) 83 return; 84 85 if (m_feedb != feedb) { 86 m_feedb = feedb; 87 reset_feedb(); 88 } 89 90 if (m_room != room) { 91 m_room = room; 92 reset_room(); 93 } 94 95 if (m_damp != damp) { 96 m_damp = damp; 97 reset_damp(); 98 } 99 100 uint32_t i, j; 101 102 for (i = 0; i < nframes; ++i) { 103 104 float out0 = *in0 * 0.05f; // 0.015f; 105 float out1 = *in1 * 0.05f; // 0.015f; 106 107 float tmp0 = 0.0f; 108 float tmp1 = 0.0f; 109 110 for (j = 0; j < NUM_COMBS; ++j) { 111 tmp0 += m_comb0[j].output(out0); 112 tmp1 += m_comb1[j].output(out1); 113 } 114 115 for (j = 0; j < NUM_ALLPASSES; ++j) { 116 tmp0 = m_allpass0[j].output(tmp0); 117 tmp1 = m_allpass1[j].output(tmp1); 118 } 119 120 if (width < 0.0f) { 121 out0 = tmp0 * (1.0f + width) - tmp1 * width; 122 out1 = tmp1 * (1.0f + width) - tmp0 * width; 123 } else { 124 out0 = tmp0 * width + tmp1 * (1.0f - width); 125 out1 = tmp1 * width + tmp0 * (1.0f - width); 126 } 127 128 *in0++ += wet * out0; 129 *in1++ += wet * out1; 130 } 131 } 132 133 protected: 134 135 static const uint32_t NUM_COMBS = 10; 136 static const uint32_t NUM_ALLPASSES = 6; 137 static const uint32_t STEREO_SPREAD = 23; 138 139 void reset_room() 140 { 141 for (uint32_t j = 0; j < NUM_COMBS; ++j) { 142 m_comb0[j].set_feedb(m_room); 143 m_comb1[j].set_feedb(m_room); 144 } 145 } 146 147 void reset_damp() 148 { 149 const float damp2 = m_damp * m_damp; 150 for (uint32_t j = 0; j < NUM_COMBS; ++j) { 151 m_comb0[j].set_damp(damp2); 152 m_comb1[j].set_damp(damp2); 153 } 154 } 155 156 void reset_feedb() 157 { 158 const float feedb2 = 2.0f * m_feedb * (2.0f - m_feedb) / 3.0f; 159 for (uint32_t j = 0; j < NUM_ALLPASSES; ++j) { 160 m_allpass0[j].set_feedb(feedb2); 161 m_allpass1[j].set_feedb(feedb2); 162 } 163 } 164 165 class sample_buffer 166 { 167 public: 168 169 sample_buffer (uint32_t size = 0) 170 : m_buffer(0), m_size(0), m_index(0) 171 { resize(size); } 172 173 virtual ~sample_buffer() 174 { delete [] m_buffer; } 175 176 void reset() 177 { ::memset(m_buffer, 0, m_size * sizeof(float)); m_index = 0; } 178 179 void resize(uint32_t size) 180 { 181 if (size < 1) 182 size = 1; 183 if (m_size != size) { 184 const uint32_t old_size = m_size; 185 if (size > old_size) { 186 float *old_buffer = m_buffer; 187 m_buffer = new float [size]; 188 m_size = size; 189 if (old_buffer) { 190 ::memcpy(m_buffer, old_buffer, 191 old_size * sizeof(float)); 192 delete [] old_buffer; 193 } 194 } 195 } 196 } 197 198 float *tick() 199 { 200 float *buf = m_buffer + m_index; 201 if (++m_index >= m_size) 202 m_index = 0; 203 return buf; 204 } 205 206 private: 207 208 float *m_buffer; 209 uint32_t m_size; 210 uint32_t m_index; 211 }; 212 213 class comb_filter : public sample_buffer 214 { 215 public: 216 217 comb_filter (uint32_t size = 0) 218 : sample_buffer(size), m_feedb(0.5f), m_damp(0.5f), m_out(0.0f) {} 219 220 void set_feedb(float feedb) 221 { m_feedb = feedb; } 222 float feedb() const 223 { return m_feedb; } 224 225 void set_damp(float damp) 226 { m_damp = damp; } 227 float damp() const 228 { return m_damp; } 229 230 void reset() 231 { sample_buffer::reset(); m_out = 0.0f; } 232 233 float output(float in) 234 { 235 float *buf = tick(); 236 float out = *buf; 237 m_out = denormal(out * (1.0f - m_damp) + m_out * m_damp); 238 *buf = in + (m_out * m_feedb); 239 return out; 240 } 241 242 private: 243 244 float m_feedb; 245 float m_damp; 246 float m_out; 247 }; 248 249 class allpass_filter : public sample_buffer 250 { 251 public: 252 253 allpass_filter(uint32_t size = 0) 254 : sample_buffer(size), m_feedb(0.5f) {} 255 256 void set_feedb(float feedb) 257 { m_feedb = feedb; } 258 float feedb () const 259 { return m_feedb; } 260 261 float output(float in) 262 { 263 float *buf = tick(); 264 float out = *buf; 265 *buf = denormal(in + out * m_feedb); 266 return out - in; 267 } 268 269 private: 270 271 float m_feedb; 272 }; 273 274 static float denormal(float v) 275 { 276 union { float f; uint32_t w; } u; 277 u.f = v; 278 return (u.w & 0x7f800000) ? v : 0.0f; 279 } 280 281 private: 282 283 float m_srate; 284 285 float m_room; 286 float m_damp; 287 float m_feedb; 288 289 comb_filter m_comb0[NUM_COMBS]; 290 comb_filter m_comb1[NUM_COMBS]; 291 292 allpass_filter m_allpass0[NUM_ALLPASSES]; 293 allpass_filter m_allpass1[NUM_ALLPASSES]; 294 }; 295 296 297 #endif // __synthv1_reverb_h 298