Create FUNDING.yml
[wdl/wdl-ol.git] / WDL / verbengine.h
blob46dfb32e212071c7575fbd682ed8df93303341fd
1 #ifndef _VERBENGINE_H_
2 #define _VERBENGINE_H_
5 /*
6 WDL - verbengine.h
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.
34 #include "heapbuf.h"
37 #include "denormal.h"
39 class WDL_ReverbAllpass
41 public:
42 WDL_ReverbAllpass() { feedback=0.5; setsize(1); }
43 ~WDL_ReverbAllpass() { }
45 void setsize(int size)
47 if (size<1)size=1;
48 if (buffer.GetSize()!=size)
50 bufidx=0;
51 buffer.Resize(size);
52 Reset();
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;
67 return output;
69 void Reset() { memset(buffer.Get(),0,buffer.GetSize()*sizeof(double)); }
70 void setfeedback(double val) { feedback=val; }
72 private:
73 double feedback;
74 WDL_TypedBuf<double> buffer;
75 int bufidx;
76 public:
77 int __pad;
79 } WDL_FIXALIGN;
82 class WDL_ReverbComb
84 public:
85 WDL_ReverbComb() { feedback=0.5; damp=0.5; filterstore=0; setsize(1); }
86 ~WDL_ReverbComb() { }
88 void setsize(int size)
90 if (size<1)size=1;
91 if (buffer.GetSize()!=size)
93 bufidx=0;
94 buffer.Resize(size);
95 Reset();
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;
109 return output;
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; }
115 private:
117 double feedback;
118 double filterstore;
119 double damp;
120 WDL_TypedBuf<double> buffer;
121 int bufidx;
122 public:
123 int __pad;
124 } WDL_FIXALIGN;
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
134 public:
135 WDL_ReverbEngine()
137 m_srate=44100.0;
138 m_roomsize=0.5;
139 m_damp=0.5;
140 SetWidth(1.0);
141 Reset(false);
143 ~WDL_ReverbEngine()
146 void SetSampleRate(double srate)
148 if (m_srate!=srate)
150 m_srate=srate;
151 Reset(true);
155 void ProcessSampleBlock(double *spl0, double *spl1, double *outp0, double *outp1, int ns)
157 int x;
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)
163 int i=ns;
164 double *p0=outp0,*p1=outp1,*i0=spl0,*i1=spl1;
165 while (i--)
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)
176 int i=ns;
177 double *p0=outp0,*p1=outp1;
178 while (i--)
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);
186 int i=ns;
187 double *p0=outp0,*p1=outp1;
188 while (i--)
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;
193 if (m_wid<0)
195 double m=-m_wid;
196 *p0 = b*m + a*(1.0-m);
197 *p1 = a*m + b*(1.0-m);
199 else
201 double m=m_wid;
202 *p0 = a*m + b*(1.0-m);
203 *p1 = b*m + a*(1.0-m);
205 p0++;
206 p1++;
211 void ProcessSample(double *spl0, double *spl1)
213 int x;
214 double in0=*spl0 * 0.015;
215 double in1=*spl1 * 0.015;
217 double out0=0.0;
218 double out1=0.0;
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);
230 if (m_wid<0)
232 double m=-m_wid;
233 *spl0 = out1*m + out0*(1.0-m);
234 *spl1 = out0*m + out1*(1.0-m);
236 else
238 double m=m_wid;
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
246 int x;
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);
254 if (doclear)
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);
268 if (doclear)
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)
281 if (wid<-1) wid=-1;
282 else if (wid>1) wid=1;
283 wid*=0.5;
284 if (wid>=0.0) wid+=0.5;
285 else wid-=0.5;
286 m_wid=wid;
287 } // -1..1
289 private:
290 double m_wid;
291 double m_roomsize;
292 double m_damp;
293 double m_srate;
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];
300 #endif