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