7 Copyright (C) 2007 and later Cockos Incorporated
9 This is based on the public domain FreeVerb source:
10 by Jezar at Dreampoint, June 2000
11 http://www.dreampoint.co.uk
13 Filter tweaks and general guidance thanks to Thomas Scott Stillwell.
15 This software is provided 'as-is', without any express or implied
16 warranty. In no event will the authors be held liable for any damages
17 arising from the use of this software.
19 Permission is granted to anyone to use this software for any purpose,
20 including commercial applications, and to alter it and redistribute it
21 freely, subject to the following restrictions:
23 1. The origin of this software must not be misrepresented; you must not
24 claim that you wrote the original software. If you use this software
25 in a product, an acknowledgment in the product documentation would be
26 appreciated but is not required.
27 2. Altered source versions must be plainly marked as such, and must not be
28 misrepresented as being the original software.
29 3. This notice may not be removed or altered from any source distribution.
39 class WDL_ReverbAllpass
42 WDL_ReverbAllpass() { feedback
=0.5; setsize(1); }
43 ~WDL_ReverbAllpass() { }
45 void setsize(int size
)
48 if (buffer
.GetSize()!=size
)
56 double process(double inp
)
58 double *bptr
=buffer
.Get()+bufidx
;
60 double bufout
= *bptr
;
62 double output
= bufout
- inp
;
63 *bptr
= denormal_filter_double(inp
+ (bufout
*feedback
));
65 if(++bufidx
>=buffer
.GetSize()) bufidx
= 0;
69 void Reset() { memset(buffer
.Get(),0,buffer
.GetSize()*sizeof(double)); }
70 void setfeedback(double val
) { feedback
=val
; }
74 WDL_TypedBuf
<double> buffer
;
85 WDL_ReverbComb() { feedback
=0.5; damp
=0.5; filterstore
=0; setsize(1); }
88 void setsize(int size
)
91 if (buffer
.GetSize()!=size
)
99 double process(double inp
)
101 double *bptr
=buffer
.Get()+bufidx
;
102 double output
= *bptr
;
103 filterstore
= denormal_filter_double((output
*(1-damp
)) + (filterstore
*damp
));
105 *bptr
= inp
+ (filterstore
*feedback
);
107 if(++bufidx
>=buffer
.GetSize()) bufidx
= 0;
111 void Reset() { memset(buffer
.Get(),0,buffer
.GetSize()*sizeof(double)); }
112 void setdamp(double val
) { damp
=val
; }
113 void setfeedback(double val
) { feedback
=val
; }
120 WDL_TypedBuf
<double> buffer
;
126 // these represent lengths in samples at 44.1khz but are scaled accordingly
127 const int wdl_verb__stereospread
=23;
128 const short wdl_verb__combtunings
[]={1116,1188,1277,1356,1422,1491,1557,1617,1685,1748};
129 const short wdl_verb__allpasstunings
[]={556,441,341,225,180,153};
132 class WDL_ReverbEngine
146 void SetSampleRate(double srate
)
155 void ProcessSampleBlock(double *spl0
, double *spl1
, double *outp0
, double *outp1
, int ns
)
158 memset(outp0
,0,ns
*sizeof(double));
159 memset(outp1
,0,ns
*sizeof(double));
161 for (x
= 0; x
< sizeof(wdl_verb__combtunings
)/sizeof(wdl_verb__combtunings
[0]); x
+= 2)
164 double *p0
=outp0
,*p1
=outp1
,*i0
=spl0
,*i1
=spl1
;
167 double a
=*i0
++,b
=*i1
++;
168 *p0
+=m_combs
[x
][0].process(a
);
169 *p1
+=m_combs
[x
][1].process(b
);
170 *p0
+++=m_combs
[x
+1][0].process(a
);
171 *p1
+++=m_combs
[x
+1][1].process(b
);
174 for (x
= 0; x
< sizeof(wdl_verb__allpasstunings
)/sizeof(wdl_verb__allpasstunings
[0])-2; x
+= 2)
177 double *p0
=outp0
,*p1
=outp1
;
180 double tmp
=m_allpasses
[x
][0].process(*p0
);
181 double tmp2
=m_allpasses
[x
][1].process(*p1
);
182 *p0
++=m_allpasses
[x
+1][0].process(tmp
);
183 *p1
++=m_allpasses
[x
+1][1].process(tmp2
);
187 double *p0
=outp0
,*p1
=outp1
;
190 double a
=m_allpasses
[x
+1][0].process(m_allpasses
[x
][0].process(*p0
))*0.015;
191 double b
=m_allpasses
[x
+1][1].process(m_allpasses
[x
][1].process(*p1
))*0.015;
196 *p0
= b
*m
+ a
*(1.0-m
);
197 *p1
= a
*m
+ b
*(1.0-m
);
202 *p0
= a
*m
+ b
*(1.0-m
);
203 *p1
= b
*m
+ a
*(1.0-m
);
211 void ProcessSample(double *spl0
, double *spl1
)
214 double in0
=*spl0
* 0.015;
215 double in1
=*spl1
* 0.015;
219 for (x
= 0; x
< sizeof(wdl_verb__combtunings
)/sizeof(wdl_verb__combtunings
[0]); x
++)
221 out0
+=m_combs
[x
][0].process(in0
);
222 out1
+=m_combs
[x
][1].process(in1
);
224 for (x
= 0; x
< sizeof(wdl_verb__allpasstunings
)/sizeof(wdl_verb__allpasstunings
[0]); x
++)
226 out0
=m_allpasses
[x
][0].process(out0
);
227 out1
=m_allpasses
[x
][1].process(out1
);
233 *spl0
= out1
*m
+ out0
*(1.0-m
);
234 *spl1
= out0
*m
+ out1
*(1.0-m
);
239 *spl0
= out0
*m
+ out1
*(1.0-m
);
240 *spl1
= out1
*m
+ out0
*(1.0-m
);
244 void Reset(bool doclear
=false) // call this after changing roomsize or dampening
247 double sc
=m_srate
/ 44100.0;
248 for (x
= 0; x
< sizeof(wdl_verb__allpasstunings
)/sizeof(wdl_verb__allpasstunings
[0]); x
++)
250 m_allpasses
[x
][0].setsize((int) (wdl_verb__allpasstunings
[x
] * sc
));
251 m_allpasses
[x
][1].setsize((int) ((wdl_verb__allpasstunings
[x
]+wdl_verb__stereospread
) * sc
));
252 m_allpasses
[x
][0].setfeedback(0.5);
253 m_allpasses
[x
][1].setfeedback(0.5);
256 m_allpasses
[x
][0].Reset();
257 m_allpasses
[x
][1].Reset();
260 for (x
= 0; x
< sizeof(wdl_verb__combtunings
)/sizeof(wdl_verb__combtunings
[0]); x
++)
262 m_combs
[x
][0].setsize((int) (wdl_verb__combtunings
[x
] * sc
));
263 m_combs
[x
][1].setsize((int) ((wdl_verb__combtunings
[x
]+wdl_verb__stereospread
) * sc
));
264 m_combs
[x
][0].setfeedback(m_roomsize
);
265 m_combs
[x
][1].setfeedback(m_roomsize
);
266 m_combs
[x
][0].setdamp(m_damp
*0.4);
267 m_combs
[x
][1].setdamp(m_damp
*0.4);
270 m_combs
[x
][0].Reset();
271 m_combs
[x
][1].Reset();
277 void SetRoomSize(double sz
) { m_roomsize
=sz
;; } // 0.3..0.99 or so
278 void SetDampening(double dmp
) { m_damp
=dmp
; } // 0..1
279 void SetWidth(double wid
)
282 else if (wid
>1) wid
=1;
284 if (wid
>=0.0) wid
+=0.5;
294 WDL_ReverbAllpass m_allpasses
[sizeof(wdl_verb__allpasstunings
)/sizeof(wdl_verb__allpasstunings
[0])][2];
295 WDL_ReverbComb m_combs
[sizeof(wdl_verb__combtunings
)/sizeof(wdl_verb__combtunings
[0])][2];