History

rename LEAF folder to leaf for easier JUCE module usage

Matthew Wang committed 6 years ago

Commit cf5c3f21 parent 3ffbba144 files · +35820 −-2Browse files

Unified · Split

44 files
  1. leaf/.DS_Store +0 −0
  2. leaf/.gitignore +11 −0
  3. leaf/Externals/.DS_Store +0 −0
  4. leaf/Externals/d_fft_mayer.c +423 −0
  5. leaf/Externals/d_fft_mayer.h +31 −0
  6. leaf/Externals/trigtbl.h +173 −0
  7. leaf/Inc/leaf-analysis.h +296 −0
  8. leaf/Inc/leaf-delay.h +229 −0
  9. leaf/Inc/leaf-distortion.h +164 −0
  10. leaf/Inc/leaf-dynamics.h +122 −0
  11. leaf/Inc/leaf-effects.h +360 −0
  12. leaf/Inc/leaf-electrical.h +103 −0
  13. leaf/Inc/leaf-envelopes.h +366 −0
  14. leaf/Inc/leaf-filters.h +486 −0
  15. leaf/Inc/leaf-global.h +52 −0
  16. leaf/Inc/leaf-instruments.h +209 −0
  17. leaf/Inc/leaf-math.h +212 −0
  18. leaf/Inc/leaf-mempool.h +159 −0
  19. leaf/Inc/leaf-midi.h +510 −0
  20. leaf/Inc/leaf-oscillators.h +1143 −0
  21. leaf/Inc/leaf-physical.h +259 −0
  22. leaf/Inc/leaf-reverb.h +175 −0
  23. leaf/Inc/leaf-sampling.h +188 −0
  24. leaf/Inc/leaf-tables.h +104 −0
  25. leaf/Src/leaf-analysis.c +1054 −0
  26. leaf/Src/leaf-delay.c +928 −0
  27. leaf/Src/leaf-distortion.c +695 −0
  28. leaf/Src/leaf-dynamics.c +281 −0
  29. leaf/Src/leaf-effects.c +1853 −0
  30. leaf/Src/leaf-electrical.c +551 −0
  31. leaf/Src/leaf-envelopes.c +1612 −0
  32. leaf/Src/leaf-filters.c +1802 −0
  33. leaf/Src/leaf-instruments.c +706 −0
  34. leaf/Src/leaf-math.c +655 −0
  35. leaf/Src/leaf-mempool.c +412 −0
  36. leaf/Src/leaf-midi.c +980 −0
  37. leaf/Src/leaf-oscillators.c +1660 −0
  38. leaf/Src/leaf-physical.c +747 −0
  39. leaf/Src/leaf-reverb.c +925 −0
  40. leaf/Src/leaf-sampling.c +866 −0
  41. leaf/Src/leaf-tables.c +14061 −0
  42. leaf/Src/leaf.c +60 −0
  43. leaf/leaf.cpp +45 −0
  44. leaf/leaf.h +154 −0
leaf/.DS_Store+0−0

Binary file not shown.

leaf/.gitignore+11−0
@@ -0,0 +1,11 @@
1+*.DS_Store
2+*.app
3+*.a
4+*.appex
5+*.vst
6+*.vst3
7+*.component
8+*.xcuserstate
9+*.zip
10+*.swp
11+*/Builds
leaf/Externals/.DS_Store+0−0

Binary file not shown.

leaf/Externals/d_fft_mayer.c+423−0
@@ -0,0 +1,423 @@
1+/*
2+** FFT and FHT routines
3+** Copyright 1988, 1993; Ron Mayer
4+**
5+** mayer_fht(fz,n);
6+** Does a hartley transform of "n" points in the array "fz".
7+** mayer_fft(n,real,imag)
8+** Does a fourier transform of "n" points of the "real" and
9+** "imag" arrays.
10+** mayer_ifft(n,real,imag)
11+** Does an inverse fourier transform of "n" points of the "real"
12+** and "imag" arrays.
13+** mayer_realfft(n,real)
14+** Does a real-valued fourier transform of "n" points of the
15+** "real" array. The real part of the transform ends
16+** up in the first half of the array and the imaginary part of the
17+** transform ends up in the second half of the array.
18+** mayer_realifft(n,real)
19+** The inverse of the realfft() routine above.
20+**
21+**
22+** NOTE: This routine uses at least 2 patented algorithms, and may be
23+** under the restrictions of a bunch of different organizations.
24+** Although I wrote it completely myself, it is kind of a derivative
25+** of a routine I once authored and released under the GPL, so it
26+** may fall under the free software foundation's restrictions;
27+** it was worked on as a Stanford Univ project, so they claim
28+** some rights to it; it was further optimized at work here, so
29+** I think this company claims parts of it. The patents are
30+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
31+** trig generator), both at Stanford Univ.
32+** If it were up to me, I'd say go do whatever you want with it;
33+** but it would be polite to give credit to the following people
34+** if you use this anywhere:
35+** Euler - probable inventor of the fourier transform.
36+** Gauss - probable inventor of the FFT.
37+** Hartley - probable inventor of the hartley transform.
38+** Buneman - for a really cool trig generator
39+** Mayer(me) - for authoring this particular version and
40+** including all the optimizations in one package.
41+** Thanks,
42+** Ron Mayer; mayer@acuson.com
43+**
44+*/
45+
46+/* This is a slightly modified version of Mayer's contribution; write
47+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
48+* of work. -msp
49+*/
50+
51+/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */
52+#ifdef _MSC_VER
53+#pragma warning( disable : 4305 ) /* uncast const double to float */
54+#pragma warning( disable : 4244 ) /* uncast double to float */
55+#pragma warning( disable : 4101 ) /* unused local variables */
56+#endif
57+
58+/* the following is needed only to declare pd_fft() as exportable in MSW */
59+#define t_sample float
60+
61+#define REAL t_sample
62+#define GOOD_TRIG
63+
64+#ifdef GOOD_TRIG
65+#else
66+#define FAST_TRIG
67+#endif
68+
69+#if defined(GOOD_TRIG)
70+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
71+#define TRIG_VARS \
72+ int t_lam=0;
73+#define TRIG_INIT(k,c,s) \
74+ { \
75+ int i; \
76+ for (i=2 ; i<=k ; i++) \
77+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
78+ t_lam = 0; \
79+ c = 1; \
80+ s = 0; \
81+ }
82+#define TRIG_NEXT(k,c,s) \
83+ { \
84+ int i,j; \
85+ (t_lam)++; \
86+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
87+ i = k-i; \
88+ s = sinwrk[i]; \
89+ c = coswrk[i]; \
90+ if (i>1) \
91+ { \
92+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
93+ j = k - j; \
94+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
95+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
96+ } \
97+ }
98+#define TRIG_RESET(k,c,s)
99+#endif
100+
101+#if defined(FAST_TRIG)
102+#define TRIG_VARS \
103+ REAL t_c,t_s;
104+#define TRIG_INIT(k,c,s) \
105+ { \
106+ t_c = costab[k]; \
107+ t_s = sintab[k]; \
108+ c = 1; \
109+ s = 0; \
110+ }
111+#define TRIG_NEXT(k,c,s) \
112+ { \
113+ REAL t = c; \
114+ c = t*t_c - s*t_s; \
115+ s = t*t_s + s*t_c; \
116+ }
117+#define TRIG_RESET(k,c,s)
118+#endif
119+
120+static REAL halsec[20]=
121+ {
122+ 0,
123+ 0,
124+ .54119610014619698439972320536638942006107206337801,
125+ .50979557910415916894193980398784391368261849190893,
126+ .50241928618815570551167011928012092247859337193963,
127+ .50060299823519630134550410676638239611758632599591,
128+ .50015063602065098821477101271097658495974913010340,
129+ .50003765191554772296778139077905492847503165398345,
130+ .50000941253588775676512870469186533538523133757983,
131+ .50000235310628608051401267171204408939326297376426,
132+ .50000058827484117879868526730916804925780637276181,
133+ .50000014706860214875463798283871198206179118093251,
134+ .50000003676714377807315864400643020315103490883972,
135+ .50000000919178552207366560348853455333939112569380,
136+ .50000000229794635411562887767906868558991922348920,
137+ .50000000057448658687873302235147272458812263401372
138+ };
139+static REAL costab[20]=
140+ {
141+ .00000000000000000000000000000000000000000000000000,
142+ .70710678118654752440084436210484903928483593768847,
143+ .92387953251128675612818318939678828682241662586364,
144+ .98078528040323044912618223613423903697393373089333,
145+ .99518472667219688624483695310947992157547486872985,
146+ .99879545620517239271477160475910069444320361470461,
147+ .99969881869620422011576564966617219685006108125772,
148+ .99992470183914454092164649119638322435060646880221,
149+ .99998117528260114265699043772856771617391725094433,
150+ .99999529380957617151158012570011989955298763362218,
151+ .99999882345170190992902571017152601904826792288976,
152+ .99999970586288221916022821773876567711626389934930,
153+ .99999992646571785114473148070738785694820115568892,
154+ .99999998161642929380834691540290971450507605124278,
155+ .99999999540410731289097193313960614895889430318945,
156+ .99999999885102682756267330779455410840053741619428
157+ };
158+static REAL sintab[20]=
159+ {
160+ 1.0000000000000000000000000000000000000000000000000,
161+ .70710678118654752440084436210484903928483593768846,
162+ .38268343236508977172845998403039886676134456248561,
163+ .19509032201612826784828486847702224092769161775195,
164+ .09801714032956060199419556388864184586113667316749,
165+ .04906767432741801425495497694268265831474536302574,
166+ .02454122852291228803173452945928292506546611923944,
167+ .01227153828571992607940826195100321214037231959176,
168+ .00613588464915447535964023459037258091705788631738,
169+ .00306795676296597627014536549091984251894461021344,
170+ .00153398018628476561230369715026407907995486457522,
171+ .00076699031874270452693856835794857664314091945205,
172+ .00038349518757139558907246168118138126339502603495,
173+ .00019174759731070330743990956198900093346887403385,
174+ .00009587379909597734587051721097647635118706561284,
175+ .00004793689960306688454900399049465887274686668768
176+ };
177+static REAL coswrk[20]=
178+ {
179+ .00000000000000000000000000000000000000000000000000,
180+ .70710678118654752440084436210484903928483593768847,
181+ .92387953251128675612818318939678828682241662586364,
182+ .98078528040323044912618223613423903697393373089333,
183+ .99518472667219688624483695310947992157547486872985,
184+ .99879545620517239271477160475910069444320361470461,
185+ .99969881869620422011576564966617219685006108125772,
186+ .99992470183914454092164649119638322435060646880221,
187+ .99998117528260114265699043772856771617391725094433,
188+ .99999529380957617151158012570011989955298763362218,
189+ .99999882345170190992902571017152601904826792288976,
190+ .99999970586288221916022821773876567711626389934930,
191+ .99999992646571785114473148070738785694820115568892,
192+ .99999998161642929380834691540290971450507605124278,
193+ .99999999540410731289097193313960614895889430318945,
194+ .99999999885102682756267330779455410840053741619428
195+ };
196+static REAL sinwrk[20]=
197+ {
198+ 1.0000000000000000000000000000000000000000000000000,
199+ .70710678118654752440084436210484903928483593768846,
200+ .38268343236508977172845998403039886676134456248561,
201+ .19509032201612826784828486847702224092769161775195,
202+ .09801714032956060199419556388864184586113667316749,
203+ .04906767432741801425495497694268265831474536302574,
204+ .02454122852291228803173452945928292506546611923944,
205+ .01227153828571992607940826195100321214037231959176,
206+ .00613588464915447535964023459037258091705788631738,
207+ .00306795676296597627014536549091984251894461021344,
208+ .00153398018628476561230369715026407907995486457522,
209+ .00076699031874270452693856835794857664314091945205,
210+ .00038349518757139558907246168118138126339502603495,
211+ .00019174759731070330743990956198900093346887403385,
212+ .00009587379909597734587051721097647635118706561284,
213+ .00004793689960306688454900399049465887274686668768
214+ };
215+
216+
217+#define SQRT2_2 0.70710678118654752440084436210484
218+#define SQRT2 2*0.70710678118654752440084436210484
219+
220+void mayer_fht(REAL *fz, int n)
221+{
222+/* REAL a,b;
223+REAL c1,s1,s2,c2,s3,c3,s4,c4;
224+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
225+ int k,k1,k2,k3,k4,kx;
226+ REAL *fi,*fn,*gi;
227+ TRIG_VARS;
228+
229+ for (k1=1,k2=0;k1<n;k1++)
230+ {
231+ REAL aa;
232+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
233+ if (k1>k2)
234+ {
235+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
236+ }
237+ }
238+ for ( k=0 ; (1<<k)<n ; k++ );
239+ k &= 1;
240+ if (k==0)
241+ {
242+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
243+ {
244+ REAL f0,f1,f2,f3;
245+ f1 = fi[0 ]-fi[1 ];
246+ f0 = fi[0 ]+fi[1 ];
247+ f3 = fi[2 ]-fi[3 ];
248+ f2 = fi[2 ]+fi[3 ];
249+ fi[2 ] = (f0-f2);
250+ fi[0 ] = (f0+f2);
251+ fi[3 ] = (f1-f3);
252+ fi[1 ] = (f1+f3);
253+ }
254+ }
255+ else
256+ {
257+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
258+ {
259+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
260+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
261+ bc1 = fi[0 ] - gi[0 ];
262+ bs1 = fi[0 ] + gi[0 ];
263+ bc2 = fi[2 ] - gi[2 ];
264+ bs2 = fi[2 ] + gi[2 ];
265+ bc3 = fi[4 ] - gi[4 ];
266+ bs3 = fi[4 ] + gi[4 ];
267+ bc4 = fi[6 ] - gi[6 ];
268+ bs4 = fi[6 ] + gi[6 ];
269+ bf1 = (bs1 - bs2);
270+ bf0 = (bs1 + bs2);
271+ bg1 = (bc1 - bc2);
272+ bg0 = (bc1 + bc2);
273+ bf3 = (bs3 - bs4);
274+ bf2 = (bs3 + bs4);
275+ bg3 = SQRT2*bc4;
276+ bg2 = SQRT2*bc3;
277+ fi[4 ] = bf0 - bf2;
278+ fi[0 ] = bf0 + bf2;
279+ fi[6 ] = bf1 - bf3;
280+ fi[2 ] = bf1 + bf3;
281+ gi[4 ] = bg0 - bg2;
282+ gi[0 ] = bg0 + bg2;
283+ gi[6 ] = bg1 - bg3;
284+ gi[2 ] = bg1 + bg3;
285+ }
286+ }
287+ if (n<16) return;
288+
289+ do
290+ {
291+ REAL s1,c1;
292+ int ii;
293+ k += 2;
294+ k1 = 1 << k;
295+ k2 = k1 << 1;
296+ k4 = k2 << 1;
297+ k3 = k2 + k1;
298+ kx = k1 >> 1;
299+ fi = fz;
300+ gi = fi + kx;
301+ fn = fz + n;
302+ do
303+ {
304+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
305+ f1 = fi[0 ] - fi[k1];
306+ f0 = fi[0 ] + fi[k1];
307+ f3 = fi[k2] - fi[k3];
308+ f2 = fi[k2] + fi[k3];
309+ fi[k2] = f0 - f2;
310+ fi[0 ] = f0 + f2;
311+ fi[k3] = f1 - f3;
312+ fi[k1] = f1 + f3;
313+ g1 = gi[0 ] - gi[k1];
314+ g0 = gi[0 ] + gi[k1];
315+ g3 = SQRT2 * gi[k3];
316+ g2 = SQRT2 * gi[k2];
317+ gi[k2] = g0 - g2;
318+ gi[0 ] = g0 + g2;
319+ gi[k3] = g1 - g3;
320+ gi[k1] = g1 + g3;
321+ gi += k4;
322+ fi += k4;
323+ } while (fi<fn);
324+ TRIG_INIT(k,c1,s1);
325+ for (ii=1;ii<kx;ii++)
326+ {
327+ REAL c2,s2;
328+ TRIG_NEXT(k,c1,s1);
329+ c2 = c1*c1 - s1*s1;
330+ s2 = 2*(c1*s1);
331+ fn = fz + n;
332+ fi = fz +ii;
333+ gi = fz +k1-ii;
334+ do
335+ {
336+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
337+ b = s2*fi[k1] - c2*gi[k1];
338+ a = c2*fi[k1] + s2*gi[k1];
339+ f1 = fi[0 ] - a;
340+ f0 = fi[0 ] + a;
341+ g1 = gi[0 ] - b;
342+ g0 = gi[0 ] + b;
343+ b = s2*fi[k3] - c2*gi[k3];
344+ a = c2*fi[k3] + s2*gi[k3];
345+ f3 = fi[k2] - a;
346+ f2 = fi[k2] + a;
347+ g3 = gi[k2] - b;
348+ g2 = gi[k2] + b;
349+ b = s1*f2 - c1*g3;
350+ a = c1*f2 + s1*g3;
351+ fi[k2] = f0 - a;
352+ fi[0 ] = f0 + a;
353+ gi[k3] = g1 - b;
354+ gi[k1] = g1 + b;
355+ b = c1*g2 - s1*f3;
356+ a = s1*g2 + c1*f3;
357+ gi[k2] = g0 - a;
358+ gi[0 ] = g0 + a;
359+ fi[k3] = f1 - b;
360+ fi[k1] = f1 + b;
361+ gi += k4;
362+ fi += k4;
363+ } while (fi<fn);
364+ }
365+ TRIG_RESET(k,c1,s1);
366+ } while (k4<n);
367+}
368+
369+void mayer_fft(int n, REAL *real, REAL *imag)
370+{
371+ REAL a,b,c,d;
372+ REAL q,r,s,t;
373+ int i,j,k;
374+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
375+ a = real[i]; b = real[j]; q=a+b; r=a-b;
376+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
377+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
378+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
379+ }
380+ mayer_fht(real,n);
381+ mayer_fht(imag,n);
382+}
383+
384+void mayer_ifft(int n, REAL *real, REAL *imag)
385+{
386+ REAL a,b,c,d;
387+ REAL q,r,s,t;
388+ int i,j,k;
389+ mayer_fht(real,n);
390+ mayer_fht(imag,n);
391+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
392+ a = real[i]; b = real[j]; q=a+b; r=a-b;
393+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
394+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
395+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
396+ }
397+}
398+
399+void mayer_realfft(int n, REAL *real)
400+{
401+ REAL a,b;
402+ int i,j,k;
403+ mayer_fht(real,n);
404+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
405+ a = real[i];
406+ b = real[j];
407+ real[j] = (a-b)*0.5;
408+ real[i] = (a+b)*0.5;
409+ }
410+}
411+
412+void mayer_realifft(int n, REAL *real)
413+{
414+ REAL a,b;
415+ int i,j,k;
416+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
417+ a = real[i];
418+ b = real[j];
419+ real[j] = (a-b);
420+ real[i] = (a+b);
421+ }
422+ mayer_fht(real,n);
423+}
leaf/Externals/d_fft_mayer.h+31−0
@@ -0,0 +1,31 @@
1+/*
2+ * d_fft_mayer.h
3+ *
4+ * Created: 5/4/2017 10:33:59 PM
5+ * Author: Kenny
6+ */
7+
8+
9+#ifndef D_FFT_MAYER_H_
10+#define D_FFT_MAYER_H_
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+typedef float t_sample; /* a float type at most the same size */
17+
18+#define REAL t_sample
19+
20+void mayer_fht(REAL *fz, int n);
21+void mayer_fft(int n, REAL *real, REAL *imag);
22+void mayer_ifft(int n, REAL *real, REAL *imag);
23+void mayer_realfft(int n, REAL *real);
24+void mayer_realifft(int n, REAL *real);
25+
26+
27+#ifdef __cplusplus
28+}
29+#endif
30+
31+#endif /* D_FFT_MAYER_H_ */
leaf/Externals/trigtbl.h+173−0
@@ -0,0 +1,173 @@
1+
2+/*
3+** Please only distribute this with it's associated FHT routine.
4+** This algorithm is apparently patented(!) and the code copyrighted.
5+** See the comment with the fht routine for more info.
6+** -Thanks,
7+** Ron Mayer
8+*/
9+
10+#ifdef __cplusplus
11+extern "C" {
12+#endif
13+
14+#ifdef REAL
15+#else
16+#define REAL double
17+#endif
18+
19+#ifdef GOOD_TRIG
20+#else
21+#define FAST_TRIG
22+#endif
23+
24+#if defined(GOOD_TRIG)
25+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
26+#define TRIG_VARS \
27+ int t_lam=0;
28+#define TRIG_INIT(k,c,s) \
29+ { \
30+ int i; \
31+ for (i=2 ; i<=k ; i++) \
32+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
33+ t_lam = 0; \
34+ c = 1; \
35+ s = 0; \
36+ }
37+#define TRIG_NEXT(k,c,s) \
38+ { \
39+ int i,j; \
40+ (t_lam)++; \
41+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
42+ i = k-i; \
43+ s = sinwrk[i]; \
44+ c = coswrk[i]; \
45+ if (i>1) \
46+ { \
47+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
48+ j = k - j; \
49+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
50+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
51+ } \
52+ }
53+#define TRIG_RESET(k,c,s)
54+#endif
55+
56+#if defined(FAST_TRIG)
57+#define TRIG_VARS \
58+ REAL t_c,t_s;
59+#define TRIG_INIT(k,c,s) \
60+ { \
61+ t_c = costab[k]; \
62+ t_s = sintab[k]; \
63+ c = 1; \
64+ s = 0; \
65+ }
66+#define TRIG_NEXT(k,c,s) \
67+ { \
68+ REAL t = c; \
69+ c = t*t_c - s*t_s; \
70+ s = t*t_s + s*t_c; \
71+ }
72+#define TRIG_RESET(k,c,s)
73+#endif
74+
75+static REAL halsec[20]=
76+ {
77+ 0,
78+ 0,
79+ .54119610014619698439972320536638942006107206337801,
80+ .50979557910415916894193980398784391368261849190893,
81+ .50241928618815570551167011928012092247859337193963,
82+ .50060299823519630134550410676638239611758632599591,
83+ .50015063602065098821477101271097658495974913010340,
84+ .50003765191554772296778139077905492847503165398345,
85+ .50000941253588775676512870469186533538523133757983,
86+ .50000235310628608051401267171204408939326297376426,
87+ .50000058827484117879868526730916804925780637276181,
88+ .50000014706860214875463798283871198206179118093251,
89+ .50000003676714377807315864400643020315103490883972,
90+ .50000000919178552207366560348853455333939112569380,
91+ .50000000229794635411562887767906868558991922348920,
92+ .50000000057448658687873302235147272458812263401372
93+ };
94+static REAL costab[20]=
95+ {
96+ .00000000000000000000000000000000000000000000000000,
97+ .70710678118654752440084436210484903928483593768847,
98+ .92387953251128675612818318939678828682241662586364,
99+ .98078528040323044912618223613423903697393373089333,
100+ .99518472667219688624483695310947992157547486872985,
101+ .99879545620517239271477160475910069444320361470461,
102+ .99969881869620422011576564966617219685006108125772,
103+ .99992470183914454092164649119638322435060646880221,
104+ .99998117528260114265699043772856771617391725094433,
105+ .99999529380957617151158012570011989955298763362218,
106+ .99999882345170190992902571017152601904826792288976,
107+ .99999970586288221916022821773876567711626389934930,
108+ .99999992646571785114473148070738785694820115568892,
109+ .99999998161642929380834691540290971450507605124278,
110+ .99999999540410731289097193313960614895889430318945,
111+ .99999999885102682756267330779455410840053741619428
112+ };
113+static REAL sintab[20]=
114+ {
115+ 1.0000000000000000000000000000000000000000000000000,
116+ .70710678118654752440084436210484903928483593768846,
117+ .38268343236508977172845998403039886676134456248561,
118+ .19509032201612826784828486847702224092769161775195,
119+ .09801714032956060199419556388864184586113667316749,
120+ .04906767432741801425495497694268265831474536302574,
121+ .02454122852291228803173452945928292506546611923944,
122+ .01227153828571992607940826195100321214037231959176,
123+ .00613588464915447535964023459037258091705788631738,
124+ .00306795676296597627014536549091984251894461021344,
125+ .00153398018628476561230369715026407907995486457522,
126+ .00076699031874270452693856835794857664314091945205,
127+ .00038349518757139558907246168118138126339502603495,
128+ .00019174759731070330743990956198900093346887403385,
129+ .00009587379909597734587051721097647635118706561284,
130+ .00004793689960306688454900399049465887274686668768
131+ };
132+static REAL coswrk[20]=
133+ {
134+ .00000000000000000000000000000000000000000000000000,
135+ .70710678118654752440084436210484903928483593768847,
136+ .92387953251128675612818318939678828682241662586364,
137+ .98078528040323044912618223613423903697393373089333,
138+ .99518472667219688624483695310947992157547486872985,
139+ .99879545620517239271477160475910069444320361470461,
140+ .99969881869620422011576564966617219685006108125772,
141+ .99992470183914454092164649119638322435060646880221,
142+ .99998117528260114265699043772856771617391725094433,
143+ .99999529380957617151158012570011989955298763362218,
144+ .99999882345170190992902571017152601904826792288976,
145+ .99999970586288221916022821773876567711626389934930,
146+ .99999992646571785114473148070738785694820115568892,
147+ .99999998161642929380834691540290971450507605124278,
148+ .99999999540410731289097193313960614895889430318945,
149+ .99999999885102682756267330779455410840053741619428
150+ };
151+static REAL sinwrk[20]=
152+ {
153+ 1.0000000000000000000000000000000000000000000000000,
154+ .70710678118654752440084436210484903928483593768846,
155+ .38268343236508977172845998403039886676134456248561,
156+ .19509032201612826784828486847702224092769161775195,
157+ .09801714032956060199419556388864184586113667316749,
158+ .04906767432741801425495497694268265831474536302574,
159+ .02454122852291228803173452945928292506546611923944,
160+ .01227153828571992607940826195100321214037231959176,
161+ .00613588464915447535964023459037258091705788631738,
162+ .00306795676296597627014536549091984251894461021344,
163+ .00153398018628476561230369715026407907995486457522,
164+ .00076699031874270452693856835794857664314091945205,
165+ .00038349518757139558907246168118138126339502603495,
166+ .00019174759731070330743990956198900093346887403385,
167+ .00009587379909597734587051721097647635118706561284,
168+ .00004793689960306688454900399049465887274686668768
169+ };
170+
171+#ifdef __cplusplus
172+}
173+#endif
leaf/Inc/leaf-analysis.h+296−0
@@ -0,0 +1,296 @@
1+/*==============================================================================
2+
3+ leaf-analysis.h
4+ Created: 25 Oct 2019 10:30:52am
5+ Author: Matthew Wang
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_ANALYSIS_H_INCLUDED
10+#define LEAF_ANALYSIS_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-global.h"
19+#include "leaf-mempool.h"
20+#include "leaf-math.h"
21+#include "leaf-filters.h"
22+#include "leaf-envelopes.h"
23+
24+ /*!
25+ * @internal
26+ * Header.
27+ * @include basic-oscillators.h
28+ * @example basic-oscillators.c
29+ * An example.
30+ */
31+
32+ //==============================================================================
33+
34+ /* Envelope Follower */
35+ typedef struct _tEnvelopeFollower
36+ {
37+ float y;
38+ float a_thresh;
39+ float d_coeff;
40+
41+ } _tEnvelopeFollower;
42+
43+ typedef _tEnvelopeFollower* tEnvelopeFollower;
44+
45+ void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff);
46+ void tEnvelopeFollower_free (tEnvelopeFollower* const);
47+ void tEnvelopeFollower_initToPool (tEnvelopeFollower* const, float attackThreshold, float decayCoeff, tMempool* const);
48+ void tEnvelopeFollower_freeFromPool (tEnvelopeFollower* const, tMempool* const);
49+
50+ float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x);
51+ int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
52+ int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh);
53+
54+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
55+
56+ /* Zero Crossing Detector */
57+ typedef struct _tZeroCrossing {
58+ int count;
59+ int maxWindowSize;
60+ int currentWindowSize;
61+ float invCurrentWindowSize;
62+ float* inBuffer;
63+ uint16_t* countBuffer;
64+ int prevPosition;
65+ int position;
66+ } _tZeroCrossing;
67+
68+ typedef _tZeroCrossing* tZeroCrossing;
69+
70+ void tZeroCrossing_init (tZeroCrossing* const, int maxWindowSize);
71+ void tZeroCrossing_free (tZeroCrossing* const);
72+ void tZeroCrossing_initToPool (tZeroCrossing* const, int maxWindowSize, tMempool* const);
73+ void tZeroCrossing_freeFromPool (tZeroCrossing* const, tMempool* const);
74+
75+ float tZeroCrossing_tick (tZeroCrossing* const, float input);
76+ void tZeroCrossing_setWindow (tZeroCrossing* const, float windowSize);
77+
78+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
79+
80+ /* PowerEnvelopeFollower */
81+ typedef struct _tPowerFollower {
82+ float factor, oneminusfactor;
83+ float curr;
84+
85+ } _tPowerFollower;
86+
87+ typedef _tPowerFollower* tPowerFollower;
88+
89+ void tPowerFollower_init (tPowerFollower* const, float factor);
90+ void tPowerFollower_free (tPowerFollower* const);
91+ void tPowerFollower_initToPool (tPowerFollower* const, float factor, tMempool* const);
92+ void tPowerFollower_freeFromPool (tPowerFollower* const, tMempool* const);
93+
94+ float tPowerFollower_tick (tPowerFollower* const, float input);
95+ float tPowerFollower_sample (tPowerFollower* const);
96+ int tPowerFollower_setFactor (tPowerFollower* const, float factor);
97+
98+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
99+
100+ // ENV~ from PD, modified for LEAF
101+#define MAXOVERLAP 32
102+#define INITVSTAKEN 64
103+#define ENV_WINDOW_SIZE 1024
104+#define ENV_HOP_SIZE 256
105+
106+ typedef struct _tEnvPD
107+ {
108+ float buf[ENV_WINDOW_SIZE + INITVSTAKEN];
109+ uint16_t x_phase; /* number of points since last output */
110+ uint16_t x_period; /* requested period of output */
111+ uint16_t x_realperiod; /* period rounded up to vecsize multiple */
112+ uint16_t x_npoints; /* analysis window size in samples */
113+ float x_result; /* result to output */
114+ float x_sumbuf[MAXOVERLAP]; /* summing buffer */
115+ float x_f;
116+ uint16_t windowSize, hopSize, blockSize;
117+ uint16_t x_allocforvs; /* extra buffer for DSP vector size */
118+ } _tEnvPD;
119+
120+ typedef _tEnvPD* tEnvPD;
121+
122+ void tEnvPD_init (tEnvPD* const, int windowSize, int hopSize, int blockSize);
123+ void tEnvPD_free (tEnvPD* const);
124+ void tEnvPD_initToPool (tEnvPD* const, int windowSize, int hopSize, int blockSize, tMempool* const);
125+ void tEnvPD_freeFromPool (tEnvPD* const, tMempool* const);
126+
127+ float tEnvPD_tick (tEnvPD* const);
128+ void tEnvPD_processBlock (tEnvPD* const, float* in);
129+
130+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
131+
132+ /* tAttackDetection */
133+#define DEFBLOCKSIZE 1024
134+#define DEFTHRESHOLD 6
135+#define DEFATTACK 10
136+#define DEFRELEASE 10
137+
138+ typedef struct _tAttackDetection
139+ {
140+ float env;
141+
142+ //Attack & Release times in msec
143+ int atk;
144+ int rel;
145+
146+ //Attack & Release coefficients based on times
147+ float atk_coeff;
148+ float rel_coeff;
149+
150+ int blocksize;
151+ int samplerate;
152+
153+ //RMS amplitude of previous block - used to decide if attack is present
154+ float prevAmp;
155+
156+ float threshold;
157+ } _tAttackDetection;
158+
159+ typedef _tAttackDetection* tAttackDetection;
160+
161+ void tAttackDetection_init (tAttackDetection* const, int blocksize, int atk, int rel);
162+ void tAttackDetection_free (tAttackDetection* const);
163+ void tAttackDetection_initToPool (tAttackDetection* const, int blocksize, int atk, int rel, tMempool* const);
164+ void tAttackDetection_freeFromPool (tAttackDetection* const, tMempool* const);
165+
166+ // set expected input blocksize
167+ void tAttackDetection_setBlocksize (tAttackDetection* const, int size);
168+
169+ // change atkDetector sample rate
170+ void tAttackDetection_setSamplerate (tAttackDetection* const, int inRate);
171+
172+ // set attack time and coeff
173+ void tAttackDetection_setAttack (tAttackDetection* const, int inAtk);
174+
175+ // set release time and coeff
176+ void tAttackDetection_setRelease (tAttackDetection* const, int inRel);
177+
178+ // set level above which values are identified as attacks
179+ void tAttackDetection_setThreshold (tAttackDetection* const, float thres);
180+
181+ // find largest transient in input block, return index of attack
182+ int tAttackDetection_detect (tAttackDetection* const, float *in);
183+
184+ //==============================================================================
185+
186+ // tSNAC: period detector
187+ // from Katja Vetters http://www.katjaas.nl/helmholtz/helmholtz.html
188+#define SNAC_FRAME_SIZE 1024 // default analysis framesize // should be the same as (or smaller than?) PS_FRAME_SIZE
189+#define DEFOVERLAP 1 // default overlap
190+#define DEFBIAS 0.2f // default bias
191+#define DEFMINRMS 0.003f // default minimum RMS
192+#define SEEK 0.85f // seek-length as ratio of framesize
193+
194+ typedef struct _tSNAC
195+ {
196+ float* inputbuf;
197+ float* processbuf;
198+ float* spectrumbuf;
199+ float* biasbuf;
200+ uint16_t timeindex;
201+ uint16_t framesize;
202+ uint16_t overlap;
203+ uint16_t periodindex;
204+
205+ float periodlength;
206+ float fidelity;
207+ float biasfactor;
208+ float minrms;
209+
210+ } _tSNAC;
211+
212+ typedef _tSNAC* tSNAC;
213+
214+ void tSNAC_init (tSNAC* const, int overlaparg);
215+ void tSNAC_free (tSNAC* const);
216+ void tSNAC_initToPool (tSNAC* const, int overlaparg, tMempool* const);
217+ void tSNAC_freeFromPool (tSNAC* const, tMempool* const);
218+
219+ void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size);
220+ void tSNAC_setOverlap (tSNAC *s, int lap);
221+ void tSNAC_setBias (tSNAC *s, float bias);
222+ void tSNAC_setMinRMS (tSNAC *s, float rms);
223+
224+ /*To get freq, perform SAMPLE_RATE/snac_getperiod() */
225+ float tSNAC_getPeriod (tSNAC *s);
226+ float tSNAC_getFidelity (tSNAC *s);
227+
228+#define DEFPITCHRATIO 2.0f
229+#define DEFTIMECONSTANT 100.0f
230+#define DEFHOPSIZE 64
231+#define DEFWINDOWSIZE 64
232+#define FBA 20
233+#define HPFREQ 40.0f
234+
235+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
236+ // Period detection
237+ typedef struct _tPeriodDetection
238+ {
239+ tEnvPD env;
240+ tSNAC snac;
241+ float* inBuffer;
242+ float* outBuffer;
243+ int frameSize;
244+ int bufSize;
245+ int framesPerBuffer;
246+ int curBlock;
247+ int lastBlock;
248+ int i;
249+ int indexstore;
250+ int iLast;
251+ int index;
252+ float period;
253+
254+ uint16_t hopSize;
255+ uint16_t windowSize;
256+ uint8_t fba;
257+
258+ float timeConstant;
259+ float radius;
260+ float max;
261+ float lastmax;
262+ float deltamax;
263+
264+ float fidelityThreshold;
265+
266+ float history;
267+ float alpha;
268+ float tolerance;
269+
270+ } _tPeriodDetection;
271+
272+ typedef _tPeriodDetection* tPeriodDetection;
273+
274+ void tPeriodDetection_init (tPeriodDetection* const, float* in, float* out, int bufSize, int frameSize);
275+ void tPeriodDetection_free (tPeriodDetection* const);
276+ void tPeriodDetection_initToPool (tPeriodDetection* const, float* in, float* out, int bufSize, int frameSize, tMempool* const);
277+ void tPeriodDetection_freeFromPool (tPeriodDetection* const, tMempool* const);
278+
279+ float tPeriodDetection_tick (tPeriodDetection* const, float sample);
280+ float tPeriodDetection_getPeriod (tPeriodDetection* const);
281+ void tPeriodDetection_setHopSize (tPeriodDetection* const, int hs);
282+ void tPeriodDetection_setWindowSize (tPeriodDetection* const, int ws);
283+ void tPeriodDetection_setFidelityThreshold(tPeriodDetection* const, float threshold);
284+ void tPeriodDetection_setAlpha (tPeriodDetection* const, float alpha);
285+ void tPeriodDetection_setTolerance (tPeriodDetection* const, float tolerance);
286+
287+ //==============================================================================
288+
289+#ifdef __cplusplus
290+}
291+#endif
292+
293+#endif // LEAF_ANALYSIS_H_INCLUDED
294+
295+//==============================================================================
296+
leaf/Inc/leaf-delay.h+229−0
@@ -0,0 +1,229 @@
1+/*==============================================================================
2+
3+ leaf-delay.h
4+ Created: 20 Jan 2017 12:01:24pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_DELAY_H_INCLUDED
10+#define LEAF_DELAY_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-math.h"
19+#include "leaf-mempool.h"
20+
21+ /*!
22+ * @internal
23+ * Header.
24+ * @include basic-oscillators.h
25+ * @example basic-oscillators.c
26+ * An example.
27+ */
28+
29+ //==============================================================================
30+
31+ /* Non-interpolating delay, reimplemented from STK (Cook and Scavone). */
32+ typedef struct _tDelay
33+ {
34+ float gain;
35+ float* buff;
36+
37+ float lastOut, lastIn;
38+
39+ uint32_t inPoint, outPoint;
40+
41+ uint32_t delay, maxDelay;
42+
43+ } _tDelay;
44+
45+ typedef _tDelay* tDelay;
46+
47+ void tDelay_init (tDelay* const, uint32_t delay, uint32_t maxDelay);
48+ void tDelay_free (tDelay* const);
49+ void tDelay_initToPool (tDelay* const, uint32_t delay, uint32_t maxDelay, tMempool* const);
50+ void tDelay_freeFromPool (tDelay* const, tMempool* const);
51+
52+ void tDelay_clear (tDelay* const);
53+ int tDelay_setDelay (tDelay* const, uint32_t delay);
54+ uint32_t tDelay_getDelay (tDelay* const);
55+ void tDelay_tapIn (tDelay* const, float in, uint32_t tapDelay);
56+ float tDelay_tapOut (tDelay* const, uint32_t tapDelay);
57+ float tDelay_addTo (tDelay* const, float value, uint32_t tapDelay);
58+ float tDelay_tick (tDelay* const, float sample);
59+ float tDelay_getLastOut (tDelay* const);
60+ float tDelay_getLastIn (tDelay* const);
61+
62+ //==============================================================================
63+
64+ /* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */
65+ typedef struct _tLinearDelay
66+ {
67+ float gain;
68+ float* buff;
69+
70+ float lastOut, lastIn;
71+
72+ uint32_t inPoint, outPoint;
73+
74+ uint32_t maxDelay;
75+
76+ float delay;
77+
78+ float alpha, omAlpha;
79+
80+ } _tLinearDelay;
81+
82+ typedef _tLinearDelay* tLinearDelay;
83+
84+ void tLinearDelay_init (tLinearDelay* const, float delay, uint32_t maxDelay);
85+ void tLinearDelay_free (tLinearDelay* const);
86+ void tLinearDelay_initToPool (tLinearDelay* const, float delay, uint32_t maxDelay, tMempool* const);
87+ void tLinearDelay_freeFromPool(tLinearDelay* const, tMempool* const);
88+ void tLinearDelay_clear (tLinearDelay* const dl);
89+ int tLinearDelay_setDelay (tLinearDelay* const, float delay);
90+ float tLinearDelay_getDelay (tLinearDelay* const);
91+ void tLinearDelay_tapIn (tLinearDelay* const, float in, uint32_t tapDelay);
92+ float tLinearDelay_tapOut (tLinearDelay* const, uint32_t tapDelay);
93+ float tLinearDelay_addTo (tLinearDelay* const, float value, uint32_t tapDelay);
94+ float tLinearDelay_tick (tLinearDelay* const, float sample);
95+ void tLinearDelay_tickIn (tLinearDelay* const, float input);
96+ float tLinearDelay_tickOut (tLinearDelay* const);
97+ float tLinearDelay_getLastOut (tLinearDelay* const);
98+ float tLinearDelay_getLastIn (tLinearDelay* const);
99+
100+
101+
102+ //==============================================================================
103+
104+ /* Hermite-interpolating delay, created by adapting STK linear delay with Hermite interpolation */
105+ typedef struct _tHermiteDelay
106+ {
107+ float gain;
108+ float* buff;
109+
110+ float lastOut, lastIn;
111+
112+ uint32_t inPoint, outPoint;
113+
114+ uint32_t maxDelay;
115+
116+ float delay;
117+
118+ float alpha, omAlpha;
119+
120+ } _tHermiteDelay;
121+
122+ typedef _tHermiteDelay* tHermiteDelay;
123+
124+ void tHermiteDelay_init (tHermiteDelay* const dl, float delay, uint32_t maxDelay);
125+ void tHermiteDelay_free (tHermiteDelay* const dl);
126+ void tHermiteDelay_initToPool (tHermiteDelay* const dl, float delay, uint32_t maxDelay, tMempool* const mp);
127+ void tHermiteDelay_freeFromPool (tHermiteDelay* const dl, tMempool* const mp);
128+ void tHermiteDelay_clear (tHermiteDelay* const dl);
129+ float tHermiteDelay_tick (tHermiteDelay* const dl, float input);
130+ void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input);
131+ float tHermiteDelay_tickOut (tHermiteDelay* const dl);
132+ int tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay);
133+ float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay);
134+ void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay);
135+ float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay);
136+ float tHermiteDelay_getDelay (tHermiteDelay* const dl);
137+ float tHermiteDelay_getLastOut (tHermiteDelay* const dl);
138+ float tHermiteDelay_getLastIn (tHermiteDelay* const dl);
139+ void tHermiteDelay_setGain (tHermiteDelay* const dl, float gain);
140+ float tHermiteDelay_getGain (tHermiteDelay* const dl);
141+
142+
143+ //==============================================================================
144+
145+ /* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */
146+ typedef struct _tAllpassDelay
147+ {
148+ float gain;
149+ float* buff;
150+
151+ float lastOut, lastIn;
152+
153+ uint32_t inPoint, outPoint;
154+
155+ uint32_t maxDelay;
156+
157+ float delay;
158+
159+ float alpha, omAlpha, coeff;
160+
161+ float apInput;
162+
163+ } _tAllpassDelay;
164+
165+ typedef _tAllpassDelay* tAllpassDelay;
166+
167+ void tAllpassDelay_init (tAllpassDelay* const, float delay, uint32_t maxDelay);
168+ void tAllpassDelay_free (tAllpassDelay* const);
169+ void tAllpassDelay_initToPool (tAllpassDelay* const, float delay, uint32_t maxDelay, tMempool* const);
170+ void tAllpassDelay_freeFromPool(tAllpassDelay* const, tMempool* const);
171+
172+ void tAllpassDelay_clear (tAllpassDelay* const);
173+ int tAllpassDelay_setDelay (tAllpassDelay* const, float delay);
174+ float tAllpassDelay_getDelay (tAllpassDelay* const);
175+ void tAllpassDelay_tapIn (tAllpassDelay* const, float in, uint32_t tapDelay);
176+ float tAllpassDelay_tapOut (tAllpassDelay* const, uint32_t tapDelay);
177+ float tAllpassDelay_addTo (tAllpassDelay* const, float value, uint32_t tapDelay);
178+ float tAllpassDelay_tick (tAllpassDelay* const, float sample);
179+ float tAllpassDelay_getLastOut (tAllpassDelay* const);
180+ float tAllpassDelay_getLastIn (tAllpassDelay* const);
181+
182+ //==============================================================================
183+
184+ /* Linear interpolating delay with fixed read and write pointers, variable rate. */
185+ typedef struct _tTapeDelay
186+ {
187+ float gain;
188+ float* buff;
189+
190+ float lastOut, lastIn;
191+
192+ uint32_t inPoint;
193+
194+ uint32_t maxDelay;
195+
196+ float delay, inc, idx;
197+
198+ float apInput;
199+
200+ } _tTapeDelay;
201+
202+ typedef _tTapeDelay* tTapeDelay;
203+
204+ void tTapeDelay_init (tTapeDelay* const, float delay, uint32_t maxDelay);
205+ void tTapeDelay_free (tTapeDelay* const);
206+ void tTapeDelay_initToPool (tTapeDelay* const, float delay, uint32_t maxDelay, tMempool* const);
207+ void tTapeDelay_freeFromPool(tTapeDelay* const, tMempool* const);
208+
209+ void tTapeDelay_clear (tTapeDelay* const);
210+ void tTapeDelay_setDelay (tTapeDelay* const, float delay);
211+ float tTapeDelay_getDelay (tTapeDelay* const);
212+ void tTapeDelay_tapIn (tTapeDelay* const, float in, uint32_t tapDelay);
213+ float tTapeDelay_tapOut (tTapeDelay* const d, float tapDelay);
214+ float tTapeDelay_addTo (tTapeDelay* const, float value, uint32_t tapDelay);
215+ float tTapeDelay_tick (tTapeDelay* const, float sample);
216+ void tTapeDelay_incrementInPoint(tTapeDelay* const dl);
217+ float tTapeDelay_getLastOut (tTapeDelay* const);
218+ float tTapeDelay_getLastIn (tTapeDelay* const);
219+
220+ //==============================================================================
221+
222+#ifdef __cplusplus
223+}
224+#endif
225+
226+#endif // LEAF_DELAY_H_INCLUDED
227+
228+//==============================================================================
229+
leaf/Inc/leaf-distortion.h+164−0
@@ -0,0 +1,164 @@
1+/*==============================================================================
2+
3+ leaf-distortion.h
4+ Created: 25 Oct 2019 10:23:28am
5+ Author: Matthew Wang
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_DISTORTION_H_INCLUDED
10+#define LEAF_DISTORTION_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-global.h"
19+#include "leaf-mempool.h"
20+#include "leaf-math.h"
21+
22+ /*!
23+ * @internal
24+ * Header.
25+ * @include basic-oscillators.h
26+ * @example basic-oscillators.c
27+ * An example.
28+ */
29+
30+ //==============================================================================
31+
32+ typedef struct _tSampleReducer
33+ {
34+ float invRatio;
35+ float hold;
36+ uint32_t count;
37+ } _tSampleReducer;
38+
39+ typedef _tSampleReducer* tSampleReducer;
40+
41+ void tSampleReducer_init (tSampleReducer* const);
42+ void tSampleReducer_free (tSampleReducer* const);
43+ void tSampleReducer_initToPool (tSampleReducer* const, tMempool* const);
44+ void tSampleReducer_freeFromPool (tSampleReducer* const, tMempool* const);
45+
46+ float tSampleReducer_tick (tSampleReducer* const, float input);
47+
48+ // sampling ratio
49+ void tSampleReducer_setRatio (tSampleReducer* const, float ratio);
50+
51+ //==============================================================================
52+
53+ typedef struct _tOversampler
54+ {
55+ int ratio;
56+ float* pCoeffs;
57+ float* upState;
58+ float* downState;
59+ int numTaps;
60+ int phaseLength;
61+ } _tOversampler;
62+
63+ typedef _tOversampler* tOversampler;
64+
65+ void tOversampler_init (tOversampler* const, int order, oBool extraQuality);
66+ void tOversampler_free (tOversampler* const);
67+ void tOversampler_initToPool (tOversampler* const, int order, oBool extraQuality, tMempool* const);
68+ void tOversampler_freeFromPool (tOversampler* const, tMempool* const);
69+
70+ void tOversampler_upsample (tOversampler* const, float input, float* output);
71+ float tOversampler_downsample (tOversampler* const os, float* input);
72+ float tOversampler_tick (tOversampler* const, float input, float (*effectTick)(float));
73+ int tOversampler_getLatency (tOversampler* const os);
74+
75+ //==============================================================================
76+
77+ /* tLockhartWavefolder */
78+
79+ typedef struct _tLockhartWavefolder
80+ {
81+ double Ln1;
82+ double Fn1;
83+ double xn1;
84+
85+ double RL;
86+ double R;
87+ double VT;
88+ double Is;
89+
90+ double a;
91+ double b;
92+ double d;
93+
94+ // Antialiasing error threshold
95+ double AAthresh;
96+ double half_a;
97+ double longthing;
98+
99+ double LambertThresh, w, expw, p, r, s, myerr;
100+ double l;
101+ double u, Ln, Fn;
102+ double tempsDenom;
103+ double tempErrDenom;
104+ double tempOutDenom;
105+
106+ } _tLockhartWavefolder;
107+
108+ typedef _tLockhartWavefolder* tLockhartWavefolder;
109+
110+ void tLockhartWavefolder_init (tLockhartWavefolder* const);
111+ void tLockhartWavefolder_free (tLockhartWavefolder* const);
112+ void tLockhartWavefolder_initToPool (tLockhartWavefolder* const, tMempool* const);
113+ void tLockhartWavefolder_freeFromPool (tLockhartWavefolder* const, tMempool* const);
114+
115+ float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp);
116+
117+ //==============================================================================
118+
119+ typedef struct _tCrusher
120+ {
121+ float srr;
122+ float mult, div;
123+ float rnd;
124+
125+ uint32_t op; //which bitwise operation (0-7)
126+
127+ float gain;
128+ tSampleReducer sReducer;
129+
130+ } _tCrusher;
131+
132+ typedef _tCrusher* tCrusher;
133+
134+ void tCrusher_init (tCrusher* const);
135+ void tCrusher_free (tCrusher* const);
136+ void tCrusher_initToPool (tCrusher* const, tMempool* const);
137+ void tCrusher_freeFromPool (tCrusher* const, tMempool* const);
138+
139+ float tCrusher_tick (tCrusher* const, float input);
140+
141+ // 0.0 - 1.0
142+ void tCrusher_setOperation (tCrusher* const, float op);
143+
144+ // 0.0 - 1.0
145+ void tCrusher_setQuality (tCrusher* const, float val);
146+
147+ // what division to round to
148+ void tCrusher_setRound (tCrusher* const, float rnd);
149+
150+ // sampling ratio
151+ void tCrusher_setSamplingRatio (tCrusher* const, float ratio);
152+
153+ //==============================================================================
154+
155+
156+#ifdef __cplusplus
157+}
158+#endif
159+
160+#endif // LEAF_DISTORTION_H_INCLUDED
161+
162+//==============================================================================
163+
164+
leaf/Inc/leaf-dynamics.h+122−0
@@ -0,0 +1,122 @@
1+/*==============================================================================
2+
3+ leaf-dynamics.h
4+ Created: 30 Nov 2018 11:57:05am
5+ Author: airship
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_DYNAMICS_H_INCLUDED
10+#define LEAF_DYNAMICS_H_INCLUDED
11+
12+
13+#ifdef __cplusplus
14+extern "C" {
15+#endif
16+
17+ //==============================================================================
18+
19+#include "leaf-global.h"
20+#include "leaf-math.h"
21+#include "leaf-mempool.h"
22+#include "leaf-analysis.h"
23+
24+ /*!
25+ * @internal
26+ * Header.
27+ * @include basic-oscillators.h
28+ * @example basic-oscillators.c
29+ * An example.
30+ */
31+
32+ //==============================================================================
33+
34+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
35+
36+ /* Compressor */
37+ typedef struct _tCompressor
38+ {
39+ float tauAttack, tauRelease;
40+ float T, R, W, M; // Threshold, compression Ratio, decibel Width of knee transition, decibel Make-up gain
41+
42+ float x_G[2], y_G[2], x_T[2], y_T[2];
43+
44+ oBool isActive;
45+
46+ } _tCompressor;
47+
48+ typedef _tCompressor* tCompressor;
49+
50+ void tCompressor_init (tCompressor* const);
51+ void tCompressor_free (tCompressor* const);
52+ void tCompressor_initToPool (tCompressor* const, tMempool* const);
53+ void tCompressor_freeFromPool(tCompressor* const, tMempool* const);
54+
55+ float tCompressor_tick (tCompressor* const, float input);
56+
57+ ///
58+ /* Feedback leveller */
59+ // An auto VCA that you put into a feedback circuit to make it stay at the same level.
60+ // It can enforce level bidirectionally (amplifying and attenuating as needed) or
61+ // just attenutating. The former option allows for infinite sustain strings, for example, while
62+ // The latter option allows for decaying strings, which can never exceed
63+ // a specific level.
64+
65+ typedef struct _tFeedbackLeveler {
66+ float targetLevel; // target power level
67+ float strength; // how strongly level difference affects the VCA
68+ int mode; // 0 for upwards limiting only, 1 for biderctional limiting
69+ float curr;
70+ tPowerFollower pwrFlw; // internal power follower needed for level tracking
71+
72+ } _tFeedbackLeveler;
73+
74+ typedef _tFeedbackLeveler* tFeedbackLeveler;
75+
76+ void tFeedbackLeveler_init (tFeedbackLeveler* const, float targetLevel, float factor, float strength, int mode);
77+ void tFeedbackLeveler_free (tFeedbackLeveler* const);
78+ void tFeedbackLeveler_initToPool (tFeedbackLeveler* const, float targetLevel, float factor, float strength, int mode, tMempool* const);
79+ void tFeedbackLeveler_freeFromPool (tFeedbackLeveler* const, tMempool* const);
80+
81+ float tFeedbackLeveler_tick (tFeedbackLeveler* const, float input);
82+ float tFeedbackLeveler_sample (tFeedbackLeveler* const);
83+ void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const, float TargetLevel);
84+ void tFeedbackLeveler_setFactor (tFeedbackLeveler* const, float factor);
85+ void tFeedbackLeveler_setMode (tFeedbackLeveler* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting
86+ void tFeedbackLeveler_setStrength (tFeedbackLeveler* const, float strength);
87+
88+
89+ //==============================================================================
90+
91+
92+ //Threshold with hysteresis (like Max/MSP thresh~ object)
93+
94+ typedef struct _tThreshold {
95+ float highThresh, lowThresh;
96+ int currentValue;
97+
98+ } _tThreshold;
99+
100+ typedef _tThreshold* tThreshold;
101+
102+ void tThreshold_init (tThreshold* const, float low, float high);
103+ void tThreshold_free (tThreshold* const);
104+ void tThreshold_initToPool (tThreshold* const, float low, float high, tMempool* const);
105+ void tThreshold_freeFromPool(tThreshold* const, tMempool* const);
106+
107+ int tThreshold_tick (tThreshold* const, float input);
108+ void tThreshold_setLow (tThreshold* const, float low);
109+ void tThreshold_setHigh (tThreshold* const, float high);
110+
111+
112+
113+ //////======================================================================
114+
115+#ifdef __cplusplus
116+}
117+#endif
118+
119+#endif // LEAF_DYNAMICS_H_INCLUDED
120+
121+//==============================================================================
122+
leaf/Inc/leaf-effects.h+360−0
@@ -0,0 +1,360 @@
1+/*==============================================================================
2+
3+ leaf-effects.h
4+ Created: 20 Jan 2017 12:01:54pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_EFFECTS_H_INCLUDED
10+#define LEAF_EFFECTS_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+#include "leaf-global.h"
18+#include "leaf-math.h"
19+#include "leaf-mempool.h"
20+#include "leaf-dynamics.h"
21+#include "leaf-analysis.h"
22+#include "leaf-envelopes.h"
23+
24+ /*!
25+ * @internal
26+ * Header.
27+ * @include basic-oscillators.h
28+ * @example basic-oscillators.c
29+ * An example.
30+ */
31+
32+ //==============================================================================
33+
34+ /* tTalkbox */
35+#define NUM_TALKBOX_PARAM 4
36+
37+ typedef struct _tTalkbox
38+ {
39+ float param[NUM_TALKBOX_PARAM];
40+
41+ int bufsize;
42+ float* car0;
43+ float* car1;
44+ float* window;
45+ float* buf0;
46+ float* buf1;
47+
48+ float warpFactor;
49+ int32_t warpOn;
50+
51+ float emphasis;
52+ int32_t K, N, O, pos;
53+ float wet, dry, FX;
54+ float d0, d1, d2, d3, d4;
55+ float u0, u1, u2, u3, u4;
56+
57+
58+ } _tTalkbox;
59+
60+ typedef _tTalkbox* tTalkbox;
61+
62+ void tTalkbox_init (tTalkbox* const, int bufsize);
63+ void tTalkbox_free (tTalkbox* const);
64+ void tTalkbox_initToPool (tTalkbox* const, int bufsize, tMempool* const);
65+ void tTalkbox_freeFromPool (tTalkbox* const, tMempool* const);
66+
67+ float tTalkbox_tick (tTalkbox* const, float synth, float voice);
68+ void tTalkbox_update (tTalkbox* const);
69+ void tTalkbox_suspend (tTalkbox* const);
70+ void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
71+ void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o, float warp, int warpOn);
72+ void tTalkbox_setQuality (tTalkbox* const, float quality);
73+ void tTalkbox_setWarpFactor (tTalkbox* const voc, float warp);
74+ void tTalkbox_setWarpOn (tTalkbox* const voc, float warpOn);
75+ void tTalkbox_warpedAutocorrelate (float * x, unsigned int L, float * R, unsigned int P, float lambda);
76+ //==============================================================================
77+
78+ /* tVocoder */
79+#define NUM_VOCODER_PARAM 8
80+#define NBANDS 16
81+
82+ typedef struct _tVocoder
83+ {
84+ float param[NUM_VOCODER_PARAM];
85+
86+ float gain; //output level
87+ float thru, high; //hf thru
88+ float kout; //downsampled output
89+ int32_t kval; //downsample counter
90+ int32_t nbnd; //number of bands
91+
92+ //filter coeffs and buffers - seems it's faster to leave this global than make local copy
93+ float f[NBANDS][13]; //[0-8][0 1 2 | 0 1 2 3 | 0 1 2 3 | val rate]
94+
95+ } _tVocoder;
96+
97+ typedef _tVocoder* tVocoder;
98+
99+ void tVocoder_init (tVocoder* const);
100+ void tVocoder_free (tVocoder* const);
101+ void tVocoder_initToPool (tVocoder* const, tMempool* const);
102+ void tVocoder_freeFromPool (tVocoder* const, tMempool* const);
103+
104+ float tVocoder_tick (tVocoder* const, float synth, float voice);
105+ void tVocoder_update (tVocoder* const);
106+ void tVocoder_suspend (tVocoder* const);
107+
108+ //==============================================================================
109+
110+ // tRosenbergGlottalPulse
111+
112+ typedef struct _tRosenbergGlottalPulse
113+ {
114+
115+ float phase;
116+ float openLength;
117+ float pulseLength;
118+ float freq;
119+ float inc;
120+
121+
122+ } _tRosenbergGlottalPulse;
123+
124+ typedef _tRosenbergGlottalPulse* tRosenbergGlottalPulse;
125+
126+ void tRosenbergGlottalPulse_init (tRosenbergGlottalPulse* const);
127+ void tRosenbergGlottalPulse_free (tRosenbergGlottalPulse* const);
128+ void tRosenbergGlottalPulse_initToPool (tRosenbergGlottalPulse* const, tMempool* const);
129+ void tRosenbergGlottalPulse_freeFromPool (tRosenbergGlottalPulse* const, tMempool* const);
130+
131+ float tRosenbergGlottalPulse_tick (tRosenbergGlottalPulse* const);
132+
133+ void tRosenbergGlottalPulse_setFreq (tRosenbergGlottalPulse* const, float freq);
134+
135+ void tRosenbergGlottalPulse_setOpenLength (tRosenbergGlottalPulse* const, float openLength);
136+
137+ void tRosenbergGlottalPulse_setPulseLength (tRosenbergGlottalPulse* const, float pulseLength);
138+
139+ //==============================================================================
140+
141+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
142+
143+ /* tSOLAD : pitch shifting algorithm that underlies tRetune etc */
144+ // from Katja Vetters http://www.katjaas.nl/pitchshiftlowlatency/pitchshiftlowlatency.html
145+#define LOOPSIZE (2048*2) // (4096*2) // loop size must be power of two
146+#define LOOPMASK (LOOPSIZE - 1)
147+#define PITCHFACTORDEFAULT 1.0f
148+#define INITPERIOD 64.0f
149+#define MAXPERIOD (float)((LOOPSIZE - w->blocksize) * 0.8f)
150+#define MINPERIOD 8.0f
151+
152+ typedef struct _tSOLAD
153+ {
154+ uint16_t timeindex; // current reference time, write index
155+ uint16_t blocksize; // signal input / output block size
156+ float pitchfactor; // pitch factor between 0.25 and 4
157+ float readlag; // read pointer's lag behind write pointer
158+ float period; // period length in input signal
159+ float jump; // read pointer jump length and direction
160+ float xfadelength; // crossfade length expressed at input sample rate
161+ float xfadevalue; // crossfade phase and value
162+
163+ float* delaybuf;
164+
165+ } _tSOLAD;
166+
167+ typedef _tSOLAD* tSOLAD;
168+
169+ void tSOLAD_init (tSOLAD* const);
170+ void tSOLAD_free (tSOLAD* const);
171+ void tSOLAD_initToPool (tSOLAD* const, tMempool* const);
172+ void tSOLAD_freeFromPool (tSOLAD* const, tMempool* const);
173+
174+ // send one block of input samples, receive one block of output samples
175+ void tSOLAD_ioSamples (tSOLAD *w, float* in, float* out, int blocksize);
176+ // set periodicity analysis data
177+ void tSOLAD_setPeriod (tSOLAD *w, float period);
178+ // set pitch factor between 0.25 and 4
179+ void tSOLAD_setPitchFactor (tSOLAD *w, float pitchfactor);
180+ // force readpointer lag
181+ void tSOLAD_setReadLag (tSOLAD *w, float readlag);
182+ // reset state variables
183+ void tSOLAD_resetState (tSOLAD *w);
184+
185+ // Pitch shift
186+ typedef struct _tPitchShift
187+ {
188+ tSOLAD sola;
189+ tHighpass hp;
190+ tPeriodDetection* p;
191+
192+ float* outBuffer;
193+ int frameSize;
194+ int bufSize;
195+
196+ int framesPerBuffer;
197+ int curBlock;
198+ int lastBlock;
199+ int index;
200+
201+ float pitchFactor;
202+ float timeConstant;
203+ float radius;
204+ } _tPitchShift;
205+
206+ typedef _tPitchShift* tPitchShift;
207+
208+ void tPitchShift_init (tPitchShift* const, tPeriodDetection* const, float* out, int bufSize);
209+ void tPitchShift_free (tPitchShift* const);
210+ void tPitchShift_initToPool (tPitchShift* const, tPeriodDetection* const, float* out, int bufSize, tMempool* const);
211+ void tPitchShift_freeFromPool (tPitchShift* const, tMempool* const);
212+
213+ float tPitchShift_shift (tPitchShift* const);
214+ float tPitchShift_shiftToFunc (tPitchShift* const, float (*fun)(float));
215+ float tPitchShift_shiftToFreq (tPitchShift* const, float freq);
216+ void tPitchShift_setPitchFactor (tPitchShift* const, float pf);
217+
218+ // Retune
219+ typedef struct _tRetune
220+ {
221+ tPeriodDetection pd;
222+ tPitchShift* ps;
223+
224+ float* inBuffer;
225+ float** outBuffers;
226+ float* tickOutput;
227+ int frameSize;
228+ int bufSize;
229+
230+ uint16_t hopSize;
231+ uint16_t windowSize;
232+ uint8_t fba;
233+
234+ float* pitchFactor;
235+ float timeConstant;
236+ float radius;
237+
238+ float inputPeriod;
239+
240+ int numVoices;
241+ } _tRetune;
242+
243+ typedef _tRetune* tRetune;
244+
245+ void tRetune_init (tRetune* const, int numVoices, int bufSize, int frameSize);
246+ void tRetune_free (tRetune* const);
247+ void tRetune_initToPool (tRetune* const, int numVoices, int bufSize, int frameSize, tMempool* const);
248+ void tRetune_freeFromPool (tRetune* const, tMempool* const);
249+
250+ float* tRetune_tick (tRetune* const, float sample);
251+ void tRetune_setNumVoices (tRetune* const, int numVoices);
252+ void tRetune_setPitchFactors (tRetune* const, float pf);
253+ void tRetune_setPitchFactor (tRetune* const, float pf, int voice);
254+ void tRetune_setTimeConstant (tRetune* const, float tc);
255+ void tRetune_setHopSize (tRetune* const, int hs);
256+ void tRetune_setWindowSize (tRetune* const, int ws);
257+ void tRetune_setFidelityThreshold(tRetune* const, float threshold);
258+ float tRetune_getInputPeriod (tRetune* const);
259+ float tRetune_getInputFreq (tRetune* const);
260+
261+ // Autotune
262+ typedef struct _tAutotune
263+ {
264+ tPeriodDetection pd;
265+ tPitchShift* ps;
266+
267+ float* inBuffer;
268+ float** outBuffers;
269+ float* tickOutput;
270+ int frameSize;
271+ int bufSize;
272+
273+ uint16_t hopSize;
274+ uint16_t windowSize;
275+ uint8_t fba;
276+
277+ float* freq;
278+ float timeConstant;
279+ float radius;
280+
281+ float inputPeriod;
282+
283+ int numVoices;
284+ } _tAutotune;
285+
286+ typedef _tAutotune* tAutotune;
287+
288+ void tAutotune_init (tAutotune* const, int numVoices, int bufSize, int frameSize);
289+ void tAutotune_free (tAutotune* const);
290+ void tAutotune_initToPool (tAutotune* const, int numVoices, int bufSize, int frameSize, tMempool* const);
291+ void tAutotune_freeFromPool (tAutotune* const, tMempool* const);
292+
293+ float* tAutotune_tick (tAutotune* const, float sample);
294+ void tAutotune_setNumVoices (tAutotune* const, int numVoices);
295+ void tAutotune_setFreqs (tAutotune* const, float f);
296+ void tAutotune_setFreq (tAutotune* const, float f, int voice);
297+ void tAutotune_setTimeConstant (tAutotune* const, float tc);
298+ void tAutotune_setHopSize (tAutotune* const, int hs);
299+ void tAutotune_setWindowSize (tAutotune* const, int ws);
300+ void tAutotune_setFidelityThreshold (tAutotune* const, float threshold);
301+ void tAutotune_setAlpha (tAutotune* const, float alpha);
302+ void tAutotune_setTolerance (tAutotune* const, float tolerance);
303+ float tAutotune_getInputPeriod (tAutotune* const);
304+ float tAutotune_getInputFreq (tAutotune* const);
305+
306+ //==============================================================================
307+
308+
309+ typedef struct _tFormantShifter
310+ {
311+ int ford;
312+ float falph;
313+ float flamb;
314+ float* fk;
315+ float* fb;
316+ float* fc;
317+ float* frb;
318+ float* frc;
319+ float* fsig;
320+ float* fsmooth;
321+ float fhp;
322+ float flp;
323+ float flpa;
324+ float* fbuff;
325+ float* ftvec;
326+ float fmute;
327+ float fmutealph;
328+ unsigned int cbi;
329+ float shiftFactor;
330+ float intensity, invIntensity;
331+ tHighpass hp;
332+ tHighpass hp2;
333+ tFeedbackLeveler fbl1;
334+ tFeedbackLeveler fbl2;
335+
336+ } _tFormantShifter;
337+
338+ typedef _tFormantShifter* tFormantShifter;
339+
340+ void tFormantShifter_init (tFormantShifter* const, int order);
341+ void tFormantShifter_free (tFormantShifter* const);
342+ void tFormantShifter_initToPool (tFormantShifter* const, int order, tMempool* const);
343+ void tFormantShifter_freeFromPool (tFormantShifter* const, tMempool* const);
344+
345+ float tFormantShifter_tick (tFormantShifter* const, float input);
346+ float tFormantShifter_remove (tFormantShifter* const, float input);
347+ float tFormantShifter_add (tFormantShifter* const, float input);
348+ void tFormantShifter_ioSamples (tFormantShifter* const, float* in, float* out, int size, float fwarp);
349+ void tFormantShifter_setShiftFactor (tFormantShifter* const, float shiftFactor);
350+ void tFormantShifter_setIntensity (tFormantShifter* const, float intensity);
351+
352+ //==============================================================================
353+
354+#ifdef __cplusplus
355+}
356+#endif
357+
358+#endif // LEAF_EFFECTS_H_INCLUDED
359+
360+//==============================================================================
leaf/Inc/leaf-electrical.h+103−0
@@ -0,0 +1,103 @@
1+/*
2+ * leaf-electrical.h
3+ *
4+ * Created on: Sep 25, 2019
5+ * Author: jeffsnyder
6+ */
7+
8+#ifndef LEAF_INC_LEAF_ELECTRICAL_H_
9+#define LEAF_INC_LEAF_ELECTRICAL_H_
10+
11+#ifdef __cplusplus
12+extern "C" {
13+#endif
14+
15+ //==============================================================================
16+
17+#include "leaf-global.h"
18+#include "leaf-math.h"
19+#include "leaf-mempool.h"
20+
21+ /*!
22+ * @internal
23+ * Header.
24+ * @include basic-oscillators.h
25+ * @example basic-oscillators.c
26+ * An example.
27+ */
28+
29+ //==============================================================================
30+
31+ typedef enum WDFComponentType
32+ {
33+ SeriesAdaptor = 0,
34+ ParallelAdaptor,
35+ Resistor,
36+ Capacitor,
37+ Inductor,
38+ Inverter,
39+ ResistiveSource,
40+ IdealSource,
41+ Diode,
42+ DiodePair,
43+ RootNil,
44+ WDFComponentNil
45+ } WDFComponentType;
46+
47+ typedef struct _tWDF _tWDF; // needed to allow tWDF pointers in struct
48+ typedef _tWDF* tWDF;
49+ struct _tWDF
50+ {
51+ WDFComponentType type;
52+ float port_resistance_up;
53+ float port_resistance_left;
54+ float port_resistance_right;
55+ float port_conductance_up;
56+ float port_conductance_left;
57+ float port_conductance_right;
58+ float incident_wave_up;
59+ float incident_wave_left;
60+ float incident_wave_right;
61+ float reflected_wave_up;
62+ float reflected_wave_left;
63+ float reflected_wave_right;
64+ float gamma_zero;
65+ float sample_rate;
66+ float value;
67+ tWDF* child_left;
68+ tWDF* child_right;
69+ float (*get_port_resistance)(tWDF* const);
70+ float (*get_reflected_wave_up)(tWDF* const, float);
71+ float (*get_reflected_wave_down)(tWDF* const, float, float);
72+ void (*set_incident_wave)(tWDF* const, float, float);
73+ };
74+
75+ //WDF Linear Components
76+ void tWDF_init (tWDF* const, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR);
77+ void tWDF_free (tWDF* const);
78+ void tWDF_initToPool (tWDF* const, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR, tMempool* const);
79+ void tWDF_freeFromPool (tWDF* const, tMempool* const);
80+
81+ float tWDF_tick (tWDF* const, float sample, tWDF* const outputPoint, uint8_t paramsChanged);
82+
83+ void tWDF_setValue (tWDF* const, float value);
84+ void tWDF_setSampleRate (tWDF* const, float sample_rate);
85+ uint8_t tWDF_isLeaf (tWDF* const);
86+
87+ float tWDF_getPortResistance (tWDF* const);
88+ float tWDF_getReflectedWaveUp (tWDF* const, float input); //for tree, only uses input for resistive source
89+ float tWDF_getReflectedWaveDown (tWDF* const, float input, float incident_wave); //for roots
90+ void tWDF_setIncidentWave (tWDF* const, float incident_wave, float input);
91+
92+ float tWDF_getVoltage (tWDF* const);
93+ float tWDF_getCurrent (tWDF* const);
94+
95+
96+ //==============================================================================
97+
98+#ifdef __cplusplus
99+}
100+#endif
101+
102+#endif /* LEAF_INC_LEAF_ELECTRICAL_H_ */
103+
leaf/Inc/leaf-envelopes.h+366−0
@@ -0,0 +1,366 @@
1+/*
2+ ==============================================================================
3+
4+ leaf-envelopes.h
5+ Created: 20 Jan 2017 12:02:17pm
6+ Author: Michael R Mulshine
7+
8+ ==============================================================================
9+ */
10+
11+#ifndef LEAF_ENVELOPES_H_INCLUDED
12+#define LEAF_ENVELOPES_H_INCLUDED
13+
14+#ifdef __cplusplus
15+extern "C" {
16+#endif
17+
18+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
19+
20+#include "leaf-math.h"
21+#include "leaf-mempool.h"
22+#include "leaf-filters.h"
23+#include "leaf-delay.h"
24+#include "leaf-analysis.h"
25+#include "leaf-envelopes.h"
26+
27+ /*!
28+ * @internal
29+ * Header.
30+ * @include basic-oscillators.h
31+ * @example basic-oscillators.c
32+ * An example.
33+ */
34+
35+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
36+
37+ /* Attack-Decay envelope */
38+ typedef struct _tEnvelope {
39+
40+ const float *exp_buff;
41+ const float *inc_buff;
42+ uint32_t buff_size;
43+
44+ float next;
45+
46+ float attackInc, decayInc, rampInc;
47+
48+ int inAttack, inDecay, inRamp;
49+
50+ int loop;
51+
52+ float gain, rampPeak;
53+
54+ float attackPhase, decayPhase, rampPhase;
55+
56+ } _tEnvelope;
57+
58+ typedef _tEnvelope* tEnvelope;
59+
60+ void tEnvelope_init (tEnvelope* const, float attack, float decay, int loop);
61+ void tEnvelope_free (tEnvelope* const);
62+ void tEnvelope_initToPool (tEnvelope* const, float attack, float decay, int loop, tMempool* const);
63+ void tEnvelope_freeFromPool (tEnvelope* const, tMempool* const);
64+
65+ float tEnvelope_tick (tEnvelope* const);
66+ void tEnvelope_setAttack (tEnvelope* const, float attack);
67+ void tEnvelope_setDecay (tEnvelope* const, float decay);
68+ void tEnvelope_loop (tEnvelope* const, int loop);
69+ void tEnvelope_on (tEnvelope* const, float velocity);
70+
71+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
72+
73+
74+
75+ /* Exponential Smoother */
76+ typedef struct _tExpSmooth {
77+ float factor, oneminusfactor;
78+ float curr,dest;
79+
80+ } _tExpSmooth;
81+
82+ typedef _tExpSmooth* tExpSmooth;
83+
84+ void tExpSmooth_init (tExpSmooth* const, float val, float factor);
85+ void tExpSmooth_free (tExpSmooth* const);
86+ void tExpSmooth_initToPool (tExpSmooth* const, float val, float factor, tMempool* const);
87+ void tExpSmooth_freeFromPool (tExpSmooth* const, tMempool* const);
88+
89+ float tExpSmooth_tick (tExpSmooth* const);
90+ float tExpSmooth_sample (tExpSmooth* const);
91+ void tExpSmooth_setFactor (tExpSmooth* const, float factor);
92+ void tExpSmooth_setDest (tExpSmooth* const, float dest);
93+ void tExpSmooth_setVal (tExpSmooth* const, float val);
94+ void tExpSmooth_setValAndDest(tExpSmooth* const expsmooth, float val);
95+
96+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
97+
98+
99+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
100+
101+
102+ /* ADSR */
103+ typedef struct _tADSR
104+ {
105+ const float *exp_buff;
106+ const float *inc_buff;
107+ uint32_t buff_size;
108+
109+ float next;
110+
111+ float attackInc, decayInc, releaseInc, rampInc;
112+
113+ oBool inAttack, inDecay, inSustain, inRelease, inRamp;
114+
115+ float sustain, gain, rampPeak, releasePeak;
116+
117+ float attackPhase, decayPhase, releasePhase, rampPhase;
118+
119+ float leakFactor;
120+
121+
122+ } _tADSR;
123+
124+ typedef _tADSR* tADSR;
125+
126+ void tADSR_init (tADSR* const adsrenv, float attack, float decay, float sustain, float release);
127+ void tADSR_free (tADSR* const);
128+ void tADSR_initToPool (tADSR* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp);
129+ void tADSR_freeFromPool (tADSR* const, tMempool* const);
130+
131+ float tADSR_tick (tADSR* const);
132+ void tADSR_setAttack (tADSR* const, float attack);
133+ void tADSR_setDecay (tADSR* const, float decay);
134+ void tADSR_setSustain (tADSR* const, float sustain);
135+ void tADSR_setRelease (tADSR* const, float release);
136+ void tADSR_setLeakFactor (tADSR* const, float leakFactor);
137+ void tADSR_on (tADSR* const, float velocity);
138+ void tADSR_off (tADSR* const);
139+
140+
141+
142+
143+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
144+
145+
146+
147+ /* ADSR2 */
148+ typedef struct _tADSR2
149+ {
150+ float sampleRateInMs;
151+ float attack;
152+ float decay;
153+ float release;
154+ float attackLambda;
155+ float decayLambda;
156+ float releaseLambda;
157+ float sustain;
158+ float leakGain;
159+ float leakFactor;
160+ float targetGainSquared;
161+ float factor;
162+ float oneMinusFactor;
163+ float gain;
164+ uint8_t attacking;
165+ uint8_t gate;
166+ float env;
167+ float envTarget;
168+ } _tADSR2;
169+
170+ typedef _tADSR2* tADSR2;
171+
172+ void tADSR2_init (tADSR2* const, float attack, float decay, float sustain, float release);
173+ void tADSR2_free (tADSR2* const);
174+ void tADSR2_initToPool (tADSR2* const, float attack, float decay, float sustain, float release, tMempool* const);
175+ void tADSR2_freeFromPool (tADSR2* const, tMempool* const);
176+
177+ float tADSR2_tick (tADSR2* const);
178+ void tADSR2_setAttack (tADSR2* const, float attack);
179+ void tADSR2_setDecay (tADSR2* const, float decay);
180+ void tADSR2_setSustain (tADSR2* const, float sustain);
181+ void tADSR2_setRelease (tADSR2* const, float release);
182+ void tADSR2_setLeakFactor (tADSR2* const, float leakFactor);
183+ void tADSR2_on (tADSR2* const, float velocity);
184+ void tADSR2_off (tADSR2* const);
185+
186+
187+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
188+
189+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
190+ enum envState {
191+ env_idle = 0,
192+ env_attack,
193+ env_decay,
194+ env_sustain,
195+ env_release,
196+ env_ramp
197+ };
198+
199+ /* ADSR3 */
200+ typedef struct _tADSR3
201+ {
202+ float sampleRateInMs;
203+ int state;
204+ float output;
205+ float attackRate;
206+ float decayRate;
207+ float releaseRate;
208+ float attackCoef;
209+ float decayCoef;
210+ float releaseCoef;
211+ float sustainLevel;
212+ float targetRatioA;
213+ float targetRatioDR;
214+ float attackBase;
215+ float decayBase;
216+ float releaseBase;
217+ float leakFactor;
218+ float targetGainSquared;
219+ float factor;
220+ float oneMinusFactor;
221+ float gain;
222+
223+ } _tADSR3;
224+
225+ typedef _tADSR3* tADSR3;
226+
227+ void tADSR3_init (tADSR3* const, float attack, float decay, float sustain, float release);
228+ void tADSR3_free (tADSR3* const);
229+ void tADSR3_initToPool (tADSR3* const, float attack, float decay, float sustain, float release, tMempool* const);
230+ void tADSR3_freeFromPool (tADSR3* const, tMempool* const);
231+
232+ float tADSR3_tick (tADSR3* const);
233+ void tADSR3_setAttack (tADSR3* const, float attack);
234+ void tADSR3_setDecay (tADSR3* const, float decay);
235+ void tADSR3_setSustain (tADSR3* const, float sustain);
236+ void tADSR3_setRelease (tADSR3* const, float release);
237+ void tADSR3_setLeakFactor (tADSR3* const, float leakFactor);
238+ void tADSR3_on (tADSR3* const, float velocity);
239+ void tADSR3_off (tADSR3* const);
240+
241+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
242+
243+ //ADSR4
244+
245+
246+ typedef struct _tADSR4
247+ {
248+ const float *exp_buff;
249+ uint32_t buff_size;
250+ uint32_t buff_sizeMinusOne;
251+ float bufferSizeDividedBySampleRateInMs;
252+ float next;
253+
254+ float attackInc, decayInc, releaseInc, rampInc;
255+
256+ uint32_t whichStage;
257+
258+ float sustain, gain, rampPeak, releasePeak;
259+
260+ float attackPhase, decayPhase, releasePhase, rampPhase;
261+
262+ float leakFactor;
263+
264+
265+ } _tADSR4;
266+
267+ typedef _tADSR4* tADSR4;
268+
269+ void tADSR4_init (tADSR4* const, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize);
270+ void tADSR4_free (tADSR4* const);
271+ void tADSR4_initToPool (tADSR4* const, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize, tMempool* const);
272+ void tADSR4_freeFromPool (tADSR4* const, tMempool* const);
273+
274+ float tADSR4_tick (tADSR4* const);
275+ float tADSR4_tickNoInterp (tADSR4* const adsrenv);
276+ void tADSR4_setAttack (tADSR4* const, float attack);
277+ void tADSR4_setDecay (tADSR4* const, float decay);
278+ void tADSR4_setSustain (tADSR4* const, float sustain);
279+ void tADSR4_setRelease (tADSR4* const, float release);
280+ void tADSR4_setLeakFactor (tADSR4* const, float leakFactor);
281+ void tADSR4_on (tADSR4* const, float velocity);
282+ void tADSR4_off (tADSR4* const);
283+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
284+
285+ /* Ramp */
286+ typedef struct _tRamp {
287+ float inc;
288+ float inv_sr_ms;
289+ float minimum_time;
290+ float curr,dest;
291+ float time;
292+ float factor;
293+ int samples_per_tick;
294+
295+ } _tRamp;
296+
297+ typedef _tRamp* tRamp;
298+
299+ void tRamp_init (tRamp* const, float time, int samplesPerTick);
300+ void tRamp_free (tRamp* const);
301+ void tRamp_initToPool (tRamp* const, float time, int samplesPerTick, tMempool* const);
302+ void tRamp_freeFromPool (tRamp* const, tMempool* const);
303+
304+ float tRamp_tick (tRamp* const);
305+ float tRamp_sample (tRamp* const);
306+ void tRamp_setTime (tRamp* const, float time);
307+ void tRamp_setDest (tRamp* const, float dest);
308+ void tRamp_setVal (tRamp* const, float val);
309+
310+ ///=============
311+ /* Ramp Updown*/
312+ typedef struct _tRampUpDown {
313+ float upInc;
314+ float downInc;
315+ float inv_sr_ms;
316+ float minimum_time;
317+ float curr,dest;
318+ float upTime;
319+ float downTime;
320+ int samples_per_tick;
321+
322+ } _tRampUpDown;
323+
324+ typedef _tRampUpDown* tRampUpDown;
325+
326+ void tRampUpDown_init (tRampUpDown* const, float upTime, float downTime, int samplesPerTick);
327+ void tRampUpDown_free (tRampUpDown* const);
328+ void tRampUpDown_initToPool (tRampUpDown* const, float upTime, float downTime, int samplesPerTick, tMempool* const);
329+ void tRampUpDown_freeFromPool (tRampUpDown* const, tMempool* const);
330+
331+ float tRampUpDown_tick (tRampUpDown* const);
332+ float tRampUpDown_sample (tRampUpDown* const);
333+ void tRampUpDown_setUpTime (tRampUpDown* const, float upTime);
334+ void tRampUpDown_setDownTime (tRampUpDown* const, float downTime);
335+ void tRampUpDown_setDest (tRampUpDown* const, float dest);
336+ void tRampUpDown_setVal (tRampUpDown* const, float val);
337+
338+
339+ ///=========================
340+ //Slide (based on Max/MSP's slide~)
341+ typedef struct _tSlide {
342+ float prevOut;
343+ float currentOut;
344+ float prevIn;
345+ float invUpSlide;
346+ float invDownSlide;
347+
348+ } _tSlide;
349+
350+ typedef _tSlide* tSlide;
351+
352+ void tSlide_init (tSlide* const, float upSlide, float downSlide);
353+ void tSlide_free (tSlide* const);
354+ void tSlide_initToPool (tSlide* const, float upSlide, float downSlide, tMempool* const);
355+ void tSlide_freeFromPool (tSlide* const, tMempool* const);
356+
357+ float tSlide_tick (tSlide* const, float in);
358+
359+#ifdef __cplusplus
360+}
361+#endif
362+
363+#endif // LEAF_ENVELOPES_H_INCLUDED
364+
365+
366+
leaf/Inc/leaf-filters.h+486−0
@@ -0,0 +1,486 @@
1+/*==============================================================================
2+
3+ leaf-filters.h
4+ Created: 20 Jan 2017 12:01:10pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_FILTERS_H_INCLUDED
10+#define LEAF_FILTERS_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-math.h"
19+#include "leaf-mempool.h"
20+#include "leaf-delay.h"
21+#include "leaf-tables.h"
22+
23+ /*!
24+ * @internal
25+ * Header.
26+ * @include basic-oscillators.h
27+ * @example basic-oscillators.c
28+ * An example.
29+ */
30+
31+ //==============================================================================
32+
33+ /* tAllpass: Schroeder allpass. Comb-filter with feedforward and feedback. */
34+ typedef struct _tAllpass
35+ {
36+ float gain;
37+
38+ tLinearDelay delay;
39+
40+ float lastOut;
41+
42+ } _tAllpass;
43+
44+ typedef _tAllpass* tAllpass;
45+
46+ void tAllpass_init (tAllpass* const, float initDelay, uint32_t maxDelay);
47+ void tAllpass_free (tAllpass* const);
48+ void tAllpass_initToPool (tAllpass* const, float initDelay, uint32_t maxDelay, tMempool* const);
49+ void tAllpass_freeFromPool (tAllpass* const, tMempool* const);
50+
51+ float tAllpass_tick (tAllpass* const, float input);
52+ void tAllpass_setGain (tAllpass* const, float gain);
53+ void tAllpass_setDelay (tAllpass* const, float delay);
54+
55+
56+ //==============================================================================
57+
58+ /* tOnePole: OnePole filter, reimplemented from STK (Cook and Scavone). */
59+ typedef struct _tOnePole
60+ {
61+ float gain;
62+ float a0,a1;
63+ float b0,b1;
64+ float lastIn, lastOut;
65+
66+
67+ } _tOnePole;
68+
69+ typedef _tOnePole* tOnePole;
70+
71+ void tOnePole_init (tOnePole* const, float thePole);
72+ void tOnePole_free (tOnePole* const);
73+ void tOnePole_initToPool (tOnePole* const, float thePole, tMempool* const);
74+ void tOnePole_freeFromPool (tOnePole* const, tMempool* const);
75+
76+ float tOnePole_tick (tOnePole* const, float input);
77+ void tOnePole_setB0 (tOnePole* const, float b0);
78+ void tOnePole_setA1 (tOnePole* const, float a1);
79+ void tOnePole_setPole (tOnePole* const, float thePole);
80+ void tOnePole_setFreq (tOnePole* const, float freq);
81+ void tOnePole_setCoefficients(tOnePole* const, float b0, float a1);
82+ void tOnePole_setGain (tOnePole* const, float gain);
83+
84+ //==============================================================================
85+
86+ /* TwoPole filter, reimplemented from STK (Cook and Scavone). */
87+ typedef struct _tTwoPole
88+ {
89+ float gain;
90+ float a0, a1, a2;
91+ float b0;
92+
93+ float radius, frequency;
94+ oBool normalize;
95+
96+ float lastOut[2];
97+
98+ } _tTwoPole;
99+
100+ typedef _tTwoPole* tTwoPole;
101+
102+ void tTwoPole_init (tTwoPole* const);
103+ void tTwoPole_free (tTwoPole* const);
104+ void tTwoPole_initToPool (tTwoPole* const, tMempool* const);
105+ void tTwoPole_freeFromPool (tTwoPole* const, tMempool* const);
106+
107+ float tTwoPole_tick (tTwoPole* const, float input);
108+ void tTwoPole_setB0 (tTwoPole* const, float b0);
109+ void tTwoPole_setA1 (tTwoPole* const, float a1);
110+ void tTwoPole_setA2 (tTwoPole* const, float a2);
111+ void tTwoPole_setResonance (tTwoPole* const, float freq, float radius, oBool normalize);
112+ void tTwoPole_setCoefficients(tTwoPole* const, float b0, float a1, float a2);
113+ void tTwoPole_setGain (tTwoPole* const, float gain);
114+
115+ //==============================================================================
116+
117+ /* OneZero filter, reimplemented from STK (Cook and Scavone). */
118+ typedef struct _tOneZero
119+ {
120+ float gain;
121+ float b0,b1;
122+ float lastIn, lastOut, frequency;
123+
124+ } _tOneZero;
125+
126+ typedef _tOneZero* tOneZero;
127+
128+ void tOneZero_init (tOneZero* const, float theZero);
129+ void tOneZero_free (tOneZero* const);
130+ void tOneZero_initToPool (tOneZero* const, float theZero, tMempool* const);
131+ void tOneZero_freeFromPool (tOneZero* const, tMempool* const);
132+
133+ float tOneZero_tick (tOneZero* const, float input);
134+ void tOneZero_setB0 (tOneZero* const, float b0);
135+ void tOneZero_setB1 (tOneZero* const, float b1);
136+ void tOneZero_setZero (tOneZero* const, float theZero);
137+ void tOneZero_setCoefficients(tOneZero* const, float b0, float b1);
138+ void tOneZero_setGain (tOneZero* const, float gain);
139+ float tOneZero_getPhaseDelay (tOneZero *f, float frequency );
140+
141+ //==============================================================================
142+
143+ /* TwoZero filter, reimplemented from STK (Cook and Scavone). */
144+ typedef struct _tTwoZero
145+ {
146+ float gain;
147+ float b0, b1, b2;
148+
149+ float frequency, radius;
150+
151+ float lastIn[2];
152+
153+ } _tTwoZero;
154+
155+ typedef _tTwoZero* tTwoZero;
156+
157+ void tTwoZero_init (tTwoZero* const);
158+ void tTwoZero_free (tTwoZero* const);
159+ void tTwoZero_initToPool (tTwoZero* const, tMempool* const);
160+ void tTwoZero_freeFromPool (tTwoZero* const, tMempool* const);
161+
162+ float tTwoZero_tick (tTwoZero* const, float input);
163+ void tTwoZero_setB0 (tTwoZero* const, float b0);
164+ void tTwoZero_setB1 (tTwoZero* const, float b1);
165+ void tTwoZero_setB2 (tTwoZero* const, float b2);
166+ void tTwoZero_setNotch (tTwoZero* const, float frequency, float radius);
167+ void tTwoZero_setCoefficients(tTwoZero* const, float b0, float b1, float b2);
168+ void tTwoZero_setGain (tTwoZero* const, float gain);
169+
170+ //==============================================================================
171+
172+ /* PoleZero filter, reimplemented from STK (Cook and Scavone). */
173+ typedef struct _tPoleZero
174+ {
175+ float gain;
176+ float a0,a1;
177+ float b0,b1;
178+
179+ float lastIn, lastOut;
180+
181+ } _tPoleZero;
182+
183+ typedef _tPoleZero* tPoleZero;
184+
185+ void tPoleZero_init (tPoleZero* const);
186+ void tPoleZero_free (tPoleZero* const);
187+ void tPoleZero_initToPool (tPoleZero* const, tMempool* const);
188+ void tPoleZero_freeFromPool (tPoleZero* const, tMempool* const);
189+
190+ float tPoleZero_tick (tPoleZero* const, float input);
191+ void tPoleZero_setB0 (tPoleZero* const, float b0);
192+ void tPoleZero_setB1 (tPoleZero* const, float b1);
193+ void tPoleZero_setA1 (tPoleZero* const, float a1);
194+ void tPoleZero_setCoefficients (tPoleZero* const, float b0, float b1, float a1);
195+ void tPoleZero_setAllpass (tPoleZero* const, float coeff);
196+ void tPoleZero_setBlockZero (tPoleZero* const, float thePole);
197+ void tPoleZero_setGain (tPoleZero* const, float gain);
198+
199+ //==============================================================================
200+
201+ /* BiQuad filter, reimplemented from STK (Cook and Scavone). */
202+ typedef struct _tBiQuad
203+ {
204+ float gain;
205+ float a0, a1, a2;
206+ float b0, b1, b2;
207+
208+ float lastIn[2];
209+ float lastOut[2];
210+
211+ float frequency, radius;
212+ oBool normalize;
213+ } _tBiQuad;
214+
215+ typedef _tBiQuad* tBiQuad;
216+
217+ void tBiQuad_init (tBiQuad* const);
218+ void tBiQuad_free (tBiQuad* const);
219+ void tBiQuad_initToPool (tBiQuad* const, tMempool* const);
220+ void tBiQuad_freeFromPool (tBiQuad* const, tMempool* const);
221+
222+ float tBiQuad_tick (tBiQuad* const, float input);
223+ void tBiQuad_setB0 (tBiQuad* const, float b0);
224+ void tBiQuad_setB1 (tBiQuad* const, float b1);
225+ void tBiQuad_setB2 (tBiQuad* const, float b2);
226+ void tBiQuad_setA1 (tBiQuad* const, float a1);
227+ void tBiQuad_setA2 (tBiQuad* const, float a2);
228+ void tBiQuad_setNotch (tBiQuad* const, float freq, float radius);
229+ void tBiQuad_setResonance (tBiQuad* const, float freq, float radius, oBool normalize);
230+ void tBiQuad_setCoefficients(tBiQuad* const, float b0, float b1, float b2, float a1, float a2);
231+ void tBiQuad_setGain (tBiQuad* const, float gain);
232+
233+ //==============================================================================
234+
235+/* State Variable Filter, algorithm from Andy Simper. */
236+ typedef enum SVFType
237+ {
238+ SVFTypeHighpass = 0,
239+ SVFTypeLowpass,
240+ SVFTypeBandpass,
241+ SVFTypeNotch,
242+ SVFTypePeak,
243+ SVFTypeLowShelf,
244+ SVFTypeHighShelf
245+ } SVFType;
246+
247+ typedef struct _tSVF
248+ {
249+ SVFType type;
250+ float cutoff, Q;
251+ float ic1eq,ic2eq;
252+ float g,k,a1,a2,a3,cH,cB,cL,cBK;
253+
254+
255+ } _tSVF;
256+
257+ typedef _tSVF* tSVF;
258+
259+ void tSVF_init (tSVF* const, SVFType type, float freq, float Q);
260+ void tSVF_free (tSVF* const);
261+ void tSVF_initToPool (tSVF* const, SVFType type, float freq, float Q, tMempool* const);
262+ void tSVF_freeFromPool (tSVF* const, tMempool* const);
263+
264+ float tSVF_tick (tSVF* const, float v0);
265+ void tSVF_setFreq (tSVF* const, float freq);
266+ void tSVF_setQ (tSVF* const, float Q);
267+ void tSVF_setFreqAndQ (tSVF* const svff, float freq, float Q);
268+ //==============================================================================
269+
270+ /* Efficient State Variable Filter for 14-bit control input, [0, 4096). */
271+ typedef struct _tEfficientSVF
272+ {
273+ SVFType type;
274+ float cutoff, Q;
275+ float ic1eq,ic2eq;
276+ float g,k,a1,a2,a3;
277+
278+ } _tEfficientSVF;
279+
280+ typedef _tEfficientSVF* tEfficientSVF;
281+
282+ void tEfficientSVF_init (tEfficientSVF* const, SVFType type, uint16_t input, float Q);
283+ void tEfficientSVF_free (tEfficientSVF* const);
284+ void tEfficientSVF_initToPool (tEfficientSVF* const, SVFType type, uint16_t input, float Q, tMempool* const);
285+ void tEfficientSVF_freeFromPool (tEfficientSVF* const, tMempool* const);
286+
287+ float tEfficientSVF_tick (tEfficientSVF* const, float v0);
288+ void tEfficientSVF_setFreq (tEfficientSVF* const, uint16_t controlFreq);
289+ void tEfficientSVF_setQ (tEfficientSVF* const, float Q);
290+
291+ //==============================================================================
292+
293+ /* Simple Highpass filter. */
294+ typedef struct _tHighpass
295+ {
296+ float xs, ys, R;
297+ float frequency;
298+
299+ } _tHighpass;
300+
301+ typedef _tHighpass* tHighpass;
302+
303+ void tHighpass_init (tHighpass* const, float freq);
304+ void tHighpass_free (tHighpass* const);
305+ void tHighpass_initToPool (tHighpass* const, float freq, tMempool* const);
306+ void tHighpass_freeFromPool (tHighpass* const, tMempool* const);
307+
308+ float tHighpass_tick (tHighpass* const, float x);
309+ void tHighpass_setFreq (tHighpass* const, float freq);
310+ float tHighpass_getFreq (tHighpass* const);
311+
312+ //==============================================================================
313+
314+ // Butterworth Filter
315+#define NUM_SVF_BW 16
316+ typedef struct _tButterworth
317+ {
318+ float gain;
319+
320+ int N;
321+
322+ tSVF low[NUM_SVF_BW];
323+ tSVF high[NUM_SVF_BW];
324+
325+ float f1,f2;
326+
327+ } _tButterworth;
328+
329+ typedef _tButterworth* tButterworth;
330+
331+ void tButterworth_init (tButterworth* const, int N, float f1, float f2);
332+ void tButterworth_free (tButterworth* const);
333+ void tButterworth_initToPool (tButterworth* const, int N, float f1, float f2, tMempool* const);
334+ void tButterworth_freeFromPool (tButterworth* const, tMempool* const);
335+
336+ float tButterworth_tick (tButterworth* const, float input);
337+ void tButterworth_setF1 (tButterworth* const, float in);
338+ void tButterworth_setF2 (tButterworth* const, float in);
339+ void tButterworth_setFreqs (tButterworth* const, float f1, float f2);
340+
341+ //==============================================================================
342+
343+ typedef struct _tFIR
344+ {
345+ float* past;
346+ float* coeff;
347+ int numTaps;
348+ } _tFIR;
349+
350+ typedef _tFIR* tFIR;
351+
352+ void tFIR_init (tFIR* const, float* coeffs, int numTaps);
353+ void tFIR_free (tFIR* const);
354+ void tFIR_initToPool (tFIR* const, float* coeffs, int numTaps, tMempool* const);
355+ void tFIR_freeFromPool (tFIR* const, tMempool* const);
356+
357+ float tFIR_tick (tFIR* const, float input);
358+
359+
360+ //==============================================================================
361+
362+
363+ typedef struct _tMedianFilter
364+ {
365+ float* val;
366+ int* age;
367+ int m;
368+ int size;
369+ int middlePosition;
370+ int last;
371+ int pos;
372+ } _tMedianFilter;
373+
374+ typedef _tMedianFilter* tMedianFilter;
375+
376+ void tMedianFilter_init (tMedianFilter* const, int size);
377+ void tMedianFilter_free (tMedianFilter* const);
378+ void tMedianFilter_initToPool (tMedianFilter* const, int size, tMempool* const);
379+ void tMedianFilter_freeFromPool (tMedianFilter* const, tMempool* const);
380+
381+ float tMedianFilter_tick (tMedianFilter* const, float input);
382+
383+
384+
385+
386+
387+ //Vadim Zavalishin style from VA book (from implementation in RSlib posted to kvr forum)
388+
389+ typedef enum VZFilterType
390+ {
391+ Highpass = 0,
392+ Lowpass,
393+ BandpassSkirt,
394+ BandpassPeak,
395+ BandReject,
396+ Bell,
397+ Lowshelf,
398+ Highshelf,
399+ Morph,
400+ Bypass,
401+ Allpass
402+ } VZFilterType;
403+
404+
405+ typedef struct _tVZFilter
406+ {
407+ VZFilterType type;
408+ // state:
409+ float s1, s2;
410+
411+ // filter coefficients:
412+ float g; // embedded integrator gain
413+ float R2; // twice the damping coefficient (R2 == 2*R == 1/Q)
414+ float h; // factor for feedback (== 1/(1+2*R*g+g*g))
415+ float cL, cB, cH; // coefficients for low-, band-, and highpass signals
416+
417+ // parameters:
418+ float fs; // sample-rate
419+ float fc; // characteristic frequency
420+ float G; // gain
421+ float invG; //1/gain
422+ float B; // bandwidth (in octaves)
423+ float m; // morph parameter (0...1)
424+
425+ float sr; //local sampling rate of filter (may be different from leaf sr if oversampled)
426+ float inv_sr;
427+
428+ } _tVZFilter;
429+
430+ typedef _tVZFilter* tVZFilter;
431+
432+ void tVZFilter_init (tVZFilter* const, VZFilterType type, float freq, float Q);
433+ void tVZFilter_free (tVZFilter* const);
434+ void tVZFilter_initToPool (tVZFilter* const, VZFilterType type, float freq, float Q, tMempool* const);
435+ void tVZFilter_freeFromPool (tVZFilter* const, tMempool* const);
436+ void tVZFilter_setSampleRate (tVZFilter* const, float sampleRate);
437+ float tVZFilter_tick (tVZFilter* const, float input);
438+ float tVZFilter_tickEfficient (tVZFilter* const vf, float in);
439+ void tVZFilter_calcCoeffs (tVZFilter* const);
440+ void tVZFilter_setBandwidth (tVZFilter* const, float bandWidth);
441+ void tVZFilter_setFreq (tVZFilter* const, float freq);
442+ void tVZFilter_setFreqAndBandwidth (tVZFilter* const vf, float freq, float bw);
443+ void tVZFilter_setGain (tVZFilter* const, float gain);
444+ void tVZFilter_setType (tVZFilter* const, VZFilterType type);
445+ float tVZFilter_BandwidthToR (tVZFilter* const vf, float B);
446+
447+
448+
449+
450+ //diode ladder filter
451+ typedef struct _tDiodeFilter
452+ {
453+
454+ float f;
455+ float r;
456+ float Vt;
457+ float n;
458+ float gamma;
459+ float zi;
460+ float g0inv;
461+ float g1inv;
462+ float g2inv;
463+ float s0, s1, s2, s3;
464+
465+ } _tDiodeFilter;
466+
467+ typedef _tDiodeFilter* tDiodeFilter;
468+
469+ void tDiodeFilter_init (tDiodeFilter* const, float freq, float Q);
470+ void tDiodeFilter_free (tDiodeFilter* const);
471+ void tDiodeFilter_initToPool (tDiodeFilter* const, float freq, float Q, tMempool* const);
472+ void tDiodeFilter_freeFromPool (tDiodeFilter* const, tMempool* const);
473+
474+ float tDiodeFilter_tick (tDiodeFilter* const, float input);
475+ void tDiodeFilter_setFreq (tDiodeFilter* const vf, float cutoff);
476+ void tDiodeFilter_setQ (tDiodeFilter* const vf, float resonance);
477+
478+
479+#ifdef __cplusplus
480+}
481+#endif
482+
483+#endif // LEAF_FILTERS_H_INCLUDED
484+
485+//==============================================================================
486+
leaf/Inc/leaf-global.h+52−0
@@ -0,0 +1,52 @@
1+/*
2+ ==============================================================================
3+
4+ leaf-global.h
5+ Created: 24 Oct 2019 2:24:38pm
6+ Author: Matthew Wang
7+
8+ ==============================================================================
9+ */
10+
11+#ifndef LEAF_GLOBAL_H_INCLUDED
12+#define LEAF_GLOBAL_H_INCLUDED
13+
14+#ifdef __cplusplus
15+extern "C" {
16+#endif
17+
18+#include "leaf-mempool.h"
19+
20+ /*!
21+ * @ingroup leaf
22+ * @brief The struct of the global LEAF instance `leaf`. Contains global variables and settings.
23+ */
24+ struct LEAF
25+ {
26+ ///@{
27+ float sampleRate; //!< The current audio sample rate. Set with LEAF_setSampleRate().
28+ float invSampleRate; //!< The inverse of the current sample rate.
29+ int blockSize; //!< The audio block size.
30+ float twoPiTimesInvSampleRate; //!< Two-pi times the inverse of the current sample rate.
31+ float (*random)(void); //!< A pointer to the random() function provided on initialization.
32+ int clearOnAllocation; //!< A flag that determines whether memory allocated from the LEAF memory pool will be cleared.
33+ tMempool mempool; //!< The default LEAF mempool object.
34+ _tMempool _mempool;
35+ size_t header_size; //!< The size in bytes of memory region headers within mempools.
36+ ///@}
37+ };
38+ typedef struct LEAF LEAF;
39+
40+ extern LEAF leaf;
41+
42+ //==============================================================================
43+
44+#ifdef __cplusplus
45+}
46+#endif
47+
48+#endif // LEAF_GLOBAL_H_INCLUDED
49+
50+//==============================================================================
51+
52+
leaf/Inc/leaf-instruments.h+209−0
@@ -0,0 +1,209 @@
1+/*==============================================================================
2+
3+ leaf-instruments.h
4+ Created: 30 Nov 2018 10:24:44am
5+ Author: airship
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_INSTRUMENTS_H_INCLUDED
10+#define LEAF_INSTRUMENTS_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-math.h"
19+#include "leaf-mempool.h"
20+#include "leaf-oscillators.h"
21+#include "leaf-filters.h"
22+#include "leaf-envelopes.h"
23+
24+ /*!
25+ * @internal
26+ * Header.
27+ * @include basic-oscillators.h
28+ * @example basic-oscillators.c
29+ * An example.
30+ */
31+
32+ //==============================================================================
33+
34+ // 808 Cowbell
35+ typedef struct _t808Cowbell {
36+
37+ tSquare p[2];
38+ tNoise stick;
39+ tSVF bandpassOsc;
40+ tSVF bandpassStick;
41+ tEnvelope envGain;
42+ tEnvelope envStick;
43+ tEnvelope envFilter;
44+ tHighpass highpass;
45+ float oscMix;
46+ float filterCutoff;
47+ uint8_t useStick;
48+
49+ } _t808Cowbell;
50+
51+ typedef _t808Cowbell* t808Cowbell;
52+
53+ void t808Cowbell_init (t808Cowbell* const, int useStick);
54+ void t808Cowbell_free (t808Cowbell* const);
55+ void t808Cowbell_initToPool (t808Cowbell* const, int useStick, tMempool* const);
56+ void t808Cowbell_freeFromPool (t808Cowbell* const, tMempool* const);
57+
58+ float t808Cowbell_tick (t808Cowbell* const);
59+ void t808Cowbell_on (t808Cowbell* const, float vel);
60+ void t808Cowbell_setDecay (t808Cowbell* const, float decay);
61+ void t808Cowbell_setHighpassFreq (t808Cowbell* const, float freq);
62+ void t808Cowbell_setBandpassFreq (t808Cowbell* const, float freq);
63+ void t808Cowbell_setFreq (t808Cowbell* const, float freq);
64+ void t808Cowbell_setOscMix (t808Cowbell* const, float oscMix);
65+ void t808Cowbell_setStick (t808Cowbell* const, int useStick);
66+
67+ //==============================================================================
68+
69+ // 808 Hihat
70+ typedef struct _t808Hihat {
71+
72+ // 6 Square waves
73+ tSquare p[6];
74+ tNoise n;
75+ tSVF bandpassOsc;
76+ tSVF bandpassStick;
77+ tEnvelope envGain;
78+ tEnvelope envStick;
79+ tEnvelope noiseFMGain;
80+ tHighpass highpass;
81+ tNoise stick;
82+
83+ float freq;
84+ float stretch;
85+ float FM_amount;
86+ float oscNoiseMix;
87+
88+ } _t808Hihat;
89+
90+ typedef _t808Hihat* t808Hihat;
91+
92+ void t808Hihat_init (t808Hihat* const);
93+ void t808Hihat_free (t808Hihat* const);
94+ void t808Hihat_initToPool (t808Hihat* const, tMempool* const);
95+ void t808Hihat_freeFromPool (t808Hihat* const, tMempool* const);
96+
97+ float t808Hihat_tick (t808Hihat* const);
98+ void t808Hihat_on (t808Hihat* const, float vel);
99+ void t808Hihat_setOscNoiseMix (t808Hihat* const, float oscNoiseMix);
100+ void t808Hihat_setDecay (t808Hihat* const, float decay);
101+ void t808Hihat_setHighpassFreq (t808Hihat* const, float freq);
102+ void t808Hihat_setOscBandpassFreq (t808Hihat* const, float freq);
103+ void t808Hihat_setOscBandpassQ (t808Hihat* const hihat, float Q);
104+ void t808Hihat_setStickBandPassFreq (t808Hihat* const, float freq);
105+ void t808Hihat_setStickBandPassQ (t808Hihat* const hihat, float Q);
106+ void t808Hihat_setOscFreq (t808Hihat* const, float freq);
107+ void t808Hihat_setStretch (t808Hihat* const hihat, float stretch);
108+ void t808Hihat_setFM (t808Hihat* const hihat, float FM_amount);
109+
110+ //==============================================================================
111+
112+ // 808 Snare
113+ typedef struct _t808Snare {
114+
115+ // Tone 1, Tone 2, Noise
116+ tTriangle tone[2]; // Tri (not yet antialiased or wavetabled)
117+ tNoise noiseOsc;
118+ tSVF toneLowpass[2];
119+ tSVF noiseLowpass; // Lowpass from SVF filter
120+ tEnvelope toneEnvOsc[2];
121+ tEnvelope toneEnvGain[2];
122+ tEnvelope noiseEnvGain;
123+ tEnvelope toneEnvFilter[2];
124+ tEnvelope noiseEnvFilter;
125+
126+ float toneGain[2];
127+ float noiseGain;
128+
129+ float toneNoiseMix;
130+
131+ float tone1Freq, tone2Freq;
132+
133+ float noiseFilterFreq;
134+
135+ } _t808Snare;
136+
137+ typedef _t808Snare* t808Snare;
138+
139+ void t808Snare_init (t808Snare* const);
140+ void t808Snare_free (t808Snare* const);
141+ void t808Snare_initToPool (t808Snare* const, tMempool* const);
142+ void t808Snare_freeFromPool (t808Snare* const, tMempool* const);
143+
144+ float t808Snare_tick (t808Snare* const);
145+ void t808Snare_on (t808Snare* const, float vel);
146+ void t808Snare_setTone1Freq (t808Snare* const, float freq);
147+ void t808Snare_setTone2Freq (t808Snare* const, float freq);
148+ void t808Snare_setTone1Decay (t808Snare* const, float decay);
149+ void t808Snare_setTone2Decay (t808Snare* const, float decay);
150+ void t808Snare_setNoiseDecay (t808Snare* const, float decay);
151+ void t808Snare_setToneNoiseMix (t808Snare* const, float toneNoiseMix);
152+ void t808Snare_setNoiseFilterFreq (t808Snare* const, float noiseFilterFreq);
153+ void t808Snare_setNoiseFilterQ (t808Snare* const, float noiseFilterQ);
154+
155+ //==============================================================================
156+
157+ // 808 Kick
158+ typedef struct _t808Kick {
159+
160+
161+ tCycle tone; // Tri
162+ tNoise noiseOsc;
163+ tSVF toneLowpass;
164+ tEnvelope toneEnvOscChirp;
165+ tEnvelope toneEnvOscSigh;
166+ tEnvelope toneEnvGain;
167+ tEnvelope noiseEnvGain;
168+ tEnvelope toneEnvFilter;
169+
170+ float toneGain;
171+ float noiseGain;
172+
173+ float toneInitialFreq;
174+ float sighAmountInHz;
175+ float chirpRatioMinusOne;
176+ float noiseFilterFreq;
177+
178+ } _t808Kick;
179+
180+ typedef _t808Kick* t808Kick;
181+
182+ void t808Kick_init (t808Kick* const);
183+ void t808Kick_free (t808Kick* const);
184+ void t808Kick_initToPool (t808Kick* const, tMempool* const);
185+ void t808Kick_freeFromPool (t808Kick* const, tMempool* const);
186+
187+ float t808Kick_tick (t808Kick* const);
188+ void t808Kick_on (t808Kick* const, float vel);
189+ void t808Kick_setToneFreq (t808Kick* const, float freq);
190+ void t808Kick_setToneDecay (t808Kick* const, float decay);
191+ void t808Kick_setNoiseDecay (t808Kick* const, float decay);
192+ void t808Kick_setSighAmount (t808Kick* const, float sigh);
193+ void t808Kick_setChirpAmount (t808Kick* const, float chirp);
194+ void t808Kick_setToneNoiseMix (t808Kick* const, float toneNoiseMix);
195+ void t808Kick_setNoiseFilterFreq (t808Kick* const, float noiseFilterFreq);
196+ void t808Kick_setNoiseFilterQ (t808Kick* const, float noiseFilterQ);
197+
198+ //==============================================================================
199+
200+#ifdef __cplusplus
201+}
202+#endif
203+
204+#endif // LEAF_INSTRUMENTS_H_INCLUDED
205+
206+//==============================================================================
207+
208+
209+
leaf/Inc/leaf-math.h+212−0
@@ -0,0 +1,212 @@
1+/*==============================================================================
2+
3+ leaf-math.h
4+ Created: 22 Jan 2017 7:02:56pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_MATH_H_INCLUDED
10+#define LEAF_MATH_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+#include "leaf-global.h"
17+#include "math.h"
18+#include "stdint.h"
19+#include "stdlib.h"
20+
21+ //==============================================================================
22+
23+ //==============================================================================
24+
25+ typedef enum oBool
26+ {
27+ OTRUE = 1,
28+ OFALSE = 0
29+ }oBool;
30+
31+ // Allows for bitwise operations on floats
32+ union unholy_t { /* a union between a float and an integer */
33+ float f;
34+ int i;
35+ };
36+
37+#define SQRT8 2.82842712475f
38+#define WSCALE 1.30612244898f
39+#define PI (3.14159265358979f)
40+#define TWO_PI (6.28318530717958f)
41+#define HALF_PI (1.570796326794897f)
42+
43+#define VSF 1.0e-38f
44+
45+#define MAX_DELAY 8192
46+#define INV_128 0.0078125f
47+
48+#define INV_20 0.05f
49+#define INV_40 0.025f
50+#define INV_80 0.0125f
51+#define INV_160 0.00625f
52+#define INV_320 0.003125f
53+#define INV_640 0.0015625f
54+#define INV_1280 0.00078125f
55+#define INV_2560 0.000390625f
56+#define INV_5120 0.0001953125f
57+#define INV_10240 0.00009765625f
58+#define INV_20480 0.000048828125f
59+
60+
61+#define INV_TWELVE 0.0833333333f
62+#define INV_440 0.0022727273f
63+
64+#define LOG2 0.3010299957f
65+#define INV_LOG2 3.321928095f
66+
67+#define SOS_M 343.0f
68+#define TWO_TO_5 32.0f
69+#define INV_TWO_TO_5 0.03125f
70+#define TWO_TO_7 128.f
71+#define INV_TWO_TO_7 0.0078125f
72+#define TWO_TO_8 256.f
73+#define INV_TWO_TO_8 0.00390625f
74+#define TWO_TO_9 512.f
75+#define INV_TWO_TO_9 0.001953125f
76+#define TWO_TO_10 1024.f
77+#define INV_TWO_TO_10 0.0009765625f
78+#define TWO_TO_11 2048.f
79+#define INV_TWO_TO_11 0.00048828125f
80+#define TWO_TO_12 4096.f
81+#define INV_TWO_TO_12 0.00024414062f
82+#define TWO_TO_15 32768.f
83+#define TWO_TO_16 65536.f
84+#define INV_TWO_TO_15 0.00003051757f
85+#define INV_TWO_TO_16 0.00001525878f
86+#define TWO_TO_16_MINUS_ONE 65535.0f
87+#define TWO_TO_23 8388608.0f
88+#define INV_TWO_TO_23 0.00000011920929f
89+#define TWO_TO_31 2147483648.0f
90+#define INV_TWO_TO_31 0.000000000465661f
91+#define TWO_TO_32 4294967296.0f
92+#define INV_TWO_TO_32 0.000000000232831f
93+
94+#define ONE_OVER_SQRT2 0.707106781186548f
95+
96+#define LOGTEN 2.302585092994
97+
98+ // Jones shaper
99+ float LEAF_shaper (float input, float m_drive);
100+ float LEAF_reedTable (float input, float offset, float slope);
101+
102+ float LEAF_reduct (float input, float ratio);
103+ float LEAF_round (float input, float rnd);
104+ float LEAF_bitwise_xor(float input, uint32_t op);
105+
106+ float LEAF_reduct (float input, float ratio);
107+ float LEAF_round (float input, float rnd);
108+ float LEAF_bitwise_xor(float input, uint32_t op);
109+
110+ float LEAF_clip (float min, float val, float max);
111+ int LEAF_clipInt (int min, int val, int max);
112+ float LEAF_softClip (float val, float thresh);
113+ oBool LEAF_isPrime (uint64_t number );
114+
115+ float LEAF_midiToFrequency (float f);
116+ float LEAF_frequencyToMidi(float f);
117+
118+ void LEAF_generate_sine (float* buffer, int size);
119+ void LEAF_generate_sawtooth (float* buffer, float basefreq, int size);
120+ void LEAF_generate_triangle (float* buffer, float basefreq, int size);
121+ void LEAF_generate_square (float* buffer, float basefreq, int size);
122+
123+ // dope af
124+ float LEAF_chebyshevT(float in, int n);
125+ float LEAF_CompoundChebyshevT(float in, int n, float* amps);
126+
127+ // Hermite interpolation
128+ float LEAF_interpolate_hermite (float A, float B, float C, float D, float t);
129+ float LEAF_interpolate_hermite_x(float yy0, float yy1, float yy2, float yy3, float xx);
130+ float LEAF_interpolation_linear (float A, float B, float t);
131+
132+ float interpolate3max(float *buf, const int peakindex);
133+ float interpolate3phase(float *buf, const int peakindex);
134+
135+ // alternative implementation for abs()
136+ // REQUIRES: 32 bit integers
137+ int fastabs_int(int in);
138+
139+ // alternative implementation for abs()
140+ // REQUIRES: 32 bit floats
141+ float fastabsf(float f);
142+
143+ float fastexp2f(float f);
144+
145+ float fastPowf(float a, float b) ;
146+ double fastPow(double a, double b);
147+
148+
149+ void LEAF_crossfade(float fade, float* volumes);
150+
151+
152+ float LEAF_tanh(float x);
153+ void LEAF_generate_sine(float* buffer, int size);
154+ void LEAF_generate_sawtooth(float* buffer, float basefreq, int size);
155+ void LEAF_generate_triangle(float* buffer, float basefreq, int size);
156+ void LEAF_generate_square(float* buffer, float basefreq, int size);
157+
158+ //0.001 base gives a good curve that goes from 1 to near zero
159+ //1000 gives a good curve from -1.0 to 0.0
160+ void LEAF_generate_exp(float* buffer, float base, float start, float end, float offset, int size);
161+
162+ float LEAF_poly_blep(float t, float dt);
163+ float LEAF_midiToFrequency(float f);
164+
165+
166+ float fast_mtof(float f);
167+
168+ double fastexp(double x);
169+
170+ float fastexpf(float x);
171+
172+ double fasterexp(double x);
173+
174+ float fasterexpf(float x);
175+
176+ float mtof(float f);
177+
178+ float fast_mtof(float f);
179+
180+ float faster_mtof(float f);
181+
182+ float ftom(float f);
183+
184+ float powtodb(float f);
185+
186+ float rmstodb(float f);
187+
188+ float dbtopow(float f);
189+
190+ float dbtorms(float f);
191+
192+ float atodb(float a);
193+
194+ float dbtoa(float db);
195+
196+ float fastdbtoa(float db);
197+
198+ float maximum (float num1, float num2);
199+
200+ float minimum (float num1, float num2);
201+
202+
203+ //==============================================================================
204+
205+#ifdef __cplusplus
206+}
207+#endif
208+
209+#endif // LEAF_MATH_H_INCLUDED
210+
211+//==============================================================================
212+
leaf/Inc/leaf-mempool.h+159−0
@@ -0,0 +1,159 @@
1+/*==============================================================================
2+
3+ In short, mpool is distributed under so called "BSD license",
4+
5+ Copyright (c) 2009-2010 Tatsuhiko Kubo <cubicdaiya@gmail.com>
6+ All rights reserved.
7+
8+ Redistribution and use in source and binary forms, with or without modification,
9+ are permitted provided that the following conditions are met:
10+
11+ * Redistributions of source code must retain the above copyright notice,
12+ this list of conditions and the following disclaimer.
13+
14+ * Redistributions in binary form must reproduce the above copyright notice,
15+ this list of conditions and the following disclaimer in the documentation
16+ and/or other materials provided with the distribution.
17+
18+ * Neither the name of the authors nor the names of its contributors
19+ may be used to endorse or promote products derived from this software
20+ without specific prior written permission.
21+
22+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
34+ written by C99 style
35+ ==============================================================================*/
36+
37+#ifndef LEAF_MPOOL_H_INCLUDED
38+#define LEAF_MPOOL_H_INCLUDED
39+
40+#ifdef __cplusplus
41+extern "C" {
42+#endif
43+
44+ //==============================================================================
45+
46+#include <stdio.h>
47+#include <stdlib.h>
48+#include <string.h>
49+#include <stdbool.h>
50+
51+ //==============================================================================
52+
53+#define MPOOL_ALIGN_SIZE (8)
54+
55+ //#define size_t unsigned long
56+
57+ /*!
58+ * @defgroup tmempool tMempool
59+ * @ingroup mempool
60+ * An object that can contain an additional mempool for the allocation of LEAF objects.
61+ * @{
62+ */
63+
64+ // node of free list
65+ typedef struct mpool_node_t {
66+ char *pool; // memory pool field
67+ struct mpool_node_t *next; // next node pointer
68+ struct mpool_node_t *prev; // prev node pointer
69+ size_t size;
70+ } mpool_node_t;
71+
72+ typedef struct _tMempool
73+ {
74+ char* mpool; // start of the mpool
75+ size_t usize; // used size of the pool
76+ size_t msize; // max size of the pool
77+ mpool_node_t* head; // first node of memory pool free list
78+ } _tMempool;
79+
80+ typedef _tMempool* tMempool;
81+
82+ //! Initialize a tMempool for a given memory location and size to the default LEAF mempool.
83+ /*!
84+ @param pool A pointer to the tMempool to be initialized.
85+ @param memory A pointer to the chunk of memory to be used as a mempool.
86+ @param size The size of the chunk of memory to be used as a mempool.
87+ */
88+ void tMempool_init (tMempool* const pool, char* memory, size_t size);
89+
90+
91+ //! Free a tMempool from the default LEAF mempool.
92+ /*!
93+ @param pool A pointer to the tMempool to be freed.
94+ */
95+ void tMempool_free (tMempool* const pool);
96+
97+
98+ //! Initialize a tMempool for a given memory location and size to a specified mempool.
99+ /*!
100+ @param pool A pointer to the tMempool to be initialized.
101+ @param memory A pointer to the chunk of memory to be used as a mempool.
102+ @param size The size of the chuck of memory to be used as a mempool.
103+ @param poolTo A pointer to the tMempool to which a tMempool should be initialized.
104+ */
105+ void tMempool_initToPool (tMempool* const pool, char* memory, size_t size, tMempool* const poolTo);
106+
107+
108+ //! Free a tMempool from a specified mempool.
109+ /*!
110+ @param pool A pointer to the tMempool to be freed from the default LEAF mempool.
111+ @param poolFrom A pointer to the tMempool from which a tMempool should be freed.
112+ */
113+ void tMempool_freeFromPool (tMempool* const pool, tMempool* const poolFrom);
114+
115+ /*! @} */
116+
117+ //==============================================================================
118+
119+ // typedef struct mpool_t {
120+ // char* mpool; // start of the mpool
121+ // size_t usize; // used size of the pool
122+ // size_t msize; // max size of the pool
123+ // mpool_node_t* head; // first node of memory pool free list
124+ // } mpool_t;
125+
126+ void mpool_create (char* memory, size_t size, _tMempool* pool);
127+
128+ char* mpool_alloc(size_t size, _tMempool* pool);
129+ char* mpool_calloc(size_t asize, _tMempool* pool);
130+
131+ void mpool_free(char* ptr, _tMempool* pool);
132+
133+ size_t mpool_get_size(_tMempool* pool);
134+ size_t mpool_get_used(_tMempool* pool);
135+
136+ void leaf_pool_init(char* memory, size_t size);
137+
138+ char* leaf_alloc(size_t size);
139+ char* leaf_calloc(size_t size);
140+
141+ void leaf_free(char* ptr);
142+
143+ size_t leaf_pool_get_size(void);
144+ size_t leaf_pool_get_used(void);
145+
146+ char* leaf_pool_get_pool(void);
147+
148+ void leaf_mempool_overrun(void);
149+
150+#ifdef __cplusplus
151+}
152+#endif
153+
154+#endif // LEAF_MPOOL_H
155+
156+//==============================================================================
157+
158+
159+
leaf/Inc/leaf-midi.h+510−0
@@ -0,0 +1,510 @@
1+/*==============================================================================
2+
3+ leaf-midi.h
4+ Created: 30 Nov 2018 11:29:26am
5+ Author: airship
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_MIDI_H_INCLUDED
10+#define LEAF_MIDI_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-global.h"
19+#include "leaf-mempool.h"
20+#include "leaf-math.h"
21+#include "leaf-envelopes.h"
22+
23+ /*!
24+ * @internal
25+ * Header.
26+ * @include basic-oscillators.h
27+ * @example basic-oscillators.c
28+ * An example.
29+ */
30+
31+ //==============================================================================
32+
33+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
34+
35+ /*!
36+ * @defgroup tstack tStack
37+ * @ingroup midi
38+ * @brief A basic stack of integers with a fixed max size of 128, used by tPoly to keep track of MIDI notes.
39+ * @{
40+ */
41+
42+ // STACK implementation (fixed size)
43+#define STACK_SIZE 128
44+ typedef struct _tStack
45+ {
46+ int data[STACK_SIZE];
47+ uint16_t pos;
48+ uint16_t size;
49+ uint16_t capacity;
50+ oBool ordered;
51+
52+ } _tStack;
53+
54+ typedef _tStack* tStack;
55+
56+ //! Initialize a tStack to the default LEAF mempool.
57+ /*!
58+ @param stack A pointer to the tStack to be initialized.
59+ */
60+ void tStack_init (tStack* const stack);
61+
62+
63+ //! Free a tStack from the default LEAF mempool.
64+ /*!
65+ @param stack A pointer to the tStack to be freed.
66+ */
67+ void tStack_free (tStack* const stack);
68+
69+
70+ //! Initialize a tStack to a specified mempool.
71+ /*!
72+ @param stack A pointer to the tStack to be initialized.
73+ @param pool A pointer to the tMempool to which the tStack should be initialized.
74+ */
75+ void tStack_initToPool (tStack* const stack, tMempool* const pool);
76+
77+
78+ //! Free a tStack from a specified mempool.
79+ /*!
80+ @param stack A pointer to the tStack to be freed.
81+ @param pool A pointer to the tMempool from which the tStack should be freed.
82+ */
83+ void tStack_freeFromPool (tStack* const stack, tMempool* const pool);
84+
85+ //! Set the capacity of the stack.
86+ /*!
87+ @param stack A pointer to the relevant tStack.
88+ @param cap The new capacity.
89+ */
90+ void tStack_setCapacity (tStack* const stack, uint16_t cap);
91+
92+
93+ //! Add a value to the stack only if that value is not already in the stack.
94+ /*!
95+ @param stack A pointer to the relevant tStack.
96+ @param item The value to be added.
97+ */
98+ int tStack_addIfNotAlreadyThere (tStack* const stack, uint16_t item);
99+
100+
101+ //! Add a value to the stack.
102+ /*!
103+ @param stack A pointer to the relevant tStack.
104+ @param item The value to be added.
105+ */
106+ void tStack_add (tStack* const stack, uint16_t item);
107+
108+
109+ //! Remove a single instance of a value from the stack.
110+ /*!
111+ @param stack A pointer to the relevant tStack.
112+ @param item The value to be removed.
113+ */
114+ int tStack_remove (tStack* const stack, uint16_t item);
115+
116+
117+ //! Clear the stack.
118+ /*!
119+ @param stack A pointer to the relevant tStack.
120+ */
121+ void tStack_clear (tStack* const stack);
122+
123+
124+ //! Get the first value in the stack.
125+ /*!
126+ @param stack A pointer to the relevant tStack.
127+ @return The first value in the stack.
128+ */
129+ int tStack_first (tStack* const stack);
130+
131+
132+ //! Get the current size of the stack.
133+ /*!
134+ @param stack A pointer to the relevant tStack.
135+ @return The current size of the stack.
136+ */
137+ int tStack_getSize (tStack* const stack);
138+
139+ //! Check if the stack contains a value, and if it does, get the index of that value.
140+ /*!
141+ @param stack A pointer to the relevant tStack.
142+ @param item The value to check against the stack.
143+ @return The index of the value or -1 if the stack does not contain the value.
144+ */
145+ int tStack_contains (tStack* const stack, uint16_t item);
146+
147+ //! Get the next value in the stack, starting from the earliest added values.
148+ /*!
149+ @param stack A pointer to the relevant tStack.
150+ @return The next value in the stack or -1 if there are no values in the stack.
151+ */
152+ int tStack_next (tStack* const stack);
153+
154+ //! Get the value at a given index of the stack.
155+ /*!
156+ @param stack A pointer to the relevant tStack.
157+ @param index The index of the stack from which to get a value.
158+ @return The value at the given index.
159+ */
160+ int tStack_get (tStack* const stack, int index);
161+
162+ /*! @} */
163+
164+ /*!
165+ * @defgroup tpoly tPoly
166+ * @ingroup midi
167+ * @brief An object for polyphonic handling.
168+ * @{
169+ */
170+
171+ /* tPoly */
172+ typedef struct _tPoly
173+ {
174+ tStack stack;
175+ tStack orderStack;
176+
177+ tRamp* ramps;
178+ float* rampVals;
179+ oBool* firstReceived;
180+ float glideTime;
181+ oBool pitchGlideIsActive;
182+
183+ int numVoices;
184+ int maxNumVoices;
185+
186+ //int voices[POLY_NUM_MAX_VOICES][2];
187+ int** voices;
188+
189+ int notes[128][2];
190+
191+ int CCs[128];
192+
193+ uint8_t CCsRaw[128];
194+
195+ int lastVoiceToChange;
196+
197+ float pitchBend;
198+ tRamp pitchBendRamp;
199+
200+ int currentNote;
201+ int currentVoice;
202+ int currentVelocity;
203+ int maxLength;
204+
205+ } _tPoly;
206+
207+ typedef _tPoly* tPoly;
208+
209+ /* MPoly*/
210+ //! Initialize a tPoly to the default LEAF mempool.
211+ /*!
212+ @param poly A pointer to the tPoly to be initialized.
213+ @param maxNumVoices The maximum number of voices this tPoly can handle at once.
214+ */
215+ void tPoly_init (tPoly* const poly, int maxNumVoices);
216+
217+
218+ //! Free a tPoly from the default LEAF mempool.
219+ /*!
220+ @param poly A pointer to the tPoly to be freed.
221+ */
222+ void tPoly_free (tPoly* const poly);
223+
224+
225+ //! Initialize a tPoly to a specified mempool.
226+ /*!
227+ @param poly A pointer to the tPoly to be initialized.
228+ @param pool A pointer to the tMempool to which the tPoly should be initialized.
229+ */
230+ void tPoly_initToPool (tPoly* const poly, int maxNumVoices, tMempool* const pool);
231+
232+
233+ //! Free a tPoly from a specified mempool.
234+ /*!
235+ @param poly A pointer to the tPoly to be freed.
236+ @param pool A pointer to the tMempool from which the tPoly should be freed.
237+ */
238+ void tPoly_freeFromPool (tPoly* const poly, tMempool* const pool);
239+
240+ //! Add a note with a given velocity to the poly handler.
241+ /*!
242+ @param poly A pointer to the relevant tPoly.
243+ @param note The MIDI note number to add.
244+ @param vel The MIDI velocity of the note to add.
245+ @return The voice that will play the note.
246+ */
247+ int tPoly_noteOn (tPoly* const poly, int note, uint8_t vel);
248+
249+
250+ //! Remove a note from the poly handler.
251+ /*!
252+ @param poly A pointer to the relevant tPoly.
253+ @param note The MIDI note number to remove.
254+ @return The voice that was playing the removed note.
255+ */
256+ int tPoly_noteOff (tPoly* const poly, uint8_t note);
257+
258+ void tPoly_orderedAddToStack (tPoly* const poly, uint8_t note);
259+
260+
261+ //! Set the number of voices available to play notes.
262+ /*!
263+ @param poly A pointer to the relevant tPoly.
264+ @param numVoices The new number of available voices. Cannot be greater than the max number voices given in tPoly_init().
265+ */
266+ void tPoly_setNumVoices (tPoly* const poly, uint8_t numVoices);
267+
268+ //! Set whether pitch glide over note changes in voices is active.
269+ /*!
270+ @param poly A pointer to the relevant tPoly.
271+ @param isActive Whether pitch glide should be active or not.
272+ */
273+ void tPoly_setPitchGlideActive (tPoly* const poly, oBool isActive);
274+
275+ //! Set how long pitch glide over note changes in voices takes.
276+ /*!
277+ @param poly A pointer to the relevant tPoly.
278+ @param t The time to glide in milliseconds.
279+ */
280+ void tPoly_setPitchGlideTime (tPoly* const poly, float t);
281+
282+ //! Set the amount of pitch bend
283+ /*!
284+ @param poly A pointer to the relevant tPoly.
285+ @param pitchBend The new amount of pitch bend.
286+ */
287+ void tPoly_setPitchBend (tPoly* const poly, float pitchBend);
288+ void tPoly_setBendGlideTime (tPoly* const poly, float t);
289+ void tPoly_setBendSamplesPerTick (tPoly* const poly, float t);
290+
291+
292+ //! Execute all tick-rate changes in the poly handler's pitch, including glide and bend.
293+ /*!
294+ @param poly A pointer to the relevant tPoly.
295+ */
296+ void tPoly_tickPitch (tPoly* const poly);
297+
298+
299+ //! Execute the tick-rate change of the poly handler's pitch glide.
300+ /*!
301+ @param poly A pointer to the relevant tPoly.
302+ */
303+ void tPoly_tickPitchGlide (tPoly* const poly);
304+
305+
306+ //! Execute the tick-rate change of the poly handler's pitch bend.
307+ /*!
308+ @param poly A pointer to the relevant tPoly.
309+ */
310+ void tPoly_tickPitchBend (tPoly* const poly);
311+
312+
313+ //! Get the current number of voices available to play notes.
314+ /*!
315+ @param poly A pointer to the relevant tPoly.
316+ @return The current number of voices available to play notes.
317+ */
318+ int tPoly_getNumVoices (tPoly* const poly);
319+
320+ //! Get the number of voices currently playing notes.
321+ /*!
322+ @param poly A pointer to the relevant tPoly.
323+ @return The number of voices currently playing notes.
324+ */
325+ int tPoly_getNumActiveVoices (tPoly* const poly);
326+
327+ //! Get the current pitch of a given voice.
328+ /*!
329+ @param poly A pointer to the relevant tPoly.
330+ @param voice The voice to get the pitch of.
331+ @return The current pitch of the given voice as a fractional MIDI note number.
332+ */
333+ float tPoly_getPitch (tPoly* const poly, uint8_t voice);
334+
335+
336+ //! Get the current MIDI note number of a given voice.
337+ /*!
338+ @param poly A pointer to the relevant tPoly.
339+ @param voice The voice to get the MIDI note number of.
340+ @return The MIDI note number of the given voice.
341+ */
342+ int tPoly_getKey (tPoly* const poly, uint8_t voice);
343+
344+
345+ //! Get the current MIDI velocity of a given voice.
346+ /*!
347+ @param poly A pointer to the relevant tPoly.
348+ @param voice The voice to get the MIDI velocity of.
349+ @return The current MIDI velocity of the given voice.
350+ */
351+ int tPoly_getVelocity (tPoly* const poly, uint8_t voice);
352+
353+
354+ //! Get the current play state of a given voice.
355+ /*!
356+ @param poly A pointer to the relevant tPoly.
357+ @param voice The voice to get the state of.
358+ @return The current play state of the given voice.
359+ */
360+ int tPoly_isOn (tPoly* const poly, uint8_t voice);
361+
362+ /*! @} */
363+
364+ //==============================================================================
365+
366+
367+ /* tPoly */
368+ typedef struct _tSimplePoly
369+ {
370+ tStack stack;
371+
372+ int numVoices;
373+ int maxNumVoices;
374+ int** voices;
375+ int stealing_on;
376+ int recover_stolen;
377+
378+ int notes[128][2];
379+ } _tSimplePoly;
380+
381+ typedef _tSimplePoly* tSimplePoly;
382+
383+ //! Initialize a tPoly to the default LEAF mempool.
384+ /*!
385+ @param poly A pointer to the tPoly to be initialized.
386+ @param maxNumVoices The maximum number of voices this tPoly can handle at once.
387+ */
388+ void tSimplePoly_init (tSimplePoly* const poly, int maxNumVoices);
389+
390+
391+ //! Free a tPoly from the default LEAF mempool.
392+ /*!
393+ @param poly A pointer to the tPoly to be freed.
394+ */
395+ void tSimplePoly_free (tSimplePoly* const poly);
396+
397+
398+ //! Initialize a tPoly to a specified mempool.
399+ /*!
400+ @param poly A pointer to the tPoly to be initialized.
401+ @param pool A pointer to the tMempool to which the tPoly should be initialized.
402+ */
403+ void tSimplePoly_initToPool (tSimplePoly* const poly, int maxNumVoices, tMempool* const pool);
404+
405+
406+ //! Free a tPoly from a specified mempool.
407+ /*!
408+ @param poly A pointer to the tPoly to be freed.
409+ @param pool A pointer to the tMempool from which the tPoly should be freed.
410+ */
411+ void tSimplePoly_freeFromPool (tSimplePoly* const poly, tMempool* const pool);
412+
413+ //! Add a note with a given velocity to the poly handler.
414+ /*!
415+ @param poly A pointer to the relevant tPoly.
416+ @param note The MIDI note number to add.
417+ @param vel The MIDI velocity of the note to add.
418+ @return The voice that will play the note.
419+ */
420+ int tSimplePoly_noteOn (tSimplePoly* const poly, int note, uint8_t vel);
421+
422+
423+ //! Remove a note from the poly handler.
424+ /*!
425+ @param poly A pointer to the relevant tPoly.
426+ @param note The MIDI note number to remove.
427+ @return The voice that was playing the removed note.
428+ */
429+ int tSimplePoly_noteOff (tSimplePoly* const poly, uint8_t note);
430+
431+
432+
433+ void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice);
434+
435+ int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note);
436+
437+
438+ //find if there is a voice with that note -- useful for note offs where you want to wait to remove it from the poly until the release phase of the envelope is finished
439+ int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note);
440+
441+ //! Set the number of voices available to play notes.
442+ /*!
443+ @param poly A pointer to the relevant tPoly.
444+ @param numVoices The new number of available voices. Cannot be greater than the max number voices given in tPoly_init().
445+ */
446+ void tSimplePoly_setNumVoices (tSimplePoly* const poly, uint8_t numVoices);
447+
448+ //! Set whether pitch glide over note changes in voices is active.
449+ /*!
450+ @param poly A pointer to the relevant tPoly.
451+ @param isActive Whether pitch glide should be active or not.
452+ */
453+
454+ //! Get the current number of voices available to play notes.
455+ /*!
456+ @param poly A pointer to the relevant tPoly.
457+ @return The current number of voices available to play notes.
458+ */
459+ int tSimplePoly_getNumVoices (tSimplePoly* const poly);
460+
461+ //! Get the number of voices currently playing notes.
462+ /*!
463+ @param poly A pointer to the relevant tPoly.
464+ @return The number of voices currently playing notes.
465+ */
466+ int tSimplePoly_getNumActiveVoices (tSimplePoly* const poly);
467+
468+ //! Get the current MIDI note number of a given voice.
469+ /*!
470+ @param poly A pointer to the relevant tPoly.
471+ @param voice The voice to get the MIDI note number of.
472+ @return The MIDI note number of the given voice.
473+ */
474+
475+ int tSimplePoly_getPitch (tSimplePoly* const poly, uint8_t voice);
476+
477+
478+ //this one returns negative one if the voice is inactive
479+ int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice);
480+
481+
482+ //! Get the current MIDI velocity of a given voice.
483+ /*!
484+ @param poly A pointer to the relevant tPoly.
485+ @param voice The voice to get the MIDI velocity of.
486+ @return The current MIDI velocity of the given voice.
487+ */
488+ int tSimplePoly_getVelocity (tSimplePoly* const poly, uint8_t voice);
489+
490+
491+ //! Get the current play state of a given voice.
492+ /*!
493+ @param poly A pointer to the relevant tPoly.
494+ @param voice The voice to get the state of.
495+ @return The current play state of the given voice.
496+ */
497+ int tSimplePoly_isOn (tSimplePoly* const poly, uint8_t voice);
498+
499+ /*! @} */
500+ //==============================================================================
501+
502+#ifdef __cplusplus
503+}
504+#endif
505+
506+#endif // LEAF_MIDI_H_INCLUDED
507+
508+//==============================================================================
509+
510+
leaf/Inc/leaf-oscillators.h+1143−0
@@ -0,0 +1,1143 @@
1+/*==============================================================================
2+ leaf-oscillators.h
3+ Created: 20 Jan 2017 12:00:58pm
4+ Author: Michael R Mulshine
5+ ==============================================================================*/
6+
7+#ifndef LEAF_OSCILLATORS_H_INCLUDED
8+#define LEAF_OSCILLATORS_H_INCLUDED
9+
10+#ifdef __cplusplus
11+extern "C" {
12+#endif
13+
14+ //==============================================================================
15+
16+#include "leaf-math.h"
17+#include "leaf-mempool.h"
18+#include "leaf-tables.h"
19+#include "leaf-filters.h"
20+
21+ /*!
22+ * Header.
23+ * @include basic-oscillators.h
24+ * @example basic-oscillators.c
25+ * An example.
26+ */
27+
28+ //==============================================================================
29+
30+ typedef struct _tCycle
31+ {
32+ // Underlying phasor
33+ float phase;
34+ float inc,freq;
35+ } _tCycle;
36+
37+ typedef _tCycle* tCycle;
38+
39+ /*!
40+ * @defgroup tcycle tCycle
41+ * @ingroup oscillators
42+ * @brief A cycle/sine waveform oscillator. Uses wavetable synthesis.
43+ * @{
44+ */
45+
46+ //! Initialize a tCycle to the default LEAF mempool.
47+ /*!
48+ @param osc A pointer to the tCycle to be initialized.
49+ */
50+ void tCycle_init (tCycle* const osc);
51+
52+
53+ //! Free a tCycle from the default LEAF mempool.
54+ /*!
55+ @param osc A pointer to the tCycle to be freed.
56+ */
57+ void tCycle_free (tCycle* const osc);
58+
59+
60+ //! Initialize a tCycle to a specified mempool.
61+ /*!
62+ @param osc A pointer to the tCycle to be initialized.
63+ @param pool A pointer to the tMempool to which the tCycle should be initialized.
64+ */
65+ void tCycle_initToPool (tCycle* const osc, tMempool* const pool);
66+
67+
68+ //! Free a tCycle from a specified mempool.
69+ /*!
70+ @param osc A pointer to the tCycle to be freed.
71+ @param pool A pointer to the tMempool from which the tCycle should be freed.
72+ */
73+ void tCycle_freeFromPool (tCycle* const osc, tMempool* const pool);
74+
75+
76+ //! Tick a tCycle oscillator.
77+ /*!
78+ @param osc A pointer to the relevant tCycle.
79+ @return The ticked sample as a float from -1 to 1.
80+ */
81+ float tCycle_tick (tCycle* const osc);
82+
83+
84+ //! Set the frequency of a tCycle oscillator.
85+ /*!
86+ @param osc A pointer to the relevant tCycle.
87+ @param freq The frequency to set the oscillator to.
88+ */
89+ void tCycle_setFreq (tCycle* const osc, float freq);
90+
91+ /*! @} */
92+
93+ //==============================================================================
94+
95+ /* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */
96+ typedef struct _tTriangle
97+ {
98+ // Underlying phasor
99+ float phase;
100+ float inc,freq;
101+ int oct;
102+ float w;
103+ } _tTriangle;
104+
105+ typedef _tTriangle* tTriangle;
106+
107+ /*!
108+ * @defgroup ttriangle tTriangle
109+ * @ingroup oscillators
110+ * @brief An anti-aliased triangle waveform oscillator. Uses wavetable synthesis.
111+ * @{
112+ */
113+
114+ //! Initialize a tTriangle to the default LEAF mempool.
115+ /*!
116+ @param osc A pointer to the tTriangle to be initialized.
117+ */
118+ void tTriangle_init (tTriangle* const osc);
119+
120+
121+ //! Free a tTriangle from the default LEAF mempool.
122+ /*!
123+ @param osc A pointer to the tTriangle to be freed.
124+ */
125+ void tTriangle_free (tTriangle* const osc);
126+
127+
128+ //! Initialize a tTriangle to a specified mempool.
129+ /*!
130+ @param osc A pointer to the tTriangle to be initialized.
131+ @param pool A pointer to the tMempool to which the tTriangle should be initialized.
132+ */
133+ void tTriangle_initToPool (tTriangle* const osc, tMempool* const pool);
134+
135+
136+ //! Free a tTriangle from a specified mempool.
137+ /*!
138+ @param osc A pointer to the tTriangle to be freed.
139+ @param pool A pointer to the tMempool from which the tTriangle should be freed.
140+ */
141+ void tTriangle_freeFromPool (tTriangle* const osc, tMempool* const pool);
142+
143+
144+ //! Tick a tTriangle oscillator.
145+ /*!
146+ @param osc A pointer to the relevant tTriangle.
147+ @return The ticked sample as a float from -1 to 1.
148+ */
149+ float tTriangle_tick (tTriangle* const osc);
150+
151+
152+ //! Set the frequency of a tTriangle oscillator.
153+ /*!
154+ @param osc A pointer to the relevant tTriangle.
155+ @param freq The frequency to set the oscillator to.
156+ */
157+ void tTriangle_setFreq (tTriangle* const osc, float freq);
158+
159+ /*! @} */
160+
161+ //==============================================================================
162+
163+ /* tSquare: Anti-aliased Square waveform using wavetable interpolation. Wavetables constructed from sine components. */
164+ typedef struct _tSquare
165+ {
166+ // Underlying phasor
167+ float phase;
168+ float inc,freq;
169+ int oct;
170+ float w;
171+ } _tSquare;
172+
173+ typedef _tSquare* tSquare;
174+
175+ /*!
176+ * @defgroup tsquare tSquare
177+ * @ingroup oscillators
178+ * @brief An anti-aliased square waveform oscillator. Uses wavetable synthesis.
179+ * @{
180+ */
181+
182+ //! Initialize a tSquare to the default LEAF mempool.
183+ /*!
184+ @param osc A pointer to the tSquare to be initialized.
185+ */
186+ void tSquare_init (tSquare* const osc);
187+
188+
189+ //! Free a tSquare from the default LEAF mempool.
190+ /*!
191+ @param osc A pointer to the tSquare to be freed.
192+ */
193+ void tSquare_free (tSquare* const osc);
194+
195+
196+ //! Initialize a tSquare to a specified mempool.
197+ /*!
198+ @param osc A pointer to the tSquare to be initialized.
199+ @param pool A pointer to the tMempool to which the tSquare should be initialized.
200+ */
201+ void tSquare_initToPool (tSquare* const osc, tMempool* const);
202+
203+
204+ //! Free a tSquare from a specified mempool.
205+ /*!
206+ @param osc A pointer to the tSquare to be freed.
207+ @param pool A pointer to the tMempool from which the tSquare should be freed.
208+ */
209+ void tSquare_freeFromPool(tSquare* const osc, tMempool* const);
210+
211+
212+ //! Tick a tSquare oscillator.
213+ /*!
214+ @param osc A pointer to the relevant tSquare.
215+ @return The ticked sample as a float from -1 to 1.
216+ */
217+ float tSquare_tick (tSquare* const osc);
218+
219+
220+ //! Set the frequency of a tSquare oscillator.
221+ /*!
222+ @param osc A pointer to the relevant tSquare.
223+ @param freq The frequency to set the oscillator to.
224+ */
225+ void tSquare_setFreq (tSquare* const osc, float freq);
226+
227+ /*! @} */
228+
229+ //==============================================================================
230+
231+ /* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */
232+ typedef struct _tSawtooth
233+ {
234+ // Underlying phasor
235+ float phase;
236+ float inc,freq;
237+ int oct;
238+ float w;
239+ } _tSawtooth;
240+
241+ typedef _tSawtooth* tSawtooth;
242+
243+ /*!
244+ * @defgroup tsawtooth tSawtooth
245+ * @ingroup oscillators
246+ * @brief An anti-aliased sawtooth waveform oscillator. Uses wavetable synthesis.
247+ * @{
248+ */
249+
250+ //! Initialize a tSawtooth to the default LEAF mempool.
251+ /*!
252+ @param osc A pointer to the tSawtooth to be initialized.
253+ */
254+ void tSawtooth_init (tSawtooth* const osc);
255+
256+
257+ //! Free a tSawtooth from the default LEAF mempool.
258+ /*!
259+ @param osc A pointer to the tSawtooth to be freed.
260+ */
261+ void tSawtooth_free (tSawtooth* const osc);
262+
263+
264+ //! Initialize a tSawtooth to a specified mempool.
265+ /*!
266+ @param osc A pointer to the tSawtooth to be initialized.
267+ @param pool A pointer to the tMempool to which the tSawtooth should be initialized.
268+ */
269+ void tSawtooth_initToPool (tSawtooth* const osc, tMempool* const pool);
270+
271+
272+ //! Free a tSawtooth from a specified mempool.
273+ /*!
274+ @param osc A pointer to the tSawtooth to be freed.
275+ @param pool A pointer to the tMempool from which the tSawtooth should be freed.
276+ */
277+ void tSawtooth_freeFromPool (tSawtooth* const osc, tMempool* const pool);
278+
279+
280+ //! Tick a tSawtooth oscillator.
281+ /*!
282+ @param osc A pointer to the relevant tSawtooth.
283+ @return The ticked sample as a float from -1 to 1.
284+ */
285+ float tSawtooth_tick (tSawtooth* const osc);
286+
287+
288+ //! Set the frequency of a tSawtooth oscillator.
289+ /*!
290+ @param osc A pointer to the relevant tSawtooth.
291+ @param freq The frequency to set the oscillator to.
292+ */
293+ void tSawtooth_setFreq (tSawtooth* const osc, float freq);
294+
295+ /*! @} */
296+
297+ //==============================================================================
298+
299+ typedef struct _tSine
300+ {
301+ float* sine;
302+ int size;
303+ float phase;
304+ float inc,freq;
305+ } _tSine;
306+
307+ typedef _tSine* tSine;
308+
309+ /*!
310+ * @defgroup tsine tSine
311+ * @ingroup oscillators
312+ * @brief A cycle/sine waveform oscillator.
313+ * @{
314+ */
315+
316+ //! Initialize a tSine to the default LEAF mempool.
317+ /*!
318+ @param osc A pointer to the tSine to be initialized.
319+ */
320+ void tSine_init (tSine* const osc, int size);
321+
322+
323+ //! Free a tSine from the default LEAF mempool.
324+ /*!
325+ @param osc A pointer to the tSine to be freed.
326+ */
327+ void tSine_free (tSine* const osc);
328+
329+
330+ //! Initialize a tSine to a specified mempool.
331+ /*!
332+ @param osc A pointer to the tSine to be initialized.
333+ @param pool A pointer to the tMempool to which the tSine should be initialized.
334+ */
335+ void tSine_initToPool (tSine* const osc, int size, tMempool* const pool);
336+
337+
338+ //! Free a tSine from a specified mempool.
339+ /*!
340+ @param osc A pointer to the tSine to be freed.
341+ @param pool A pointer to the tMempool from which the tSine should be freed.
342+ */
343+ void tSine_freeFromPool (tSine* const osc, tMempool* const pool);
344+
345+
346+ //! Tick a tSine oscillator.
347+ /*!
348+ @param osc A pointer to the relevant tSine.
349+ @return The ticked sample as a float from -1 to 1.
350+ */
351+ float tSine_tick (tSine* const osc);
352+
353+
354+ //! Set the frequency of a tSine oscillator.
355+ /*!
356+ @param osc A pointer to the relevant tSine.
357+ @param freq The frequency to set the oscillator to.
358+ */
359+ void tSine_setFreq (tSine* const osc, float freq);
360+
361+ /*! @} */
362+
363+ //==============================================================================
364+
365+ /* tTri: Anti-aliased Triangle waveform using wavetable interpolation. */
366+ typedef struct _tTri
367+ {
368+ float phase;
369+ float inc,freq;
370+ float skew;
371+ float lastOut;
372+ } _tTri;
373+
374+ typedef _tTri* tTri;
375+
376+ /*!
377+ * @defgroup tTri tTri
378+ * @ingroup oscillators
379+ * @brief An anti-aliased triangle waveform oscillator.
380+ * @{
381+ */
382+
383+ //! Initialize a tTri to the default LEAF mempool.
384+ /*!
385+ @param osc A pointer to the tTri to be initialized.
386+ */
387+ void tTri_init (tTri* const osc);
388+
389+
390+ //! Free a tTri from the default LEAF mempool.
391+ /*!
392+ @param osc A pointer to the tTri to be freed.
393+ */
394+ void tTri_free (tTri* const osc);
395+
396+
397+ //! Initialize a tTri to a specified mempool.
398+ /*!
399+ @param osc A pointer to the tTri to be initialized.
400+ @param pool A pointer to the tMempool to which the tTri should be initialized.
401+ */
402+ void tTri_initToPool (tTri* const osc, tMempool* const pool);
403+
404+
405+ //! Free a tTri from a specified mempool.
406+ /*!
407+ @param osc A pointer to the tTri to be freed.
408+ @param pool A pointer to the tMempool from which the tTri should be freed.
409+ */
410+ void tTri_freeFromPool (tTri* const osc, tMempool* const pool);
411+
412+
413+ //! Tick a tTri oscillator.
414+ /*!
415+ @param osc A pointer to the relevant tTri.
416+ @return The ticked sample as a float from -1 to 1.
417+ */
418+ float tTri_tick (tTri* const osc);
419+
420+
421+ //! Set the frequency of a tTri oscillator.
422+ /*!
423+ @param osc A pointer to the relevant tTriangle.
424+ @param freq The frequency to set the oscillator to.
425+ */
426+ void tTri_setFreq (tTri* const osc, float freq);
427+
428+ void tTri_setSkew (tTri* const osc, float skew);
429+
430+ /*! @} */
431+
432+ //==============================================================================
433+
434+ /* tPulse: Anti-aliased Square waveform. */
435+ typedef struct _tPulse
436+ {
437+ float phase;
438+ float inc,freq;
439+ float width;
440+ } _tPulse;
441+
442+ typedef _tPulse* tPulse;
443+
444+ /*!
445+ * @defgroup tPulse tPulse
446+ * @ingroup oscillators
447+ * @brief An anti-aliased pulse waveform oscillator with changeable pulse width.
448+ * @{
449+ */
450+
451+ //! Initialize a tPulse to the default LEAF mempool.
452+ /*!
453+ @param osc A pointer to the tPulse to be initialized.
454+ */
455+ void tPulse_init (tPulse* const osc);
456+
457+
458+ //! Free a tPulse from the default LEAF mempool.
459+ /*!
460+ @param osc A pointer to the tPulse to be freed.
461+ */
462+ void tPulse_free (tPulse* const osc);
463+
464+
465+ //! Initialize a tPulse to a specified mempool.
466+ /*!
467+ @param osc A pointer to the tPulse to be initialized.
468+ @param pool A pointer to the tMempool to which the tPulse should be initialized.
469+ */
470+ void tPulse_initToPool (tPulse* const osc, tMempool* const);
471+
472+
473+ //! Free a tPulse from a specified mempool.
474+ /*!
475+ @param osc A pointer to the tPulse to be freed.
476+ @param pool A pointer to the tMempool from which the tPulse should be freed.
477+ */
478+ void tPulse_freeFromPool(tPulse* const osc, tMempool* const);
479+
480+
481+ //! Tick a tPulse oscillator.
482+ /*!
483+ @param osc A pointer to the relevant tPulse.
484+ @return The ticked sample as a float from -1 to 1.
485+ */
486+ float tPulse_tick (tPulse* const osc);
487+
488+
489+ //! Set the frequency of a tPulse oscillator.
490+ /*!
491+ @param osc A pointer to the relevant tPulse.
492+ @param freq The frequency to set the oscillator to.
493+ */
494+ void tPulse_setFreq (tPulse* const osc, float freq);
495+
496+ void tPulse_setWidth (tPulse* const osc, float width);
497+
498+ /*! @} */
499+
500+ //==============================================================================
501+
502+ /* tSawtooth: Anti-aliased Sawtooth waveform. */
503+ typedef struct _tSaw
504+ {
505+ float phase;
506+ float inc,freq;
507+ } _tSaw;
508+
509+ typedef _tSaw* tSaw;
510+
511+ /*!
512+ * @defgroup tsaw tSaw
513+ * @ingroup oscillators
514+ * @brief An anti-aliased sawtooth waveform oscillator. Uses wavetable synthesis.
515+ * @{
516+ */
517+
518+ //! Initialize a tSaw to the default LEAF mempool.
519+ /*!
520+ @param osc A pointer to the tSaw to be initialized.
521+ */
522+ void tSaw_init (tSaw* const osc);
523+
524+
525+ //! Free a tSaw from the default LEAF mempool.
526+ /*!
527+ @param osc A pointer to the tSaw to be freed.
528+ */
529+ void tSaw_free (tSaw* const osc);
530+
531+
532+ //! Initialize a tSaw to a specified mempool.
533+ /*!
534+ @param osc A pointer to the tSaw to be initialized.
535+ @param pool A pointer to the tMempool to which the tSaw should be initialized.
536+ */
537+ void tSaw_initToPool (tSaw* const osc, tMempool* const pool);
538+
539+
540+ //! Free a tSaw from a specified mempool.
541+ /*!
542+ @param osc A pointer to the tSaw to be freed.
543+ @param pool A pointer to the tMempool from which the tSaw should be freed.
544+ */
545+ void tSaw_freeFromPool (tSaw* const osc, tMempool* const pool);
546+
547+
548+ //! Tick a tSaw oscillator.
549+ /*!
550+ @param osc A pointer to the relevant tSaw.
551+ @return The ticked sample as a float from -1 to 1.
552+ */
553+ float tSaw_tick (tSaw* const osc);
554+
555+
556+ //! Set the frequency of a tSaw oscillator.
557+ /*!
558+ @param osc A pointer to the relevant tSaw.
559+ @param freq The frequency to set the oscillator to.
560+ */
561+ void tSaw_setFreq (tSaw* const osc, float freq);
562+
563+ /*! @} */
564+
565+ //==============================================================================
566+
567+ /* tPhasor: Aliasing phasor [0.0, 1.0) */
568+ typedef struct _tPhasor
569+ {
570+ float phase;
571+ float inc,freq;
572+ uint8_t phaseDidReset;
573+
574+ } _tPhasor;
575+
576+ typedef _tPhasor* tPhasor;
577+
578+ /*!
579+ * @defgroup tphasor Phasor
580+ * @ingroup oscillators
581+ * @brief An aliasing phasor.
582+ * @{
583+ */
584+
585+ //! Initialize a tPhasor to the default LEAF mempool.
586+ /*!
587+ @param osc A pointer to the tPhasor to be initialized.
588+ */
589+ void tPhasor_init (tPhasor* const osc);
590+
591+
592+ //! Free a tPhasor from the default LEAF mempool.
593+ /*!
594+ @param osc A pointer to the tPhasor to be freed.
595+ */
596+ void tPhasor_free (tPhasor* const osc);
597+
598+
599+ //! Initialize a tPhasor to a specified mempool.
600+ /*!
601+ @param osc A pointer to the tPhasor to be initialized.
602+ @param pool A pointer to the tMempool to which the tPhasor should be initialized.
603+ */
604+ void tPhasor_initToPool (tPhasor* const osc, tMempool* const);
605+
606+
607+ //! Free a tPhasor from a specified mempool.
608+ /*!
609+ @param osc A pointer to the tPhasor to be freed.
610+ @param pool A pointer to the tMempool from which the tPhasor should be freed.
611+ */
612+ void tPhasor_freeFromPool(tPhasor* const osc, tMempool* const);
613+
614+
615+ //! Tick a tPhasor oscillator.
616+ /*!
617+ @param osc A pointer to the relevant tPhasor.
618+ @return The ticked sample as a float from 0 to 1.
619+ */
620+ float tPhasor_tick (tPhasor* const osc);
621+
622+
623+ //! Set the frequency of a tPhasor oscillator.
624+ /*!
625+ @param osc A pointer to the relevant tPhasor.
626+ @param freq The frequency to set the oscillator to.
627+ */
628+ void tPhasor_setFreq (tPhasor* const osc, float freq);
629+
630+ /*! @} */
631+
632+ //==============================================================================
633+
634+ /*!
635+ * @defgroup tnoise tNoise
636+ * @ingroup oscillators
637+ * @brief A noise generator.
638+ * @{
639+ */
640+
641+ /* tNoise. WhiteNoise, PinkNoise. */
642+ /*!
643+ * Noise types
644+ */
645+ enum NoiseType
646+ {
647+ WhiteNoise, //!< White noise. Full spectrum.
648+ PinkNoise, //!< Pink noise. Inverse frequency-proportional spectrum.
649+ NoiseTypeNil,
650+ };
651+
652+ typedef enum NoiseType NoiseType;
653+
654+ typedef struct _tNoise
655+ {
656+ NoiseType type;
657+ float pinkb0, pinkb1, pinkb2;
658+ float(*rand)(void);
659+
660+ } _tNoise;
661+
662+ typedef _tNoise* tNoise;
663+
664+ //! Initialize a tNoise to the default LEAF mempool.
665+ /*!
666+ @param osc A pointer to the tNoise to be initialized.
667+ */
668+ void tNoise_init (tNoise* const noise, NoiseType type);
669+
670+
671+ //! Free a tNoise from the default LEAF mempool.
672+ /*!
673+ @param osc A pointer to the tNoise to be freed.
674+ */
675+ void tNoise_free (tNoise* const noise);
676+
677+
678+ //! Initialize a tNoise to a specified mempool.
679+ /*!
680+ @param osc A pointer to the tNoise to be initialized.
681+ @param pool A pointer to the tMempool to which the tNoise should be initialized.
682+ */
683+ void tNoise_initToPool (tNoise* const noise, NoiseType type, tMempool* const);
684+
685+
686+ //! Free a tNoise from a specified mempool.
687+ /*!
688+ @param osc A pointer to the tNoise to be freed.
689+ @param pool A pointer to the tMempool from which the tNoise should be freed.
690+ */
691+ void tNoise_freeFromPool (tNoise* const noise, tMempool* const);
692+
693+
694+ //! Tick a tNoise oscillator.
695+ /*!
696+ @param osc A pointer to the relevant tNoise.
697+ @return The ticked sample as a float from -1 to 1.
698+ */
699+ float tNoise_tick (tNoise* const noise);
700+
701+ /*! @} */
702+
703+ //==============================================================================
704+
705+ /*!
706+ * @defgroup tneuron tNeuron
707+ * @ingroup oscillators
708+ * @brief A model of a neuron, adapted to act as an oscillator.
709+ * @{
710+ */
711+
712+ /*!
713+ * Neuron modes
714+ */
715+ enum NeuronMode
716+ {
717+ NeuronNormal, //!< Normal operation
718+ NeuronTanh, //!< Tanh voltage shaping
719+ NeuronAaltoShaper, //!< Aalto voltage shaping
720+ NeuronModeNil
721+ };
722+ typedef enum NeuronMode NeuronMode;
723+
724+ typedef struct _tNeuron
725+ {
726+ tPoleZero f;
727+
728+ NeuronMode mode;
729+
730+ float voltage, current;
731+ float timeStep;
732+
733+ float alpha[3];
734+ float beta[3];
735+ float rate[3];
736+ float V[3];
737+ float P[3];
738+ float gK, gN, gL, C;
739+ } _tNeuron;
740+
741+ typedef _tNeuron* tNeuron;
742+
743+ //! Initialize a tNeuron to the default LEAF mempool.
744+ /*!
745+ @param neuron A pointer to the tNeuron to be initialized.
746+ */
747+ void tNeuron_init (tNeuron* const neuron);
748+
749+
750+ //! Free a tNeuron from the default LEAF mempool.
751+ /*!
752+ @param neuron A pointer to the tNeuron to be freed.
753+ */
754+ void tNeuron_free (tNeuron* const neuron);
755+
756+
757+ //! Initialize a tNeuron to a specified mempool.
758+ /*!
759+ @param neuron A pointer to the tNeuron to be initialized.
760+ @param pool A pointer to the tMempool to which the tNeuron should be initialized.
761+ */
762+ void tNeuron_initToPool (tNeuron* const neuron, tMempool* const pool);
763+
764+
765+ //! Free a tNeuron from a specified mempool.
766+ /*!
767+ @param neuron A pointer to the tNeuron to be freed.
768+ @param pool A pointer to the tMempool from which the tNeuron should be freed.
769+ */
770+ void tNeuron_freeFromPool(tNeuron* const neuron, tMempool* const pool);
771+
772+
773+ //! Reset the neuron model.
774+ /*!
775+ @param neuron A pointer to the relevant tNeuron.
776+ */
777+ void tNeuron_reset (tNeuron* const neuron);
778+
779+
780+ //! Tick a tNeuron oscillator.
781+ /*!
782+ @param neuron A pointer to the relevant tNeuron.
783+ @return The ticked sample as a float from -1 to 1.
784+ */
785+ float tNeuron_tick (tNeuron* const neuron);
786+
787+
788+ //! Set the tNeuron shaping mode.
789+ /*!
790+ @param neuron A pointer to the relevant tNeuron.
791+ @param mode The mode to set the tNeuron to.
792+ */
793+ void tNeuron_setMode (tNeuron* const neuron, NeuronMode mode);
794+
795+
796+ //! Set the current.
797+ /*!
798+ @param neuron A pointer to the relevant tNeuron.
799+ @param current The new current.
800+ */
801+ void tNeuron_setCurrent (tNeuron* const neuron, float current);
802+
803+
804+ //! Set the potassium value.
805+ /*!
806+ @param neuron A pointer to the relevant tNeuron.
807+ @param K The new potassium.
808+ */
809+ void tNeuron_setK (tNeuron* const neuron, float K);
810+
811+
812+ //! Set the chloride value.
813+ /*!
814+ @param neuron A pointer to the relevant tNeuron.
815+ @param L The new chloride value.
816+ */
817+ void tNeuron_setL (tNeuron* const neuron, float L);
818+
819+
820+ //! Set the sodium value.
821+ /*!
822+ @param neuron A pointer to the relevant tNeuron.
823+ @param N The new sodium value.
824+ */
825+ void tNeuron_setN (tNeuron* const neuron, float N);
826+
827+
828+ //! Set the calcium value.
829+ /*!
830+ @param neuron A pointer to the relevant tNeuron.
831+ @param C The new calcium.
832+ */
833+ void tNeuron_setC (tNeuron* const neuron, float C);
834+
835+
836+ //! Set the V1 value.
837+ /*!
838+ @param neuron A pointer to the relevant tNeuron.
839+ @param V1 The new V1.
840+ */
841+ void tNeuron_setV1 (tNeuron* const neuron, float V1);
842+
843+
844+ //! Set the V2 value.
845+ /*!
846+ @param neuron A pointer to the relevant tNeuron.
847+ @param V2 The new V2.
848+ */
849+ void tNeuron_setV2 (tNeuron* const neuron, float V2);
850+
851+
852+ //! Set the V3 value.
853+ /*!
854+ @param neuron A pointer to the relevant tNeuron.
855+ @param V3 The new V3.
856+ */
857+ void tNeuron_setV3 (tNeuron* const neuron, float V3);
858+
859+
860+ //! Set the time step.
861+ /*!
862+ @param neuron A pointer to the relevant tNeuron.
863+ @param timestep The new time step
864+ */
865+ void tNeuron_setTimeStep (tNeuron* const neuron, float timestep);
866+
867+ /*! @} */
868+
869+ //==============================================================================
870+
871+ typedef struct _tMinBLEP
872+ {
873+ float coeffs[6];
874+
875+ // FilterState
876+ float* x1, x2, y1, y2;
877+
878+ float ratio, lastRatio;
879+
880+ float overSamplingRatio;
881+ int zeroCrossings;
882+
883+ float lastValue;
884+ float lastDelta; // previous derivative ...
885+
886+ // Tweaking the Blep F
887+ float proportionalBlepFreq;
888+ uint8_t returnDerivative; // set this to return the FIRST DERIVATIVE of the blep (for first der. discontinuities)
889+
890+ int blepIndex;
891+ int numActiveBleps;
892+ //currentActiveBlepOffsets;
893+ float* offset;
894+ float* freqMultiple;
895+ float* pos_change_magnitude;
896+ float* vel_change_magnitude;
897+
898+ int minBlepSize;
899+ float* minBlepArray;
900+ float* minBlepDerivArray;
901+ } _tMinBLEP;
902+
903+ typedef _tMinBLEP* tMinBLEP;
904+
905+ void tMinBLEP_init (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio);
906+ void tMinBLEP_free (tMinBLEP* const minblep);
907+ void tMinBLEP_initToPool (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio, tMempool* const pool);
908+ void tMinBLEP_freeFromPool (tMinBLEP* const minblep, tMempool* const pool);
909+
910+ // pass in audio, identify discontinuities and return the audio with minbleps inserted
911+ float tMinBLEP_tick (tMinBLEP* const minblep, float input);
912+ void tMinBLEP_buildBLEP (tMinBLEP* const minblep);
913+ void tMinBLEP_addBLEP (tMinBLEP* const minblep, float offset, float posChange, float velChange);
914+
915+ void tMinBLEP_setOversamplingRatio (tMinBLEP* const minblep, float ratio);
916+ void tMinBLEP_setNumZeroCrossings (tMinBLEP* const minblep, int numCrossings);
917+
918+ //==============================================================================
919+
920+ /* tMBTriangle: Anti-aliased Triangle waveform using wavetable interpolation. */
921+ typedef struct _tMBTriangle
922+ {
923+ float phase;
924+ float inc,freq;
925+ float skew;
926+ float lastOut;
927+
928+ tMinBLEP minBlep;
929+ tHighpass dcBlock;
930+ } _tMBTriangle;
931+
932+ typedef _tMBTriangle* tMBTriangle;
933+
934+ /*!
935+ * @defgroup tMBTriangle tMBTriangle
936+ * @ingroup oscillators
937+ * @brief An anti-aliased triangle waveform oscillator.
938+ * @{
939+ */
940+
941+ //! Initialize a tMBTriangle to the default LEAF mempool.
942+ /*!
943+ @param osc A pointer to the tMBTriangle to be initialized.
944+ */
945+ void tMBTriangle_init (tMBTriangle* const osc);
946+
947+
948+ //! Free a tMBTriangle from the default LEAF mempool.
949+ /*!
950+ @param osc A pointer to the tMBTriangle to be freed.
951+ */
952+ void tMBTriangle_free (tMBTriangle* const osc);
953+
954+
955+ //! Initialize a tMBTriangle to a specified mempool.
956+ /*!
957+ @param osc A pointer to the tMBTriangle to be initialized.
958+ @param pool A pointer to the tMempool to which the tMBTriangle should be initialized.
959+ */
960+ void tMBTriangle_initToPool (tMBTriangle* const osc, tMempool* const pool);
961+
962+
963+ //! Free a tMBTriangle from a specified mempool.
964+ /*!
965+ @param osc A pointer to the tMBTriangle to be freed.
966+ @param pool A pointer to the tMempool from which the tMBTriangle should be freed.
967+ */
968+ void tMBTriangle_freeFromPool (tMBTriangle* const osc, tMempool* const pool);
969+
970+
971+ //! Tick a tMBTriangle oscillator.
972+ /*!
973+ @param osc A pointer to the relevant tMBTriangle.
974+ @return The ticked sample as a float from -1 to 1.
975+ */
976+ float tMBTriangle_tick (tMBTriangle* const osc);
977+
978+
979+ //! Set the frequency of a tMBTriangle oscillator.
980+ /*!
981+ @param osc A pointer to the relevant tMBTriangleangle.
982+ @param freq The frequency to set the oscillator to.
983+ */
984+ void tMBTriangle_setFreq (tMBTriangle* const osc, float freq);
985+
986+ void tMBTriangle_setSkew (tMBTriangle* const osc, float skew);
987+
988+ void tMBTriangle_sync (tMBTriangle* const osc, float phase);
989+
990+ /*! @} */
991+
992+ //==============================================================================
993+
994+ /* tMBPulse: Anti-aliased Square waveform. */
995+ typedef struct _tMBPulse
996+ {
997+ float phase;
998+ float inc,freq;
999+ float width;
1000+
1001+ tMinBLEP minBlep;
1002+ tHighpass dcBlock;
1003+ } _tMBPulse;
1004+
1005+ typedef _tMBPulse* tMBPulse;
1006+
1007+ /*!
1008+ * @defgroup tMBPulse tMBPulse
1009+ * @ingroup oscillators
1010+ * @brief An anti-aliased pulse waveform oscillator with changeable pulse width.
1011+ * @{
1012+ */
1013+
1014+ //! Initialize a tMBPulse to the default LEAF mempool.
1015+ /*!
1016+ @param osc A pointer to the tMBPulse to be initialized.
1017+ */
1018+ void tMBPulse_init (tMBPulse* const osc);
1019+
1020+
1021+ //! Free a tMBPulse from the default LEAF mempool.
1022+ /*!
1023+ @param osc A pointer to the tMBPulse to be freed.
1024+ */
1025+ void tMBPulse_free (tMBPulse* const osc);
1026+
1027+
1028+ //! Initialize a tMBPulse to a specified mempool.
1029+ /*!
1030+ @param osc A pointer to the tMBPulse to be initialized.
1031+ @param pool A pointer to the tMempool to which the tMBPulse should be initialized.
1032+ */
1033+ void tMBPulse_initToPool (tMBPulse* const osc, tMempool* const);
1034+
1035+
1036+ //! Free a tMBPulse from a specified mempool.
1037+ /*!
1038+ @param osc A pointer to the tMBPulse to be freed.
1039+ @param pool A pointer to the tMempool from which the tMBPulse should be freed.
1040+ */
1041+ void tMBPulse_freeFromPool(tMBPulse* const osc, tMempool* const);
1042+
1043+
1044+ //! Tick a tMBPulse oscillator.
1045+ /*!
1046+ @param osc A pointer to the relevant tMBPulse.
1047+ @return The ticked sample as a float from -1 to 1.
1048+ */
1049+ float tMBPulse_tick (tMBPulse* const osc);
1050+
1051+
1052+ //! Set the frequency of a tMBPulse oscillator.
1053+ /*!
1054+ @param osc A pointer to the relevant tMBPulse.
1055+ @param freq The frequency to set the oscillator to.
1056+ */
1057+ void tMBPulse_setFreq (tMBPulse* const osc, float freq);
1058+
1059+ void tMBPulse_setWidth (tMBPulse* const osc, float width);
1060+
1061+ void tMBPulse_sync (tMBPulse* const osc, float phase);
1062+
1063+
1064+ /*! @} */
1065+
1066+ //==============================================================================
1067+
1068+ /* tMBSawtooth: Anti-aliased Sawtooth waveform. */
1069+ typedef struct _tMBSaw
1070+ {
1071+ float phase;
1072+ float inc,freq;
1073+
1074+ tMinBLEP minBlep;
1075+ tHighpass dcBlock;
1076+ } _tMBSaw;
1077+
1078+ typedef _tMBSaw* tMBSaw;
1079+
1080+ /*!
1081+ * @defgroup tMBSaw tMBSaw
1082+ * @ingroup oscillators
1083+ * @brief An anti-aliased sawtooth waveform oscillator. Uses wavetable synthesis.
1084+ * @{
1085+ */
1086+
1087+ //! Initialize a tMBSaw to the default LEAF mempool.
1088+ /*!
1089+ @param osc A pointer to the tMBSaw to be initialized.
1090+ */
1091+ void tMBSaw_init (tMBSaw* const osc);
1092+
1093+
1094+ //! Free a tMBSaw from the default LEAF mempool.
1095+ /*!
1096+ @param osc A pointer to the tMBSaw to be freed.
1097+ */
1098+ void tMBSaw_free (tMBSaw* const osc);
1099+
1100+
1101+ //! Initialize a tMBSaw to a specified mempool.
1102+ /*!
1103+ @param osc A pointer to the tMBSaw to be initialized.
1104+ @param pool A pointer to the tMempool to which the tMBSaw should be initialized.
1105+ */
1106+ void tMBSaw_initToPool (tMBSaw* const osc, tMempool* const pool);
1107+
1108+
1109+ //! Free a tMBSaw from a specified mempool.
1110+ /*!
1111+ @param osc A pointer to the tMBSaw to be freed.
1112+ @param pool A pointer to the tMempool from which the tMBSaw should be freed.
1113+ */
1114+ void tMBSaw_freeFromPool (tMBSaw* const osc, tMempool* const pool);
1115+
1116+
1117+ //! Tick a tMBSaw oscillator.
1118+ /*!
1119+ @param osc A pointer to the relevant tMBSaw.
1120+ @return The ticked sample as a float from -1 to 1.
1121+ */
1122+ float tMBSaw_tick (tMBSaw* const osc);
1123+
1124+
1125+ //! Set the frequency of a tMBSaw oscillator.
1126+ /*!
1127+ @param osc A pointer to the relevant tMBSaw.
1128+ @param freq The frequency to set the oscillator to.
1129+ */
1130+ void tMBSaw_setFreq (tMBSaw* const osc, float freq);
1131+
1132+ void tMBSaw_sync (tMBSaw* const osc, float phase);
1133+
1134+ /*! @} */
1135+
1136+#ifdef __cplusplus
1137+}
1138+#endif
1139+
1140+#endif // LEAF_OSCILLATORS_H_INCLUDED
1141+
1142+//==============================================================================
1143+
leaf/Inc/leaf-physical.h+259−0
@@ -0,0 +1,259 @@
1+/*
2+ ==============================================================================
3+
4+ leaf-physical.h
5+ Created: 30 Nov 2018 10:41:55am
6+ Author: airship
7+
8+ ==============================================================================
9+ */
10+
11+#ifndef LEAF_PHYSICAL_H_INCLUDED
12+#define LEAF_PHYSICAL_H_INCLUDED
13+
14+#ifdef __cplusplus
15+extern "C" {
16+#endif
17+
18+ //==============================================================================
19+
20+#include "leaf-global.h"
21+#include "leaf-math.h"
22+#include "leaf-mempool.h"
23+#include "leaf-delay.h"
24+#include "leaf-filters.h"
25+#include "leaf-oscillators.h"
26+#include "leaf-envelopes.h"
27+#include "leaf-dynamics.h"
28+
29+ /*!
30+ * @internal
31+ * Header.
32+ * @include basic-oscillators.h
33+ * @example basic-oscillators.c
34+ * An example.
35+ */
36+
37+ //==============================================================================
38+
39+ /* Karplus Strong model */
40+ typedef struct _tPluck
41+ {
42+ tAllpassDelay delayLine; // Allpass or Linear?? big difference...
43+ tOneZero loopFilter;
44+ tOnePole pickFilter;
45+ tNoise noise;
46+
47+ float lastOut;
48+ float loopGain;
49+ float lastFreq;
50+
51+ float sr;
52+
53+ } _tPluck;
54+
55+ typedef _tPluck* tPluck;
56+
57+ void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]);
58+ void tPluck_free (tPluck* const);
59+ void tPluck_initToPool (tPluck* const, float lowestFrequency, tMempool* const);
60+ void tPluck_freeFromPool (tPluck* const, tMempool* const);
61+
62+ float tPluck_tick (tPluck* const);
63+
64+ // Pluck the string.
65+ void tPluck_pluck (tPluck* const, float amplitude);
66+
67+ // Start a note with the given frequency and amplitude.;
68+ void tPluck_noteOn (tPluck* const, float frequency, float amplitude );
69+
70+ // Stop a note with the given amplitude (speed of decay).
71+ void tPluck_noteOff (tPluck* const, float amplitude );
72+
73+ // Set instrument parameters for a particular frequency.
74+ void tPluck_setFrequency (tPluck* const, float frequency );
75+
76+ // Perform the control change specified by \e number and \e value (0.0 - 128.0).
77+ void tPluck_controlChange (tPluck* const, int number, float value);
78+
79+ // tPluck Utilities.
80+ float tPluck_getLastOut (tPluck* const);
81+
82+ //==============================================================================
83+
84+ typedef enum SKControlType
85+ {
86+ SKPickPosition = 0,
87+ SKStringDamping,
88+ SKDetune,
89+ SKControlTypeNil
90+ } SKControlType;
91+
92+ /* Stif Karplus Strong model */
93+ typedef struct _tKarplusStrong
94+ {
95+ tAllpassDelay delayLine;
96+ tLinearDelay combDelay;
97+ tOneZero filter;
98+ tNoise noise;
99+ tBiQuad biquad[4];
100+
101+ uint32_t length;
102+ float loopGain;
103+ float baseLoopGain;
104+ float lastFrequency;
105+ float lastLength;
106+ float stretching;
107+ float pluckAmplitude;
108+ float pickupPosition;
109+
110+ float lastOut;
111+
112+ } _tKarplusStrong;
113+
114+ typedef _tKarplusStrong* tKarplusStrong;
115+
116+ void tKarplusStrong_init (tKarplusStrong* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]);
117+ void tKarplusStrong_free (tKarplusStrong* const);
118+ void tKarplusStrong_initToPool (tKarplusStrong* const, float lowestFrequency, tMempool* const);
119+ void tKarplusStrong_freeFromPool (tKarplusStrong* const, tMempool* const);
120+
121+ float tKarplusStrong_tick (tKarplusStrong* const);
122+
123+ // Pluck the string.
124+ void tKarplusStrong_pluck (tKarplusStrong* const, float amplitude);
125+
126+ // Start a note with the given frequency and amplitude.;
127+ void tKarplusStrong_noteOn (tKarplusStrong* const, float frequency, float amplitude );
128+
129+ // Stop a note with the given amplitude (speed of decay).
130+ void tKarplusStrong_noteOff (tKarplusStrong* const, float amplitude );
131+
132+ // Set instrument parameters for a particular frequency.
133+ void tKarplusStrong_setFrequency (tKarplusStrong* const, float frequency );
134+
135+ // Perform the control change specified by \e number and \e value (0.0 - 128.0).
136+ // Use SKPickPosition, SKStringDamping, or SKDetune for type.
137+ void tKarplusStrong_controlChange (tKarplusStrong* const, SKControlType type, float value);
138+
139+ // Set the stretch "factor" of the string (0.0 - 1.0).
140+ void tKarplusStrong_setStretch (tKarplusStrong* const, float stretch );
141+
142+ // Set the pluck or "excitation" position along the string (0.0 - 1.0).
143+ void tKarplusStrong_setPickupPosition (tKarplusStrong* const, float position );
144+
145+ // Set the base loop gain.
146+ void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const, float aGain );
147+
148+ // tKarplusStrong utilities.
149+ float tKarplusStrong_getLastOut (tKarplusStrong* const);
150+
151+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
152+
153+ /* Simple Living String */
154+ typedef struct _tSimpleLivingString {
155+ float freq, waveLengthInSamples; // the frequency of the string, determining delay length
156+ float dampFreq; // frequency for the bridge LP filter, in Hz
157+ float decay; // amplitude damping factor for the string (only active in mode 0)
158+ float levMode;
159+ float curr;
160+ tLinearDelay delayLine;
161+ tOnePole bridgeFilter;
162+ tHighpass DCblocker;
163+ tFeedbackLeveler fbLev;
164+ tExpSmooth wlSmooth;
165+ } _tSimpleLivingString;
166+
167+ typedef _tSimpleLivingString* tSimpleLivingString;
168+
169+ void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq,
170+ float decay, float targetLev, float levSmoothFactor,
171+ float levStrength, int levMode);
172+ void tSimpleLivingString_free (tSimpleLivingString* const);
173+ void tSimpleLivingString_initToPool (tSimpleLivingString* const, float freq, float dampFreq,
174+ float decay, float targetLev, float levSmoothFactor,
175+ float levStrength, int levMode, tMempool* const);
176+ void tSimpleLivingString_freeFromPool (tSimpleLivingString* const, tMempool* const);
177+
178+ float tSimpleLivingString_tick (tSimpleLivingString* const, float input);
179+ float tSimpleLivingString_sample (tSimpleLivingString* const);
180+ void tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq);
181+ void tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples
182+ void tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq);
183+ void tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0
184+ void tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev);
185+ void tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor);
186+ void tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength);
187+ void tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode);
188+
189+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
190+
191+ /* Living String */
192+ typedef struct _tLivingString {
193+ float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length
194+ float pickPos; // the pick position, dividing the string in two, in ratio
195+ float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj)
196+ float dampFreq; // frequency for the bridge LP filter, in Hz
197+ float decay; // amplitude damping factor for the string (only active in mode 0)
198+ float levMode;
199+ float curr;
200+ tLinearDelay delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model
201+ tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL;
202+ tHighpass DCblockerL, DCblockerU;
203+ tFeedbackLeveler fbLevU, fbLevL;
204+ tExpSmooth wlSmooth, ppSmooth;
205+ } _tLivingString;
206+
207+ typedef _tLivingString* tLivingString;
208+
209+ void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex,
210+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
211+ float levStrength, int levMode);
212+ void tLivingString_free (tLivingString* const);
213+ void tLivingString_initToPool (tLivingString* const, float freq, float pickPos, float prepIndex,
214+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
215+ float levStrength, int levMode, tMempool* const);
216+ void tLivingString_freeFromPool (tLivingString* const, tMempool* const);
217+
218+ float tLivingString_tick (tLivingString* const, float input);
219+ float tLivingString_sample (tLivingString* const);
220+ void tLivingString_setFreq (tLivingString* const, float freq);
221+ void tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples
222+ void tLivingString_setPickPos (tLivingString* const, float pickPos);
223+ void tLivingString_setPrepIndex (tLivingString* const, float prepIndex);
224+ void tLivingString_setDampFreq (tLivingString* const, float dampFreq);
225+ void tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0
226+ void tLivingString_setTargetLev (tLivingString* const, float targetLev);
227+ void tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor);
228+ void tLivingString_setLevStrength (tLivingString* const, float levStrength);
229+ void tLivingString_setLevMode (tLivingString* const, int levMode);
230+
231+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
232+
233+ //Reed Table - borrowed from STK
234+ typedef struct _tReedTable {
235+ float offset, slope;
236+ } _tReedTable;
237+
238+ typedef _tReedTable* tReedTable;
239+
240+ void tReedTable_init (tReedTable* const, float offset, float slope);
241+ void tReedTable_free (tReedTable* const);
242+ void tReedTable_initToPool (tReedTable* const, float offset, float slope, tMempool* const);
243+ void tReedTable_freeFromPool (tReedTable* const, tMempool* const);
244+
245+ float tReedTable_tick (tReedTable* const, float input);
246+ float tReedTable_tanh_tick (tReedTable* const, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code
247+ void tReedTable_setOffset (tReedTable* const, float offset);
248+ void tReedTable_setSlope (tReedTable* const, float slope);
249+
250+ //==============================================================================
251+
252+#ifdef __cplusplus
253+}
254+#endif
255+
256+#endif // LEAF_PHYSICAL_H_INCLUDED
257+
258+//==============================================================================
259+
leaf/Inc/leaf-reverb.h+175−0
@@ -0,0 +1,175 @@
1+/*==============================================================================
2+
3+ leaf-reverb.h
4+ Created: 20 Jan 2017 12:02:04pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#ifndef LEAF_REVERB_H_INCLUDED
10+#define LEAF_REVERB_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+ //==============================================================================
17+
18+#include "leaf-global.h"
19+#include "leaf-math.h"
20+#include "leaf-mempool.h"
21+#include "leaf-delay.h"
22+#include "leaf-filters.h"
23+#include "leaf-oscillators.h"
24+
25+ /*!
26+ * @internal
27+ * Header.
28+ * @include basic-oscillators.h
29+ * @example basic-oscillators.c
30+ * An example.
31+ */
32+
33+ //==============================================================================
34+
35+ /* PRCReverb: Reverb, reimplemented from STK (Cook and Scavone). */
36+ typedef struct _tPRCReverb
37+ {
38+ float mix, t60;
39+
40+ float inv_441;
41+
42+ tDelay allpassDelays[2];
43+ tDelay combDelay;
44+ float allpassCoeff;
45+ float combCoeff;
46+
47+ float lastIn, lastOut;
48+
49+ } _tPRCReverb;
50+
51+ typedef _tPRCReverb* tPRCReverb;
52+
53+ void tPRCReverb_init (tPRCReverb* const, float t60);
54+ void tPRCReverb_free (tPRCReverb* const);
55+ void tPRCReverb_initToPool (tPRCReverb* const, float t60, tMempool* const);
56+ void tPRCReverb_freeFromPool (tPRCReverb* const, tMempool* const);
57+
58+ void tPRCReverb_clear (tPRCReverb* const);
59+ float tPRCReverb_tick (tPRCReverb* const, float input);
60+
61+ // Set reverb time in seconds.
62+ void tPRCReverb_setT60 (tPRCReverb* const, float t60);
63+
64+ // Set mix between dry input and wet output signal.
65+ void tPRCReverb_setMix (tPRCReverb* const, float mix);
66+
67+ //==============================================================================
68+
69+ /* NReverb: Reverb, reimplemented from STK (Cook and Scavone). */
70+ typedef struct _tNReverb
71+ {
72+ float mix, t60;
73+
74+ float inv_sr, inv_441;
75+
76+ tLinearDelay allpassDelays[8];
77+ tLinearDelay combDelays[6];
78+ float allpassCoeff;
79+ float combCoeffs[6];
80+ float lowpassState;
81+
82+ float lastIn, lastOut;
83+
84+ } _tNReverb;
85+
86+ typedef _tNReverb* tNReverb;
87+
88+ void tNReverb_init (tNReverb* const, float t60);
89+ void tNReverb_free (tNReverb* const);
90+ void tNReverb_initToPool (tNReverb* const, float t60, tMempool* const);
91+ void tNReverb_freeFromPool (tNReverb* const, tMempool* const);
92+
93+ void tNReverb_clear (tNReverb* const);
94+ float tNReverb_tick (tNReverb* const, float input);
95+ void tNReverb_tickStereo (tNReverb* const rev, float input, float* output);
96+
97+ // Set reverb time in seconds.
98+ void tNReverb_setT60 (tNReverb* const, float t60);
99+
100+ // Set mix between dry input and wet output signal.
101+ void tNReverb_setMix (tNReverb* const, float mix);
102+
103+ //==============================================================================
104+
105+ typedef struct _tDattorroReverb
106+ {
107+ float predelay;
108+ float input_filter;
109+ float feedback_filter;
110+ float feedback_gain;
111+ float mix;
112+ uint32_t frozen;
113+
114+ float size, size_max, t;
115+
116+ float f1_delay_2_last,
117+ f2_delay_2_last;
118+
119+ float f1_last,
120+ f2_last;
121+
122+ // INPUT
123+ tTapeDelay in_delay;
124+ tOnePole in_filter;
125+ tAllpass in_allpass[4];
126+
127+ // FEEDBACK 1
128+ tAllpass f1_allpass;
129+ tTapeDelay f1_delay_1;
130+ tOnePole f1_filter;
131+ tTapeDelay f1_delay_2;
132+ tTapeDelay f1_delay_3;
133+ tHighpass f1_hp;
134+
135+ tCycle f1_lfo;
136+
137+ // FEEDBACK 2
138+ tAllpass f2_allpass;
139+ tTapeDelay f2_delay_1;
140+ tOnePole f2_filter;
141+ tTapeDelay f2_delay_2;
142+ tTapeDelay f2_delay_3;
143+ tHighpass f2_hp;
144+
145+ tCycle f2_lfo;
146+
147+ } _tDattorroReverb;
148+
149+ typedef _tDattorroReverb* tDattorroReverb;
150+
151+ void tDattorroReverb_init (tDattorroReverb* const);
152+ void tDattorroReverb_free (tDattorroReverb* const);
153+ void tDattorroReverb_initToPool (tDattorroReverb* const, tMempool* const);
154+ void tDattorroReverb_freeFromPool (tDattorroReverb* const, tMempool* const);
155+
156+ void tDattorroReverb_clear (tDattorroReverb* const);
157+ float tDattorroReverb_tick (tDattorroReverb* const, float input);
158+ void tDattorroReverb_tickStereo (tDattorroReverb* const rev, float input, float* output);
159+ void tDattorroReverb_setMix (tDattorroReverb* const, float mix);
160+ void tDattorroReverb_setFreeze (tDattorroReverb* const rev, uint32_t freeze);
161+ void tDattorroReverb_setHP (tDattorroReverb* const, float freq);
162+ void tDattorroReverb_setSize (tDattorroReverb* const, float size);
163+ void tDattorroReverb_setInputDelay (tDattorroReverb* const, float preDelay);
164+ void tDattorroReverb_setInputFilter (tDattorroReverb* const, float freq);
165+ void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const, float freq);
166+ void tDattorroReverb_setFeedbackGain (tDattorroReverb* const, float gain);
167+
168+#ifdef __cplusplus
169+}
170+#endif
171+
172+#endif // LEAF_REVERB_H_INCLUDED
173+
174+//==============================================================================
175+
leaf/Inc/leaf-sampling.h+188−0
@@ -0,0 +1,188 @@
1+/*==============================================================================
2+
3+ leaf-sampling.h
4+ Created: 23 Jan 2019 11:22:09am
5+ Author: Mike Mulshine
6+
7+ ==============================================================================*/
8+
9+
10+#ifndef LEAF_SAMPLING_H_INCLUDED
11+#define LEAF_SAMPLING_H_INCLUDED
12+
13+#ifdef __cplusplus
14+extern "C" {
15+#endif
16+
17+ //==============================================================================
18+
19+#include "leaf-global.h"
20+#include "leaf-math.h"
21+#include "leaf-mempool.h"
22+#include "leaf-envelopes.h"
23+#include "leaf-mempool.h"
24+#include "leaf-analysis.h"
25+
26+ /*!
27+ * @internal
28+ * Header.
29+ * @include basic-oscillators.h
30+ * @example basic-oscillators.c
31+ * An example.
32+ */
33+
34+ //==============================================================================
35+
36+ typedef enum RecordMode
37+ {
38+ RecordOneShot = 0,
39+ RecordLoop,
40+ RecordModeNil
41+ } RecordMode;
42+
43+ typedef struct _tBuffer
44+ {
45+ float* buff;
46+
47+ uint32_t idx;
48+ uint32_t bufferLength;
49+ uint32_t recordedLength;
50+ RecordMode mode;
51+
52+ int active;
53+
54+ } _tBuffer;
55+
56+ typedef _tBuffer* tBuffer;
57+
58+ void tBuffer_init (tBuffer* const, uint32_t length);
59+ void tBuffer_free (tBuffer* const);
60+ void tBuffer_initToPool (tBuffer* const, uint32_t length, tMempool* const);
61+ void tBuffer_freeFromPool (tBuffer* const, tMempool* const);
62+
63+ void tBuffer_tick (tBuffer* const, float sample);
64+
65+ void tBuffer_read (tBuffer* const, float* buff, uint32_t len);
66+
67+ float tBuffer_get (tBuffer* const, int idx);
68+
69+ void tBuffer_record (tBuffer* const);
70+ void tBuffer_stop (tBuffer* const);
71+ int tBuffer_getRecordPosition (tBuffer* const);
72+
73+ void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
74+
75+ void tBuffer_clear (tBuffer* const);
76+
77+ uint32_t tBuffer_getBufferLength (tBuffer* const);
78+ uint32_t tBuffer_getRecordedLength (tBuffer* const sb);
79+
80+ //==============================================================================
81+
82+ typedef enum PlayMode
83+ {
84+ PlayNormal,
85+ PlayLoop,
86+ PlayBackAndForth,
87+ PlayModeNil
88+ } PlayMode;
89+
90+ typedef struct _tSampler
91+ {
92+ tBuffer samp;
93+
94+ tRamp gain;
95+
96+ float idx;
97+ float inc;
98+ float last;
99+ float iinc;
100+ int8_t dir;
101+ int8_t flip;
102+ int8_t bnf;
103+
104+ int32_t start, targetstart;
105+ int32_t end, targetend;
106+
107+ uint32_t len;
108+ uint32_t cfxlen;
109+ float numticks;
110+ PlayMode mode;
111+ int retrigger;
112+
113+ int active;
114+
115+ uint8_t inCrossfade;
116+
117+ float flipStart;
118+ float flipIdx;
119+
120+ } _tSampler;
121+
122+ typedef _tSampler* tSampler;
123+
124+ void tSampler_init (tSampler* const, tBuffer* const);
125+ void tSampler_free (tSampler* const);
126+ void tSampler_initToPool (tSampler* const, tBuffer* const, tMempool* const);
127+ void tSampler_freeFromPool (tSampler* const, tMempool* const);
128+
129+ float tSampler_tick (tSampler* const);
130+
131+ void tSampler_setSample (tSampler* const, tBuffer* const);
132+
133+ void tSampler_setMode (tSampler* const, PlayMode mode);
134+
135+ void tSampler_play (tSampler* const);
136+ void tSampler_stop (tSampler* const);
137+
138+ void tSampler_setStart (tSampler* const, int32_t start);
139+ void tSampler_setEnd (tSampler* const, int32_t end);
140+ void tSampler_setLength (tSampler* const, int32_t length);
141+
142+ void tSampler_setCrossfadeLength (tSampler* const sp, uint32_t length);
143+
144+ void tSampler_setRate (tSampler* const, float rate);
145+
146+ //==============================================================================
147+
148+ typedef struct _tAutoSampler
149+ {
150+ tSampler sampler;
151+ tEnvelopeFollower ef;
152+ uint32_t windowSize;
153+ float threshold;
154+ float previousPower;
155+ uint32_t sampleCounter;
156+ uint32_t powerCounter;
157+ uint8_t sampleTriggered;
158+ } _tAutoSampler;
159+
160+ typedef _tAutoSampler* tAutoSampler;
161+
162+ void tAutoSampler_init (tAutoSampler* const, tBuffer* const);
163+ void tAutoSampler_free (tAutoSampler* const);
164+ void tAutoSampler_initToPool (tAutoSampler* const, tBuffer* const, tMempool* const);
165+ void tAutoSampler_freeFromPool (tAutoSampler* const, tMempool* const);
166+
167+ float tAutoSampler_tick (tAutoSampler* const, float input);
168+
169+ void tAutoSampler_setBuffer (tAutoSampler* const, tBuffer* const);
170+
171+ void tAutoSampler_setMode (tAutoSampler* const, PlayMode mode);
172+
173+ void tAutoSampler_play (tAutoSampler* const);
174+ void tAutoSampler_stop (tAutoSampler* const);
175+
176+ void tAutoSampler_setThreshold (tAutoSampler* const, float thresh);
177+ void tAutoSampler_setWindowSize (tAutoSampler* const, uint32_t size);
178+ void tAutoSampler_setCrossfadeLength (tAutoSampler* const, uint32_t length);
179+
180+ void tAutoSampler_setRate (tAutoSampler* const, float rate);
181+
182+#ifdef __cplusplus
183+}
184+#endif
185+
186+#endif // LEAF_SAMPLING_H_INCLUDED
187+
188+//==============================================================================
leaf/Inc/leaf-tables.h+104−0
@@ -0,0 +1,104 @@
1+/*==============================================================================
2+
3+ leaf-tables.h
4+ Created: 4 Dec 2016 9:42:41pm
5+ Author: Michael R Mulshine
6+
7+==============================================================================*/
8+
9+#ifndef LEAF_TABLES_H_INCLUDED
10+#define LEAF_TABLES_H_INCLUDED
11+
12+#ifdef __cplusplus
13+extern "C" {
14+#endif
15+
16+//==============================================================================
17+
18+#include "leaf-math.h"
19+
20+//==============================================================================
21+
22+#define USE_SAWTOOTH_TABLE 1
23+#define USE_SQUARE_TABLE 1
24+#define USE_TRIANGLE_TABLE 1
25+#define USE_SHAPER_TABLE 1
26+
27+#define SINE_TABLE_SIZE 2048
28+#define SAW_TABLE_SIZE 2048
29+#define SQR_TABLE_SIZE 2048
30+#define TRI_TABLE_SIZE 2048
31+#define EXP_DECAY_TABLE_SIZE 65536
32+#define ATTACK_DECAY_INC_TABLE_SIZE 65536
33+#define TANH1_TABLE_SIZE 65536
34+#define DECAY_COEFF_TABLE_SIZE 4096
35+#define MTOF1_TABLE_SIZE 4096
36+#define FILTERTAN_TABLE_SIZE 4096
37+
38+#define SHAPER1_TABLE_SIZE 65536
39+extern const float __leaf_table_shaper1[SHAPER1_TABLE_SIZE];
40+
41+#define COEFFS_SIZE 32
42+extern const float* __leaf_tableref_firCoeffs[COEFFS_SIZE];
43+extern const float __leaf_tablesize_firNumTaps[COEFFS_SIZE];
44+extern const float __leaf_table_fir2XLow[32];
45+extern const float __leaf_table_fir4XLow[64];
46+extern const float __leaf_table_fir8XLow[64];
47+extern const float __leaf_table_fir16XLow[128];
48+extern const float __leaf_table_fir32XLow[256];
49+extern const float __leaf_table_fir64XLow[256];
50+extern const float __leaf_table_fir2XHigh[128];
51+extern const float __leaf_table_fir4XHigh[256];
52+extern const float __leaf_table_fir8XHigh[256];
53+extern const float __leaf_table_fir16XHigh[512];
54+extern const float __leaf_table_fir32XHigh[512];
55+extern const float __leaf_table_fir64XHigh[1024];
56+
57+typedef enum TableName
58+{
59+ T20 = 0,
60+ T40,
61+ T80,
62+ T160,
63+ T320,
64+ T640,
65+ T1280,
66+ T2560,
67+ T5120,
68+ T10240,
69+ T20480,
70+ TableNameNil
71+} TableName;
72+
73+// mtof lookup table based on input range [0.0,1.0) in 4096 increments - midi frequency values scaled between m25 and m134 (from the Snyderphonics DrumBox code)
74+
75+extern const float __leaf_table_exp_decay[EXP_DECAY_TABLE_SIZE];
76+extern const float __leaf_table_attack_decay_inc[ATTACK_DECAY_INC_TABLE_SIZE];
77+
78+extern const float __leaf_table_filtertan[FILTERTAN_TABLE_SIZE];
79+
80+extern const float __leaf_table_mtof1[MTOF1_TABLE_SIZE];
81+extern const float __leaf_table_decayCoeffTable[DECAY_COEFF_TABLE_SIZE];
82+
83+extern const float __leaf_table_tanh1[TANH1_TABLE_SIZE];
84+
85+//==============================================================================
86+
87+/* Sine wave table ripped from http://aquaticus.info/pwm-sine-wave. */
88+extern const float __leaf_table_sinewave[SINE_TABLE_SIZE];
89+
90+extern const float __leaf_table_sawtooth[11][SAW_TABLE_SIZE];
91+
92+extern const float __leaf_table_triangle[11][TRI_TABLE_SIZE];
93+
94+extern const float __leaf_table_squarewave[11][SQR_TABLE_SIZE];
95+
96+//==============================================================================
97+
98+#ifdef __cplusplus
99+}
100+#endif
101+
102+#endif // LEAF_TABLES_H_INCLUDED
103+
104+//==============================================================================
leaf/Src/leaf-analysis.c+1054−0
@@ -0,0 +1,1054 @@
1+/*==============================================================================
2+
3+ leaf-analysis.c
4+ Created: 30 Nov 2018 11:56:49am
5+ Author: airship
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-analysis.h"
12+#include "..\Externals\d_fft_mayer.h"
13+
14+#else
15+
16+#include "../Inc/leaf-analysis.h"
17+#include "../Externals/d_fft_mayer.h"
18+
19+#endif
20+
21+//===========================================================================
22+/* Envelope Follower */
23+//===========================================================================
24+
25+void tEnvelopeFollower_init(tEnvelopeFollower* const ef, float attackThreshold, float decayCoeff)
26+{
27+ _tEnvelopeFollower* e = *ef = (_tEnvelopeFollower*) leaf_alloc(sizeof(_tEnvelopeFollower));
28+
29+ e->y = 0.0f;
30+ e->a_thresh = attackThreshold;
31+ e->d_coeff = decayCoeff;
32+}
33+
34+void tEnvelopeFollower_free(tEnvelopeFollower* const ef)
35+{
36+ _tEnvelopeFollower* e = *ef;
37+
38+ leaf_free((char*)e);
39+}
40+
41+void tEnvelopeFollower_initToPool (tEnvelopeFollower* const ef, float attackThreshold, float decayCoeff, tMempool* const mp)
42+{
43+ _tMempool* m = *mp;
44+ _tEnvelopeFollower* e = *ef = (_tEnvelopeFollower*) mpool_alloc(sizeof(_tEnvelopeFollower), m);
45+
46+ e->y = 0.0f;
47+ e->a_thresh = attackThreshold;
48+ e->d_coeff = decayCoeff;
49+}
50+
51+void tEnvelopeFollower_freeFromPool (tEnvelopeFollower* const ef, tMempool* const mp)
52+{
53+ _tMempool* m = *mp;
54+ _tEnvelopeFollower* e = *ef;
55+
56+ mpool_free((char*)e, m);
57+}
58+
59+float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x)
60+{
61+ _tEnvelopeFollower* e = *ef;
62+
63+ if (x < 0.0f ) x = -x; /* Absolute value. */
64+
65+ if ((x >= e->y) && (x > e->a_thresh)) e->y = x; /* If we hit a peak, ride the peak to the top. */
66+ else e->y = e->y * e->d_coeff; /* Else, exponential decay of output. */
67+
68+ //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision?
69+ //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive
70+
71+ if( e->y < VSF) e->y = 0.0f;
72+
73+ return e->y;
74+}
75+
76+int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff)
77+{
78+ _tEnvelopeFollower* e = *ef;
79+ return e->d_coeff = decayCoeff;
80+}
81+
82+int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh)
83+{
84+ _tEnvelopeFollower* e = *ef;
85+ return e->a_thresh = attackThresh;
86+}
87+
88+
89+
90+
91+
92+// zero crossing detector
93+
94+void tZeroCrossing_init (tZeroCrossing* const zc, int maxWindowSize)
95+{
96+ tZeroCrossing_initToPool (zc, maxWindowSize, &leaf.mempool);
97+}
98+void tZeroCrossing_free (tZeroCrossing* const zc)
99+{
100+ tZeroCrossing_freeFromPool (zc, &leaf.mempool);
101+}
102+void tZeroCrossing_initToPool (tZeroCrossing* const zc, int maxWindowSize, tMempool* const mp)
103+{
104+ _tMempool* m = *mp;
105+ _tZeroCrossing* z = *zc = (_tZeroCrossing*) mpool_alloc(sizeof(_tZeroCrossing), m);
106+
107+ z->count = 0;
108+ z->maxWindowSize = maxWindowSize;
109+ z->currentWindowSize = maxWindowSize;
110+ z->invCurrentWindowSize = 1.0f / maxWindowSize;
111+ z->position = 0;
112+ z->prevPosition = maxWindowSize;
113+ z->inBuffer = (float*) mpool_calloc(sizeof(float) * maxWindowSize, m);
114+ z->countBuffer = (uint16_t*) mpool_calloc(sizeof(uint16_t) * maxWindowSize, m);
115+}
116+
117+void tZeroCrossing_freeFromPool (tZeroCrossing* const zc, tMempool* const mp)
118+{
119+ _tMempool* m = *mp;
120+ _tZeroCrossing* z = *zc;
121+ mpool_free((char*)z->inBuffer, m);
122+ mpool_free((char*)z->countBuffer, m);
123+ mpool_free((char*)z, m);
124+}
125+
126+//returns proportion of zero crossings within window size (0.0 would be none in window, 1.0 would be all zero crossings)
127+float tZeroCrossing_tick (tZeroCrossing* const zc, float input)
128+{
129+ _tZeroCrossing* z = *zc;
130+
131+ z->inBuffer[z->position] = input;
132+ int futurePosition = ((z->position + 1) % z->currentWindowSize);
133+ float output = 0.0f;
134+
135+ //add new value to count
136+ if ((z->inBuffer[z->position] * z->inBuffer[z->prevPosition]) < 0.0f)
137+ {
138+ //zero crossing happened, add it to the count array
139+ z->countBuffer[z->position] = 1;
140+ z->count++;
141+ }
142+ else
143+ {
144+ z->countBuffer[z->position] = 0;
145+ }
146+
147+ //remove oldest value from count
148+ if (z->countBuffer[futurePosition] > 0)
149+ {
150+ z->count--;
151+ if (z->count < 0)
152+ {
153+ z->count = 0;
154+ }
155+ }
156+
157+ z->prevPosition = z->position;
158+ z->position = futurePosition;
159+
160+ output = z->count * z->invCurrentWindowSize;
161+
162+ return output;
163+}
164+
165+
166+void tZeroCrossing_setWindow (tZeroCrossing* const zc, float windowSize)
167+{
168+ _tZeroCrossing* z = *zc;
169+ if (windowSize <= z->maxWindowSize)
170+ {
171+ z->currentWindowSize = windowSize;
172+ }
173+ else
174+ {
175+ z->currentWindowSize = z->maxWindowSize;
176+ }
177+ z->invCurrentWindowSize = 1.0f / z->currentWindowSize;
178+}
179+
180+
181+
182+
183+
184+//===========================================================================
185+/* Power Follower */
186+//===========================================================================
187+void tPowerFollower_init(tPowerFollower* const pf, float factor)
188+{
189+ _tPowerFollower* p = *pf = (_tPowerFollower*) leaf_alloc(sizeof(_tPowerFollower));
190+
191+ p->curr=0.0f;
192+ p->factor=factor;
193+ p->oneminusfactor=1.0f-factor;
194+}
195+
196+void tPowerFollower_free(tPowerFollower* const pf)
197+{
198+ _tPowerFollower* p = *pf;
199+
200+ leaf_free((char*)p);
201+}
202+
203+void tPowerFollower_initToPool (tPowerFollower* const pf, float factor, tMempool* const mp)
204+{
205+ _tMempool* m = *mp;
206+ _tPowerFollower* p = *pf = (_tPowerFollower*) mpool_alloc(sizeof(_tPowerFollower), m);
207+
208+ p->curr=0.0f;
209+ p->factor=factor;
210+ p->oneminusfactor=1.0f-factor;
211+}
212+
213+void tPowerFollower_freeFromPool (tPowerFollower* const pf, tMempool* const mp)
214+{
215+ _tMempool* m = *mp;
216+ _tPowerFollower* p = *pf;
217+
218+ mpool_free((char*)p, m);
219+}
220+
221+int tPowerFollower_setFactor(tPowerFollower* const pf, float factor)
222+{
223+ _tPowerFollower* p = *pf;
224+
225+ if (factor<0) factor=0;
226+ if (factor>1) factor=1;
227+ p->factor=factor;
228+ p->oneminusfactor=1.0f-factor;
229+ return 0;
230+}
231+
232+float tPowerFollower_tick(tPowerFollower* const pf, float input)
233+{
234+ _tPowerFollower* p = *pf;
235+ p->curr = p->factor*input*input+p->oneminusfactor*p->curr;
236+ return p->curr;
237+}
238+
239+float tPowerFollower_sample(tPowerFollower* const pf)
240+{
241+ _tPowerFollower* p = *pf;
242+ return p->curr;
243+}
244+
245+
246+
247+
248+//===========================================================================
249+/* ---------------- env~ - simple envelope follower. ----------------- */
250+//===========================================================================
251+
252+void tEnvPD_init(tEnvPD* const xpd, int ws, int hs, int bs)
253+{
254+ _tEnvPD* x = *xpd = (_tEnvPD*) leaf_calloc(sizeof(_tEnvPD));
255+
256+ int period = hs, npoints = ws;
257+
258+ int i;
259+
260+ if (npoints < 1) npoints = 1024;
261+ if (period < 1) period = npoints/2;
262+ if (period < npoints / MAXOVERLAP + 1)
263+ period = npoints / MAXOVERLAP + 1;
264+
265+ x->x_npoints = npoints;
266+ x->x_phase = 0;
267+ x->x_period = period;
268+
269+ x->windowSize = npoints;
270+ x->hopSize = period;
271+ x->blockSize = bs;
272+
273+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0.0f;
274+ for (i = 0; i < npoints; i++)
275+ x->buf[i] = (1.0f - cosf((TWO_PI * i) / npoints))/npoints;
276+ for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0.0f;
277+
278+ x->x_f = 0.0f;
279+
280+ x->x_allocforvs = INITVSTAKEN;
281+
282+ // ~ ~ ~ dsp ~ ~ ~
283+ if (x->x_period % x->blockSize)
284+ {
285+ x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize);
286+ }
287+ else
288+ {
289+ x->x_realperiod = x->x_period;
290+ }
291+ // ~ ~ ~ ~ ~ ~ ~ ~
292+}
293+
294+void tEnvPD_free (tEnvPD* const xpd)
295+{
296+ _tEnvPD* x = *xpd;
297+
298+ leaf_free((char*)x);
299+}
300+
301+void tEnvPD_initToPool (tEnvPD* const xpd, int ws, int hs, int bs, tMempool* const mp)
302+{
303+ _tMempool* m = *mp;
304+ _tEnvPD* x = *xpd = (_tEnvPD*) mpool_calloc(sizeof(_tEnvPD), m);
305+
306+ int period = hs, npoints = ws;
307+
308+ int i;
309+
310+ if (npoints < 1) npoints = 1024;
311+ if (period < 1) period = npoints/2;
312+ if (period < npoints / MAXOVERLAP + 1)
313+ period = npoints / MAXOVERLAP + 1;
314+
315+ x->x_npoints = npoints;
316+ x->x_phase = 0;
317+ x->x_period = period;
318+
319+ x->windowSize = npoints;
320+ x->hopSize = period;
321+ x->blockSize = bs;
322+
323+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
324+ for (i = 0; i < npoints; i++)
325+ x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints;
326+ for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0;
327+
328+ x->x_f = 0;
329+
330+ x->x_allocforvs = INITVSTAKEN;
331+
332+ // ~ ~ ~ dsp ~ ~ ~
333+ if (x->x_period % x->blockSize)
334+ {
335+ x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize);
336+ }
337+ else
338+ {
339+ x->x_realperiod = x->x_period;
340+ }
341+ // ~ ~ ~ ~ ~ ~ ~ ~
342+}
343+
344+void tEnvPD_freeFromPool (tEnvPD* const xpd, tMempool* const mp)
345+{
346+ _tMempool* m = *mp;
347+ _tEnvPD* x = *xpd;
348+
349+ mpool_free((char*)x, m);
350+}
351+
352+float tEnvPD_tick (tEnvPD* const xpd)
353+{
354+ _tEnvPD* x = *xpd;
355+ return powtodb(x->x_result);
356+}
357+
358+void tEnvPD_processBlock(tEnvPD* const xpd, float* in)
359+{
360+ _tEnvPD* x = *xpd;
361+
362+ int n = x->blockSize;
363+
364+ int count;
365+ t_sample *sump;
366+ in += n;
367+ for (count = x->x_phase, sump = x->x_sumbuf;
368+ count < x->x_npoints; count += x->x_realperiod, sump++)
369+ {
370+ t_sample *hp = x->buf + count;
371+ t_sample *fp = in;
372+ t_sample sum = *sump;
373+ int i;
374+
375+ for (i = 0; i < n; i++)
376+ {
377+ fp--;
378+ sum += *hp++ * (*fp * *fp);
379+ }
380+ *sump = sum;
381+ }
382+ sump[0] = 0;
383+ x->x_phase -= n;
384+ if (x->x_phase < 0)
385+ {
386+ x->x_result = x->x_sumbuf[0];
387+ for (count = x->x_realperiod, sump = x->x_sumbuf;
388+ count < x->x_npoints; count += x->x_realperiod, sump++)
389+ sump[0] = sump[1];
390+ sump[0] = 0;
391+ x->x_phase = x->x_realperiod - n;
392+ }
393+}
394+
395+//===========================================================================
396+// ATTACKDETECTION
397+//===========================================================================
398+/********Private function prototypes**********/
399+static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel);
400+static void atkdtk_envelope(tAttackDetection* const a, float *in);
401+
402+/********Constructor/Destructor***************/
403+
404+void tAttackDetection_init(tAttackDetection* const ad, int blocksize, int atk, int rel)
405+{
406+ *ad = (_tAttackDetection*) leaf_alloc(sizeof(_tAttackDetection));
407+
408+ atkdtk_init(ad, blocksize, atk, rel);
409+}
410+
411+void tAttackDetection_free(tAttackDetection* const ad)
412+{
413+ _tAttackDetection* a = *ad;
414+
415+ leaf_free((char*)a);
416+}
417+
418+void tAttackDetection_initToPool (tAttackDetection* const ad, int blocksize, int atk, int rel, tMempool* const mp)
419+{
420+ _tMempool* m = *mp;
421+ *ad = (_tAttackDetection*) mpool_alloc(sizeof(_tAttackDetection), m);
422+
423+ atkdtk_init(ad, blocksize, atk, rel);
424+}
425+
426+void tAttackDetection_freeFromPool (tAttackDetection* const ad, tMempool* const mp)
427+{
428+ _tMempool* m = *mp;
429+ _tAttackDetection* a = *ad;
430+
431+ mpool_free((char*)a, m);
432+}
433+
434+/*******Public Functions***********/
435+
436+
437+void tAttackDetection_setBlocksize(tAttackDetection* const ad, int size)
438+{
439+ _tAttackDetection* a = *ad;
440+
441+ if(!((size==64)|(size==128)|(size==256)|(size==512)|(size==1024)|(size==2048)))
442+ size = DEFBLOCKSIZE;
443+ a->blocksize = size;
444+
445+ return;
446+
447+}
448+
449+void tAttackDetection_setSamplerate(tAttackDetection* const ad, int inRate)
450+{
451+ _tAttackDetection* a = *ad;
452+
453+ a->samplerate = inRate;
454+
455+ //Reset atk and rel to recalculate coeff
456+ tAttackDetection_setAttack(ad, a->atk);
457+ tAttackDetection_setRelease(ad, a->rel);
458+}
459+
460+void tAttackDetection_setThreshold(tAttackDetection* const ad, float thres)
461+{
462+ _tAttackDetection* a = *ad;
463+ a->threshold = thres;
464+}
465+
466+void tAttackDetection_setAttack(tAttackDetection* const ad, int inAtk)
467+{
468+ _tAttackDetection* a = *ad;
469+ a->atk = inAtk;
470+ a->atk_coeff = pow(0.01, 1.0/(a->atk * a->samplerate * 0.001));
471+}
472+
473+void tAttackDetection_setRelease(tAttackDetection* const ad, int inRel)
474+{
475+ _tAttackDetection* a = *ad;
476+ a->rel = inRel;
477+ a->rel_coeff = pow(0.01, 1.0/(a->rel * a->samplerate * 0.001));
478+}
479+
480+
481+int tAttackDetection_detect(tAttackDetection* const ad, float *in)
482+{
483+ _tAttackDetection* a = *ad;
484+
485+ int result;
486+
487+ atkdtk_envelope(ad, in);
488+
489+ if(a->env >= a->prevAmp*2) //2 times greater = 6dB increase
490+ result = 1;
491+ else
492+ result = 0;
493+
494+ a->prevAmp = a->env;
495+
496+ return result;
497+}
498+
499+/*******Private Functions**********/
500+
501+static void atkdtk_init(tAttackDetection* const ad, int blocksize, int atk, int rel)
502+{
503+ _tAttackDetection* a = *ad;
504+
505+ a->env = 0;
506+ a->blocksize = blocksize;
507+ a->threshold = DEFTHRESHOLD;
508+ a->samplerate = leaf.sampleRate;
509+ a->prevAmp = 0;
510+
511+ a->env = 0;
512+
513+ tAttackDetection_setAttack(ad, atk);
514+ tAttackDetection_setRelease(ad, rel);
515+}
516+
517+static void atkdtk_envelope(tAttackDetection* const ad, float *in)
518+{
519+ _tAttackDetection* a = *ad;
520+
521+ int i = 0;
522+ float tmp;
523+ for(i = 0; i < a->blocksize; ++i){
524+ tmp = fastabsf(in[i]);
525+
526+ if(tmp > a->env)
527+ a->env = a->atk_coeff * (a->env - tmp) + tmp;
528+ else
529+ a->env = a->rel_coeff * (a->env - tmp) + tmp;
530+ }
531+
532+}
533+
534+//===========================================================================
535+// SNAC
536+//===========================================================================
537+/******************************************************************************/
538+/***************************** private procedures *****************************/
539+/******************************************************************************/
540+
541+#define REALFFT mayer_realfft
542+#define REALIFFT mayer_realifft
543+
544+static void snac_analyzeframe(tSNAC* const s);
545+static void snac_autocorrelation(tSNAC* const s);
546+static void snac_normalize(tSNAC* const s);
547+static void snac_pickpeak(tSNAC* const s);
548+static void snac_periodandfidelity(tSNAC* const s);
549+static void snac_biasbuf(tSNAC* const s);
550+static float snac_spectralpeak(tSNAC* const s, float periodlength);
551+
552+
553+/******************************************************************************/
554+/******************************** constructor, destructor *********************/
555+/******************************************************************************/
556+
557+
558+void tSNAC_init(tSNAC* const snac, int overlaparg)
559+{
560+ _tSNAC* s = *snac = (_tSNAC*) leaf_calloc(sizeof(_tSNAC));
561+
562+ s->biasfactor = DEFBIAS;
563+ s->timeindex = 0;
564+ s->periodindex = 0;
565+ s->periodlength = 0.;
566+ s->fidelity = 0.;
567+ s->minrms = DEFMINRMS;
568+ s->framesize = SNAC_FRAME_SIZE;
569+
570+ s->inputbuf = (float*) leaf_calloc(sizeof(float) * SNAC_FRAME_SIZE);
571+ s->processbuf = (float*) leaf_calloc(sizeof(float) * (SNAC_FRAME_SIZE * 2));
572+ s->spectrumbuf = (float*) leaf_calloc(sizeof(float) * (SNAC_FRAME_SIZE / 2));
573+ s->biasbuf = (float*) leaf_calloc(sizeof(float) * SNAC_FRAME_SIZE);
574+
575+ snac_biasbuf(snac);
576+ tSNAC_setOverlap(snac, overlaparg);
577+}
578+
579+void tSNAC_free(tSNAC* const snac)
580+{
581+ _tSNAC* s = *snac;
582+
583+ leaf_free((char*)s->inputbuf);
584+ leaf_free((char*)s->processbuf);
585+ leaf_free((char*)s->spectrumbuf);
586+ leaf_free((char*)s->biasbuf);
587+ leaf_free((char*)s);
588+}
589+
590+void tSNAC_initToPool (tSNAC* const snac, int overlaparg, tMempool* const mp)
591+{
592+ _tMempool* m = *mp;
593+ _tSNAC* s = *snac = (_tSNAC*) mpool_alloc(sizeof(_tSNAC), m);
594+
595+ s->biasfactor = DEFBIAS;
596+ s->timeindex = 0;
597+ s->periodindex = 0;
598+ s->periodlength = 0.;
599+ s->fidelity = 0.;
600+ s->minrms = DEFMINRMS;
601+ s->framesize = SNAC_FRAME_SIZE;
602+
603+ s->inputbuf = (float*) mpool_calloc(sizeof(float) * SNAC_FRAME_SIZE, m);
604+ s->processbuf = (float*) mpool_calloc(sizeof(float) * (SNAC_FRAME_SIZE * 2), m);
605+ s->spectrumbuf = (float*) mpool_calloc(sizeof(float) * (SNAC_FRAME_SIZE / 2), m);
606+ s->biasbuf = (float*) mpool_calloc(sizeof(float) * SNAC_FRAME_SIZE, m);
607+
608+ snac_biasbuf(snac);
609+ tSNAC_setOverlap(snac, overlaparg);
610+}
611+
612+void tSNAC_freeFromPool (tSNAC* const snac, tMempool* const mp)
613+{
614+ _tMempool* m = *mp;
615+ _tSNAC* s = *snac;
616+
617+ mpool_free((char*)s->inputbuf, m);
618+ mpool_free((char*)s->processbuf, m);
619+ mpool_free((char*)s->spectrumbuf, m);
620+ mpool_free((char*)s->biasbuf, m);
621+ mpool_free((char*)s, m);
622+}
623+
624+/******************************************************************************/
625+/************************** public access functions****************************/
626+/******************************************************************************/
627+
628+
629+void tSNAC_ioSamples(tSNAC* const snac, float *in, float *out, int size)
630+{
631+ _tSNAC* s = *snac;
632+
633+ int timeindex = s->timeindex;
634+ int mask = s->framesize - 1;
635+ int outindex = 0;
636+ float *inputbuf = s->inputbuf;
637+ float *processbuf = s->processbuf;
638+
639+ // call analysis function when it is time
640+ if(!(timeindex & (s->framesize / s->overlap - 1))) snac_analyzeframe(snac);
641+
642+ while(size--)
643+ {
644+ inputbuf[timeindex] = *in++;
645+ out[outindex++] = processbuf[timeindex++];
646+ timeindex &= mask;
647+ }
648+ s->timeindex = timeindex;
649+}
650+
651+void tSNAC_setOverlap(tSNAC* const snac, int lap)
652+{
653+ _tSNAC* s = *snac;
654+ if(!((lap==1)|(lap==2)|(lap==4)|(lap==8))) lap = DEFOVERLAP;
655+ s->overlap = lap;
656+}
657+
658+
659+void tSNAC_setBias(tSNAC* const snac, float bias)
660+{
661+ _tSNAC* s = *snac;
662+ if(bias > 1.) bias = 1.;
663+ if(bias < 0.) bias = 0.;
664+ s->biasfactor = bias;
665+ snac_biasbuf(snac);
666+ return;
667+}
668+
669+
670+void tSNAC_setMinRMS(tSNAC* const snac, float rms)
671+{
672+ _tSNAC* s = *snac;
673+ if(rms > 1.) rms = 1.;
674+ if(rms < 0.) rms = 0.;
675+ s->minrms = rms;
676+ return;
677+}
678+
679+
680+float tSNAC_getPeriod(tSNAC* const snac)
681+{
682+ _tSNAC* s = *snac;
683+ return(s->periodlength);
684+}
685+
686+
687+float tSNAC_getFidelity(tSNAC* const snac)
688+{
689+ _tSNAC* s = *snac;
690+ return(s->fidelity);
691+}
692+
693+
694+/******************************************************************************/
695+/***************************** private procedures *****************************/
696+/******************************************************************************/
697+
698+
699+// main analysis function
700+static void snac_analyzeframe(tSNAC* const snac)
701+{
702+ _tSNAC* s = *snac;
703+
704+ int n, tindex = s->timeindex;
705+ int framesize = s->framesize;
706+ int mask = framesize - 1;
707+ float norm = 1. / sqrt((float)(framesize * 2));
708+
709+ float *inputbuf = s->inputbuf;
710+ float *processbuf = s->processbuf;
711+
712+ // copy input to processing buffers
713+ for(n=0; n<framesize; n++)
714+ {
715+ processbuf[n] = inputbuf[tindex] * norm;
716+ tindex++;
717+ tindex &= mask;
718+ }
719+
720+ // zeropadding
721+ for(n=framesize; n<(framesize<<1); n++) processbuf[n] = 0.;
722+
723+ // call analysis procedures
724+ snac_autocorrelation(snac);
725+ snac_normalize(snac);
726+ snac_pickpeak(snac);
727+ snac_periodandfidelity(snac);
728+}
729+
730+
731+static void snac_autocorrelation(tSNAC* const snac)
732+{
733+ _tSNAC* s = *snac;
734+
735+ int n, m;
736+ int framesize = s->framesize;
737+ int fftsize = framesize * 2;
738+ float *processbuf = s->processbuf;
739+ float *spectrumbuf = s->spectrumbuf;
740+
741+ REALFFT(fftsize, processbuf);
742+
743+ // compute power spectrum
744+ processbuf[0] *= processbuf[0]; // DC
745+ processbuf[framesize] *= processbuf[framesize]; // Nyquist
746+
747+ for(n=1; n<framesize; n++)
748+ {
749+ processbuf[n] = processbuf[n] * processbuf[n]
750+ + processbuf[fftsize-n] * processbuf[fftsize-n]; // imag coefficients appear reversed
751+ processbuf[fftsize-n] = 0.;
752+ }
753+
754+ // store power spectrum up to SR/4 for possible later use
755+ for(m=0; m<(framesize>>1); m++)
756+ {
757+ spectrumbuf[m] = processbuf[m];
758+ }
759+
760+ // transform power spectrum to autocorrelation function
761+ REALIFFT(fftsize, processbuf);
762+ return;
763+}
764+
765+
766+static void snac_normalize(tSNAC* const snac)
767+{
768+ _tSNAC* s = *snac;
769+
770+ int framesize = s->framesize;
771+ int framesizeplustimeindex = s->framesize + s->timeindex;
772+ int timeindexminusone = s->timeindex - 1;
773+ int n, m;
774+ int mask = framesize - 1;
775+ int seek = framesize * SEEK;
776+ float *inputbuf = s->inputbuf;
777+ float *processbuf= s->processbuf;
778+ float signal1, signal2;
779+
780+ // minimum RMS implemented as minimum autocorrelation at index 0
781+ // functionally equivalent to white noise floor
782+ float rms = s->minrms / sqrt(1.0f / (float)framesize);
783+ float minrzero = rms * rms;
784+ float rzero = processbuf[0];
785+ if(rzero < minrzero) rzero = minrzero;
786+ double normintegral = (double)rzero * 2.;
787+
788+ // normalize biased autocorrelation function
789+ // inputbuf is circular buffer: timeindex may be non-zero when overlap > 1
790+ processbuf[0] = 1;
791+ for(n=1, m=s->timeindex+1; n<seek; n++, m++)
792+ {
793+ signal1 = inputbuf[(n + timeindexminusone)&mask];
794+ signal2 = inputbuf[(framesizeplustimeindex - n)&mask];
795+ normintegral -= (double)(signal1 * signal1 + signal2 * signal2);
796+ processbuf[n] /= (float)normintegral * 0.5f;
797+ }
798+
799+ // flush instable function tail
800+ for(n = seek; n<framesize; n++) processbuf[n] = 0.;
801+ return;
802+}
803+
804+
805+static void snac_periodandfidelity(tSNAC* const snac)
806+{
807+ _tSNAC* s = *snac;
808+
809+ float periodlength;
810+
811+ if(s->periodindex)
812+ {
813+ periodlength = (float)s->periodindex +
814+ interpolate3phase(s->processbuf, s->periodindex);
815+ if(periodlength < 8) periodlength = snac_spectralpeak(snac, periodlength);
816+ s->periodlength = periodlength;
817+ s->fidelity = interpolate3max(s->processbuf, s->periodindex);
818+ }
819+ return;
820+}
821+
822+// select the peak which most probably represents period length
823+static void snac_pickpeak(tSNAC* const snac)
824+{
825+ _tSNAC* s = *snac;
826+
827+ int n, peakindex=0;
828+ int seek = s->framesize * SEEK;
829+ float *processbuf= s->processbuf;
830+ float maxvalue = 0.;
831+ float biasedpeak;
832+ float *biasbuf = s->biasbuf;
833+
834+ // skip main lobe
835+ for(n=1; n<seek; n++)
836+ {
837+ if(processbuf[n] < 0.) break;
838+ }
839+
840+ // find interpolated / biased maximum in SNAC function
841+ // interpolation finds the 'real maximum'
842+ // biasing favours the first candidate
843+ for(; n<seek-1; n++)
844+ {
845+ if(processbuf[n] >= processbuf[n-1])
846+ {
847+ if(processbuf[n] > processbuf[n+1]) // we have a local peak
848+ {
849+ biasedpeak = interpolate3max(processbuf, n) * biasbuf[n];
850+
851+ if(biasedpeak > maxvalue)
852+ {
853+ maxvalue = biasedpeak;
854+ peakindex = n;
855+ }
856+ }
857+ }
858+ }
859+ s->periodindex = peakindex;
860+ return;
861+}
862+
863+
864+// verify period length via frequency domain (up till SR/4)
865+// frequency domain is more precise than lag domain for period lengths < 8
866+// argument 'periodlength' is initial estimation from autocorrelation
867+static float snac_spectralpeak(tSNAC* const snac, float periodlength)
868+{
869+ _tSNAC* s = *snac;
870+
871+ if(periodlength < 4.0f) return periodlength;
872+
873+ float max = 0.;
874+ int n, startbin, stopbin, peakbin = 0;
875+ int spectrumsize = s->framesize>>1;
876+ float *spectrumbuf = s->spectrumbuf;
877+ float peaklocation = (float)(s->framesize * 2.0f) / periodlength;
878+
879+ startbin = (int)(peaklocation * 0.8f + 0.5f);
880+ if(startbin < 1) startbin = 1;
881+ stopbin = (int)(peaklocation * 1.25f + 0.5f);
882+ if(stopbin >= spectrumsize - 1) stopbin = spectrumsize - 1;
883+
884+ for(n=startbin; n<stopbin; n++)
885+ {
886+ if(spectrumbuf[n] >= spectrumbuf[n-1])
887+ {
888+ if(spectrumbuf[n] > spectrumbuf[n+1])
889+ {
890+ if(spectrumbuf[n] > max)
891+ {
892+ max = spectrumbuf[n];
893+ peakbin = n;
894+ }
895+ }
896+ }
897+ }
898+
899+ // calculate amplitudes in peak region
900+ for(n=(peakbin-1); n<(peakbin+2); n++)
901+ {
902+ spectrumbuf[n] = sqrtf(spectrumbuf[n]);
903+ }
904+
905+ peaklocation = (float)peakbin + interpolate3phase(spectrumbuf, peakbin);
906+ periodlength = (float)(s->framesize * 2.0f) / peaklocation;
907+
908+ return periodlength;
909+}
910+
911+
912+// modified logarithmic bias function
913+static void snac_biasbuf(tSNAC* const snac)
914+{
915+ _tSNAC* s = *snac;
916+
917+ int n;
918+ int maxperiod = (int)(s->framesize * (float)SEEK);
919+ float bias = s->biasfactor / logf((float)(maxperiod - 4));
920+ float *biasbuf = s->biasbuf;
921+
922+ for(n=0; n<5; n++) // periods < 5 samples can't be tracked
923+ {
924+ biasbuf[n] = 0.0f;
925+ }
926+
927+ for(n=5; n<maxperiod; n++)
928+ {
929+ biasbuf[n] = 1.0f - (float)logf(n - 4) * bias;
930+ }
931+}
932+
933+//===========================================================================
934+// PERIODDETECTION
935+//===========================================================================
936+void tPeriodDetection_init (tPeriodDetection* const pd, float* in, float* out, int bufSize, int frameSize)
937+{
938+ tPeriodDetection_initToPool(pd, in, out, bufSize, frameSize, &leaf.mempool);
939+}
940+
941+void tPeriodDetection_free (tPeriodDetection* const pd)
942+{
943+ tPeriodDetection_freeFromPool(pd, &leaf.mempool);
944+}
945+
946+void tPeriodDetection_initToPool (tPeriodDetection* const pd, float* in, float* out, int bufSize, int frameSize, tMempool* const mp)
947+{
948+ _tMempool* m = *mp;
949+ _tPeriodDetection* p = *pd = (_tPeriodDetection*) mpool_calloc(sizeof(_tPeriodDetection), m);
950+
951+ p->inBuffer = in;
952+ p->outBuffer = out;
953+ p->bufSize = bufSize;
954+ p->frameSize = frameSize;
955+ p->framesPerBuffer = p->bufSize / p->frameSize;
956+ p->curBlock = 1;
957+ p->lastBlock = 0;
958+ p->index = 0;
959+
960+ p->hopSize = DEFHOPSIZE;
961+ p->windowSize = DEFWINDOWSIZE;
962+ p->fba = FBA;
963+
964+ tEnvPD_initToPool(&p->env, p->windowSize, p->hopSize, p->frameSize, mp);
965+
966+ tSNAC_initToPool(&p->snac, DEFOVERLAP, mp);
967+
968+ p->timeConstant = DEFTIMECONSTANT;
969+ p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant);
970+ p->fidelityThreshold = 0.95;
971+}
972+
973+void tPeriodDetection_freeFromPool (tPeriodDetection* const pd, tMempool* const mp)
974+{
975+ _tMempool* m = *mp;
976+ _tPeriodDetection* p = *pd;
977+
978+ tEnvPD_freeFromPool(&p->env, mp);
979+ tSNAC_freeFromPool(&p->snac, mp);
980+ mpool_free((char*)p, m);
981+}
982+
983+float tPeriodDetection_tick (tPeriodDetection* pd, float sample)
984+{
985+ _tPeriodDetection* p = *pd;
986+
987+ int i, iLast;
988+
989+ i = (p->curBlock*p->frameSize);
990+ iLast = (p->lastBlock*p->frameSize)+p->index;
991+
992+ p->i = i;
993+ p->iLast = iLast;
994+
995+ p->inBuffer[i+p->index] = sample;
996+
997+ p->index++;
998+ p->indexstore = p->index;
999+ if (p->index >= p->frameSize)
1000+ {
1001+ p->index = 0;
1002+
1003+ tEnvPD_processBlock(&p->env, &(p->inBuffer[i]));
1004+
1005+ tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize);
1006+ float fidelity = tSNAC_getFidelity(&p->snac);
1007+ // Fidelity threshold recommended by Katja Vetters is 0.95 for most instruments/voices http://www.katjaas.nl/helmholtz/helmholtz.html
1008+ if (fidelity > p->fidelityThreshold) p->period = tSNAC_getPeriod(&p->snac);
1009+
1010+ p->curBlock++;
1011+ if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0;
1012+ p->lastBlock++;
1013+ if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0;
1014+ }
1015+
1016+ return p->period;
1017+}
1018+
1019+float tPeriodDetection_getPeriod(tPeriodDetection* pd)
1020+{
1021+ _tPeriodDetection* p = *pd;
1022+ return p->period;
1023+}
1024+
1025+void tPeriodDetection_setHopSize(tPeriodDetection* pd, int hs)
1026+{
1027+ _tPeriodDetection* p = *pd;
1028+ p->hopSize = hs;
1029+}
1030+
1031+void tPeriodDetection_setWindowSize(tPeriodDetection* pd, int ws)
1032+{
1033+ _tPeriodDetection* p = *pd;
1034+ p->windowSize = ws;
1035+}
1036+
1037+void tPeriodDetection_setFidelityThreshold(tPeriodDetection* pd, float threshold)
1038+{
1039+ _tPeriodDetection* p = *pd;
1040+ p->fidelityThreshold = threshold;
1041+}
1042+
1043+void tPeriodDetection_setAlpha (tPeriodDetection* pd, float alpha)
1044+{
1045+ _tPeriodDetection* p = *pd;
1046+ p->alpha = LEAF_clip(0.0f, alpha, 1.0f);
1047+}
1048+
1049+void tPeriodDetection_setTolerance (tPeriodDetection* pd, float tolerance)
1050+{
1051+ _tPeriodDetection* p = *pd;
1052+ if (tolerance < 0.0f) p->tolerance = 0.0f;
1053+ else p->tolerance = tolerance;
1054+}
leaf/Src/leaf-delay.c+928−0
@@ -0,0 +1,928 @@
1+/*==============================================================================
2+
3+ leaf-delay.c
4+ Created: 20 Jan 2017 12:01:24pm
5+ Author: Michael R Mulshine
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-delay.h"
12+#include "..\leaf.h"
13+
14+#else
15+
16+#include "../Inc/leaf-delay.h"
17+#include "../leaf.h"
18+
19+#endif
20+
21+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Delay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
22+void tDelay_init (tDelay* const dl, uint32_t delay, uint32_t maxDelay)
23+{
24+ tDelay_initToPool(dl, delay, maxDelay, &leaf.mempool);
25+}
26+
27+void tDelay_free(tDelay* const dl)
28+{
29+ tDelay_freeFromPool(dl, &leaf.mempool);
30+}
31+
32+void tDelay_initToPool (tDelay* const dl, uint32_t delay, uint32_t maxDelay, tMempool* const mp)
33+{
34+ _tMempool* m = *mp;
35+ _tDelay* d = *dl = (_tDelay*) mpool_alloc(sizeof(_tDelay), m);
36+
37+ d->maxDelay = maxDelay;
38+
39+ d->delay = delay;
40+
41+ d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
42+
43+ d->inPoint = 0;
44+ d->outPoint = 0;
45+
46+ d->lastIn = 0.0f;
47+ d->lastOut = 0.0f;
48+
49+ d->gain = 1.0f;
50+
51+ tDelay_setDelay(dl, d->delay);
52+}
53+
54+void tDelay_freeFromPool (tDelay* const dl, tMempool* const mp)
55+{
56+ _tMempool* m = *mp;
57+ _tDelay* d = *dl;
58+
59+ mpool_free((char*)d->buff, m);
60+ mpool_free((char*)d, m);
61+}
62+
63+void tDelay_clear(tDelay* const dl)
64+{
65+ _tDelay* d = *dl;
66+ for (int i = 0; i < d->maxDelay; i++)
67+ {
68+ d->buff[i] = 0;
69+ }
70+}
71+
72+float tDelay_tick (tDelay* const dl, float input)
73+{
74+ _tDelay* d = *dl;
75+
76+ // Input
77+ d->lastIn = input;
78+ d->buff[d->inPoint] = input * d->gain;
79+ if (++(d->inPoint) == d->maxDelay) d->inPoint = 0;
80+
81+ // Output
82+ d->lastOut = d->buff[d->outPoint];
83+ if (++(d->outPoint) == d->maxDelay) d->outPoint = 0;
84+
85+ return d->lastOut;
86+}
87+
88+int tDelay_setDelay (tDelay* const dl, uint32_t delay)
89+{
90+ _tDelay* d = *dl;
91+
92+ d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
93+
94+ // read chases write
95+ if ( d->inPoint >= delay ) d->outPoint = d->inPoint - d->delay;
96+ else d->outPoint = d->maxDelay + d->inPoint - d->delay;
97+
98+ return 0;
99+}
100+
101+float tDelay_tapOut (tDelay* const dl, uint32_t tapDelay)
102+{
103+ _tDelay* d = *dl;
104+
105+ int32_t tap = d->inPoint - tapDelay - 1;
106+
107+ // Check for wraparound.
108+ while ( tap < 0 ) tap += d->maxDelay;
109+
110+ return d->buff[tap];
111+
112+}
113+
114+void tDelay_tapIn (tDelay* const dl, float value, uint32_t tapDelay)
115+{
116+ _tDelay* d = *dl;
117+
118+ int32_t tap = d->inPoint - tapDelay - 1;
119+
120+ // Check for wraparound.
121+ while ( tap < 0 ) tap += d->maxDelay;
122+
123+ d->buff[tap] = value;
124+}
125+
126+float tDelay_addTo (tDelay* const dl, float value, uint32_t tapDelay)
127+{
128+ _tDelay* d = *dl;
129+
130+ int32_t tap = d->inPoint - tapDelay - 1;
131+
132+ // Check for wraparound.
133+ while ( tap < 0 ) tap += d->maxDelay;
134+
135+ return (d->buff[tap] += value);
136+}
137+
138+uint32_t tDelay_getDelay (tDelay* const dl)
139+{
140+ _tDelay* d = *dl;
141+ return d->delay;
142+}
143+
144+float tDelay_getLastOut (tDelay* const dl)
145+{
146+ _tDelay* d = *dl;
147+ return d->lastOut;
148+}
149+
150+float tDelay_getLastIn (tDelay* const dl)
151+{
152+ _tDelay* d = *dl;
153+ return d->lastIn;
154+}
155+
156+void tDelay_setGain (tDelay* const dl, float gain)
157+{
158+ _tDelay* d = *dl;
159+ if (gain < 0.0f) d->gain = 0.0f;
160+ else d->gain = gain;
161+}
162+
163+float tDelay_getGain (tDelay* const dl)
164+{
165+ _tDelay* d = *dl;
166+ return d->gain;
167+}
168+
169+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
170+void tLinearDelay_init (tLinearDelay* const dl, float delay, uint32_t maxDelay)
171+{
172+ tLinearDelay_initToPool(dl, delay, maxDelay, &leaf.mempool);
173+}
174+
175+void tLinearDelay_free(tLinearDelay* const dl)
176+{
177+ tLinearDelay_freeFromPool(dl, &leaf.mempool);
178+}
179+
180+void tLinearDelay_initToPool (tLinearDelay* const dl, float delay, uint32_t maxDelay, tMempool* const mp)
181+{
182+ _tMempool* m = *mp;
183+ _tLinearDelay* d = *dl = (_tLinearDelay*) mpool_alloc(sizeof(_tLinearDelay), m);
184+
185+ d->maxDelay = maxDelay;
186+
187+ if (delay > maxDelay) d->delay = maxDelay;
188+ else if (delay < 0.0f) d->delay = 0.0f;
189+ else d->delay = delay;
190+
191+ d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
192+
193+ d->gain = 1.0f;
194+
195+ d->lastIn = 0.0f;
196+ d->lastOut = 0.0f;
197+
198+ d->inPoint = 0;
199+ d->outPoint = 0;
200+
201+ tLinearDelay_setDelay(dl, d->delay);
202+}
203+
204+void tLinearDelay_freeFromPool(tLinearDelay* const dl, tMempool* const mp)
205+{
206+ _tMempool* m = *mp;
207+ _tLinearDelay* d = *dl;
208+
209+ mpool_free((char*)d->buff, m);
210+ mpool_free((char*)d, m);
211+}
212+
213+void tLinearDelay_clear(tLinearDelay* const dl)
214+{
215+ _tLinearDelay* d = *dl;
216+ for (int i = 0; i < d->maxDelay; i++)
217+ {
218+ d->buff[i] = 0;
219+ }
220+}
221+
222+float tLinearDelay_tick (tLinearDelay* const dl, float input)
223+{
224+ _tLinearDelay* d = *dl;
225+
226+ d->buff[d->inPoint] = input * d->gain;
227+
228+ // Increment input pointer modulo length.
229+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
230+
231+ uint32_t idx = (uint32_t) d->outPoint;
232+ // First 1/2 of interpolation
233+ d->lastOut = d->buff[idx] * d->omAlpha;
234+ // Second 1/2 of interpolation
235+ if ((idx + 1) < d->maxDelay)
236+ d->lastOut += d->buff[idx+1] * d->alpha;
237+ else
238+ d->lastOut += d->buff[0] * d->alpha;
239+
240+ // Increment output pointer modulo length
241+ if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
242+
243+ return d->lastOut;
244+}
245+
246+void tLinearDelay_tickIn (tLinearDelay* const dl, float input)
247+{
248+ _tLinearDelay* d = *dl;
249+
250+ d->buff[d->inPoint] = input * d->gain;
251+
252+ // Increment input pointer modulo length.
253+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
254+}
255+
256+float tLinearDelay_tickOut (tLinearDelay* const dl)
257+{
258+ _tLinearDelay* d = *dl;
259+
260+ uint32_t idx = (uint32_t) d->outPoint;
261+ // First 1/2 of interpolation
262+ d->lastOut = d->buff[idx] * d->omAlpha;
263+ // Second 1/2 of interpolation
264+ if ((idx + 1) < d->maxDelay)
265+ d->lastOut += d->buff[idx+1] * d->alpha;
266+ else
267+ d->lastOut += d->buff[0] * d->alpha;
268+
269+ // Increment output pointer modulo length
270+ if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
271+
272+ return d->lastOut;
273+}
274+
275+int tLinearDelay_setDelay (tLinearDelay* const dl, float delay)
276+{
277+ _tLinearDelay* d = *dl;
278+
279+ d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
280+
281+ float outPointer = d->inPoint - d->delay;
282+
283+ while ( outPointer < 0 )
284+ outPointer += d->maxDelay; // modulo maximum length
285+
286+ d->outPoint = (uint32_t) outPointer; // integer part
287+
288+ d->alpha = outPointer - d->outPoint; // fractional part
289+ d->omAlpha = 1.0f - d->alpha;
290+
291+ if ( d->outPoint == d->maxDelay ) d->outPoint = 0;
292+
293+ return 0;
294+}
295+
296+float tLinearDelay_tapOut (tLinearDelay* const dl, uint32_t tapDelay)
297+{
298+ _tLinearDelay* d = *dl;
299+
300+ uint32_t tap = d->inPoint - tapDelay - 1;
301+ // Check for wraparound.
302+ while ( tap < 0 ) tap += d->maxDelay;
303+
304+ return d->buff[tap];
305+}
306+
307+void tLinearDelay_tapIn (tLinearDelay* const dl, float value, uint32_t tapDelay)
308+{
309+ _tLinearDelay* d = *dl;
310+
311+ uint32_t tap = d->inPoint - tapDelay - 1;
312+
313+ // Check for wraparound.
314+ while ( tap < 0 ) tap += d->maxDelay;
315+
316+ d->buff[tap] = value;
317+}
318+
319+float tLinearDelay_addTo (tLinearDelay* const dl, float value, uint32_t tapDelay)
320+{
321+ _tLinearDelay* d = *dl;
322+
323+ int32_t tap = d->inPoint - tapDelay - 1;
324+
325+ // Check for wraparound.
326+ while ( tap < 0 ) tap += d->maxDelay;
327+
328+ return (d->buff[tap] += value);
329+}
330+
331+float tLinearDelay_getDelay (tLinearDelay* const dl)
332+{
333+ _tLinearDelay* d = *dl;
334+ return d->delay;
335+}
336+
337+float tLinearDelay_getLastOut (tLinearDelay* const dl)
338+{
339+ _tLinearDelay* d = *dl;
340+ return d->lastOut;
341+}
342+
343+float tLinearDelay_getLastIn (tLinearDelay* const dl)
344+{
345+ _tLinearDelay* d = *dl;
346+ return d->lastIn;
347+}
348+
349+void tLinearDelay_setGain (tLinearDelay* const dl, float gain)
350+{
351+ _tLinearDelay* d = *dl;
352+ if (gain < 0.0f) d->gain = 0.0f;
353+ else d->gain = gain;
354+}
355+
356+float tLinearDelay_getGain (tLinearDelay* const dl)
357+{
358+ _tLinearDelay* d = *dl;
359+ return d->gain;
360+}
361+
362+
363+
364+
365+
366+/// Hermite Interpolated Delay
367+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
368+void tHermiteDelay_init (tHermiteDelay* const dl, float delay, uint32_t maxDelay)
369+{
370+ tHermiteDelay_initToPool(dl, delay, maxDelay, &leaf.mempool);
371+}
372+
373+void tHermiteDelay_free(tHermiteDelay* const dl)
374+{
375+ tHermiteDelay_freeFromPool(dl, &leaf.mempool);
376+}
377+
378+void tHermiteDelay_initToPool (tHermiteDelay* const dl, float delay, uint32_t maxDelay, tMempool* const mp)
379+{
380+ _tMempool* m = *mp;
381+ _tHermiteDelay* d = *dl = (_tHermiteDelay*) mpool_alloc(sizeof(_tHermiteDelay), m);
382+
383+ d->maxDelay = maxDelay;
384+
385+ if (delay > maxDelay) d->delay = maxDelay;
386+ else if (delay < 0.0f) d->delay = 0.0f;
387+ else d->delay = delay;
388+
389+ d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
390+
391+ d->gain = 1.0f;
392+
393+ d->lastIn = 0.0f;
394+ d->lastOut = 0.0f;
395+
396+ d->inPoint = 0;
397+ d->outPoint = 0;
398+
399+ tHermiteDelay_setDelay(dl, d->delay);
400+}
401+
402+void tHermiteDelay_freeFromPool(tHermiteDelay* const dl, tMempool* const mp)
403+{
404+ _tMempool* m = *mp;
405+ _tHermiteDelay* d = *dl;
406+
407+ mpool_free((char*)d->buff, m);
408+ mpool_free((char*)d, m);
409+}
410+
411+
412+void tHermiteDelay_clear(tHermiteDelay* const dl)
413+{
414+ _tHermiteDelay* d = *dl;
415+ for (int i = 0; i < d->maxDelay; i++)
416+ {
417+ d->buff[i] = 0;
418+ }
419+}
420+
421+float tHermiteDelay_tick (tHermiteDelay* const dl, float input)
422+{
423+ _tHermiteDelay* d = *dl;
424+
425+ d->buff[d->inPoint] = input * d->gain;
426+
427+ // Increment input pointer modulo length.
428+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
429+
430+
431+ uint32_t idx = (uint32_t) d->outPoint;
432+ d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
433+ d->buff[idx],
434+ d->buff[(idx + 1) % d->maxDelay],
435+ d->buff[(idx + 2) % d->maxDelay],
436+ d->alpha);
437+
438+ // Increment output pointer modulo length
439+ if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
440+
441+ return d->lastOut;
442+}
443+
444+void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input)
445+{
446+ _tHermiteDelay* d = *dl;
447+
448+ d->buff[d->inPoint] = input * d->gain;
449+
450+ // Increment input pointer modulo length.
451+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
452+}
453+
454+float tHermiteDelay_tickOut (tHermiteDelay* const dl)
455+{
456+ _tHermiteDelay* d = *dl;
457+
458+ uint32_t idx = (uint32_t) d->outPoint;
459+
460+
461+
462+ d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
463+ d->buff[idx],
464+ d->buff[(idx + 1) % d->maxDelay],
465+ d->buff[(idx + 2) % d->maxDelay],
466+ d->alpha);
467+
468+ // Increment output pointer modulo length
469+ if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
470+
471+ return d->lastOut;
472+}
473+
474+int tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay)
475+{
476+ _tHermiteDelay* d = *dl;
477+
478+ d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
479+
480+ float outPointer = d->inPoint - d->delay;
481+
482+ while ( outPointer < 0 )
483+ outPointer += d->maxDelay; // modulo maximum length
484+
485+ d->outPoint = (uint32_t) outPointer; // integer part
486+
487+ d->alpha = outPointer - d->outPoint; // fractional part
488+ d->omAlpha = 1.0f - d->alpha;
489+
490+ if ( d->outPoint == d->maxDelay ) d->outPoint = 0;
491+
492+ return 0;
493+}
494+
495+float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay)
496+{
497+ _tHermiteDelay* d = *dl;
498+
499+ uint32_t tap = d->inPoint - tapDelay - 1;
500+
501+ // Check for wraparound.
502+ while ( tap < 0 ) tap += d->maxDelay;
503+
504+ return d->buff[tap];
505+
506+}
507+
508+void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
509+{
510+ _tHermiteDelay* d = *dl;
511+
512+ int32_t tap = d->inPoint - tapDelay - 1;
513+
514+ // Check for wraparound.
515+ while ( tap < 0 ) tap += d->maxDelay;
516+
517+ d->buff[tap] = value;
518+}
519+
520+float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay)
521+{
522+ _tHermiteDelay* d = *dl;
523+
524+ int32_t tap = d->inPoint - tapDelay - 1;
525+
526+ // Check for wraparound.
527+ while ( tap < 0 ) tap += d->maxDelay;
528+
529+ return (d->buff[tap] += value);
530+}
531+
532+float tHermiteDelay_getDelay (tHermiteDelay* const dl)
533+{
534+ _tHermiteDelay* d = *dl;
535+ return d->delay;
536+}
537+
538+float tHermiteDelay_getLastOut (tHermiteDelay* const dl)
539+{
540+ _tHermiteDelay* d = *dl;
541+ return d->lastOut;
542+}
543+
544+float tHermiteDelay_getLastIn (tHermiteDelay* const dl)
545+{
546+ _tHermiteDelay* d = *dl;
547+ return d->lastIn;
548+}
549+
550+void tHermiteDelay_setGain (tHermiteDelay* const dl, float gain)
551+{
552+ _tHermiteDelay* d = *dl;
553+ if (gain < 0.0f) d->gain = 0.0f;
554+ else d->gain = gain;
555+}
556+
557+float tHermiteDelay_getGain (tHermiteDelay* const dl)
558+{
559+ _tHermiteDelay* d = *dl;
560+ return d->gain;
561+}
562+
563+
564+
565+
566+
567+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ AllpassDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
568+void tAllpassDelay_init (tAllpassDelay* const dl, float delay, uint32_t maxDelay)
569+{
570+ tAllpassDelay_initToPool(dl, delay, maxDelay, &leaf.mempool);
571+}
572+
573+void tAllpassDelay_free(tAllpassDelay* const dl)
574+{
575+ tAllpassDelay_freeFromPool(dl, &leaf.mempool);
576+}
577+
578+void tAllpassDelay_initToPool (tAllpassDelay* const dl, float delay, uint32_t maxDelay, tMempool* const mp)
579+{
580+ _tMempool* m = *mp;
581+ _tAllpassDelay* d = *dl = (_tAllpassDelay*) mpool_alloc(sizeof(_tAllpassDelay), m);
582+
583+ d->maxDelay = maxDelay;
584+
585+ if (delay > maxDelay) d->delay = maxDelay;
586+ else if (delay < 0.0f) d->delay = 0.0f;
587+ else d->delay = delay;
588+
589+ d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
590+
591+ d->gain = 1.0f;
592+
593+ d->lastIn = 0.0f;
594+ d->lastOut = 0.0f;
595+
596+ d->inPoint = 0;
597+ d->outPoint = 0;
598+
599+ tAllpassDelay_setDelay(dl, d->delay);
600+
601+ d->apInput = 0.0f;
602+}
603+
604+void tAllpassDelay_freeFromPool(tAllpassDelay* const dl, tMempool* const mp)
605+{
606+ _tMempool* m = *mp;
607+ _tAllpassDelay* d = *dl;
608+
609+ mpool_free((char*)d->buff, m);
610+ mpool_free((char*)d, m);
611+}
612+
613+void tAllpassDelay_clear(tAllpassDelay* const dl)
614+{
615+ _tAllpassDelay* d = *dl;
616+ for (int i = 0; i < d->maxDelay; i++)
617+ {
618+ d->buff[i] = 0;
619+ }
620+}
621+
622+float tAllpassDelay_tick (tAllpassDelay* const dl, float input)
623+{
624+ _tAllpassDelay* d = *dl;
625+
626+ d->buff[d->inPoint] = input * d->gain;
627+
628+ // Increment input pointer modulo length.
629+ if ( ++(d->inPoint) >= d->maxDelay ) d->inPoint = 0;
630+
631+ // Do allpass interpolation delay.
632+ float out = d->lastOut * -d->coeff;
633+ out += d->apInput + ( d->coeff * d->buff[d->outPoint] );
634+ d->lastOut = out;
635+
636+ // Save allpass input
637+ d->apInput = d->buff[d->outPoint];
638+
639+ // Increment output pointer modulo length.
640+ if (++(d->outPoint) >= d->maxDelay ) d->outPoint = 0;
641+
642+ return d->lastOut;
643+}
644+
645+int tAllpassDelay_setDelay (tAllpassDelay* const dl, float delay)
646+{
647+ _tAllpassDelay* d = *dl;
648+
649+ d->delay = LEAF_clip(0.5f, delay, d->maxDelay);
650+
651+ // outPoint chases inPoint
652+ float outPointer = (float)d->inPoint - d->delay + 1.0f;
653+
654+ while ( outPointer < 0 ) outPointer += d->maxDelay; // mod max length
655+
656+ d->outPoint = (uint32_t) outPointer; // integer part
657+
658+ if ( d->outPoint >= d->maxDelay ) d->outPoint = 0;
659+
660+ d->alpha = 1.0f + (float)d->outPoint - outPointer; // fractional part
661+
662+ if ( d->alpha < 0.5f )
663+ {
664+ // The optimal range for alpha is about 0.5 - 1.5 in order to
665+ // achieve the flattest phase delay response.
666+
667+ d->outPoint += 1;
668+
669+ if ( d->outPoint >= d->maxDelay ) d->outPoint -= d->maxDelay;
670+
671+ d->alpha += 1.0f;
672+ }
673+
674+ d->coeff = (1.0f - d->alpha) / (1.0f + d->alpha); // coefficient for allpass
675+
676+ return 0;
677+}
678+
679+float tAllpassDelay_tapOut (tAllpassDelay* const dl, uint32_t tapDelay)
680+{
681+ _tAllpassDelay* d = *dl;
682+
683+ int32_t tap = d->inPoint - tapDelay - 1;
684+
685+ // Check for wraparound.
686+ while ( tap < 0 ) tap += d->maxDelay;
687+
688+ return d->buff[tap];
689+
690+}
691+
692+void tAllpassDelay_tapIn (tAllpassDelay* const dl, float value, uint32_t tapDelay)
693+{
694+ _tAllpassDelay* d = *dl;
695+
696+ int32_t tap = d->inPoint - tapDelay - 1;
697+
698+ // Check for wraparound.
699+ while ( tap < 0 ) tap += d->maxDelay;
700+
701+ d->buff[tap] = value;
702+}
703+
704+float tAllpassDelay_addTo (tAllpassDelay* const dl, float value, uint32_t tapDelay)
705+{
706+ _tAllpassDelay* d = *dl;
707+
708+ int32_t tap = d->inPoint - tapDelay - 1;
709+
710+ // Check for wraparound.
711+ while ( tap < 0 ) tap += d->maxDelay;
712+
713+ return (d->buff[tap] += value);
714+}
715+
716+float tAllpassDelay_getDelay (tAllpassDelay* const dl)
717+{
718+ _tAllpassDelay* d = *dl;
719+ return d->delay;
720+}
721+
722+float tAllpassDelay_getLastOut (tAllpassDelay* const dl)
723+{
724+ _tAllpassDelay* d = *dl;
725+ return d->lastOut;
726+}
727+
728+float tAllpassDelay_getLastIn (tAllpassDelay* const dl)
729+{
730+ _tAllpassDelay* d = *dl;
731+ return d->lastIn;
732+}
733+
734+void tAllpassDelay_setGain (tAllpassDelay* const dl, float gain)
735+{
736+ _tAllpassDelay* d = *dl;
737+ if (gain < 0.0f) d->gain = 0.0f;
738+ else d->gain = gain;
739+}
740+
741+float tAllpassDelay_getGain (tAllpassDelay* const dl)
742+{
743+ _tAllpassDelay* d = *dl;
744+ return d->gain;
745+}
746+
747+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TapeDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
748+void tTapeDelay_init (tTapeDelay* const dl, float delay, uint32_t maxDelay)
749+{
750+ tTapeDelay_initToPool(dl, delay, maxDelay, &leaf.mempool);
751+}
752+
753+void tTapeDelay_free(tTapeDelay* const dl)
754+{
755+ tTapeDelay_freeFromPool(dl, &leaf.mempool);
756+}
757+
758+void tTapeDelay_initToPool (tTapeDelay* const dl, float delay, uint32_t maxDelay, tMempool* const mp)
759+{
760+ _tMempool* m = *mp;
761+ _tTapeDelay* d = *dl = (_tTapeDelay*) mpool_alloc(sizeof(_tTapeDelay), m);
762+
763+ d->maxDelay = maxDelay;
764+
765+ d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
766+
767+ d->gain = 1.0f;
768+
769+ d->lastIn = 0.0f;
770+ d->lastOut = 0.0f;
771+
772+ d->idx = 0.0f;
773+ d->inc = 1.0f;
774+ d->inPoint = 0;
775+
776+ tTapeDelay_setDelay(dl, delay);
777+}
778+
779+void tTapeDelay_freeFromPool(tTapeDelay* const dl, tMempool* const mp)
780+{
781+ _tMempool* m = *mp;
782+ _tTapeDelay* d = *dl;
783+
784+ mpool_free((char*)d->buff, m);
785+ mpool_free((char*)d, m);
786+}
787+
788+void tTapeDelay_clear(tTapeDelay* const dl)
789+{
790+ _tTapeDelay* d = *dl;
791+ for (int i = 0; i < d->maxDelay; i++)
792+ {
793+ d->buff[i] = 0;
794+ }
795+}
796+
797+//#define SMOOTH_FACTOR 10.f
798+
799+float tTapeDelay_tick (tTapeDelay* const dl, float input)
800+{
801+ _tTapeDelay* d = *dl;
802+
803+ d->buff[d->inPoint] = input * d->gain;
804+
805+ // Increment input pointer modulo length.
806+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
807+
808+ int idx = (int) d->idx;
809+ float alpha = d->idx - idx;
810+
811+ d->lastOut = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
812+ d->buff[idx],
813+ d->buff[(idx + 1) % d->maxDelay],
814+ d->buff[(idx + 2) % d->maxDelay],
815+ alpha);
816+
817+ float diff = (d->inPoint - d->idx);
818+ while (diff < 0.f) diff += d->maxDelay;
819+
820+ d->inc = 1.0f + (diff - d->delay) / d->delay; //* SMOOTH_FACTOR;
821+
822+ d->idx += d->inc;
823+
824+ if (d->idx >= d->maxDelay) d->idx = 0.0f;
825+
826+ if (d->lastOut)
827+ return d->lastOut;
828+ return 0.0f;
829+}
830+
831+void tTapeDelay_incrementInPoint(tTapeDelay* const dl)
832+{
833+ _tTapeDelay* d = *dl;
834+ // Increment input pointer modulo length.
835+ if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
836+}
837+
838+
839+void tTapeDelay_setRate(tTapeDelay* const dl, float rate)
840+{
841+ _tTapeDelay* d = *dl;
842+ d->inc = rate;
843+}
844+
845+void tTapeDelay_setDelay (tTapeDelay* const dl, float delay)
846+{
847+ _tTapeDelay* d = *dl;
848+ d->delay = LEAF_clip(1.f, delay, d->maxDelay);
849+}
850+
851+float tTapeDelay_tapOut (tTapeDelay* const dl, float tapDelay)
852+{
853+ _tTapeDelay* d = *dl;
854+
855+ float tap = (float) d->inPoint - tapDelay - 1.f;
856+
857+ // Check for wraparound.
858+ while ( tap < 0.f ) tap += (float)d->maxDelay;
859+
860+ int idx = (int) tap;
861+
862+ float alpha = tap - idx;
863+
864+ float samp = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
865+ d->buff[idx],
866+ d->buff[(idx + 1) % d->maxDelay],
867+ d->buff[(idx + 2) % d->maxDelay],
868+ alpha);
869+
870+ return samp;
871+
872+}
873+
874+void tTapeDelay_tapIn (tTapeDelay* const dl, float value, uint32_t tapDelay)
875+{
876+ _tTapeDelay* d = *dl;
877+
878+ int32_t tap = d->inPoint - tapDelay - 1;
879+
880+ // Check for wraparound.
881+ while ( tap < 0 ) tap += d->maxDelay;
882+
883+ d->buff[tap] = value;
884+}
885+
886+float tTapeDelay_addTo (tTapeDelay* const dl, float value, uint32_t tapDelay)
887+{
888+ _tTapeDelay* d = *dl;
889+
890+ int32_t tap = d->inPoint - tapDelay - 1;
891+
892+ // Check for wraparound.
893+ while ( tap < 0 ) tap += d->maxDelay;
894+
895+ return (d->buff[tap] += value);
896+}
897+
898+float tTapeDelay_getDelay (tTapeDelay *dl)
899+{
900+ _tTapeDelay* d = *dl;
901+ return d->delay;
902+}
903+
904+float tTapeDelay_getLastOut (tTapeDelay* const dl)
905+{
906+ _tTapeDelay* d = *dl;
907+ return d->lastOut;
908+}
909+
910+float tTapeDelay_getLastIn (tTapeDelay* const dl)
911+{
912+ _tTapeDelay* d = *dl;
913+ return d->lastIn;
914+}
915+
916+void tTapeDelay_setGain (tTapeDelay* const dl, float gain)
917+{
918+ _tTapeDelay* d = *dl;
919+ if (gain < 0.0f) d->gain = 0.0f;
920+ else d->gain = gain;
921+}
922+
923+float tTapeDelay_getGain (tTapeDelay* const dl)
924+{
925+ _tTapeDelay* d = *dl;
926+ return d->gain;
927+}
928+
leaf/Src/leaf-distortion.c+695−0
@@ -0,0 +1,695 @@
1+//
2+// leaf-distortion.c
3+// LEAF
4+//
5+// Created by Jeff Snyder, Matthew Wang, Michael Mulshine, and Joshua Becker
6+// Copyright © 2019 Princeton University. All rights reserved.
7+//
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-distortion.h"
12+#include "..\Inc\leaf-tables.h"
13+#else
14+
15+
16+#include "../Inc/leaf-distortion.h"
17+#include "../Inc/leaf-tables.h"
18+
19+#endif
20+
21+//============================================================================================================
22+// Sample-Rate reducer
23+//============================================================================================================
24+
25+
26+void tSampleReducer_init(tSampleReducer* const sr)
27+{
28+ _tSampleReducer* s = *sr = (_tSampleReducer*) leaf_alloc(sizeof(_tSampleReducer));
29+
30+ s->invRatio = 1.0f;
31+ s->hold = 0.0f;
32+ s->count = 0;
33+}
34+
35+void tSampleReducer_free (tSampleReducer* const sr)
36+{
37+ _tSampleReducer* s = *sr;
38+
39+ leaf_free((char*)s);
40+}
41+
42+void tSampleReducer_initToPool (tSampleReducer* const sr, tMempool* const mp)
43+{
44+ _tMempool* m = *mp;
45+ _tSampleReducer* s = *sr = (_tSampleReducer*) mpool_alloc(sizeof(_tSampleReducer), m);
46+
47+ s->invRatio = 1.0f;
48+ s->hold = 0.0f;
49+ s->count = 0;
50+}
51+
52+void tSampleReducer_freeFromPool (tSampleReducer* const sr, tMempool* const mp)
53+{
54+ _tMempool* m = *mp;
55+ _tSampleReducer* s = *sr;
56+
57+ mpool_free((char*)s, m);
58+}
59+
60+float tSampleReducer_tick(tSampleReducer* const sr, float input)
61+{
62+ _tSampleReducer* s = *sr;
63+ if (s->count > s->invRatio)
64+ {
65+ s->hold = input;
66+ s->count = 0;
67+ }
68+
69+ s->count++;
70+ return s->hold;
71+}
72+
73+
74+void tSampleReducer_setRatio(tSampleReducer* const sr, float ratio)
75+{
76+ _tSampleReducer* s = *sr;
77+ if ((ratio <= 1.0f) && (ratio >= 0.0f))
78+ s->invRatio = 1.0f / ratio;
79+
80+}
81+
82+//============================================================================================================
83+// Oversampler
84+//============================================================================================================
85+// Latency is equal to the phase length (numTaps / ratio)
86+void tOversampler_init(tOversampler* const osr, int ratio, oBool extraQuality)
87+{
88+ _tOversampler* os = *osr = (_tOversampler*) leaf_alloc(sizeof(_tOversampler));
89+
90+ uint8_t offset = 0;
91+ if (extraQuality) offset = 6;
92+ if (ratio == 2 || ratio == 4 ||
93+ ratio == 8 || ratio == 16 ||
94+ ratio == 32 || ratio == 64) {
95+ os->ratio = ratio;
96+ int idx = (int)(log2f(os->ratio))-1+offset;
97+ os->numTaps = __leaf_tablesize_firNumTaps[idx];
98+ os->phaseLength = os->numTaps / os->ratio;
99+ os->pCoeffs = (float*) __leaf_tableref_firCoeffs[idx];
100+ os->upState = (float*) leaf_alloc(sizeof(float) * os->numTaps * 2);
101+ os->downState = (float*) leaf_alloc(sizeof(float) * os->numTaps * 2);
102+ }
103+}
104+
105+void tOversampler_free(tOversampler* const osr)
106+{
107+ _tOversampler* os = *osr;
108+
109+ leaf_free((char*)os->upState);
110+ leaf_free((char*)os->downState);
111+ leaf_free((char*)os);
112+}
113+
114+void tOversampler_initToPool (tOversampler* const osr, int ratio, oBool extraQuality, tMempool* const mp)
115+{
116+ _tMempool* m = *mp;
117+ _tOversampler* os = *osr = (_tOversampler*) mpool_alloc(sizeof(_tOversampler), m);
118+
119+ uint8_t offset = 0;
120+ if (extraQuality) offset = 6;
121+ if (ratio == 2 || ratio == 4 ||
122+ ratio == 8 || ratio == 16 ||
123+ ratio == 32 || ratio == 64) {
124+ os->ratio = ratio;
125+ int idx = (int)(log2f(os->ratio))-1+offset;
126+ os->numTaps = __leaf_tablesize_firNumTaps[idx];
127+ os->phaseLength = os->numTaps / os->ratio;
128+ os->pCoeffs = (float*) __leaf_tableref_firCoeffs[idx];
129+ os->upState = (float*) mpool_alloc(sizeof(float) * os->numTaps * 2, m);
130+ os->downState = (float*) mpool_alloc(sizeof(float) * os->numTaps * 2, m);
131+ }
132+}
133+
134+void tOversampler_freeFromPool (tOversampler* const osr, tMempool* const mp)
135+{
136+ _tMempool* m = *mp;
137+ _tOversampler* os = *osr;
138+
139+ mpool_free((char*)os->upState, m);
140+ mpool_free((char*)os->downState, m);
141+ mpool_free((char*)os, m);
142+}
143+
144+float tOversampler_tick(tOversampler* const osr, float input, float (*effectTick)(float))
145+{
146+ _tOversampler* os = *osr;
147+
148+ float buf[os->ratio];
149+
150+ tOversampler_upsample(osr, input, buf);
151+
152+ for (int i = 0; i < os->ratio; ++i) {
153+ buf[i] = effectTick(buf[i]);
154+ }
155+
156+ return tOversampler_downsample(osr, buf);
157+}
158+
159+// From CMSIS DSP Library
160+void tOversampler_upsample(tOversampler* const osr, float input, float* output)
161+{
162+ _tOversampler* os = *osr;
163+
164+ float *pState = os->upState; /* State pointer */
165+ float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
166+ float *pStateCur;
167+ float *ptr1; /* Temporary pointer for state buffer */
168+ float *ptr2; /* Temporary pointer for coefficient buffer */
169+ float sum0; /* Accumulators */
170+ uint32_t i, tapCnt; /* Loop counters */
171+ uint32_t phaseLen = os->phaseLength; /* Length of each polyphase filter component */
172+ uint32_t j;
173+
174+ /* os->pState buffer contains previous frame (phaseLen - 1) samples */
175+ /* pStateCur points to the location where the new input data should be written */
176+ pStateCur = os->upState + (phaseLen - 1U);
177+
178+ /* Copy new input sample into the state buffer */
179+ *pStateCur = input;
180+
181+ /* Address modifier index of coefficient buffer */
182+ j = 1U;
183+
184+ /* Loop over the Interpolation factor. */
185+ i = os->ratio;
186+
187+ while (i > 0U)
188+ {
189+ /* Set accumulator to zero */
190+ sum0 = 0.0f;
191+
192+ /* Initialize state pointer */
193+ ptr1 = pState;
194+
195+ /* Initialize coefficient pointer */
196+ ptr2 = pCoeffs + (os->ratio - j);
197+
198+ /* Loop over the polyPhase length.
199+ Repeat until we've computed numTaps-(4*os->L) coefficients. */
200+
201+ /* Initialize tapCnt with number of samples */
202+ tapCnt = phaseLen;
203+
204+ while (tapCnt > 0U)
205+ {
206+ /* Perform the multiply-accumulate */
207+ sum0 += *ptr1++ * *ptr2;
208+
209+ /* Upsampling is done by stuffing L-1 zeros between each sample.
210+ * So instead of multiplying zeros with coefficients,
211+ * Increment the coefficient pointer by interpolation factor times. */
212+ ptr2 += os->ratio;
213+
214+ /* Decrement loop counter */
215+ tapCnt--;
216+ }
217+
218+ /* The result is in the accumulator, store in the destination buffer. */
219+ *output++ = sum0 * os->ratio;
220+
221+ /* Increment the address modifier index of coefficient buffer */
222+ j++;
223+
224+ /* Decrement the loop counter */
225+ i--;
226+ }
227+
228+ /* Advance the state pointer by 1
229+ * to process the next group of interpolation factor number samples */
230+ pState = pState + 1;
231+
232+ /* Processing is complete.
233+ Now copy the last phaseLen - 1 samples to the satrt of the state buffer.
234+ This prepares the state buffer for the next function call. */
235+
236+ /* Points to the start of the state buffer */
237+ pStateCur = os->upState;
238+
239+ /* Initialize tapCnt with number of samples */
240+ tapCnt = (phaseLen - 1U);
241+
242+ /* Copy data */
243+ while (tapCnt > 0U)
244+ {
245+ *pStateCur++ = *pState++;
246+
247+ /* Decrement loop counter */
248+ tapCnt--;
249+ }
250+}
251+
252+// From CMSIS DSP Library
253+float tOversampler_downsample(tOversampler *const osr, float* input)
254+{
255+ _tOversampler* os = *osr;
256+
257+ float *pState = os->downState; /* State pointer */
258+ float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
259+ float *pStateCur; /* Points to the current sample of the state */
260+ float *px0; /* Temporary pointer for state buffer */
261+ float *pb; /* Temporary pointer for coefficient buffer */
262+ float x0, c0; /* Temporary variables to hold state and coefficient values */
263+ float acc0; /* Accumulator */
264+ uint32_t numTaps = os->numTaps; /* Number of filter coefficients in the filter */
265+ uint32_t i, tapCnt;
266+ float output;
267+
268+ /* os->pState buffer contains previous frame (numTaps - 1) samples */
269+ /* pStateCur points to the location where the new input data should be written */
270+ pStateCur = os->downState + (numTaps - 1U);
271+
272+ /* Copy decimation factor number of new input samples into the state buffer */
273+ i = os->ratio;
274+
275+ do
276+ {
277+ *pStateCur++ = *input++;
278+
279+ } while (--i);
280+
281+ /* Set accumulator to zero */
282+ acc0 = 0.0f;
283+
284+ /* Initialize state pointer */
285+ px0 = pState;
286+
287+ /* Initialize coeff pointer */
288+ pb = pCoeffs;
289+
290+ /* Initialize tapCnt with number of taps */
291+ tapCnt = numTaps;
292+
293+ while (tapCnt > 0U)
294+ {
295+ /* Read coefficients */
296+ c0 = *pb++;
297+
298+ /* Fetch 1 state variable */
299+ x0 = *px0++;
300+
301+ /* Perform the multiply-accumulate */
302+ acc0 += x0 * c0;
303+
304+ /* Decrement loop counter */
305+ tapCnt--;
306+ }
307+
308+ /* Advance the state pointer by the decimation factor
309+ * to process the next group of decimation factor number samples */
310+ pState = pState + os->ratio;
311+
312+ /* The result is in the accumulator, store in the destination buffer. */
313+ output = acc0;
314+
315+ /* Processing is complete.
316+ Now copy the last numTaps - 1 samples to the start of the state buffer.
317+ This prepares the state buffer for the next function call. */
318+
319+ /* Points to the start of the state buffer */
320+ pStateCur = os->downState;
321+
322+ /* Initialize tapCnt with number of taps */
323+ tapCnt = (numTaps - 1U);
324+
325+ /* Copy data */
326+ while (tapCnt > 0U)
327+ {
328+ *pStateCur++ = *pState++;
329+
330+ /* Decrement loop counter */
331+ tapCnt--;
332+ }
333+
334+ return output;
335+}
336+
337+int tOversampler_getLatency(tOversampler* const osr)
338+{
339+ _tOversampler* os = *osr;
340+ return os->phaseLength;
341+}
342+
343+//============================================================================================================
344+// WAVEFOLDER
345+//============================================================================================================
346+
347+
348+//from the paper: Virtual Analog Model of the Lockhart Wavefolder
349+//by Fabián Esqueda, Henri Pöntynen, Julian D. Parker and Stefan Bilbao
350+
351+void tLockhartWavefolder_init(tLockhartWavefolder* const wf)
352+{
353+ tLockhartWavefolder_initToPool (wf, &leaf.mempool);
354+}
355+
356+void tLockhartWavefolder_free(tLockhartWavefolder* const wf)
357+{
358+ _tLockhartWavefolder* w = *wf;
359+
360+ leaf_free((char*)w);
361+}
362+
363+void tLockhartWavefolder_initToPool (tLockhartWavefolder* const wf, tMempool* const mp)
364+{
365+ _tMempool* m = *mp;
366+ _tLockhartWavefolder* w = *wf = (_tLockhartWavefolder*) mpool_alloc(sizeof(_tLockhartWavefolder), m);
367+
368+ w->Ln1 = 0.0;
369+ w->Fn1 = 0.0;
370+ w->xn1 = 0.0;
371+
372+ w->RL = 7.5e3;
373+ w->R = 15e3;
374+ w->VT = 26e-3;
375+ w->Is = 10e-16;
376+
377+ w->a = 2.0*w->RL/w->R;
378+ w->b = (w->R+2.0*w->RL)/(w->VT*w->R);
379+ w->d = (w->RL*w->Is)/w->VT;
380+ w->half_a = 0.5 * w->a;
381+ w->longthing = (0.5*w->VT/w->b);
382+
383+
384+ // Antialiasing error threshold
385+ w->AAthresh = 10e-10; //10
386+
387+ w->LambertThresh = 10e-10; //12 //was 8
388+
389+
390+ w->w = 0.0f;
391+ w->expw = 0.0f;
392+ w->p = 0.0f;
393+ w->r = 0.0f;
394+ w->s= 0.0f;
395+ w->myerr = 0.0f;
396+ w->l = 0.0f;
397+ w->u = 0.0f;
398+ w->Ln = 0.0f;
399+ w->Fn = 0.0f;
400+ w->tempsDenom = 0.0f;
401+ w->tempErrDenom = 0.0f;
402+ w->tempOutDenom = 0.0f;
403+
404+
405+}
406+
407+void tLockhartWavefolder_freeFromPool (tLockhartWavefolder* const wf, tMempool* const mp)
408+{
409+ _tMempool* m = *mp;
410+ _tLockhartWavefolder* w = *wf;
411+
412+ mpool_free((char*)w, m);
413+}
414+
415+
416+
417+double tLockhartWavefolderLambert(tLockhartWavefolder* const wf, double x, double ln)
418+{
419+ _tLockhartWavefolder* mwf = *wf;
420+
421+
422+ // Initial guess (use previous value)
423+ mwf->w = ln;
424+
425+ // Haley's method (Sec. 4.2 of the paper)
426+ for(int i=0; i<3000; i+=1) { //1000
427+
428+ mwf->expw = exp(mwf->w);
429+ /*
430+ if (isinf(mwf->expw) || isnan(mwf->expw))
431+ {
432+ mwf->expw = 10e-5;
433+ LEAF_error();
434+ }
435+ */
436+ mwf->p = mwf->w*mwf->expw - x;
437+ /*
438+ if (isinf(mwf->p) || isnan(mwf->p))
439+ {
440+ mwf->p = 10e-5;
441+ LEAF_error();
442+ }
443+ */
444+ mwf->r = (mwf->w+1.0)*mwf->expw;
445+ /*
446+ if (isinf(mwf->r) || isnan(mwf->r))
447+ {
448+ mwf->r = 10e-5;
449+ LEAF_error();
450+ }
451+ */
452+ mwf->tempsDenom = (2.0*(mwf->w+1.0));
453+ /*
454+ if ((mwf->tempsDenom == 0.0) || isinf(mwf->tempsDenom) || isnan(mwf->tempsDenom))
455+ {
456+ mwf->tempsDenom = 10e-5;
457+ LEAF_error();
458+ }
459+ */
460+ mwf->s = (mwf->w+2.0)/mwf->tempsDenom;
461+ /*
462+ if (isnan(mwf->s) || isinf(mwf->s))
463+ {
464+ mwf->s = 10e-5;
465+ LEAF_error();
466+ }
467+ */
468+ mwf->tempErrDenom = (mwf->r-(mwf->p*mwf->s));
469+ /*
470+ if ((mwf->tempErrDenom == 0.0) || isinf(mwf->tempErrDenom) || isnan(mwf->tempErrDenom))
471+ {
472+ mwf->tempErrDenom = 10e-5;
473+ LEAF_error();
474+ }
475+ */
476+ mwf->myerr = (mwf->p/mwf->tempErrDenom);
477+ /*
478+ if (isnan(mwf->myerr) || isinf(mwf->myerr))
479+ {
480+ mwf->myerr = 10e-5;
481+ LEAF_error();
482+ }
483+ */
484+
485+ if ((fabs(mwf->myerr))<mwf->LambertThresh) {
486+
487+ break;
488+ }
489+
490+ mwf->w = mwf->w - mwf->myerr;
491+
492+ /*
493+ if (isinf(mwf->w) || isnan(mwf->w))
494+ {
495+ mwf->w = 10e-5;
496+ LEAF_error();
497+ }
498+*/
499+
500+ }
501+ return mwf->w;
502+}
503+
504+float tLockhartWavefolder_tick(tLockhartWavefolder* const wf, float in)
505+{
506+ _tLockhartWavefolder* w = *wf;
507+
508+ float out = 0.0f;
509+
510+ // Compute Antiderivative
511+ w->l = (in > 0.0) - (in < 0.0);
512+ w->u = w->d*exp(w->l*w->b*in);
513+ /*
514+ if ((w->u == 0.0) || isinf(w->u) || isnan(w->u))
515+ {
516+ w->u = 10e-5;
517+ LEAF_error();
518+ }
519+ */
520+
521+ w->Ln = tLockhartWavefolderLambert(wf,w->u,w->Ln1);
522+ /*
523+ if ((w->Ln == 0.0) || isinf(w->Ln) || isnan(w->Ln))
524+ {
525+ w->Ln = 10e-5;
526+ LEAF_error();
527+ }
528+*/
529+ w->Fn = (w->longthing*(w->Ln*(w->Ln + 2.0))) - (w->half_a*in*in);
530+ /*
531+ if ((w->Fn == 0.0) || isinf(w->Fn) || isnan(w->Fn))
532+ {
533+ w->Fn = 10e-5;
534+ LEAF_error();
535+ }
536+ */
537+ // Check for ill-conditioning
538+
539+ if (fabs(in-w->xn1)<w->AAthresh)
540+ {
541+
542+ // Compute Averaged Wavefolder Output
543+ double xn = 0.5*(in+w->xn1);
544+ w->u = w->d*exp(w->l*w->b*xn);
545+ /*
546+ if ((w->u == 0.0) || isinf(w->u) || isnan(w->u))
547+ {
548+ w->u = 10e-5;
549+ LEAF_error();
550+
551+ }
552+ */
553+ w->Ln = tLockhartWavefolderLambert(wf,w->u,w->Ln1);
554+ /*
555+ if ((w->Ln == 0.0) || isinf(w->Ln) || isnan(w->Ln))
556+ {
557+ w->Ln = 10e-5;
558+ LEAF_error();
559+ }
560+ */
561+ out = (float)((w->l*w->VT*w->Ln) - (w->a*xn));
562+
563+ }
564+ else
565+ {
566+
567+ // Apply AA Form
568+ w->tempOutDenom = (in-w->xn1);
569+ /*
570+ if ((w->tempOutDenom == 0.0) || isinf(w->tempOutDenom))
571+ {
572+ w->tempOutDenom = 10e-5;
573+ LEAF_error();
574+ }
575+ */
576+ out = ((w->Fn-w->Fn1)/w->tempOutDenom);
577+ /*
578+ if (isinf(out) || isnan(out))
579+ {
580+ out = 10e-5;
581+ LEAF_error();
582+ }
583+ */
584+
585+ }
586+
587+ // Update States
588+ w->Ln1 = w->Ln;
589+ w->Fn1 = w->Fn;
590+ w->xn1 = (double)in;
591+
592+ return out;
593+}
594+
595+//============================================================================================================
596+// CRUSHER
597+//============================================================================================================
598+#define SCALAR 5000.f
599+
600+void tCrusher_init (tCrusher* const cr)
601+{
602+ _tCrusher* c = *cr = (_tCrusher*) leaf_alloc(sizeof(_tCrusher));
603+
604+ c->op = 4;
605+ c->div = SCALAR;
606+ c->rnd = 0.25f;
607+ c->srr = 0.25f;
608+ tSampleReducer_init(&c->sReducer);
609+ c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
610+}
611+
612+void tCrusher_free (tCrusher* const cr)
613+{
614+ _tCrusher* c = *cr;
615+ tSampleReducer_free(&c->sReducer);
616+ leaf_free((char*)c);
617+}
618+
619+void tCrusher_initToPool (tCrusher* const cr, tMempool* const mp)
620+{
621+ _tMempool* m = *mp;
622+ _tCrusher* c = *cr = (_tCrusher*) mpool_alloc(sizeof(_tCrusher), m);
623+
624+ c->op = 4;
625+ c->div = SCALAR;
626+ c->rnd = 0.25f;
627+ c->srr = 0.25f;
628+ tSampleReducer_initToPool(&c->sReducer, mp);
629+ c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
630+}
631+
632+void tCrusher_freeFromPool (tCrusher* const cr, tMempool* const mp)
633+{
634+ _tMempool* m = *mp;
635+ _tCrusher* c = *cr;
636+ tSampleReducer_freeFromPool(&c->sReducer, mp);
637+ mpool_free((char*)c, m);
638+}
639+
640+float tCrusher_tick (tCrusher* const cr, float input)
641+{
642+ _tCrusher* c = *cr;
643+
644+ float sample = input;
645+
646+ sample *= SCALAR; // SCALAR is 5000 by default
647+
648+ sample = (int32_t) sample;
649+
650+ sample /= c->div;
651+
652+ sample = LEAF_bitwise_xor(sample, c->op << 23);
653+
654+ sample = LEAF_clip(-1.f, sample, 1.f);
655+
656+ sample = LEAF_round(sample, c->rnd);
657+
658+ sample = tSampleReducer_tick(&c->sReducer, sample);
659+
660+ return sample * c->gain;
661+
662+}
663+
664+void tCrusher_setOperation (tCrusher* const cr, float op)
665+{
666+ _tCrusher* c = *cr;
667+ c->op = (uint32_t) (op * 8.0f);
668+}
669+
670+// 0.0 - 1.0
671+void tCrusher_setQuality (tCrusher* const cr, float val)
672+{
673+ _tCrusher* c = *cr;
674+
675+ val = LEAF_clip(0.0f, val, 1.0f);
676+
677+ c->div = 0.01f + val * SCALAR;
678+
679+ c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
680+}
681+
682+// what decimal to round to
683+void tCrusher_setRound (tCrusher* const cr, float rnd)
684+{
685+ _tCrusher* c = *cr;
686+ c->rnd = fabsf(rnd);
687+}
688+
689+void tCrusher_setSamplingRatio (tCrusher* const cr, float ratio)
690+{
691+ _tCrusher* c = *cr;
692+ c->srr = ratio;
693+ tSampleReducer_setRatio(&c->sReducer, ratio);
694+
695+}
leaf/Src/leaf-dynamics.c+281−0
@@ -0,0 +1,281 @@
1+/*==============================================================================
2+
3+ leaf-dynamics.c
4+ Created: 30 Nov 2018 11:56:49am
5+ Author: airship
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-dynamics.h"
12+
13+#else
14+
15+#include "../Inc/leaf-dynamics.h"
16+
17+#endif
18+
19+//==============================================================================
20+
21+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compressor ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
22+
23+/*
24+ tCompressor* tCompressorInit(int tauAttack, int tauRelease)
25+ {
26+ tCompressor* c = &leaf.tCompressorRegistry[leaf.registryIndex[T_COMPRESSOR]++];
27+
28+ c->tauAttack = tauAttack;
29+ c->tauRelease = tauRelease;
30+
31+ c->x_G[0] = 0.0f, c->x_G[1] = 0.0f,
32+ c->y_G[0] = 0.0f, c->y_G[1] = 0.0f,
33+ c->x_T[0] = 0.0f, c->x_T[1] = 0.0f,
34+ c->y_T[0] = 0.0f, c->y_T[1] = 0.0f;
35+
36+ c->T = 0.0f; // Threshold
37+ c->R = 1.0f; // compression Ratio
38+ c->M = 0.0f; // decibel Make-up gain
39+ c->W = 0.0f; // decibel Width of knee transition
40+
41+ return c;
42+ }
43+ */
44+void tCompressor_init(tCompressor* const comp)
45+{
46+ _tCompressor* c = *comp = (_tCompressor*) leaf_alloc(sizeof(_tCompressor));
47+
48+ c->tauAttack = 100;
49+ c->tauRelease = 100;
50+
51+ c->isActive = OFALSE;
52+
53+ c->T = 0.0f; // Threshold
54+ c->R = 0.5f; // compression Ratio
55+ c->M = 3.0f; // decibel Width of knee transition
56+ c->W = 1.0f; // decibel Make-up gain
57+}
58+
59+void tCompressor_free(tCompressor* const comp)
60+{
61+ _tCompressor* c = *comp;
62+
63+ leaf_free((char*)c);
64+}
65+
66+void tCompressor_initToPool (tCompressor* const comp, tMempool* const mp)
67+{
68+ _tMempool* m = *mp;
69+ _tCompressor* c = *comp = (_tCompressor*) mpool_alloc(sizeof(_tCompressor), m);
70+
71+ c->tauAttack = 100;
72+ c->tauRelease = 100;
73+
74+ c->isActive = OFALSE;
75+
76+ c->T = 0.0f; // Threshold
77+ c->R = 0.5f; // compression Ratio
78+ c->M = 3.0f; // decibel Width of knee transition
79+ c->W = 1.0f; // decibel Make-up gain
80+}
81+
82+void tCompressor_freeFromPool(tCompressor* const comp, tMempool* const mp)
83+{
84+ _tMempool* m = *mp;
85+ _tCompressor* c = *comp;
86+
87+ mpool_free((char*)c, m);
88+}
89+
90+float tCompressor_tick(tCompressor* const comp, float in)
91+{
92+ _tCompressor* c = *comp;
93+
94+ float slope, overshoot;
95+ float alphaAtt, alphaRel;
96+
97+ float in_db = 20.0f * log10f( fmaxf( fabsf( in), 0.000001f)), out_db = 0.0f;
98+
99+ c->y_T[1] = c->y_T[0];
100+
101+ slope = c->R - 1.0f; // feed-forward topology; was 1/C->R - 1
102+
103+ overshoot = in_db - c->T;
104+
105+
106+ if (overshoot <= -(c->W * 0.5f))
107+ {
108+ out_db = in_db;
109+ c->isActive = OFALSE;
110+ }
111+ else if ((overshoot > -(c->W * 0.5f)) && (overshoot < (c->W * 0.5f)))
112+ {
113+ out_db = in_db + slope * (powf((overshoot + c->W*0.5f),2) / (2.0f * c->W)); // .^ 2 ???
114+ c->isActive = OTRUE;
115+ }
116+ else if (overshoot >= (c->W * 0.5f))
117+ {
118+ out_db = in_db + slope * overshoot;
119+ c->isActive = OTRUE;
120+ }
121+
122+
123+
124+ c->x_T[0] = out_db - in_db;
125+
126+ alphaAtt = expf(-1.0f/(0.001f * c->tauAttack * leaf.sampleRate));
127+ alphaRel = expf(-1.0f/(0.001f * c->tauRelease * leaf.sampleRate));
128+
129+ if (c->x_T[0] > c->y_T[1])
130+ c->y_T[0] = alphaAtt * c->y_T[1] + (1-alphaAtt) * c->x_T[0];
131+ else
132+ c->y_T[0] = alphaRel * c->y_T[1] + (1-alphaRel) * c->x_T[0];
133+
134+ float attenuation = powf(10.0f, ((c->M - c->y_T[0])/20.0f));
135+
136+ return attenuation * in;
137+}
138+
139+/* Feedback Leveler */
140+
141+void tFeedbackLeveler_init(tFeedbackLeveler* const fb, float targetLevel, float factor, float strength, int mode)
142+{
143+ _tFeedbackLeveler* p = *fb = (_tFeedbackLeveler*) leaf_alloc(sizeof(_tFeedbackLeveler));
144+
145+ p->curr=0.0f;
146+ p->targetLevel=targetLevel;
147+ tPowerFollower_init(&p->pwrFlw,factor);
148+ p->mode=mode;
149+ p->strength=strength;
150+}
151+
152+void tFeedbackLeveler_free(tFeedbackLeveler* const fb)
153+{
154+ _tFeedbackLeveler* p = *fb;
155+
156+ tPowerFollower_free(&p->pwrFlw);
157+ leaf_free((char*)p);
158+}
159+
160+void tFeedbackLeveler_initToPool (tFeedbackLeveler* const fb, float targetLevel, float factor, float strength, int mode, tMempool* const mp)
161+{
162+ _tMempool* m = *mp;
163+ _tFeedbackLeveler* p = *fb = (_tFeedbackLeveler*) mpool_alloc(sizeof(_tFeedbackLeveler), m);
164+
165+ p->curr=0.0f;
166+ p->targetLevel=targetLevel;
167+ tPowerFollower_initToPool(&p->pwrFlw,factor, mp);
168+ p->mode=mode;
169+ p->strength=strength;
170+}
171+
172+void tFeedbackLeveler_freeFromPool (tFeedbackLeveler* const fb, tMempool* const mp)
173+{
174+ _tMempool* m = *mp;
175+ _tFeedbackLeveler* p = *fb;
176+
177+ tPowerFollower_freeFromPool(&p->pwrFlw, mp);
178+ mpool_free((char*)p, m);
179+}
180+
181+void tFeedbackLeveler_setStrength(tFeedbackLeveler* const fb, float strength)
182+{ // strength is how strongly level diff is affecting the amp ratio
183+ // try 0.125 for a start
184+ _tFeedbackLeveler* p = *fb;
185+ p->strength=strength;
186+}
187+
188+void tFeedbackLeveler_setFactor(tFeedbackLeveler* const fb, float factor)
189+{
190+ _tFeedbackLeveler* p = *fb;
191+ tPowerFollower_setFactor(&p->pwrFlw,factor);
192+}
193+
194+void tFeedbackLeveler_setMode(tFeedbackLeveler* const fb, int mode)
195+{ // 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting)
196+ _tFeedbackLeveler* p = *fb;
197+ p->mode=mode;
198+}
199+
200+float tFeedbackLeveler_tick(tFeedbackLeveler* const fb, float input)
201+{
202+ _tFeedbackLeveler* p = *fb;
203+ float levdiff=(tPowerFollower_tick(&p->pwrFlw, input)-p->targetLevel);
204+ if (p->mode==0 && levdiff<0.0f) levdiff=0.0f;
205+ p->curr=input*(1.0f-p->strength*levdiff);
206+ return p->curr;
207+}
208+
209+float tFeedbackLeveler_sample(tFeedbackLeveler* const fb)
210+{
211+ _tFeedbackLeveler* p = *fb;
212+ return p->curr;
213+}
214+
215+
216+void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const fb, float TargetLevel)
217+{
218+ _tFeedbackLeveler* p = *fb;
219+ p->targetLevel=TargetLevel;
220+}
221+
222+
223+
224+void tThreshold_init(tThreshold* const th, float low, float high)
225+{
226+ tThreshold_initToPool(th, low, high, &leaf.mempool);
227+}
228+
229+void tThreshold_free(tThreshold* const th)
230+{
231+ tThreshold_freeFromPool(th, &leaf.mempool);
232+}
233+
234+void tThreshold_initToPool (tThreshold* const th, float low, float high, tMempool* const mp)
235+{
236+ _tMempool* m = *mp;
237+ _tThreshold* t = *th = (_tThreshold*) mpool_alloc(sizeof(_tThreshold), m);
238+
239+ t->highThresh = high;
240+ t->lowThresh = low;
241+
242+ t->currentValue = 0;
243+}
244+
245+void tThreshold_freeFromPool(tThreshold* const th, tMempool* const mp)
246+{
247+ _tMempool* m = *mp;
248+ _tThreshold* t = *th;
249+
250+ mpool_free((char*)t, m);
251+}
252+
253+int tThreshold_tick(tThreshold* const th, float in)
254+{
255+ _tThreshold* t = *th;
256+
257+ if (in >= t->highThresh)
258+ {
259+ t->currentValue = 1;
260+ }
261+ else if (in <= t->lowThresh)
262+ {
263+ t->currentValue = 0;
264+ }
265+
266+ return t->currentValue;
267+}
268+
269+void tThreshold_setLow(tThreshold* const th, float low)
270+{
271+ _tThreshold* t = *th;
272+
273+ t->lowThresh = low;
274+}
275+
276+void tThreshold_setHigh(tThreshold* const th, float high)
277+{
278+ _tThreshold* t = *th;
279+
280+ t->highThresh = high;
281+}
leaf/Src/leaf-effects.c+1853−0
@@ -0,0 +1,1853 @@
1+/*==============================================================================
2+
3+ leaf-vocoder.c
4+ Created: 20 Jan 2017 12:01:54pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-effects.c"
12+#include "..\leaf.h"
13+
14+#else
15+
16+#include "../Inc/leaf-effects.h"
17+#include "../leaf.h"
18+
19+#endif
20+
21+
22+
23+//============================================================================================================
24+// TALKBOX
25+//============================================================================================================
26+
27+//LPC vocoder adapted from MDA's excellent open source talkbox plugin code
28+void tTalkbox_init(tTalkbox* const voc, int bufsize)
29+{
30+
31+ _tTalkbox* v = *voc = (_tTalkbox*) leaf_alloc(sizeof(_tTalkbox));
32+
33+ v->param[0] = 0.5f; //wet
34+ v->param[1] = 0.0f; //dry
35+ v->param[2] = 0; // Swap
36+ v->param[3] = 1.0f; //quality
37+ v->warpFactor = 0.0f;
38+ v->warpOn = 0;
39+ v->bufsize = bufsize;
40+
41+ v->car0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
42+ v->car1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
43+ v->window = (float*) leaf_alloc(sizeof(float) * v->bufsize);
44+ v->buf0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
45+ v->buf1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
46+
47+ tTalkbox_update(voc);
48+ tTalkbox_suspend(voc);
49+}
50+
51+void tTalkbox_free(tTalkbox* const voc)
52+{
53+ _tTalkbox* v = *voc;
54+
55+ leaf_free((char*)v->buf1);
56+ leaf_free((char*)v->buf0);
57+ leaf_free((char*)v->window);
58+ leaf_free((char*)v->car1);
59+ leaf_free((char*)v->car0);
60+
61+ leaf_free((char*)v);
62+}
63+
64+void tTalkbox_initToPool (tTalkbox* const voc, int bufsize, tMempool* const mp)
65+{
66+ _tMempool* m = *mp;
67+ _tTalkbox* v = *voc = (_tTalkbox*) mpool_alloc(sizeof(_tTalkbox), m);
68+
69+ v->param[0] = 0.5f; //wet
70+ v->param[1] = 0.0f; //dry
71+ v->param[2] = 0; // Swap
72+ v->param[3] = 1.0f; //quality
73+ v->warpFactor = 0.0f;
74+ v->warpOn = 0;
75+ v->bufsize = bufsize;
76+
77+ v->car0 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
78+ v->car1 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
79+ v->window = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
80+ v->buf0 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
81+ v->buf1 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
82+
83+ tTalkbox_update(voc);
84+ tTalkbox_suspend(voc);
85+}
86+
87+void tTalkbox_freeFromPool (tTalkbox* const voc, tMempool* const mp)
88+{
89+ _tMempool* m = *mp;
90+ _tTalkbox* v = *voc;
91+
92+ mpool_free((char*)v->buf1, m);
93+ mpool_free((char*)v->buf0, m);
94+ mpool_free((char*)v->window, m);
95+ mpool_free((char*)v->car1, m);
96+ mpool_free((char*)v->car0, m);
97+
98+ mpool_free((char*)v, m);
99+}
100+
101+void tTalkbox_update(tTalkbox* const voc) ///update internal parameters...
102+{
103+ _tTalkbox* v = *voc;
104+
105+ float fs = leaf.sampleRate;
106+ if(fs < 8000.0f) fs = 8000.0f;
107+ if(fs > 96000.0f) fs = 96000.0f;
108+
109+ int32_t n = (int32_t)(0.01633f * fs); //this sets the window time to 16ms if the buffer is large enough. Buffer needs to be at least 784 samples at 48000
110+ if(n > v->bufsize) n = v->bufsize;
111+
112+ //O = (VstInt32)(0.0005f * fs);
113+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs);
114+
115+ if(n != v->N) //recalc hanning window
116+ {
117+ v->N = n;
118+ float dp = TWO_PI / v->N;
119+ float p = 0.0f;
120+ for(n=0; n<v->N; n++)
121+ {
122+ v->window[n] = 0.5f - 0.5f * cosf(p);
123+ p += dp;
124+ }
125+ }
126+ v->wet = 0.5f * v->param[0] * v->param[0];
127+ v->dry = 2.0f * v->param[1] * v->param[1];
128+}
129+
130+void tTalkbox_suspend(tTalkbox* const voc) ///clear any buffers...
131+{
132+ _tTalkbox* v = *voc;
133+
134+ v->pos = v->K = 0;
135+ v->emphasis = 0.0f;
136+ v->FX = 0;
137+
138+ v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f;
139+ v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f;
140+
141+ for (int32_t i = 0; i < v->bufsize; i++)
142+ {
143+ v->buf0[i] = 0;
144+ v->buf1[i] = 0;
145+ v->car0[i] = 0;
146+ v->car1[i] = 0;
147+ }
148+}
149+
150+// warped autocorrelation adapted from ten.enegatum@liam's post on music-dsp 2004-04-07 09:37:51
151+//find the order-P autocorrelation array, R, for the sequence x of length L and warping of lambda
152+//wAutocorrelate(&pfSrc[stIndex],siglen,R,P,0);
153+void tTalkbox_warpedAutocorrelate(float * x, unsigned int L, float * R, unsigned int P, float lambda)
154+{
155+ double dl[L];
156+ double Rt[L];
157+ double r1,r2,r1t;
158+ R[0]=0;
159+ Rt[0]=0;
160+ r1=0;
161+ r2=0;
162+ r1t=0;
163+ for(int32_t k=0; k<L;k++)
164+ {
165+ Rt[0] += (double)(x[k]) * (double)(x[k]);
166+
167+ dl[k]= r1 - (double)(lambda) * (double)(x[k]-r2);
168+ r1 = x[k];
169+ r2 = dl[k];
170+ }
171+ for(int32_t i=1; i<=P; i++)
172+ {
173+ Rt[i]=0;
174+ r1=0;
175+ r2=0;
176+ for(unsigned int k=0; k<L;k++)
177+ {
178+ Rt[i] += (double) (dl[k]) * (double)(x[k]);
179+
180+ r1t = dl[k];
181+ dl[k]= r1 - (double)(lambda) * (double)(r1t-r2);
182+ r1 = r1t;
183+ r2 = dl[k];
184+ }
185+ }
186+ for(int32_t i=0; i<=P; i++)
187+ {
188+ R[i]=(float)(Rt[i]);
189+ }
190+
191+}
192+
193+
194+
195+#define ORD_MAX 35 // Was 100.
196+// order is defined by the set_quality function.
197+// it's set to max out at 0.0005 of sample rate (if you don't go above 1.0f in the quality setting) == at 48000 that's 24.
198+// -JS
199+void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o, float warp, int warpOn)
200+{
201+ float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x;
202+ int32_t i, j, nn=n;
203+
204+ if (warpOn == 0)
205+ {
206+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
207+ {
208+ z[j] = r[j] = 0.0f;
209+ for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
210+ }
211+ }
212+ else
213+ {
214+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
215+ {
216+ z[j] = r[j] = 0.0f;
217+ }
218+ tTalkbox_warpedAutocorrelate(buf, n, r, o, warp);
219+ }
220+
221+ r[0] *= 1.001f; //stability fix
222+
223+ float min = 0.00001f;
224+ if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; }
225+
226+ tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs
227+
228+ //this is for stability to keep reflection coefficients inside the unit circle
229+ //but in Harma's papers I've seen 0.998. just needs to be less than 1 it seems but maybe some wiggle room to avoid instability from floating point precision -JS
230+ for(i=0; i<=o; i++)
231+ {
232+ if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f;
233+ }
234+
235+ for(i=0; i<n; i++)
236+ {
237+ x = G * car[i];
238+ for(j=o; j>0; j--) //lattice filter
239+ {
240+ x -= k[j] * z[j-1];
241+ z[j] = z[j-1] + k[j] * x;
242+ }
243+ buf[i] = z[0] = x; //output buf[] will be windowed elsewhere
244+ }
245+}
246+
247+
248+void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g)
249+{
250+ int i, j;
251+ float a[ORD_MAX], at[ORD_MAX], e=r[0];
252+
253+ for(i=0; i<=p; i++) a[i] = 0.0f; //probably don't need to clear at[] or k[]
254+ at[0] = 0.0f;
255+ for(i=1; i<=p; i++)
256+ {
257+ k[i] = -r[i];
258+
259+ for(j=1; j<i; j++)
260+ {
261+ at[j] = a[j];
262+ k[i] -= a[j] * r[i-j];
263+ }
264+ if(fabs(e) < 1.0e-20f) { e = 0.0f; break; }
265+ k[i] /= e;
266+
267+ a[i] = k[i];
268+ for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
269+
270+ e *= 1.0f - k[i] * k[i];
271+ }
272+
273+ if(e < 1.0e-20f) e = 0.0f;
274+ *g = sqrtf(e);
275+}
276+
277+float tTalkbox_tick(tTalkbox* const voc, float synth, float voice)
278+{
279+ _tTalkbox* v = *voc;
280+
281+ int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N;
282+ float e=v->emphasis, w, o, x, fx=v->FX;
283+ float p, q, h0=0.3f, h1=0.77f;
284+
285+ o = voice;
286+ x = synth;
287+
288+
289+
290+ p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p;
291+ q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q;
292+ v->d4 = x;
293+ x = p + q;
294+
295+ if(v->K++)
296+ {
297+ v->K = 0;
298+
299+ v->car0[p0] = v->car1[p1] = x; //carrier input
300+
301+ x = o - e; e = o; //6dB/oct pre-emphasis
302+
303+ w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows
304+ if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O, v->warpFactor, v->warpOn); p0 = 0; }
305+
306+ w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w;
307+ if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O, v->warpFactor, v->warpOn); p1 = 0; }
308+ }
309+
310+ p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p;
311+ q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q;
312+ v->u4 = fx;
313+ x = p + q;
314+
315+ o = x;
316+
317+ v->emphasis = e;
318+ v->pos = p0;
319+ v->FX = fx;
320+
321+
322+ return o;
323+}
324+
325+void tTalkbox_setQuality(tTalkbox* const voc, float quality)
326+{
327+ _tTalkbox* v = *voc;
328+
329+ v->param[3] = quality;
330+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate);
331+ if (v->O >= ORD_MAX)
332+ {
333+ v->O = ORD_MAX-1;
334+ }
335+}
336+
337+void tTalkbox_setWarpFactor(tTalkbox* const voc, float warpFactor)
338+{
339+ _tTalkbox* v = *voc;
340+
341+ v->warpFactor = warpFactor;
342+}
343+
344+void tTalkbox_setWarpOn(tTalkbox* const voc, float warpOn)
345+{
346+ _tTalkbox* v = *voc;
347+
348+ v->warpOn = warpOn;
349+}
350+
351+
352+//============================================================================================================
353+// VOCODER
354+//============================================================================================================
355+
356+void tVocoder_init (tVocoder* const voc)
357+{
358+ _tVocoder* v = *voc = (_tVocoder*) leaf_alloc(sizeof(_tVocoder));
359+
360+ v->param[0] = 0.33f; //input select
361+ v->param[1] = 0.50f; //output dB
362+ v->param[2] = 0.40f; //hi thru
363+ v->param[3] = 0.40f; //hi band
364+ v->param[4] = 0.16f; //envelope
365+ v->param[5] = 0.55f; //filter q
366+ v->param[6] = 0.6667f;//freq range
367+ v->param[7] = 0.33f; //num bands
368+
369+ tVocoder_update(voc);
370+}
371+
372+void tVocoder_free (tVocoder* const voc)
373+{
374+ _tVocoder* v = *voc;
375+
376+ leaf_free((char*)v);
377+}
378+
379+void tVocoder_initToPool (tVocoder* const voc, tMempool* const mp)
380+{
381+ _tMempool* m = *mp;
382+ _tVocoder* v = *voc = (_tVocoder*) mpool_alloc(sizeof(_tVocoder), m);
383+
384+ v->param[0] = 0.33f; //input select
385+ v->param[1] = 0.50f; //output dB
386+ v->param[2] = 0.40f; //hi thru
387+ v->param[3] = 0.40f; //hi band
388+ v->param[4] = 0.16f; //envelope
389+ v->param[5] = 0.55f; //filter q
390+ v->param[6] = 0.6667f;//freq range
391+ v->param[7] = 0.33f; //num bands
392+
393+ tVocoder_update(voc);
394+}
395+
396+void tVocoder_freeFromPool (tVocoder* const voc, tMempool* const mp)
397+{
398+ _tMempool* m = *mp;
399+ _tVocoder* v = *voc;
400+
401+ mpool_free((char*)v, m);
402+}
403+
404+void tVocoder_update (tVocoder* const voc)
405+{
406+ _tVocoder* v = *voc;
407+
408+ float tpofs = 6.2831853f * leaf.invSampleRate;
409+
410+ float rr, th, re;
411+
412+ float sh;
413+
414+ int32_t i;
415+
416+ v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f);
417+
418+ v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]);
419+ v->high = v->param[3] * v->param[3] * v->param[3] * v->thru;
420+ v->thru *= v->param[2] * v->param[2] * v->param[2];
421+
422+ if(v->param[7]<0.5f)
423+ {
424+ v->nbnd=8;
425+ re=0.003f;
426+ v->f[1][2] = 3000.0f;
427+ v->f[2][2] = 2200.0f;
428+ v->f[3][2] = 1500.0f;
429+ v->f[4][2] = 1080.0f;
430+ v->f[5][2] = 700.0f;
431+ v->f[6][2] = 390.0f;
432+ v->f[7][2] = 190.0f;
433+ }
434+ else
435+ {
436+ v->nbnd=16;
437+ re=0.0015f;
438+ v->f[ 1][2] = 5000.0f; //+1000
439+ v->f[ 2][2] = 4000.0f; //+750
440+ v->f[ 3][2] = 3250.0f; //+500
441+ v->f[ 4][2] = 2750.0f; //+450
442+ v->f[ 5][2] = 2300.0f; //+300
443+ v->f[ 6][2] = 2000.0f; //+250
444+ v->f[ 7][2] = 1750.0f; //+250
445+ v->f[ 8][2] = 1500.0f; //+250
446+ v->f[ 9][2] = 1250.0f; //+250
447+ v->f[10][2] = 1000.0f; //+250
448+ v->f[11][2] = 750.0f; //+210
449+ v->f[12][2] = 540.0f; //+190
450+ v->f[13][2] = 350.0f; //+155
451+ v->f[14][2] = 195.0f; //+100
452+ v->f[15][2] = 95.0f;
453+ }
454+
455+ if(v->param[4]<0.05f) //freeze
456+ {
457+ for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f;
458+ }
459+ else
460+ {
461+ v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed
462+
463+ rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion
464+ for(i=1;i<v->nbnd;i++)
465+ {
466+ v->f[i][12] = (float)(0.025 - rr * (double)i);
467+ if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12];
468+ }
469+ v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate
470+ }
471+
472+ rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]);
473+ sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift
474+
475+ for(i=1;i<v->nbnd;i++)
476+ {
477+ v->f[i][2] *= sh;
478+ th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
479+ v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0
480+ v->f[i][1] = (float)(-rr * rr); //a1
481+ //was .98
482+ v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks
483+ th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
484+ v->f[i][2] = (float)(2.0 * rr * cos(th));
485+ }
486+}
487+
488+float tVocoder_tick (tVocoder* const voc, float synth, float voice)
489+{
490+ _tVocoder* v = *voc;
491+
492+ float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp;
493+ uint32_t i, k = v->kval, nb = v->nbnd;
494+
495+ a = voice; //speech
496+ b = synth; //synth
497+
498+ tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis
499+ v->f[0][7] = a;
500+ a = tmp;
501+
502+ if(tmp<0.0f) tmp = -tmp;
503+ v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope
504+ o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru
505+
506+ v->f[0][3] = b; //integrate carrier for HF band
507+
508+ if(++k & 0x1) //this block runs at half sample rate
509+ {
510+ oo = 0.0f;
511+ aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson
512+ v->f[0][9] = v->f[0][8]; v->f[0][8] = a;
513+ bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4];
514+ v->f[0][5] = v->f[0][4]; v->f[0][4] = b;
515+
516+ for(i=1; i<nb; i++) //filter bank: 4th-order band pass
517+ {
518+ tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb;
519+ v->f[i][4] = v->f[i][3];
520+ v->f[i][3] = tmp;
521+ tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6];
522+ v->f[i][6] = v->f[i][5];
523+ v->f[i][5] = tmp;
524+
525+ tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa;
526+ v->f[i][8] = v->f[i][7];
527+ v->f[i][7] = tmp;
528+ tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10];
529+ v->f[i][10] = v->f[i][9];
530+ v->f[i][9] = tmp;
531+
532+ if(tmp<0.0f) tmp = -tmp;
533+ v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp);
534+ oo += v->f[i][5] * v->f[i][11];
535+ }
536+ }
537+ o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz)
538+
539+ v->kout = oo;
540+ v->kval = k & 0x1;
541+ if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal
542+
543+ for(i=1;i<nb;i++)
544+ if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10)
545+ for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals
546+
547+ if(fabs(o)>10.0f) tVocoder_suspend(voc); //catch instability
548+
549+ return o;
550+
551+}
552+
553+void tVocoder_suspend (tVocoder* const voc)
554+{
555+ _tVocoder* v = *voc;
556+
557+ int32_t i, j;
558+
559+ for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes
560+ v->kout = 0.0f;
561+ v->kval = 0;
562+}
563+
564+
565+
566+/// Glottal Pulse (Rosenberg model)
567+
568+void tRosenbergGlottalPulse_init (tRosenbergGlottalPulse* const gp)
569+{
570+ tRosenbergGlottalPulse_initToPool(gp, &leaf.mempool);
571+}
572+void tRosenbergGlottalPulse_free (tRosenbergGlottalPulse* const gp)
573+{
574+ tRosenbergGlottalPulse_freeFromPool(gp, &leaf.mempool);
575+}
576+void tRosenbergGlottalPulse_initToPool (tRosenbergGlottalPulse* const gp, tMempool* const mp)
577+{
578+
579+ _tMempool* m = *mp;
580+ _tRosenbergGlottalPulse* g = *gp = (_tRosenbergGlottalPulse*) mpool_alloc(sizeof(_tRosenbergGlottalPulse), m);
581+
582+ g->phase = 0.0f;
583+ g->openLength = 0.0f;
584+ g->pulseLength = 0.0f;
585+ g->freq = 0.0f;
586+ g->inc = 0.0f;
587+
588+
589+}
590+void tRosenbergGlottalPulse_freeFromPool (tRosenbergGlottalPulse* const gp, tMempool* const mp)
591+{
592+ _tMempool* m = *mp;
593+ _tRosenbergGlottalPulse* g = *gp;
594+ mpool_free((char*)g, m);
595+}
596+
597+float tRosenbergGlottalPulse_tick (tRosenbergGlottalPulse* const gp)
598+{
599+ _tRosenbergGlottalPulse* g = *gp;
600+
601+ float output = 0.0f;
602+
603+ // Phasor increment
604+ g->phase += g->inc;
605+ while (g->phase >= 1.0f) g->phase -= 1.0f;
606+ while (g->phase < 0.0f) g->phase += 1.0f;
607+
608+ if (g->phase < g->openLength)
609+ {
610+ output = 0.5f*(1.0f-cosf(PI * g->phase));
611+ }
612+
613+ else if (g->phase < g->pulseLength)
614+ {
615+ output = cosf(HALF_PI * (g->phase-g->openLength)/(g->pulseLength-g->openLength));
616+ }
617+
618+ else
619+ {
620+ output = 0.0f;
621+ }
622+ return output;
623+}
624+
625+void tRosenbergGlottalPulse_setFreq (tRosenbergGlottalPulse* const gp, float freq)
626+{
627+ _tRosenbergGlottalPulse* g = *gp;
628+ g->freq = freq;
629+ g->inc = freq * leaf.invSampleRate;
630+}
631+
632+void tRosenbergGlottalPulse_setOpenLength (tRosenbergGlottalPulse* const gp, float openLength)
633+{
634+ _tRosenbergGlottalPulse* g = *gp;
635+ g->openLength = openLength;
636+}
637+
638+void tRosenbergGlottalPulse_setPulseLength (tRosenbergGlottalPulse* const gp, float pulseLength)
639+{
640+ _tRosenbergGlottalPulse* g = *gp;
641+ g->pulseLength = pulseLength;
642+}
643+
644+
645+
646+
647+//============================================================================================================
648+// SOLAD
649+//============================================================================================================
650+/******************************************************************************/
651+/***************** static function declarations *******************************/
652+/******************************************************************************/
653+
654+static void solad_init(_tSOLAD *w);
655+static inline float read_sample(_tSOLAD *w, float floatindex);
656+static void pitchdown(_tSOLAD *w, float *out);
657+static void pitchup(_tSOLAD *w, float *out);
658+
659+/******************************************************************************/
660+/***************** public access functions ************************************/
661+/******************************************************************************/
662+
663+// init
664+void tSOLAD_init(tSOLAD* const wp)
665+{
666+ _tSOLAD* w = *wp = (_tSOLAD*) leaf_calloc(sizeof(_tSOLAD));
667+
668+ w->pitchfactor = 1.;
669+ w->delaybuf = (float*) leaf_calloc(sizeof(float) * (LOOPSIZE+16));
670+
671+ solad_init(w);
672+}
673+
674+void tSOLAD_free(tSOLAD* const wp)
675+{
676+ _tSOLAD* w = *wp;
677+
678+ leaf_free((char*)w->delaybuf);
679+ leaf_free((char*)w);
680+}
681+
682+void tSOLAD_initToPool (tSOLAD* const wp, tMempool* const mp)
683+{
684+ _tMempool* m = *mp;
685+
686+ _tSOLAD* w = *wp = (_tSOLAD*) mpool_calloc(sizeof(_tSOLAD), m);
687+
688+ w->pitchfactor = 1.;
689+ w->delaybuf = (float*) mpool_calloc(sizeof(float) * (LOOPSIZE+16), m);
690+
691+ solad_init(w);
692+}
693+
694+void tSOLAD_freeFromPool (tSOLAD* const wp, tMempool* const mp)
695+{
696+ _tMempool* m = *mp;
697+ _tSOLAD* w = *wp;
698+
699+ mpool_free((char*)w->delaybuf, m);
700+ mpool_free((char*)w, m);
701+}
702+
703+// send one block of input samples, receive one block of output samples
704+void tSOLAD_ioSamples(tSOLAD* const wp, float* in, float* out, int blocksize)
705+{
706+ _tSOLAD* w = *wp;
707+
708+ int i = w->timeindex;
709+ int n = w->blocksize = blocksize;
710+
711+ if(!i) w->delaybuf[LOOPSIZE] = in[0]; // copy one sample for interpolation
712+ while(n--) w->delaybuf[i++] = *in++; // copy one input block to delay buffer
713+
714+ if(w->pitchfactor > 1) pitchup(w, out);
715+ else pitchdown(w, out);
716+
717+ w->timeindex += blocksize;
718+ w->timeindex &= LOOPMASK;
719+}
720+
721+// set periodicity analysis data
722+void tSOLAD_setPeriod(tSOLAD* const wp, float period)
723+{
724+ _tSOLAD* w = *wp;
725+
726+ if(period > MAXPERIOD) period = MAXPERIOD;
727+ if(period > MINPERIOD) w->period = period; // ignore period when too small
728+}
729+
730+// set pitch factor between 0.25 and 4
731+void tSOLAD_setPitchFactor(tSOLAD* const wp, float pitchfactor)
732+{
733+ _tSOLAD* w = *wp;
734+
735+ if (pitchfactor <= 0.0f) return;
736+ w->pitchfactor = pitchfactor;
737+}
738+
739+// force readpointer lag
740+void tSOLAD_setReadLag(tSOLAD* const wp, float readlag)
741+{
742+ _tSOLAD* w = *wp;
743+
744+ if(readlag < 0) readlag = 0;
745+ if(readlag < w->readlag) // do not jump backward, only forward
746+ {
747+ w->jump = w->readlag - readlag;
748+ w->readlag = readlag;
749+ w->xfadelength = readlag;
750+ w->xfadevalue = 1;
751+ }
752+}
753+
754+// reset state variables
755+void tSOLAD_resetState(tSOLAD* const wp)
756+{
757+ _tSOLAD* w = *wp;
758+
759+ int n = LOOPSIZE + 1;
760+ float *buf = w->delaybuf;
761+
762+ while(n--) *buf++ = 0;
763+ solad_init(w);
764+}
765+
766+/******************************************************************************/
767+/******************** private procedures **************************************/
768+/******************************************************************************/
769+
770+/*
771+ Function pitchdown() is called to read samples from the delay buffer when pitch
772+ factor is between 0.25 and 1. The read pointer lags behind because of the slowed
773+ down speed, and it must jump forward towards the write pointer soon as there is
774+ sufficient space to jump. That is, if there is at least one period of the input
775+ signal between read pointer and write pointer. When short periods follow up on
776+ long periods, the read pointer may have space to jump over more than one period
777+ lenghts. Jump length must be [periodlength ^ 2] in any case.
778+
779+ A linear crossfade function joins the jump-from point with the jump-to point.
780+ The crossfade must be completed before another read pointer jump is allowed.
781+ Length of the crossfade function is stored as a number of samples in terms of
782+ the input sample rate. This length is dynamically translated
783+ to a crossfade length expressed in output reading rate, according to pitch
784+ factor which can change before the crossfade is completed. Crossfade length does
785+ not cover an invariable length in periods for all pitch transposition factors.
786+ For pitch factors from 0.5 till 1, crossfade length is stretched in the
787+ output just as much as the signal itself, as crossfade speed is set to equal
788+ pitch factor. For pitch factors below 0.5, the read pointer wants to jump
789+ forward before one period is read, therefore the crossfade length as expressed
790+ in output periods must be shorter. Crossfade speed is set to [1 - pitchfactor]
791+ for those cases. Pitch factor 0.5 is the natural switch point between crossfade
792+ speeds [pitchfactor] and [1 - pitchfactor] because 0.5 == 1 - 0.5. The crossfade
793+ speed modification for pitch factors below 0.5 also means that much of the
794+ original signal content will be skipped.
795+ */
796+
797+
798+static void pitchdown(_tSOLAD* const w, float *out)
799+{
800+ int n = w->blocksize;
801+ float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values!
802+ float pitchfactor = w->pitchfactor;
803+ float period = w->period;
804+ float readlag = w->readlag;
805+ float readlagstep = 1 - pitchfactor;
806+ float jump = w->jump;
807+ float xfadevalue = w->xfadevalue;
808+ float xfadelength = w->xfadelength;
809+ float xfadespeed, xfadestep, readindex, outputsample;
810+
811+ if(pitchfactor > 0.5) xfadespeed = pitchfactor;
812+ else xfadespeed = 1 - pitchfactor;
813+ xfadestep = xfadespeed / xfadelength;
814+
815+ while(n--)
816+ {
817+ if(readlag > period) // check if read pointer may jump forward...
818+ {
819+ if(xfadevalue <= 0) // ...but do not interrupt crossfade
820+ {
821+ jump = period; // jump forward
822+ while((jump * 2) < readlag) jump *= 2; // use available space
823+ readlag -= jump; // reduce read pointer lag
824+ xfadevalue = 1; // start crossfade
825+ xfadelength = period - 1;
826+ xfadestep = xfadespeed / xfadelength;
827+ }
828+ }
829+
830+ readindex = refindex - readlag;
831+ outputsample = read_sample(w, readindex);
832+
833+ if(xfadevalue > 0)
834+ {
835+ outputsample *= (1 - xfadevalue); // fadein
836+ outputsample += read_sample(w, readindex - jump) * xfadevalue; // fadeout
837+ xfadevalue -= xfadestep;
838+ }
839+
840+ *out++ = outputsample;
841+ refindex += 1;
842+ readlag += readlagstep;
843+ }
844+
845+ w->jump = jump; // state variables
846+ w->readlag = readlag;
847+ w->xfadevalue = xfadevalue;
848+ w->xfadelength = xfadelength;
849+}
850+
851+
852+/*
853+ Function pitchup() for pitch factors above 1 is more complicated than
854+ pitchdown(). The read pointer increments faster than the write pointer and a
855+ backward jump must happen in time, reckoning with the crossfade region. The read
856+ pointer backward jump length is always one period. In order to minimize the area
857+ of signal duplicates, crossfade length is aimed at [period / pitchfactor].
858+ This leads to a crossfade speed of [pitchfactor * pitchfactor].
859+
860+ Some samples for the fade out (but not all of them) must already be in the
861+ buffer, otherwise we will run out of input samples before the crossfade is
862+ completed. The ratio of past samples and future samples for a crossfade of any
863+ length is as follows:
864+
865+ past samples: xfadelength * (1 - 1 / pitchfactor)
866+ future samples: xfadelength * (1 / pitchfactor)
867+
868+ For example in the case of pitch factor 1.5 this would be:
869+
870+ past samples: xfadelength * (1 - 1 / 1.5) = xfadelength * 1 / 3
871+ future samples: xfadelength * (1 / 1.5) = xfadelength * 2 / 3
872+
873+ In the case of pitch factor 4 this would be:
874+
875+ past samples: xfadelength * (1 - 1 / 4) = xfadelength * 3 / 4
876+ future samples: xfadelength * (1 / 4) = xfadelength * 1 / 4
877+
878+ The read pointer lag must therefore preserve a minimum dependent on pitch
879+ factor. The minimum is called 'limit' here:
880+
881+ limit = period * (pitchfactor - 1) / pitchfactor * pitchfactor
882+
883+ Components of this expression are combined to reuse them in operations, while
884+ (pitchfactor - 1) is changed to (pitchfactor - 0.99) to avoid numerical
885+ resolution issues for pitch factors slightly above 1:
886+
887+ xfadespeed = pitchfactor * pitchfactor
888+ limitfactor = (pitchfactor - 0.99) / xfadespeed
889+ limit = period * limitfactor
890+
891+ When read lag is smaller than this limit, the read pointer must preferably
892+ jump backward, unless a previous crossfade is not yet completed. Crossfades must
893+ preferably be completed, unless the read pointer lag becomes smaller than zero.
894+ With fluctuating period lengths and pitch factors, the readpointer lag limit may
895+ change from one input block to the next in such a way that the actual lag is
896+ suddenly much smaller than the limit, and the intended crossfade length can not
897+ be applied. Therefore the crossfade length is simply calculated from the
898+ available amount of samples for all cases, like so:
899+
900+ xfadelength = readlag / limitfactor
901+
902+ For most occurrences, this will amount to a crossfade length reduced to
903+ [period / pitchfactor] in the output for pitch factors above 1, while in some
904+ cases it will be considerably shorter. Fortunately, an incidental aberration of
905+ the intended crossfade length hardly ever creates an audible artifact. The
906+ reason to specify preferred crossfade length according to pitch factor is to
907+ minimize the impression of echoes without sacrificing too much of the signal
908+ content. The readpointer jump length remains one period in any case.
909+
910+ Sometimes, the input signal periodicity may decrease substantially between one
911+ signal block and the next. In such cases it may be possible for the read pointer
912+ to jump forward and reduce latency. For every signal block, a check on this
913+ possibility is done. A previous crossfade must be completed before a forward
914+ jump is allowed.
915+ */
916+static void pitchup(_tSOLAD* const w, float *out)
917+{
918+ int n = w->blocksize;
919+ float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values
920+ float pitchfactor = w->pitchfactor;
921+ float period = w->period;
922+ float readlag = w->readlag;
923+ float jump = w->jump;
924+ float xfadevalue = w->xfadevalue;
925+ float xfadelength = w->xfadelength;
926+
927+ float readlagstep = pitchfactor - 1;
928+ float xfadespeed = pitchfactor * pitchfactor;
929+ float xfadestep = xfadespeed / xfadelength;
930+ float limitfactor = (pitchfactor - (float)0.99) / xfadespeed;
931+ float limit = period * limitfactor;
932+ float readindex, outputsample;
933+
934+ if((readlag > (period + 2 * limit)) & (xfadevalue < 0))
935+ {
936+ jump = period; // jump forward
937+ while((jump * 2) < (readlag - 2 * limit)) jump *= 2; // use available space
938+ readlag -= jump; // reduce read pointer lag
939+ xfadevalue = 1; // start crossfade
940+ xfadelength = period - 1;
941+ xfadestep = xfadespeed / xfadelength;
942+ }
943+
944+ while(n--)
945+ {
946+ if(readlag < limit) // check if read pointer should jump backward...
947+ {
948+ if((xfadevalue < 0) | (readlag < 0)) // ...but try not to interrupt crossfade
949+ {
950+ xfadelength = readlag / limitfactor;
951+ if(xfadelength < 1) xfadelength = 1;
952+ xfadestep = xfadespeed / xfadelength;
953+
954+ jump = -period; // jump backward
955+ readlag += period; // increase read pointer lag
956+ xfadevalue = 1; // start crossfade
957+ }
958+ }
959+
960+ readindex = refindex - readlag;
961+ outputsample = read_sample(w, readindex);
962+
963+ if(xfadevalue > 0)
964+ {
965+ outputsample *= (1 - xfadevalue);
966+ outputsample += read_sample(w, readindex - jump) * xfadevalue;
967+ xfadevalue -= xfadestep;
968+ }
969+
970+ *out++ = outputsample;
971+ refindex += 1;
972+ readlag -= readlagstep;
973+ }
974+
975+ w->readlag = readlag; // state variables
976+ w->jump = jump;
977+ w->xfadelength = xfadelength;
978+ w->xfadevalue = xfadevalue;
979+}
980+
981+// read one sample from delay buffer, with linear interpolation
982+static inline float read_sample(_tSOLAD* const w, float floatindex)
983+{
984+ int index = (int)floatindex;
985+ float fraction = floatindex - (float)index;
986+ float *buf = w->delaybuf;
987+ index &= LOOPMASK;
988+
989+ return (buf[index] + (fraction * (buf[index+1] - buf[index])));
990+}
991+
992+static void solad_init(_tSOLAD* const w)
993+{
994+ w->timeindex = 0;
995+ w->xfadevalue = -1;
996+ w->period = INITPERIOD;
997+ w->readlag = INITPERIOD;
998+ w->blocksize = INITPERIOD;
999+}
1000+
1001+//============================================================================================================
1002+// PITCHSHIFT
1003+//============================================================================================================
1004+
1005+static int pitchshift_attackdetect(_tPitchShift* ps)
1006+{
1007+ float envout;
1008+
1009+ _tPeriodDetection* p = *ps->p;
1010+
1011+ envout = tEnvPD_tick(&p->env);
1012+
1013+ if (envout >= 1.0f)
1014+ {
1015+ p->lastmax = p->max;
1016+ if (envout > p->max)
1017+ {
1018+ p->max = envout;
1019+ }
1020+ else
1021+ {
1022+ p->deltamax = envout - p->max;
1023+ p->max = p->max * ps->radius;
1024+ }
1025+ p->deltamax = p->max - p->lastmax;
1026+ }
1027+
1028+ p->fba = p->fba ? (p->fba - 1) : 0;
1029+
1030+ return (p->fba == 0 && (p->max > 60 && p->deltamax > 6)) ? 1 : 0;
1031+}
1032+
1033+void tPitchShift_init (tPitchShift* const psr, tPeriodDetection* pd, float* out, int bufSize)
1034+{
1035+ _tPitchShift* ps = *psr = (_tPitchShift*) leaf_calloc(sizeof(_tPitchShift));
1036+ _tPeriodDetection* p = *pd;
1037+
1038+ ps->p = pd;
1039+
1040+ ps->outBuffer = out;
1041+ ps->bufSize = bufSize;
1042+ ps->frameSize = p->frameSize;
1043+ ps->framesPerBuffer = ps->bufSize / ps->frameSize;
1044+ ps->curBlock = 1;
1045+ ps->lastBlock = 0;
1046+ ps->index = 0;
1047+ ps->pitchFactor = 1.0f;
1048+
1049+ tSOLAD_init(&ps->sola);
1050+
1051+ tHighpass_init(&ps->hp, HPFREQ);
1052+
1053+ tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
1054+}
1055+
1056+void tPitchShift_free(tPitchShift* const psr)
1057+{
1058+ _tPitchShift* ps = *psr;
1059+
1060+ tSOLAD_free(&ps->sola);
1061+ tHighpass_free(&ps->hp);
1062+ leaf_free((char*)ps);
1063+}
1064+
1065+void tPitchShift_initToPool (tPitchShift* const psr, tPeriodDetection* const pd, float* out, int bufSize, tMempool* const mp)
1066+{
1067+ _tMempool* m = *mp;
1068+
1069+ _tPitchShift* ps = *psr = (_tPitchShift*) mpool_calloc(sizeof(_tPitchShift), m);
1070+
1071+ _tPeriodDetection* p = *pd;
1072+
1073+ ps->p = pd;
1074+
1075+ ps->outBuffer = out;
1076+ ps->bufSize = bufSize;
1077+ ps->frameSize = p->frameSize;
1078+ ps->framesPerBuffer = ps->bufSize / ps->frameSize;
1079+ ps->curBlock = 1;
1080+ ps->lastBlock = 0;
1081+ ps->index = 0;
1082+ ps->pitchFactor = 1.0f;
1083+
1084+ tSOLAD_initToPool(&ps->sola, mp);
1085+
1086+ tHighpass_initToPool(&ps->hp, HPFREQ, mp);
1087+
1088+ tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
1089+}
1090+
1091+void tPitchShift_freeFromPool (tPitchShift* const psr, tMempool* const mp)
1092+{
1093+ _tMempool* m = *mp;
1094+ _tPitchShift* ps = *psr;
1095+
1096+ tSOLAD_freeFromPool(&ps->sola, mp);
1097+ tHighpass_freeFromPool(&ps->hp, mp);
1098+ mpool_free((char*)ps, m);
1099+}
1100+
1101+void tPitchShift_setPitchFactor(tPitchShift* psr, float pf)
1102+{
1103+ _tPitchShift* ps = *psr;
1104+
1105+ ps->pitchFactor = pf;
1106+}
1107+
1108+float tPitchShift_shift (tPitchShift* psr)
1109+{
1110+ _tPitchShift* ps = *psr;
1111+ _tPeriodDetection* p = *ps->p;
1112+
1113+ float period, out;
1114+ int i, iLast;
1115+
1116+ i = p->i;
1117+ iLast = p->iLast;
1118+
1119+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
1120+
1121+ if (p->indexstore >= ps->frameSize)
1122+ {
1123+ period = tPeriodDetection_getPeriod(&p);
1124+
1125+ if(pitchshift_attackdetect(ps) == 1)
1126+ {
1127+ p->fba = 5;
1128+ tSOLAD_setReadLag(&ps->sola, p->windowSize);
1129+ }
1130+
1131+ tSOLAD_setPeriod(&ps->sola, period);
1132+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
1133+
1134+ tSOLAD_ioSamples(&ps->sola, &(p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
1135+ }
1136+
1137+ return out;
1138+}
1139+
1140+float tPitchShift_shiftToFreq (tPitchShift* psr, float freq)
1141+{
1142+ _tPitchShift* ps = *psr;
1143+ _tPeriodDetection* p = *ps->p;
1144+
1145+ float period, out;
1146+ int i, iLast;
1147+
1148+ i = p->i;
1149+ iLast = p->iLast;
1150+
1151+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
1152+
1153+ if (p->indexstore >= ps->frameSize)
1154+ {
1155+ period = tPeriodDetection_getPeriod(&p);
1156+
1157+ if(pitchshift_attackdetect(ps) == 1)
1158+ {
1159+ p->fba = 5;
1160+ tSOLAD_setReadLag(&ps->sola, p->windowSize);
1161+ }
1162+
1163+ tSOLAD_setPeriod(&ps->sola, period);
1164+
1165+ if (period != 0) ps->pitchFactor = period*freq*leaf.invSampleRate;
1166+ else ps->pitchFactor = 1.0f;
1167+
1168+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
1169+
1170+ tSOLAD_ioSamples(&ps->sola, &(p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
1171+ }
1172+ return out;
1173+}
1174+
1175+float tPitchShift_shiftToFunc (tPitchShift* psr, float (*fun)(float))
1176+{
1177+ _tPitchShift* ps = *psr;
1178+ _tPeriodDetection* p = *ps->p;
1179+
1180+ float period, out;
1181+ int i, iLast;
1182+
1183+ i = p->i;
1184+ iLast = p->iLast;
1185+
1186+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
1187+
1188+ if (p->indexstore >= ps->frameSize)
1189+ {
1190+ period = tPeriodDetection_getPeriod(&p);
1191+
1192+ if(pitchshift_attackdetect(ps) == 1)
1193+ {
1194+ p->fba = 5;
1195+ tSOLAD_setReadLag(&ps->sola, p->windowSize);
1196+ }
1197+
1198+ tSOLAD_setPeriod(&ps->sola, period);
1199+
1200+ ps->pitchFactor = period/fun(period);
1201+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
1202+
1203+ tSOLAD_ioSamples(&ps->sola, &(p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
1204+
1205+ ps->curBlock++;
1206+ if (ps->curBlock >= p->framesPerBuffer) ps->curBlock = 0;
1207+ ps->lastBlock++;
1208+ if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
1209+ }
1210+
1211+ return out;
1212+}
1213+
1214+//============================================================================================================
1215+// RETUNE
1216+//============================================================================================================
1217+
1218+void tRetune_init(tRetune* const rt, int numVoices, int bufSize, int frameSize)
1219+{
1220+ tRetune_initToPool(rt, numVoices, bufSize, frameSize, &leaf.mempool);
1221+}
1222+
1223+void tRetune_free(tRetune* const rt)
1224+{
1225+ tRetune_freeFromPool(rt, &leaf.mempool);
1226+}
1227+
1228+void tRetune_initToPool (tRetune* const rt, int numVoices, int bufSize, int frameSize, tMempool* const mp)
1229+{
1230+ _tMempool* m = *mp;
1231+ _tRetune* r = *rt = (_tRetune*) mpool_alloc(sizeof(_tRetune), m);
1232+
1233+ r->bufSize = bufSize;
1234+ r->frameSize = frameSize;
1235+ r->numVoices = numVoices;
1236+
1237+ r->inBuffer = (float*) mpool_calloc(sizeof(float) * r->bufSize, m);
1238+ r->outBuffers = (float**) mpool_calloc(sizeof(float*) * r->numVoices, m);
1239+
1240+ r->hopSize = DEFHOPSIZE;
1241+ r->windowSize = DEFWINDOWSIZE;
1242+ r->fba = FBA;
1243+ tRetune_setTimeConstant(rt, DEFTIMECONSTANT);
1244+
1245+ r->inputPeriod = 0.0f;
1246+
1247+ r->ps = (tPitchShift*) mpool_calloc(sizeof(tPitchShift) * r->numVoices, m);
1248+ r->pitchFactor = (float*) mpool_calloc(sizeof(float) * r->numVoices, m);
1249+ r->tickOutput = (float*) mpool_calloc(sizeof(float) * r->numVoices, m);
1250+ for (int i = 0; i < r->numVoices; ++i)
1251+ {
1252+ r->outBuffers[i] = (float*) mpool_calloc(sizeof(float) * r->bufSize, m);
1253+ }
1254+
1255+ tPeriodDetection_initToPool(&r->pd, r->inBuffer, r->outBuffers[0], r->bufSize, r->frameSize, mp);
1256+
1257+ for (int i = 0; i < r->numVoices; ++i)
1258+ {
1259+ tPitchShift_initToPool(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize, mp);
1260+ }
1261+}
1262+
1263+void tRetune_freeFromPool (tRetune* const rt, tMempool* const mp)
1264+{
1265+ _tMempool* m = *mp;
1266+ _tRetune* r = *rt;
1267+
1268+ tPeriodDetection_freeFromPool(&r->pd, mp);
1269+ for (int i = 0; i < r->numVoices; ++i)
1270+ {
1271+ tPitchShift_freeFromPool(&r->ps[i], mp);
1272+ mpool_free((char*)r->outBuffers[i], m);
1273+ }
1274+ mpool_free((char*)r->tickOutput, m);
1275+ mpool_free((char*)r->pitchFactor, m);
1276+ mpool_free((char*)r->ps, m);
1277+ mpool_free((char*)r->inBuffer, m);
1278+ mpool_free((char*)r->outBuffers, m);
1279+ mpool_free((char*)r, m);
1280+}
1281+
1282+float* tRetune_tick(tRetune* const rt, float sample)
1283+{
1284+ _tRetune* r = *rt;
1285+
1286+ r->inputPeriod = tPeriodDetection_tick(&r->pd, sample);
1287+
1288+ for (int v = 0; v < r->numVoices; ++v)
1289+ {
1290+ r->tickOutput[v] = tPitchShift_shift(&r->ps[v]);
1291+ }
1292+
1293+ return r->tickOutput;
1294+}
1295+
1296+void tRetune_setNumVoices(tRetune* const rt, int numVoices)
1297+{
1298+ _tRetune* r = *rt;
1299+
1300+ for (int i = 0; i < r->numVoices; ++i)
1301+ {
1302+ tPitchShift_free(&r->ps[i]);
1303+ leaf_free((char*)r->outBuffers[i]);
1304+ }
1305+ leaf_free((char*)r->tickOutput);
1306+ leaf_free((char*)r->pitchFactor);
1307+ leaf_free((char*)r->ps);
1308+ leaf_free((char*)r->outBuffers);
1309+
1310+ r->numVoices = numVoices;
1311+
1312+ r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
1313+ r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
1314+ r->pitchFactor = (float*) leaf_alloc(sizeof(float) * r->numVoices);
1315+ r->tickOutput = (float*) leaf_alloc(sizeof(float) * r->numVoices);
1316+ for (int i = 0; i < r->numVoices; ++i)
1317+ {
1318+ r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
1319+ tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
1320+ }
1321+}
1322+
1323+void tRetune_setPitchFactors(tRetune* const rt, float pf)
1324+{
1325+ _tRetune* r = *rt;
1326+
1327+ for (int i = 0; i < r->numVoices; ++i)
1328+ {
1329+ r->pitchFactor[i] = pf;
1330+ tPitchShift_setPitchFactor(&r->ps[i], r->pitchFactor[i]);
1331+ }
1332+}
1333+
1334+void tRetune_setPitchFactor(tRetune* const rt, float pf, int voice)
1335+{
1336+ _tRetune* r = *rt;
1337+
1338+ r->pitchFactor[voice] = pf;
1339+ tPitchShift_setPitchFactor(&r->ps[voice], r->pitchFactor[voice]);
1340+}
1341+
1342+void tRetune_setTimeConstant(tRetune* const rt, float tc)
1343+{
1344+ _tRetune* r = *rt;
1345+
1346+ r->timeConstant = tc;
1347+ r->radius = expf(-1000.0f * r->hopSize * leaf.invSampleRate / r->timeConstant);
1348+}
1349+
1350+void tRetune_setHopSize(tRetune* const rt, int hs)
1351+{
1352+ _tRetune* r = *rt;
1353+
1354+ r->hopSize = hs;
1355+ tPeriodDetection_setHopSize(&r->pd, r->hopSize);
1356+}
1357+
1358+void tRetune_setWindowSize(tRetune* const rt, int ws)
1359+{
1360+ _tRetune* r = *rt;
1361+
1362+ r->windowSize = ws;
1363+ tPeriodDetection_setWindowSize(&r->pd, r->windowSize);
1364+}
1365+
1366+void tRetune_setFidelityThreshold(tRetune* const rt, float threshold)
1367+{
1368+ _tRetune* r = *rt;
1369+
1370+ tPeriodDetection_setFidelityThreshold(&r->pd, threshold);
1371+}
1372+
1373+float tRetune_getInputPeriod(tRetune* const rt)
1374+{
1375+ _tRetune* r = *rt;
1376+
1377+ return (r->inputPeriod * leaf.invSampleRate);
1378+}
1379+
1380+float tRetune_getInputFreq(tRetune* const rt)
1381+{
1382+ _tRetune* r = *rt;
1383+
1384+ return 1.0f/(r->inputPeriod * leaf.invSampleRate);
1385+}
1386+
1387+//============================================================================================================
1388+// AUTOTUNE
1389+//============================================================================================================
1390+
1391+void tAutotune_init(tAutotune* const rt, int numVoices, int bufSize, int frameSize)
1392+{
1393+ tAutotune_initToPool(rt, numVoices, bufSize, frameSize, &leaf.mempool);
1394+}
1395+
1396+void tAutotune_free(tAutotune* const rt)
1397+{
1398+ tAutotune_freeFromPool(rt, &leaf.mempool);
1399+}
1400+
1401+void tAutotune_initToPool (tAutotune* const rt, int numVoices, int bufSize, int frameSize, tMempool* const mp)
1402+{
1403+ _tMempool* m = *mp;
1404+ _tAutotune* r = *rt = (_tAutotune*) mpool_alloc(sizeof(_tAutotune), m);
1405+
1406+ r->bufSize = bufSize;
1407+ r->frameSize = frameSize;
1408+ r->numVoices = numVoices;
1409+
1410+ r->inBuffer = (float*) mpool_alloc(sizeof(float) * r->bufSize, m);
1411+ r->outBuffers = (float**) mpool_alloc(sizeof(float*) * r->numVoices, m);
1412+
1413+ r->hopSize = DEFHOPSIZE;
1414+ r->windowSize = DEFWINDOWSIZE;
1415+ r->fba = FBA;
1416+ tAutotune_setTimeConstant(rt, DEFTIMECONSTANT);
1417+
1418+ r->ps = (tPitchShift*) mpool_alloc(sizeof(tPitchShift) * r->numVoices, m);
1419+ r->freq = (float*) mpool_alloc(sizeof(float) * r->numVoices, m);
1420+ r->tickOutput = (float*) mpool_alloc(sizeof(float) * r->numVoices, m);
1421+ for (int i = 0; i < r->numVoices; ++i)
1422+ {
1423+ r->outBuffers[i] = (float*) mpool_alloc(sizeof(float) * r->bufSize, m);
1424+ }
1425+
1426+ tPeriodDetection_initToPool(&r->pd, r->inBuffer, r->outBuffers[0], r->bufSize, r->frameSize, mp);
1427+
1428+ for (int i = 0; i < r->numVoices; ++i)
1429+ {
1430+ tPitchShift_initToPool(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize, mp);
1431+ }
1432+
1433+ r->inputPeriod = 0.0f;
1434+}
1435+
1436+void tAutotune_freeFromPool (tAutotune* const rt, tMempool* const mp)
1437+{
1438+ _tMempool* m = *mp;
1439+ _tAutotune* r = *rt;
1440+
1441+ tPeriodDetection_freeFromPool(&r->pd, mp);
1442+ for (int i = 0; i < r->numVoices; ++i)
1443+ {
1444+ tPitchShift_freeFromPool(&r->ps[i], mp);
1445+ mpool_free((char*)r->outBuffers[i], m);
1446+ }
1447+ mpool_free((char*)r->tickOutput, m);
1448+ mpool_free((char*)r->freq, m);
1449+ mpool_free((char*)r->ps, m);
1450+ mpool_free((char*)r->inBuffer, m);
1451+ mpool_free((char*)r->outBuffers, m);
1452+ mpool_free((char*)r, m);
1453+}
1454+
1455+float* tAutotune_tick(tAutotune* const rt, float sample)
1456+{
1457+ _tAutotune* r = *rt;
1458+
1459+ float tempPeriod = tPeriodDetection_tick(&r->pd, sample);
1460+ if (tempPeriod < 1000.0f) //to avoid trying to follow consonants JS
1461+ {
1462+ r->inputPeriod = tempPeriod;
1463+ }
1464+
1465+ for (int v = 0; v < r->numVoices; ++v)
1466+ {
1467+ r->tickOutput[v] = tPitchShift_shiftToFreq(&r->ps[v], r->freq[v]);
1468+ }
1469+
1470+ return r->tickOutput;
1471+}
1472+
1473+void tAutotune_setNumVoices(tAutotune* const rt, int numVoices)
1474+{
1475+ _tAutotune* r = *rt;
1476+
1477+ for (int i = 0; i < r->numVoices; ++i)
1478+ {
1479+ tPitchShift_free(&r->ps[i]);
1480+ leaf_free((char*)r->outBuffers[i]);
1481+ }
1482+ leaf_free((char*)r->tickOutput);
1483+ leaf_free((char*)r->freq);
1484+ leaf_free((char*)r->ps);
1485+ leaf_free((char*)r->outBuffers);
1486+
1487+ r->numVoices = numVoices;
1488+
1489+ r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
1490+ r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
1491+ r->freq = (float*) leaf_alloc(sizeof(float) * r->numVoices);
1492+ r->tickOutput = (float*) leaf_alloc(sizeof(float) * r->numVoices);
1493+ for (int i = 0; i < r->numVoices; ++i)
1494+ {
1495+ r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
1496+ tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
1497+ }
1498+}
1499+
1500+void tAutotune_setFreqs(tAutotune* const rt, float f)
1501+{
1502+ _tAutotune* r = *rt;
1503+
1504+ for (int i = 0; i < r->numVoices; ++i)
1505+ {
1506+ r->freq[i] = f;
1507+ }
1508+}
1509+
1510+void tAutotune_setFreq(tAutotune* const rt, float f, int voice)
1511+{
1512+ _tAutotune* r = *rt;
1513+
1514+ r->freq[voice] = f;
1515+}
1516+
1517+void tAutotune_setTimeConstant(tAutotune* const rt, float tc)
1518+{
1519+ _tAutotune* r = *rt;
1520+
1521+ r->timeConstant = tc;
1522+ r->radius = expf(-1000.0f * r->hopSize * leaf.invSampleRate / r->timeConstant);
1523+}
1524+
1525+void tAutotune_setHopSize(tAutotune* const rt, int hs)
1526+{
1527+ _tAutotune* r = *rt;
1528+
1529+ r->hopSize = hs;
1530+ tPeriodDetection_setHopSize(&r->pd, r->hopSize);
1531+}
1532+
1533+void tAutotune_setWindowSize(tAutotune* const rt, int ws)
1534+{
1535+ _tAutotune* r = *rt;
1536+
1537+ r->windowSize = ws;
1538+ tPeriodDetection_setWindowSize(&r->pd, r->windowSize);
1539+}
1540+
1541+void tAutotune_setFidelityThreshold(tAutotune* const rt, float threshold)
1542+{
1543+ _tAutotune* r = *rt;
1544+
1545+ tPeriodDetection_setFidelityThreshold(&r->pd, threshold);
1546+}
1547+
1548+void tAutotune_setAlpha (tAutotune* rt, float alpha)
1549+{
1550+ _tAutotune* r = *rt;
1551+ tPeriodDetection_setAlpha(&r->pd, alpha);
1552+}
1553+
1554+void tAutotune_setTolerance (tAutotune* rt, float tolerance)
1555+{
1556+ _tAutotune* r = *rt;
1557+ tPeriodDetection_setTolerance(&r->pd, tolerance);
1558+}
1559+
1560+float tAutotune_getInputPeriod(tAutotune* const rt)
1561+{
1562+ _tAutotune* r = *rt;
1563+
1564+ return r->inputPeriod;
1565+}
1566+
1567+float tAutotune_getInputFreq(tAutotune* const rt)
1568+{
1569+ _tAutotune* r = *rt;
1570+
1571+ return 1.0f/r->inputPeriod;
1572+}
1573+
1574+//============================================================================================================
1575+// FORMANTSHIFTER
1576+//============================================================================================================
1577+// algorithm from Tom Baran's autotalent code.
1578+
1579+void tFormantShifter_init(tFormantShifter* const fsr, int order)
1580+{
1581+ _tFormantShifter* fs = *fsr = (_tFormantShifter*) leaf_alloc(sizeof(_tFormantShifter));
1582+
1583+ fs->ford = order;
1584+ fs->fk = (float*) leaf_calloc(sizeof(float) * fs->ford);
1585+ fs->fb = (float*) leaf_calloc(sizeof(float) * fs->ford);
1586+ fs->fc = (float*) leaf_calloc(sizeof(float) * fs->ford);
1587+ fs->frb = (float*) leaf_calloc(sizeof(float) * fs->ford);
1588+ fs->frc = (float*) leaf_calloc(sizeof(float) * fs->ford);
1589+ fs->fsig = (float*) leaf_calloc(sizeof(float) * fs->ford);
1590+ fs->fsmooth = (float*) leaf_calloc(sizeof(float) * fs->ford);
1591+ fs->ftvec = (float*) leaf_calloc(sizeof(float) * fs->ford);
1592+ fs->fbuff = (float*) leaf_calloc(sizeof(float*) * fs->ford);
1593+
1594+ fs->falph = powf(0.001f, 40.0f * leaf.invSampleRate);
1595+ fs->flamb = -(0.8517f*sqrtf(atanf(0.06583f*leaf.sampleRate))-0.1916f);
1596+ fs->fhp = 0.0f;
1597+ fs->flp = 0.0f;
1598+ fs->flpa = powf(0.001f, 10.0f * leaf.invSampleRate);
1599+ fs->fmute = 1.0f;
1600+ fs->fmutealph = powf(0.001f, 0.5f * leaf.invSampleRate);
1601+ fs->cbi = 0;
1602+ fs->intensity = 1.0f;
1603+ fs->invIntensity = 1.0f;
1604+ tHighpass_init(&fs->hp, 10.0f);
1605+ tHighpass_init(&fs->hp2, 10.0f);
1606+ tFeedbackLeveler_init(&fs->fbl1, 0.99f, 0.005f, 0.125f, 0);
1607+ tFeedbackLeveler_init(&fs->fbl2, 0.99f, 0.005f, 0.125f, 0);
1608+}
1609+
1610+void tFormantShifter_free(tFormantShifter* const fsr)
1611+{
1612+ _tFormantShifter* fs = *fsr;
1613+
1614+ leaf_free((char*)fs->fk);
1615+ leaf_free((char*)fs->fb);
1616+ leaf_free((char*)fs->fc);
1617+ leaf_free((char*)fs->frb);
1618+ leaf_free((char*)fs->frc);
1619+ leaf_free((char*)fs->fsig);
1620+ leaf_free((char*)fs->fsmooth);
1621+ leaf_free((char*)fs->ftvec);
1622+ leaf_free((char*)fs->fbuff);
1623+ tHighpass_free(&fs->hp);
1624+ tHighpass_free(&fs->hp2);
1625+ tFeedbackLeveler_free(&fs->fbl1);
1626+ tFeedbackLeveler_free(&fs->fbl2);
1627+ leaf_free((char*)fs);
1628+}
1629+
1630+void tFormantShifter_initToPool (tFormantShifter* const fsr, int order, tMempool* const mp)
1631+{
1632+ _tMempool* m = *mp;
1633+ _tFormantShifter* fs = *fsr = (_tFormantShifter*) mpool_alloc(sizeof(_tFormantShifter), m);
1634+
1635+ fs->ford = order;
1636+ fs->fk = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1637+ fs->fb = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1638+ fs->fc = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1639+ fs->frb = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1640+ fs->frc = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1641+ fs->fsig = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1642+ fs->fsmooth = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1643+ fs->ftvec = (float*) mpool_calloc(sizeof(float) * fs->ford, m);
1644+
1645+ fs->fbuff = (float*) mpool_calloc(sizeof(float*) * fs->ford, m);
1646+
1647+
1648+ fs->falph = powf(0.001f, 10.0f * leaf.invSampleRate);
1649+ fs->flamb = -(0.8517f*sqrtf(atanf(0.06583f*leaf.sampleRate))-0.1916f);
1650+ fs->fhp = 0.0f;
1651+ fs->flp = 0.0f;
1652+ fs->flpa = powf(0.001f, 10.0f * leaf.invSampleRate);
1653+ fs->fmute = 1.0f;
1654+ fs->fmutealph = powf(0.001f, 1.0f * leaf.invSampleRate);
1655+ fs->cbi = 0;
1656+ fs->intensity = 1.0f;
1657+ fs->invIntensity = 1.0f;
1658+ tHighpass_initToPool(&fs->hp, 20.0f, mp);
1659+ tHighpass_initToPool(&fs->hp2, 20.0f, mp);
1660+ tFeedbackLeveler_initToPool(&fs->fbl1, 0.8f, .005f, 0.125, 1, mp);
1661+ tFeedbackLeveler_initToPool(&fs->fbl2, 0.8f, .005f, 0.125, 1, mp);
1662+}
1663+
1664+void tFormantShifter_freeFromPool (tFormantShifter* const fsr, tMempool* const mp)
1665+{
1666+ _tMempool* m = *mp;
1667+ _tFormantShifter* fs = *fsr;
1668+
1669+ mpool_free((char*)fs->fk, m);
1670+ mpool_free((char*)fs->fb, m);
1671+ mpool_free((char*)fs->fc, m);
1672+ mpool_free((char*)fs->frb, m);
1673+ mpool_free((char*)fs->frc, m);
1674+ mpool_free((char*)fs->fsig, m);
1675+ mpool_free((char*)fs->fsmooth, m);
1676+ mpool_free((char*)fs->ftvec, m);
1677+ mpool_free((char*)fs->fbuff, m);
1678+ tHighpass_freeFromPool(&fs->hp, mp);
1679+ tHighpass_freeFromPool(&fs->hp2, mp);
1680+ tFeedbackLeveler_freeFromPool(&fs->fbl1, mp);
1681+ tFeedbackLeveler_freeFromPool(&fs->fbl2, mp);
1682+ mpool_free((char*)fs, m);
1683+}
1684+
1685+float tFormantShifter_tick(tFormantShifter* const fsr, float in)
1686+{
1687+ return tFormantShifter_add(fsr, tFormantShifter_remove(fsr, in));
1688+}
1689+
1690+float tFormantShifter_remove(tFormantShifter* const fsr, float in)
1691+{
1692+ _tFormantShifter* fs = *fsr;
1693+ in = tFeedbackLeveler_tick(&fs->fbl1, in);
1694+ in = tHighpass_tick(&fs->hp, in * fs->intensity);
1695+
1696+
1697+ float fa, fb, fc, foma, falph, ford, flamb, tf, fk;
1698+
1699+ ford = fs->ford;
1700+ falph = fs->falph;
1701+ foma = (1.0f - falph);
1702+ flamb = fs->flamb;
1703+
1704+ tf = in;
1705+
1706+ fa = tf - fs->fhp;
1707+ fs->fhp = tf;
1708+ fb = fa;
1709+ for(int i = 0; i < ford; i++)
1710+ {
1711+ fs->fsig[i] = fa*fa*foma + fs->fsig[i]*falph;
1712+ fc = (fb - fs->fc[i])*flamb + fs->fb[i];
1713+ fs->fc[i] = fc;
1714+ fs->fb[i] = fb;
1715+ fk = fa*fc*foma + fs->fk[i]*falph;
1716+ fs->fk[i] = fk;
1717+ tf = fk/(fs->fsig[i] + 0.000001f);
1718+ tf = tf*foma + fs->fsmooth[i]*falph;
1719+ fs->fsmooth[i] = tf;
1720+ fs->fbuff[i] = tf;
1721+ fb = fc - tf*fa;
1722+ fa = fa - tf*fc;
1723+ }
1724+
1725+ //return fa * 0.1f;
1726+ return fa;
1727+}
1728+
1729+float tFormantShifter_add(tFormantShifter* const fsr, float in)
1730+{
1731+ _tFormantShifter* fs = *fsr;
1732+
1733+ float fa, fb, fc, ford, flpa, flamb, tf, tf2, f0resp, f1resp, frlamb;
1734+ ford = fs->ford;
1735+
1736+ flpa = fs->flpa;
1737+ flamb = fs->flamb;
1738+ tf = fs->shiftFactor * (1.0f+flamb)/(1.0f-flamb);
1739+ frlamb = (tf-1.0f)/(tf+1.0f);
1740+
1741+ tf2 = in;
1742+ fa = 0.0f;
1743+ fb = fa;
1744+ for (int i=0; i<ford; i++)
1745+ {
1746+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
1747+ tf = fs->fbuff[i];
1748+ fb = fc - tf*fa;
1749+ fs->ftvec[i] = tf*fc;
1750+ fa = fa - fs->ftvec[i];
1751+ }
1752+ tf = -fa;
1753+ for (int i=ford-1; i>=0; i--)
1754+ {
1755+ tf = tf + fs->ftvec[i];
1756+ }
1757+ f0resp = tf;
1758+
1759+ // second time: compute 1-response
1760+ fa = 1.0f;
1761+ fb = fa;
1762+ for (int i=0; i<ford; i++)
1763+ {
1764+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
1765+ tf = fs->fbuff[i];
1766+ fb = fc - tf*fa;
1767+ fs->ftvec[i] = tf*fc;
1768+ fa = fa - fs->ftvec[i];
1769+ }
1770+ tf = -fa;
1771+ for (int i=ford-1; i>=0; i--)
1772+ {
1773+ tf = tf + fs->ftvec[i];
1774+ }
1775+ f1resp = tf;
1776+
1777+ // now solve equations for output, based on 0-response and 1-response
1778+ tf = 2.0f*tf2;
1779+ tf2 = tf;
1780+ tf = (1.0f - f1resp + f0resp);
1781+ if (tf!=0.0f)
1782+ {
1783+ tf2 = (tf2 + f0resp) / tf;
1784+ }
1785+ else
1786+ {
1787+ tf2 = 0.0f;
1788+ }
1789+
1790+ // third time: update delay registers
1791+ fa = tf2;
1792+ fb = fa;
1793+ for (int i=0; i<ford; i++)
1794+ {
1795+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
1796+ fs->frc[i] = fc;
1797+ fs->frb[i] = fb;
1798+ tf = fs->fbuff[i];
1799+ fb = fc - tf*fa;
1800+ fa = fa - tf*fc;
1801+ }
1802+ tf = tf2;
1803+ tf = tf + flpa * fs->flp; // lowpass post-emphasis filter
1804+ fs->flp = tf;
1805+
1806+ // Bring up the gain slowly when formant correction goes from disabled
1807+ // to enabled, while things stabilize.
1808+ if (fs->fmute>0.5f)
1809+ {
1810+ tf = tf*(fs->fmute - 0.5f)*2.0f;
1811+ }
1812+ else
1813+ {
1814+ tf = 0.0f;
1815+ }
1816+ tf2 = fs->fmutealph;
1817+ fs->fmute = (1.0f-tf2) + tf2*fs->fmute;
1818+ // now tf is signal output
1819+ // ...and we're done messing with formants
1820+ //tf = tFeedbackLeveler_tick(&fs->fbl2, tf);
1821+ tf = tHighpass_tick(&fs->hp2, tanhf(tf));
1822+
1823+ return tf * fs->invIntensity;
1824+}
1825+
1826+// 1.0f is no change, 2.0f is an octave up, 0.5f is an octave down
1827+void tFormantShifter_setShiftFactor(tFormantShifter* const fsr, float shiftFactor)
1828+{
1829+ _tFormantShifter* fs = *fsr;
1830+ fs->shiftFactor = shiftFactor;
1831+}
1832+
1833+void tFormantShifter_setIntensity(tFormantShifter* const fsr, float intensity)
1834+{
1835+ _tFormantShifter* fs = *fsr;
1836+
1837+
1838+
1839+ fs->intensity = LEAF_clip(1.0f, intensity, 100.0f);
1840+
1841+ // tFeedbackLeveler_setTargetLevel(&fs->fbl1, fs->intensity);
1842+ //tFeedbackLeveler_setTargetLevel(&fs->fbl2, fs->intensity);
1843+ //make sure you don't divide by zero, doofies
1844+ if (fs->intensity != 0.0f)
1845+ {
1846+ fs->invIntensity = 1.0f/fs->intensity;
1847+ }
1848+ else
1849+ {
1850+ fs->invIntensity = 1.0f;
1851+ }
1852+
1853+}
leaf/Src/leaf-electrical.c+551−0
@@ -0,0 +1,551 @@
1+/*
2+ * leaf-electrical.c
3+ *
4+ * Created on: Sep 25, 2019
5+ * Author: jeffsnyder
6+ */
7+
8+#if _WIN32 || _WIN64
9+
10+#include "..\Inc\leaf-electrical.h"
11+#include "..\leaf.h"
12+
13+#else
14+
15+#include "../Inc/leaf-electrical.h"
16+#include "../leaf.h"
17+
18+#endif
19+
20+//==============================================================================
21+
22+static float get_port_resistance_for_resistor(tWDF* const r);
23+static float get_port_resistance_for_capacitor(tWDF* const r);
24+static float get_port_resistance_for_inductor(tWDF* const r);
25+static float get_port_resistance_for_resistive(tWDF* const r);
26+static float get_port_resistance_for_inverter(tWDF* const r);
27+static float get_port_resistance_for_series(tWDF* const r);
28+static float get_port_resistance_for_parallel(tWDF* const r);
29+static float get_port_resistance_for_root(tWDF* const r);
30+
31+static void set_incident_wave_for_leaf(tWDF* const r, float incident_wave, float input);
32+static void set_incident_wave_for_leaf_inverted(tWDF* const r, float incident_wave, float input);
33+static void set_incident_wave_for_inverter(tWDF* const r, float incident_wave, float input);
34+static void set_incident_wave_for_series(tWDF* const r, float incident_wave, float input);
35+static void set_incident_wave_for_parallel(tWDF* const r, float incident_wave, float input);
36+
37+static float get_reflected_wave_for_resistor(tWDF* const r, float input);
38+static float get_reflected_wave_for_capacitor(tWDF* const r, float input);
39+static float get_reflected_wave_for_resistive(tWDF* const r, float input);
40+static float get_reflected_wave_for_inverter(tWDF* const r, float input);
41+static float get_reflected_wave_for_series(tWDF* const r, float input);
42+static float get_reflected_wave_for_parallel(tWDF* const r, float input);
43+
44+static float get_reflected_wave_for_ideal(tWDF* const n, float input, float incident_wave);
45+static float get_reflected_wave_for_diode(tWDF* const n, float input, float incident_wave);
46+static float get_reflected_wave_for_diode_pair(tWDF* const n, float input, float incident_wave);
47+
48+static void wdf_init(tWDF* const wdf, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR)
49+{
50+ _tWDF* r = *wdf;
51+
52+ r->type = type;
53+ r->child_left = rL;
54+ r->child_right = rR;
55+ r->incident_wave_up = 0.0f;
56+ r->incident_wave_left = 0.0f;
57+ r->incident_wave_right = 0.0f;
58+ r->reflected_wave_up = 0.0f;
59+ r->reflected_wave_left = 0.0f;
60+ r->reflected_wave_right = 0.0f;
61+ r->sample_rate = leaf.sampleRate;
62+ r->value = value;
63+
64+ tWDF* child;
65+ if (r->child_left != NULL) child = r->child_left;
66+ else child = r->child_right;
67+
68+ if (r->type == Resistor)
69+ {
70+ r->port_resistance_up = r->value;
71+ r->port_conductance_up = 1.0f / r->value;
72+
73+ r->get_port_resistance = &get_port_resistance_for_resistor;
74+ r->get_reflected_wave_up = &get_reflected_wave_for_resistor;
75+ r->set_incident_wave = &set_incident_wave_for_leaf;
76+ }
77+ else if (r->type == Capacitor)
78+ {
79+ r->port_conductance_up = r->sample_rate * 2.0f * r->value;
80+ r->port_resistance_up = 1.0f / r->port_conductance_up; //based on trapezoidal discretization
81+
82+ r->get_port_resistance = &get_port_resistance_for_capacitor;
83+ r->get_reflected_wave_up = &get_reflected_wave_for_capacitor;
84+ r->set_incident_wave = &set_incident_wave_for_leaf;
85+ }
86+ else if (r->type == Inductor)
87+ {
88+ r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
89+ r->port_conductance_up = 1.0f / r->port_resistance_up;
90+
91+ r->get_port_resistance = &get_port_resistance_for_inductor;
92+ r->get_reflected_wave_up = &get_reflected_wave_for_capacitor; // same as capacitor
93+ r->set_incident_wave = &set_incident_wave_for_leaf_inverted;
94+ }
95+ else if (r->type == ResistiveSource)
96+ {
97+ r->port_resistance_up = r->value;
98+ r->port_conductance_up = 1.0f / r->port_resistance_up;
99+
100+ r->get_port_resistance = &get_port_resistance_for_resistive;
101+ r->get_reflected_wave_up = &get_reflected_wave_for_resistive;
102+ r->set_incident_wave = &set_incident_wave_for_leaf;
103+ }
104+ else if (r->type == Inverter)
105+ {
106+ r->port_resistance_up = tWDF_getPortResistance(r->child_left);
107+ r->port_conductance_up = 1.0f / r->port_resistance_up;
108+
109+ r->get_port_resistance = &get_port_resistance_for_inverter;
110+ r->get_reflected_wave_up = &get_reflected_wave_for_inverter;
111+ r->set_incident_wave = &set_incident_wave_for_inverter;
112+ }
113+ else if (r->type == SeriesAdaptor)
114+ {
115+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
116+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
117+ r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
118+ r->port_conductance_up = 1.0f / r->port_resistance_up;
119+ r->port_conductance_left = 1.0f / r->port_resistance_left;
120+ r->port_conductance_right = 1.0f / r->port_resistance_right;
121+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
122+
123+ r->get_port_resistance = &get_port_resistance_for_series;
124+ r->get_reflected_wave_up = &get_reflected_wave_for_series;
125+ r->set_incident_wave = &set_incident_wave_for_series;
126+ }
127+ else if (r->type == ParallelAdaptor)
128+ {
129+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
130+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
131+ r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
132+ r->port_conductance_up = 1.0f / r->port_resistance_up;
133+ r->port_conductance_left = 1.0f / r->port_resistance_left;
134+ r->port_conductance_right = 1.0f / r->port_resistance_right;
135+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
136+
137+ r->get_port_resistance = &get_port_resistance_for_parallel;
138+ r->get_reflected_wave_up = &get_reflected_wave_for_parallel;
139+ r->set_incident_wave = &set_incident_wave_for_parallel;
140+ }
141+ else if (r->type == IdealSource)
142+ {
143+ r->port_resistance_up = tWDF_getPortResistance(child);
144+ r->port_conductance_up = 1.0f / r->port_resistance_up;
145+
146+ r->get_reflected_wave_down = &get_reflected_wave_for_ideal;
147+ r->get_port_resistance = &get_port_resistance_for_root;
148+ }
149+ else if (r->type == Diode)
150+ {
151+ r->port_resistance_up = tWDF_getPortResistance(child);
152+ r->port_conductance_up = 1.0f / r->port_resistance_up;
153+
154+ r->get_reflected_wave_down = &get_reflected_wave_for_diode;
155+ r->get_port_resistance = &get_port_resistance_for_root;
156+ }
157+ else if (r->type == DiodePair)
158+ {
159+ r->port_resistance_up = tWDF_getPortResistance(child);
160+ r->port_conductance_up = 1.0f / r->port_resistance_up;
161+
162+ r->get_reflected_wave_down = &get_reflected_wave_for_diode_pair;
163+ r->get_port_resistance = &get_port_resistance_for_root;
164+ }
165+}
166+//WDF
167+void tWDF_init(tWDF* const wdf, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR)
168+{
169+ *wdf = (_tWDF*) leaf_alloc(sizeof(_tWDF));
170+
171+ wdf_init(wdf, type, value, rL, rR);
172+}
173+
174+void tWDF_free(tWDF* const wdf)
175+{
176+ _tWDF* r = *wdf;
177+
178+ leaf_free((char*)r);
179+}
180+
181+void tWDF_initToPool (tWDF* const wdf, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR, tMempool* const mp)
182+{
183+ _tMempool* m = *mp;
184+ *wdf = (_tWDF*) mpool_alloc(sizeof(_tWDF), m);
185+
186+ wdf_init(wdf, type, value, rL, rR);
187+}
188+
189+void tWDF_freeFromPool (tWDF* const wdf, tMempool* const mp)
190+{
191+ _tMempool* m = *mp;
192+ _tWDF* r = *wdf;
193+
194+ mpool_free((char*)r, m);
195+}
196+
197+float tWDF_tick(tWDF* const wdf, float sample, tWDF* const outputPoint, uint8_t paramsChanged)
198+{
199+ _tWDF* r = *wdf;
200+
201+ tWDF* child;
202+ if (r->child_left != NULL) child = r->child_left;
203+ else child = r->child_right;
204+
205+ //step 0 : update port resistances if something changed
206+ if (paramsChanged) tWDF_getPortResistance(wdf);
207+
208+ //step 1 : set inputs to what they should be
209+ float input = sample;
210+
211+ //step 2 : scan the waves up the tree
212+ r->incident_wave_up = tWDF_getReflectedWaveUp(child, input);
213+
214+ //step 3 : do root scattering computation
215+ r->reflected_wave_up = tWDF_getReflectedWaveDown(wdf, input, r->incident_wave_up);
216+
217+ //step 4 : propogate waves down the tree
218+ tWDF_setIncidentWave(child, r->reflected_wave_up, input);
219+
220+ //step 5 : grab whatever voltages or currents we want as outputs
221+ return tWDF_getVoltage(outputPoint);
222+}
223+
224+void tWDF_setValue(tWDF* const wdf, float value)
225+{
226+ _tWDF* r = *wdf;
227+ r->value = value;
228+}
229+
230+void tWDF_setSampleRate(tWDF* const wdf, float sample_rate)
231+{
232+ _tWDF* r = *wdf;
233+ r->sample_rate = sample_rate;
234+}
235+
236+uint8_t tWDF_isLeaf(tWDF* const wdf)
237+{
238+ _tWDF* r = *wdf;
239+ if (r->child_left == NULL && r->child_right == NULL) return 1;
240+ return 0;
241+}
242+
243+float tWDF_getPortResistance(tWDF* const wdf)
244+{
245+ _tWDF* r = *wdf;
246+ return r->get_port_resistance(wdf);
247+}
248+
249+void tWDF_setIncidentWave(tWDF* const wdf, float incident_wave, float input)
250+{
251+ _tWDF* r = *wdf;
252+ r->set_incident_wave(wdf, incident_wave, input);
253+}
254+
255+float tWDF_getReflectedWaveUp(tWDF* const wdf, float input)
256+{
257+ _tWDF* r = *wdf;
258+ return r->get_reflected_wave_up(wdf, input);
259+}
260+
261+float tWDF_getReflectedWaveDown(tWDF* const wdf, float input, float incident_wave)
262+{
263+ _tWDF* r = *wdf;
264+ return r->get_reflected_wave_down(wdf, input, incident_wave);
265+}
266+
267+float tWDF_getVoltage(tWDF* const wdf)
268+{
269+ _tWDF* r = *wdf;
270+ return ((r->incident_wave_up * 0.5f) + (r->reflected_wave_up * 0.5f));
271+}
272+
273+float tWDF_getCurrent(tWDF* const wdf)
274+{
275+ _tWDF* r = *wdf;
276+ return (((r->incident_wave_up * 0.5f) - (r->reflected_wave_up * 0.5f)) * r->port_conductance_up);
277+}
278+
279+//============ Static Functions to be Pointed To ====================
280+//===================================================================
281+//============ Get and Calculate Port Resistances ===================
282+
283+static float get_port_resistance_for_resistor(tWDF* const wdf)
284+{
285+ _tWDF* r = *wdf;
286+
287+ r->port_resistance_up = r->value;
288+ r->port_conductance_up = 1.0f / r->value;
289+
290+ return r->port_resistance_up;
291+}
292+
293+static float get_port_resistance_for_capacitor(tWDF* const wdf)
294+{
295+ _tWDF* r = *wdf;
296+
297+ r->port_conductance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
298+ r->port_resistance_up = (1.0f / r->port_conductance_up);
299+
300+ return r->port_resistance_up;
301+}
302+
303+static float get_port_resistance_for_inductor(tWDF* const wdf)
304+{
305+ _tWDF* r = *wdf;
306+
307+ r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
308+ r->port_conductance_up = (1.0f / r->port_resistance_up);
309+
310+ return r->port_resistance_up;
311+}
312+
313+static float get_port_resistance_for_resistive(tWDF* const wdf)
314+{
315+ _tWDF* r = *wdf;
316+
317+ r->port_resistance_up = r->value;
318+ r->port_conductance_up = 1.0f / r->port_resistance_up;
319+
320+ return r->port_resistance_up;
321+}
322+
323+static float get_port_resistance_for_inverter(tWDF* const wdf)
324+{
325+ _tWDF* r = *wdf;
326+
327+ r->port_resistance_up = tWDF_getPortResistance(r->child_left);
328+ r->port_conductance_up = 1.0f / r->port_resistance_up;
329+
330+ return r->port_resistance_up;
331+}
332+
333+static float get_port_resistance_for_series(tWDF* const wdf)
334+{
335+ _tWDF* r = *wdf;
336+
337+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
338+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
339+ r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
340+ r->port_conductance_up = 1.0f / r->port_resistance_up;
341+ r->port_conductance_left = 1.0f / r->port_resistance_left;
342+ r->port_conductance_right = 1.0f / r->port_resistance_right;
343+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
344+
345+ return r->port_resistance_up;
346+}
347+
348+static float get_port_resistance_for_parallel(tWDF* const wdf)
349+{
350+ _tWDF* r = *wdf;
351+
352+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
353+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
354+ r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
355+ r->port_conductance_up = 1.0f / r->port_resistance_up;
356+ r->port_conductance_left = 1.0f / r->port_resistance_left;
357+ r->port_conductance_right = 1.0f / r->port_resistance_right;
358+ r->gamma_zero = 1.0f / (r->port_conductance_right + r->port_conductance_left);
359+
360+ return r->port_resistance_up;
361+}
362+
363+static float get_port_resistance_for_root(tWDF* const wdf)
364+{
365+ _tWDF* r = *wdf;
366+
367+ tWDF* child;
368+ if (r->child_left != NULL) child = r->child_left;
369+ else child = r->child_right;
370+
371+ r->port_resistance_up = tWDF_getPortResistance(child);
372+ r->port_conductance_up = 1.0f / r->port_resistance_up;
373+
374+ return r->port_resistance_up;
375+}
376+
377+//===================================================================
378+//================ Set Incident Waves ===============================
379+
380+static void set_incident_wave_for_leaf(tWDF* const wdf, float incident_wave, float input)
381+{
382+ _tWDF* r = *wdf;
383+ r->incident_wave_up = incident_wave;
384+}
385+
386+static void set_incident_wave_for_leaf_inverted(tWDF* const wdf, float incident_wave, float input)
387+{
388+ _tWDF* r = *wdf;
389+ r->incident_wave_up = -1.0f * incident_wave;
390+}
391+
392+static void set_incident_wave_for_inverter(tWDF* const wdf, float incident_wave, float input)
393+{
394+ _tWDF* r = *wdf;
395+ r->incident_wave_up = incident_wave;
396+ tWDF_setIncidentWave(r->child_left, -1.0f * incident_wave, input);
397+}
398+
399+static void set_incident_wave_for_series(tWDF* const wdf, float incident_wave, float input)
400+{
401+ _tWDF* r = *wdf;
402+
403+ r->incident_wave_up = incident_wave;
404+ float gamma_left = r->port_resistance_left * r->gamma_zero;
405+ float gamma_right = r->port_resistance_right * r->gamma_zero;
406+ float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
407+ float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
408+// downPorts[0]->b = yl * ( downPorts[0]->a * ((1.0 / yl) - 1) - downPorts[1]->a - descendingWave );
409+// downPorts[1]->b = yr * ( downPorts[1]->a * ((1.0 / yr) - 1) - downPorts[0]->a - descendingWave );
410+ tWDF_setIncidentWave(r->child_left, (-1.0f * gamma_left * incident_wave) + (gamma_right * left_wave) - (gamma_left * right_wave), input);
411+ tWDF_setIncidentWave(r->child_right, (-1.0f * gamma_right * incident_wave) + (gamma_left * right_wave) - (gamma_right * left_wave), input);
412+ // From rt-wdf
413+// tWDF_setIncidentWave(r->child_left, gamma_left * (left_wave * ((1.0f / gamma_left) - 1.0f) - right_wave - incident_wave));
414+// tWDF_setIncidentWave(r->child_right, gamma_right * (right_wave * ((1.0f / gamma_right) - 1.0f) - left_wave - incident_wave));
415+
416+}
417+
418+static void set_incident_wave_for_parallel(tWDF* const wdf, float incident_wave, float input)
419+{
420+ _tWDF* r = *wdf;
421+
422+ r->incident_wave_up = incident_wave;
423+ float gamma_left = r->port_conductance_left * r->gamma_zero;
424+ float gamma_right = r->port_conductance_right * r->gamma_zero;
425+ float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
426+ float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
427+// downPorts[0]->b = ( ( dl - 1 ) * downPorts[0]->a + dr * downPorts[1]->a + du * descendingWave );
428+// downPorts[1]->b = ( dl * downPorts[0]->a + ( dr - 1 ) * downPorts[1]->a + du * descendingWave );
429+ tWDF_setIncidentWave(r->child_left, (gamma_left - 1.0f) * left_wave + gamma_right * right_wave + incident_wave, input);
430+ tWDF_setIncidentWave(r->child_right, gamma_left * left_wave + (gamma_right - 1.0f) * right_wave + incident_wave, input);
431+}
432+
433+//===================================================================
434+//================ Get Reflected Waves ==============================
435+
436+static float get_reflected_wave_for_resistor(tWDF* const wdf, float input)
437+{
438+ _tWDF* r = *wdf;
439+ r->reflected_wave_up = 0.0f;
440+ return r->reflected_wave_up;
441+}
442+
443+static float get_reflected_wave_for_capacitor(tWDF* const wdf, float input)
444+{
445+ _tWDF* r = *wdf;
446+ r->reflected_wave_up = r->incident_wave_up;
447+ return r->reflected_wave_up;
448+}
449+
450+static float get_reflected_wave_for_resistive(tWDF* const wdf, float input)
451+{
452+ _tWDF* r = *wdf;
453+ r->reflected_wave_up = input;
454+ return r->reflected_wave_up;
455+}
456+
457+static float get_reflected_wave_for_inverter(tWDF* const wdf, float input)
458+{
459+ _tWDF* r = *wdf;
460+ r->reflected_wave_up = -1.0f * tWDF_getReflectedWaveUp(r->child_left, input);
461+ return r->reflected_wave_up;
462+}
463+
464+static float get_reflected_wave_for_series(tWDF* const wdf, float input)
465+{
466+ _tWDF* r = *wdf;
467+ //-( downPorts[0]->a + downPorts[1]->a );
468+ r->reflected_wave_up = (-1.0f * (tWDF_getReflectedWaveUp(r->child_left, input) + tWDF_getReflectedWaveUp(r->child_right, input)));
469+ return r->reflected_wave_up;
470+}
471+
472+static float get_reflected_wave_for_parallel(tWDF* const wdf, float input)
473+{
474+ _tWDF* r = *wdf;
475+
476+ float gamma_left = r->port_conductance_left * r->gamma_zero;
477+ float gamma_right = r->port_conductance_right * r->gamma_zero;
478+ //return ( dl * downPorts[0]->a + dr * downPorts[1]->a );
479+ r->reflected_wave_up = (gamma_left * tWDF_getReflectedWaveUp(r->child_left, input) + gamma_right * tWDF_getReflectedWaveUp(r->child_right, input));
480+ return r->reflected_wave_up;
481+}
482+
483+static float get_reflected_wave_for_ideal(tWDF* const wdf, float input, float incident_wave)
484+{
485+ return (2.0f * input) - incident_wave;
486+}
487+
488+#define l2A 0.1640425613334452f
489+#define l2B -1.098865286222744f
490+#define l2Y 3.148297929334117f
491+#define l2K -2.213475204444817f
492+static float log2Approximation(float x)
493+{
494+ return (l2A * x*x*x) + (l2B * x*x) + (l2Y * x) + l2K;
495+}
496+
497+#define wX1 -3.684303659906469f
498+#define wX2 1.972967391708859f
499+#define wA 9.451797158780131e-3f
500+#define wB 0.1126446405111627f
501+#define wY 0.4451353886588814f
502+#define wK 0.5836596684310648f
503+static float wrightOmega3(float x)
504+{
505+ if (x <= wX1)
506+ {
507+ return 0;
508+ }
509+ else if (x < wX2)
510+ {
511+ return (wA * x*x*x) + (wB * x*x) + (wY * x) + wK;
512+ }
513+ else
514+ {
515+ return x - logf(x);
516+ }
517+}
518+
519+static float wrightOmegaApproximation(float x)
520+{
521+ float w3 = wrightOmega3(x);
522+ return w3 - ((w3 - expf(x - w3)) / (w3 + 1.0f));
523+}
524+
525+static float lambertW(float a, float r, float I, float iVT)
526+{
527+ return wrightOmegaApproximation(((a + r*I) * iVT) + log((r * I) * iVT));
528+}
529+
530+#define Is_DIODE 2.52e-9f
531+#define VT_DIODE 0.02585f
532+static float get_reflected_wave_for_diode(tWDF* const wdf, float input, float incident_wave)
533+{
534+ _tWDF* n = *wdf;
535+
536+ float a = incident_wave;
537+ float r = n->port_resistance_up;
538+ return a + 2.0f*r*Is_DIODE - 2.0f*VT_DIODE*lambertW(a, r, Is_DIODE, 1.0f/VT_DIODE);
539+}
540+
541+static float get_reflected_wave_for_diode_pair(tWDF* const wdf, float input, float incident_wave)
542+{
543+ _tWDF* n = *wdf;
544+
545+ float a = incident_wave;
546+ float sgn = 0.0f;
547+ if (a > 0.0f) sgn = 1.0f;
548+ else if (a < 0.0f) sgn = -1.0f;
549+ float r = n->port_resistance_up;
550+ return a + 2 * sgn * (r*Is_DIODE - VT_DIODE*lambertW(sgn*a, r, Is_DIODE, 1.0f/VT_DIODE));
551+}
leaf/Src/leaf-envelopes.c+1612−0
@@ -0,0 +1,1612 @@
1+/*
2+ ==============================================================================
3+
4+ leaf-envelopes.c
5+ Created: 20 Jan 2017 12:02:17pm
6+ Author: Michael R Mulshine
7+
8+ ==============================================================================
9+*/
10+
11+
12+#if _WIN32 || _WIN64
13+
14+#include "..\Inc\leaf-envelopes.h"
15+#include "..\Inc\leaf-tables.h"
16+#include "..\leaf.h"
17+
18+#else
19+
20+#include "../Inc/leaf-envelopes.h"
21+#include "../Inc/leaf-tables.h"
22+#include "../leaf.h"
23+
24+#endif
25+
26+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Envelope ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
27+void tEnvelope_init(tEnvelope* const envlp, float attack, float decay, int loop)
28+{
29+ _tEnvelope* env = *envlp = (_tEnvelope*) leaf_alloc(sizeof(_tEnvelope));
30+
31+ env->exp_buff = __leaf_table_exp_decay;
32+ env->inc_buff = __leaf_table_attack_decay_inc;
33+ env->buff_size = sizeof(__leaf_table_exp_decay);
34+
35+ env->loop = loop;
36+
37+ if (attack > 8192.0f)
38+ attack = 8192.0f;
39+ if (attack < 0.0f)
40+ attack = 0.0f;
41+
42+ if (decay > 8192.0f)
43+ decay = 8192.0f;
44+ if (decay < 0.0f)
45+ decay = 0.0f;
46+
47+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
48+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
49+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
50+
51+ if (attackIndex < 0)
52+ attackIndex = 0;
53+ if (decayIndex < 0)
54+ decayIndex = 0;
55+ if (rampIndex < 0)
56+ rampIndex = 0;
57+
58+ env->inRamp = OFALSE;
59+ env->inAttack = OFALSE;
60+ env->inDecay = OFALSE;
61+
62+ env->attackInc = env->inc_buff[attackIndex];
63+ env->decayInc = env->inc_buff[decayIndex];
64+ env->rampInc = env->inc_buff[rampIndex];
65+}
66+
67+void tEnvelope_free(tEnvelope* const envlp)
68+{
69+ _tEnvelope* env = *envlp;
70+ leaf_free((char*)env);
71+}
72+
73+void tEnvelope_initToPool (tEnvelope* const envlp, float attack, float decay, int loop, tMempool* const mp)
74+{
75+ _tMempool* m = *mp;
76+ _tEnvelope* env = *envlp = (_tEnvelope*) mpool_alloc(sizeof(_tEnvelope), m);
77+
78+ env->exp_buff = __leaf_table_exp_decay;
79+ env->inc_buff = __leaf_table_attack_decay_inc;
80+ env->buff_size = sizeof(__leaf_table_exp_decay);
81+
82+ env->loop = loop;
83+
84+ if (attack > 8192.0f)
85+ attack = 8192.0f;
86+ if (attack < 0.0f)
87+ attack = 0.0f;
88+
89+ if (decay > 8192.0f)
90+ decay = 8192.0f;
91+ if (decay < 0.0f)
92+ decay = 0.0f;
93+
94+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
95+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
96+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
97+
98+ if (attackIndex < 0)
99+ attackIndex = 0;
100+ if (decayIndex < 0)
101+ decayIndex = 0;
102+ if (rampIndex < 0)
103+ rampIndex = 0;
104+
105+ env->inRamp = OFALSE;
106+ env->inAttack = OFALSE;
107+ env->inDecay = OFALSE;
108+
109+ env->attackInc = env->inc_buff[attackIndex];
110+ env->decayInc = env->inc_buff[decayIndex];
111+ env->rampInc = env->inc_buff[rampIndex];
112+}
113+
114+void tEnvelope_freeFromPool (tEnvelope* const envlp, tMempool* const mp)
115+{
116+ _tMempool* m = *mp;
117+ _tEnvelope* env = *envlp;
118+ mpool_free((char*)env, m);
119+}
120+
121+void tEnvelope_setAttack(tEnvelope* const envlp, float attack)
122+{
123+ _tEnvelope* env = *envlp;
124+
125+ int32_t attackIndex;
126+
127+ if (attack < 0.0f) {
128+ attackIndex = 0.0f;
129+ } else if (attack < 8192.0f) {
130+ attackIndex = ((int32_t)(attack * 8.0f))-1;
131+ } else {
132+ attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
133+ }
134+
135+ env->attackInc = env->inc_buff[attackIndex];
136+}
137+
138+void tEnvelope_setDecay(tEnvelope* const envlp, float decay)
139+{
140+ _tEnvelope* env = *envlp;
141+
142+ int32_t decayIndex;
143+
144+ if (decay < 0.0f) {
145+ decayIndex = 0;
146+ } else if (decay < 8192.0f) {
147+ decayIndex = ((int32_t)(decay * 8.0f)) - 1;
148+ } else {
149+ decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
150+ }
151+
152+ env->decayInc = env->inc_buff[decayIndex];
153+}
154+
155+void tEnvelope_loop(tEnvelope* const envlp, int loop)
156+{
157+ _tEnvelope* env = *envlp;
158+ env->loop = loop;
159+}
160+
161+
162+void tEnvelope_on(tEnvelope* const envlp, float velocity)
163+{
164+ _tEnvelope* env = *envlp;
165+
166+ if (env->inAttack || env->inDecay) // In case envelope retriggered while it is still happening.
167+ {
168+ env->rampPhase = 0;
169+ env->inRamp = OTRUE;
170+ env->rampPeak = env->next;
171+ }
172+ else // Normal start.
173+ {
174+ env->inAttack = OTRUE;
175+ }
176+
177+
178+ env->attackPhase = 0;
179+ env->decayPhase = 0;
180+ env->inDecay = OFALSE;
181+ env->gain = velocity;
182+}
183+
184+float tEnvelope_tick(tEnvelope* const envlp)
185+{
186+ _tEnvelope* env = *envlp;
187+
188+ if (env->inRamp)
189+ {
190+ if (env->rampPhase > UINT16_MAX)
191+ {
192+ env->inRamp = OFALSE;
193+ env->inAttack = OTRUE;
194+ env->next = 0.0f;
195+ }
196+ else
197+ {
198+ env->next = env->rampPeak * env->exp_buff[(uint32_t)env->rampPhase];
199+ }
200+
201+ env->rampPhase += env->rampInc;
202+ }
203+
204+ if (env->inAttack)
205+ {
206+
207+ // If attack done, time to turn around.
208+ if (env->attackPhase > UINT16_MAX)
209+ {
210+ env->inDecay = OTRUE;
211+ env->inAttack = OFALSE;
212+ env->next = env->gain * 1.0f;
213+ }
214+ else
215+ {
216+ // do interpolation !
217+ env->next = env->gain * env->exp_buff[UINT16_MAX - (uint32_t)env->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
218+ }
219+
220+ // Increment envelope attack.
221+ env->attackPhase += env->attackInc;
222+
223+ }
224+
225+ if (env->inDecay)
226+ {
227+
228+ // If decay done, finish.
229+ if (env->decayPhase >= UINT16_MAX)
230+ {
231+ env->inDecay = OFALSE;
232+
233+ if (env->loop)
234+ {
235+ env->attackPhase = 0;
236+ env->decayPhase = 0;
237+ env->inAttack = OTRUE;
238+ }
239+ else
240+ {
241+ env->next = 0.0f;
242+ }
243+
244+ } else {
245+
246+ env->next = env->gain * (env->exp_buff[(uint32_t)env->decayPhase]); // do interpolation !
247+ }
248+
249+ // Increment envelope decay;
250+ env->decayPhase += env->decayInc;
251+ }
252+
253+ return env->next;
254+}
255+
256+
257+
258+/* ADSR */
259+void tADSR_init(tADSR* const adsrenv, float attack, float decay, float sustain, float release)
260+{
261+ tADSR_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
262+}
263+
264+void tADSR_free(tADSR* const adsrenv)
265+{
266+ tADSR_freeFromPool(adsrenv, &leaf.mempool);
267+}
268+
269+void tADSR_initToPool (tADSR* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
270+{
271+ _tMempool* m = *mp;
272+ _tADSR* adsr = *adsrenv = (_tADSR*) mpool_alloc(sizeof(_tADSR), m);
273+
274+ adsr->exp_buff = __leaf_table_exp_decay;
275+ adsr->inc_buff = __leaf_table_attack_decay_inc;
276+ adsr->buff_size = sizeof(__leaf_table_exp_decay);
277+
278+ if (attack > 8192.0f)
279+ attack = 8192.0f;
280+ if (attack < 0.0f)
281+ attack = 0.0f;
282+
283+ if (decay > 8192.0f)
284+ decay = 8192.0f;
285+ if (decay < 0.0f)
286+ decay = 0.0f;
287+
288+ if (sustain > 1.0f)
289+ sustain = 1.0f;
290+ if (sustain < 0.0f)
291+ sustain = 0.0f;
292+
293+ if (release > 8192.0f)
294+ release = 8192.0f;
295+ if (release < 0.0f)
296+ release = 0.0f;
297+
298+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
299+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
300+ int16_t releaseIndex = ((int16_t)(release * 8.0f))-1;
301+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
302+
303+ if (attackIndex < 0)
304+ attackIndex = 0;
305+ if (decayIndex < 0)
306+ decayIndex = 0;
307+ if (releaseIndex < 0)
308+ releaseIndex = 0;
309+ if (rampIndex < 0)
310+ rampIndex = 0;
311+
312+ adsr->next = 0.0f;
313+
314+ adsr->inRamp = OFALSE;
315+ adsr->inAttack = OFALSE;
316+ adsr->inDecay = OFALSE;
317+ adsr->inSustain = OFALSE;
318+ adsr->inRelease = OFALSE;
319+
320+ adsr->sustain = sustain;
321+
322+ adsr->attackInc = adsr->inc_buff[attackIndex];
323+ adsr->decayInc = adsr->inc_buff[decayIndex];
324+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
325+ adsr->rampInc = adsr->inc_buff[rampIndex];
326+
327+ adsr->leakFactor = 1.0f;
328+}
329+
330+void tADSR_freeFromPool (tADSR* const adsrenv, tMempool* const mp)
331+{
332+ _tMempool* m = *mp;
333+ _tADSR* adsr = *adsrenv;
334+ mpool_free((char*)adsr, m);
335+}
336+
337+void tADSR_setAttack(tADSR* const adsrenv, float attack)
338+{
339+ _tADSR* adsr = *adsrenv;
340+
341+ int32_t attackIndex;
342+
343+ if (attack < 0.0f) {
344+ attackIndex = 0.0f;
345+ } else if (attack < 8192.0f) {
346+ attackIndex = ((int32_t)(attack * 8.0f))-1;
347+ } else {
348+ attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
349+ }
350+
351+ adsr->attackInc = adsr->inc_buff[attackIndex];
352+}
353+
354+void tADSR_setDecay(tADSR* const adsrenv, float decay)
355+{
356+ _tADSR* adsr = *adsrenv;
357+
358+ int32_t decayIndex;
359+
360+ if (decay < 0.0f) {
361+ decayIndex = 0.0f;
362+ } else if (decay < 8192.0f) {
363+ decayIndex = ((int32_t)(decay * 8.0f)) - 1;
364+ } else {
365+ decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
366+ }
367+
368+ adsr->decayInc = adsr->inc_buff[decayIndex];
369+}
370+
371+void tADSR_setSustain(tADSR* const adsrenv, float sustain)
372+{
373+ _tADSR* adsr = *adsrenv;
374+
375+ if (sustain > 1.0f) adsr->sustain = 1.0f;
376+ else if (sustain < 0.0f) adsr->sustain = 0.0f;
377+ else adsr->sustain = sustain;
378+}
379+
380+void tADSR_setRelease(tADSR* const adsrenv, float release)
381+{
382+ _tADSR* adsr = *adsrenv;
383+
384+ int32_t releaseIndex;
385+
386+ if (release < 0.0f) {
387+ releaseIndex = 0.0f;
388+ } else if (release < 8192.0f) {
389+ releaseIndex = ((int32_t)(release * 8.0f)) - 1;
390+ } else {
391+ releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
392+ }
393+
394+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
395+}
396+
397+// 0.999999 is slow leak, 0.9 is fast leak
398+void tADSR_setLeakFactor(tADSR* const adsrenv, float leakFactor)
399+{
400+ _tADSR* adsr = *adsrenv;
401+
402+
403+ adsr->leakFactor = leakFactor;
404+}
405+
406+void tADSR_on(tADSR* const adsrenv, float velocity)
407+{
408+ _tADSR* adsr = *adsrenv;
409+
410+ if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
411+ {
412+ adsr->rampPhase = 0;
413+ adsr->inRamp = OTRUE;
414+ adsr->rampPeak = adsr->next;
415+ }
416+ else // Normal start.
417+ {
418+ adsr->inAttack = OTRUE;
419+ }
420+
421+ adsr->attackPhase = 0;
422+ adsr->decayPhase = 0;
423+ adsr->releasePhase = 0;
424+ adsr->inDecay = OFALSE;
425+ adsr->inSustain = OFALSE;
426+ adsr->inRelease = OFALSE;
427+ adsr->gain = velocity;
428+}
429+
430+void tADSR_off(tADSR* const adsrenv)
431+{
432+ _tADSR* adsr = *adsrenv;
433+
434+ if (adsr->inRelease) return;
435+
436+ adsr->inAttack = OFALSE;
437+ adsr->inDecay = OFALSE;
438+ adsr->inSustain = OFALSE;
439+ adsr->inRelease = OTRUE;
440+
441+ adsr->releasePeak = adsr->next;
442+}
443+
444+float tADSR_tick(tADSR* const adsrenv)
445+{
446+ _tADSR* adsr = *adsrenv;
447+
448+
449+ if (adsr->inRamp)
450+ {
451+ if (adsr->rampPhase > UINT16_MAX)
452+ {
453+ adsr->inRamp = OFALSE;
454+ adsr->inAttack = OTRUE;
455+ adsr->next = 0.0f;
456+ }
457+ else
458+ {
459+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
460+ }
461+
462+ adsr->rampPhase += adsr->rampInc;
463+ }
464+
465+ if (adsr->inAttack)
466+ {
467+
468+ // If attack done, time to turn around.
469+ if (adsr->attackPhase > UINT16_MAX)
470+ {
471+ adsr->inDecay = OTRUE;
472+ adsr->inAttack = OFALSE;
473+ adsr->next = adsr->gain * 1.0f;
474+ }
475+ else
476+ {
477+ // do interpolation !
478+ adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
479+ }
480+
481+ // Increment ADSR attack.
482+ adsr->attackPhase += adsr->attackInc;
483+
484+ }
485+
486+ if (adsr->inDecay)
487+ {
488+
489+ // If decay done, sustain.
490+ if (adsr->decayPhase >= UINT16_MAX)
491+ {
492+ adsr->inDecay = OFALSE;
493+ adsr->inSustain = OTRUE;
494+ adsr->next = adsr->gain * adsr->sustain;
495+ }
496+
497+ else
498+ {
499+ adsr->next = (adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
500+ }
501+
502+ // Increment ADSR decay.
503+ adsr->decayPhase += adsr->decayInc;
504+ }
505+
506+ if (adsr->inSustain)
507+ {
508+ adsr->next = adsr->next * adsr->leakFactor;
509+ }
510+
511+ if (adsr->inRelease)
512+ {
513+ // If release done, finish.
514+ if (adsr->releasePhase >= UINT16_MAX)
515+ {
516+ adsr->inRelease = OFALSE;
517+ adsr->next = 0.0f;
518+ }
519+ else {
520+
521+ adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation !
522+ }
523+
524+ // Increment envelope release;
525+ adsr->releasePhase += adsr->releaseInc;
526+ }
527+
528+
529+ return adsr->next;
530+}
531+
532+
533+
534+
535+/* ADSR 2*/
536+//This one is adapted from the VCV Rack code
537+//-JS
538+
539+
540+
541+const float ADSR2_MIN_TIME = 1e-3f;
542+const float ADSR2_INV_MIN_TIME = 1000.0f;
543+const float ADSR2_MAX_TIME = 10.f;
544+const float ADSR2_LAMBDA_BASE = 10000.0f;
545+
546+
547+void tADSR2_init(tADSR2* const adsrenv, float attack, float decay, float sustain, float release)
548+{
549+ tADSR2_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
550+}
551+
552+void tADSR2_free(tADSR2* const adsrenv)
553+{
554+ tADSR2_freeFromPool(adsrenv, &leaf.mempool);
555+}
556+
557+void tADSR2_initToPool (tADSR2* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
558+{
559+ _tMempool* m = *mp;
560+ _tADSR2* adsr = *adsrenv = (_tADSR2*) mpool_alloc(sizeof(_tADSR2), m);
561+ adsr->sampleRateInMs = leaf.sampleRate * 0.001f;
562+ adsr->attack = LEAF_clip(0.0f, attack * 0.001f, 1.0f);
563+ adsr->attackLambda = powf(ADSR2_LAMBDA_BASE, -adsr->attack) * ADSR2_INV_MIN_TIME;
564+
565+
566+ adsr->decay = LEAF_clip(0.0f, decay * 0.001f, 1.0f);
567+ adsr->decayLambda = powf(ADSR2_LAMBDA_BASE, -adsr->decay) * ADSR2_INV_MIN_TIME;
568+
569+
570+ adsr->sustain= sustain;
571+
572+
573+ adsr->release = LEAF_clip(0.0f, release * 0.001f, 1.0f);
574+ adsr->releaseLambda = powf(ADSR2_LAMBDA_BASE, -adsr->release) * ADSR2_INV_MIN_TIME;
575+
576+ adsr->attacking = 0;
577+ adsr->gate = 0;
578+ adsr->gain = 1.0f;
579+ adsr->targetGainSquared = 1.0f;
580+ adsr->factor = 0.01f;
581+ adsr->oneMinusFactor = 0.99f;
582+ adsr->env = 0.0f;
583+ adsr->leakFactor = 1.0f;
584+}
585+
586+void tADSR2_freeFromPool (tADSR2* const adsrenv, tMempool* const mp)
587+{
588+ _tMempool* m = *mp;
589+ _tADSR2* adsr = *adsrenv;
590+ mpool_free((char*)adsr, m);
591+}
592+
593+void tADSR2_setAttack(tADSR2* const adsrenv, float attack)
594+{
595+ _tADSR2* adsr = *adsrenv;
596+ adsr->attack = LEAF_clip(0.0f, attack * 0.001f, 1.0f);
597+ adsr->attackLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->attack) * ADSR2_INV_MIN_TIME;
598+
599+}
600+
601+void tADSR2_setDecay(tADSR2* const adsrenv, float decay)
602+{
603+ _tADSR2* adsr = *adsrenv;
604+ adsr->decay = LEAF_clip(0.0f, decay * 0.001f, 1.0f);
605+ adsr->decayLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->decay) * ADSR2_INV_MIN_TIME;
606+
607+}
608+
609+void tADSR2_setSustain(tADSR2* const adsrenv, float sustain)
610+{
611+ _tADSR2* adsr = *adsrenv;
612+ adsr->sustain = sustain;
613+
614+ if (adsr->gate)
615+ {
616+ if (adsr->attacking == 0)
617+ {
618+ adsr->envTarget = sustain;
619+ }
620+ }
621+}
622+
623+void tADSR2_setRelease(tADSR2* const adsrenv, float release)
624+{
625+ _tADSR2* adsr = *adsrenv;
626+ adsr->release = LEAF_clip(0.0f, release * 0.001f, 1.0f);
627+ adsr->releaseLambda = fastPow(ADSR2_LAMBDA_BASE, -adsr->release) * ADSR2_INV_MIN_TIME;
628+}
629+
630+// 0.999999 is slow leak, 0.9 is fast leak
631+void tADSR2_setLeakFactor(tADSR2* const adsrenv, float leakFactor)
632+{
633+ _tADSR2* adsr = *adsrenv;
634+
635+ adsr->leakFactor = leakFactor;
636+}
637+
638+void tADSR2_on(tADSR2* const adsrenv, float velocity)
639+{
640+ _tADSR2* adsr = *adsrenv;
641+ adsr->targetGainSquared = velocity * velocity;
642+ adsr->envTarget = 1.2f;
643+ adsr->leakGain = 1.0f;
644+ adsr->gate = 1;
645+ adsr->attacking = 1;
646+}
647+
648+void tADSR2_off(tADSR2* const adsrenv)
649+{
650+ _tADSR2* adsr = *adsrenv;
651+ adsr->gate = 0;
652+ adsr->envTarget = 0.0f;
653+}
654+
655+float tADSR2_tick(tADSR2* const adsrenv)
656+{
657+ _tADSR2* adsr = *adsrenv;
658+ float lambda;
659+
660+ if (adsr->gate)
661+ {
662+ if (adsr->attacking)
663+ {
664+ lambda = adsr->attackLambda;
665+ }
666+ else
667+ {
668+ lambda = adsr->decayLambda;
669+ }
670+ }
671+ else
672+ {
673+ lambda = adsr->releaseLambda;
674+ }
675+
676+
677+ // Adjust env
678+ adsr->env += (adsr->envTarget - adsr->env) * lambda * leaf.invSampleRate;
679+
680+ // Turn off attacking state if envelope is HIGH
681+ if (adsr->env >= 1.0f)
682+ {
683+ adsr->attacking = 0;
684+ adsr->envTarget = adsr->sustain;
685+ }
686+
687+ //smooth the gain value -- this is not ideal, a retrigger while the envelope is still going with a new gain will cause a jump, although it will be smoothed quickly. Maybe doing the math so the range is computed based on the gain rather than 0.->1. is preferable? But that's harder to get the exponential curve right without a lookup.
688+ adsr->gain = ((adsr->factor*adsr->targetGainSquared)+(adsr->oneMinusFactor*adsr->gain));
689+ adsr->leakGain *= adsr->leakFactor;
690+ return adsr->env * adsr->gain * adsr->leakGain;
691+}
692+
693+/* ADSR 3*/
694+//This one doesn't use any lookup table - by Nigel Redmon from his blog. Thanks, Nigel!
695+//-JS
696+
697+float calcADSR3Coef(double rate, double targetRatio)
698+{
699+ return (rate <= 0.0f) ? 0.0f : exp(-log((1.0 + targetRatio) / targetRatio) / rate);
700+}
701+
702+
703+void tADSR3_init(tADSR3* const adsrenv, float attack, float decay, float sustain, float release)
704+{
705+ tADSR3_initToPool(adsrenv, attack, decay, sustain, release, &leaf.mempool);
706+}
707+
708+void tADSR3_free(tADSR3* const adsrenv)
709+{
710+ tADSR3_freeFromPool(adsrenv, &leaf.mempool);
711+}
712+
713+void tADSR3_initToPool (tADSR3* const adsrenv, float attack, float decay, float sustain, float release, tMempool* const mp)
714+{
715+ _tMempool* m = *mp;
716+ _tADSR3* adsr = *adsrenv = (_tADSR3*) mpool_alloc(sizeof(_tADSR3), m);
717+ adsr->sampleRateInMs = leaf.sampleRate * 0.001f;
718+ adsr->targetRatioA = 0.3f;
719+ adsr->targetRatioDR = 0.0001f;
720+ adsr->attackRate = attack * adsr->sampleRateInMs;
721+ adsr->attackCoef = calcADSR3Coef(attack * adsr->sampleRateInMs, adsr->targetRatioA);
722+ adsr->attackBase = (1.0f + adsr->targetRatioA) * (1.0f - adsr->attackCoef);
723+
724+ adsr->decayRate = decay * adsr->sampleRateInMs;
725+ adsr->decayCoef = calcADSR3Coef(decay * adsr->sampleRateInMs,adsr-> targetRatioDR);
726+ adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
727+
728+ adsr->sustainLevel = sustain;
729+ adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
730+
731+ adsr->releaseRate = release * adsr->sampleRateInMs;
732+ adsr->releaseCoef = calcADSR3Coef(release * adsr->sampleRateInMs, adsr->targetRatioDR);
733+ adsr->releaseBase = -adsr->targetRatioDR * (1.0f - adsr->releaseCoef);
734+
735+ adsr->state = env_idle;
736+ adsr->gain = 1.0f;
737+ adsr->targetGainSquared = 1.0f;
738+ adsr->factor = 0.01f;
739+ adsr->oneMinusFactor = 0.99f;
740+ adsr->output = 0.0f;
741+ adsr->leakFactor = 1.0f;
742+}
743+
744+void tADSR3_freeFromPool (tADSR3* const adsrenv, tMempool* const mp)
745+{
746+ _tMempool* m = *mp;
747+ _tADSR3* adsr = *adsrenv;
748+ mpool_free((char*)adsr, m);
749+}
750+
751+void tADSR3_setAttack(tADSR3* const adsrenv, float attack)
752+{
753+ _tADSR3* adsr = *adsrenv;
754+
755+ adsr->attackRate = attack * adsr->sampleRateInMs;
756+ adsr->attackCoef = calcADSR3Coef(adsr->attackRate, adsr->targetRatioA);
757+ adsr->attackBase = (1.0f + adsr->targetRatioA) * (1.0f - adsr->attackCoef);
758+}
759+
760+void tADSR3_setDecay(tADSR3* const adsrenv, float decay)
761+{
762+ _tADSR3* adsr = *adsrenv;
763+
764+ adsr->decayRate = decay * adsr->sampleRateInMs;
765+ adsr->decayCoef = calcADSR3Coef(adsr->decayRate,adsr-> targetRatioDR);
766+ adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
767+}
768+
769+void tADSR3_setSustain(tADSR3* const adsrenv, float sustain)
770+{
771+ _tADSR3* adsr = *adsrenv;
772+
773+ adsr->sustainLevel = sustain;
774+ adsr->decayBase = (adsr->sustainLevel - adsr->targetRatioDR) * (1.0f - adsr->decayCoef);
775+}
776+
777+void tADSR3_setRelease(tADSR3* const adsrenv, float release)
778+{
779+ _tADSR3* adsr = *adsrenv;
780+
781+ adsr->releaseRate = release * adsr->sampleRateInMs;
782+ adsr->releaseCoef = calcADSR3Coef(adsr->releaseRate, adsr->targetRatioDR);
783+ adsr->releaseBase = -adsr->targetRatioDR * (1.0f - adsr->releaseCoef);
784+}
785+
786+// 0.999999 is slow leak, 0.9 is fast leak
787+void tADSR3_setLeakFactor(tADSR3* const adsrenv, float leakFactor)
788+{
789+ _tADSR3* adsr = *adsrenv;
790+
791+ adsr->leakFactor = leakFactor;
792+}
793+
794+void tADSR3_on(tADSR3* const adsrenv, float velocity)
795+{
796+ _tADSR3* adsr = *adsrenv;
797+ adsr->state = env_attack;
798+ adsr->targetGainSquared = velocity * velocity;
799+}
800+
801+void tADSR3_off(tADSR3* const adsrenv)
802+{
803+ _tADSR3* adsr = *adsrenv;
804+
805+ if (adsr->state != env_idle)
806+ {
807+ adsr->state = env_release;
808+ }
809+}
810+
811+float tADSR3_tick(tADSR3* const adsrenv)
812+{
813+ _tADSR3* adsr = *adsrenv;
814+
815+
816+ switch (adsr->state) {
817+ case env_idle:
818+ break;
819+ case env_attack:
820+ adsr->output = adsr->attackBase + adsr->output * adsr->attackCoef;
821+ if (adsr->output >= 1.0f) {
822+ adsr->output = 1.0f;
823+ adsr->state = env_decay;
824+ }
825+ break;
826+ case env_decay:
827+ adsr->output = adsr->decayBase + adsr->output * adsr->decayCoef * adsr->leakFactor;
828+ if (adsr->output <= adsr->sustainLevel) {
829+ adsr->output = adsr->sustainLevel;
830+ adsr->state = env_sustain;
831+ }
832+ break;
833+ case env_sustain:
834+ adsr->output = adsr->output * adsr->leakFactor;
835+ break;
836+ case env_release:
837+ adsr->output = adsr->releaseBase + adsr->output * adsr->releaseCoef;
838+ if (adsr->output <= 0.0f) {
839+ adsr->output = 0.0f;
840+ adsr->state = env_idle;
841+ }
842+ }
843+ //smooth the gain value -- this is not ideal, a retrigger while the envelope is still going with a new gain will cause a jump, although it will be smoothed quickly. Maybe doing the math so the range is computed based on the gain rather than 0.->1. is preferable? But that's harder to get the exponential curve right without a lookup.
844+ adsr->gain = (adsr->factor*adsr->targetGainSquared)+(adsr->oneMinusFactor*adsr->gain);
845+ return adsr->output * adsr->gain;
846+}
847+
848+
849+/* ADSR 4 */ // new version of our original table-based ADSR but with the table passed in by the user
850+// use this if the size of the big ADSR tables is too much.
851+void tADSR4_init (tADSR4* const adsrenv, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize)
852+{
853+ tADSR4_initToPool (adsrenv, attack, decay, sustain, release, expBuffer, bufferSize, &leaf.mempool);
854+}
855+
856+void tADSR4_free(tADSR4* const adsrenv)
857+{
858+ tADSR4_freeFromPool(adsrenv, &leaf.mempool);
859+}
860+
861+//initialize with an exponential function that decays -- i.e. a call to LEAF_generate_exp(expBuffer, 0.001f, 0.0f, 1.0f, -0.0008f, EXP_BUFFER_SIZE);
862+//times are in ms
863+void tADSR4_initToPool (tADSR4* const adsrenv, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize, tMempool* const mp)
864+{
865+ _tMempool* m = *mp;
866+ _tADSR4* adsr = *adsrenv = (_tADSR4*) mpool_alloc(sizeof(_tADSR4), m);
867+
868+ adsr->exp_buff = expBuffer;
869+ adsr->buff_size = bufferSize;
870+ adsr->buff_sizeMinusOne = bufferSize - 1;
871+
872+ adsr->bufferSizeDividedBySampleRateInMs = bufferSize / (leaf.sampleRate * 0.001f);
873+
874+ if (attack < 0.0f)
875+ attack = 0.0f;
876+
877+ if (decay < 0.0f)
878+ decay = 0.0f;
879+
880+ if (sustain > 1.0f)
881+ sustain = 1.0f;
882+ if (sustain < 0.0f)
883+ sustain = 0.0f;
884+
885+ if (release < 0.0f)
886+ release = 0.0f;
887+
888+ adsr->next = 0.0f;
889+
890+ adsr->whichStage = env_idle;
891+
892+ adsr->sustain = sustain;
893+
894+ adsr->attackInc = adsr->bufferSizeDividedBySampleRateInMs / attack;
895+ adsr->decayInc = adsr->bufferSizeDividedBySampleRateInMs / decay;
896+ adsr->releaseInc = adsr->bufferSizeDividedBySampleRateInMs / release;
897+ adsr->rampInc = adsr->bufferSizeDividedBySampleRateInMs / 8.0f;
898+
899+ adsr->leakFactor = 1.0f;
900+}
901+
902+void tADSR4_freeFromPool (tADSR4* const adsrenv, tMempool* const mp)
903+{
904+ _tMempool* m = *mp;
905+ _tADSR4* adsr = *adsrenv;
906+ mpool_free((char*)adsr, m);
907+}
908+
909+void tADSR4_setAttack(tADSR4* const adsrenv, float attack)
910+{
911+ _tADSR4* adsr = *adsrenv;
912+
913+ if (attack < 0.0f)
914+ {
915+ attack = 0.0f;
916+ }
917+
918+ adsr->attackInc = adsr->bufferSizeDividedBySampleRateInMs / attack;
919+}
920+
921+void tADSR4_setDecay(tADSR4* const adsrenv, float decay)
922+{
923+ _tADSR4* adsr = *adsrenv;
924+
925+ if (decay < 0.0f)
926+ {
927+ decay = 0.0f;
928+ }
929+ adsr->decayInc = adsr->bufferSizeDividedBySampleRateInMs / decay;
930+}
931+
932+void tADSR4_setSustain(tADSR4* const adsrenv, float sustain)
933+{
934+ _tADSR4* adsr = *adsrenv;
935+
936+ if (sustain > 1.0f) adsr->sustain = 1.0f;
937+ else if (sustain < 0.0f) adsr->sustain = 0.0f;
938+ else adsr->sustain = sustain;
939+}
940+
941+void tADSR4_setRelease(tADSR4* const adsrenv, float release)
942+{
943+ _tADSR4* adsr = *adsrenv;
944+
945+ if (release < 0.0f)
946+ {
947+ release = 0.0f;
948+ }
949+ adsr->releaseInc = adsr->bufferSizeDividedBySampleRateInMs / release;
950+}
951+
952+// 0.999999 is slow leak, 0.9 is fast leak
953+void tADSR4_setLeakFactor(tADSR4* const adsrenv, float leakFactor)
954+{
955+ _tADSR4* adsr = *adsrenv;
956+
957+
958+ adsr->leakFactor = leakFactor;
959+}
960+
961+void tADSR4_on(tADSR4* const adsrenv, float velocity)
962+{
963+ _tADSR4* adsr = *adsrenv;
964+
965+ if (adsr->whichStage != env_idle) // In case ADSR retriggered while it is still happening.
966+ {
967+ adsr->rampPhase = 0;
968+ adsr->whichStage = env_ramp;
969+ adsr->rampPeak = adsr->next;
970+ }
971+ else // Normal start.
972+ {
973+ adsr->whichStage = env_attack;
974+ }
975+
976+ adsr->attackPhase = 0;
977+ adsr->decayPhase = 0;
978+ adsr->releasePhase = 0;
979+ adsr->gain = velocity;
980+}
981+
982+void tADSR4_off(tADSR4* const adsrenv)
983+{
984+ _tADSR4* adsr = *adsrenv;
985+
986+ if (adsr->whichStage == env_idle)
987+ {
988+ return;
989+ }
990+ else
991+ {
992+ adsr->whichStage = env_release;
993+ adsr->releasePeak = adsr->next;
994+ }
995+}
996+
997+float tADSR4_tick(tADSR4* const adsrenv)
998+{
999+ _tADSR4* adsr = *adsrenv;
1000+
1001+ switch (adsr->whichStage)
1002+ {
1003+ case env_ramp:
1004+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1005+ {
1006+ adsr->whichStage = env_attack;
1007+ adsr->next = 0.0f;
1008+ }
1009+ else
1010+ {
1011+ uint32_t intPart = (uint32_t)adsr->rampPhase;
1012+ float floatPart = adsr->rampPhase - intPart;
1013+ float secondValue;
1014+ if (adsr->rampPhase + 1.0f > adsr->buff_sizeMinusOne)
1015+ {
1016+ secondValue = 0.0f;
1017+ }
1018+ else
1019+ {
1020+ secondValue = adsr->exp_buff[(uint32_t)((adsr->rampPhase)+1)];
1021+ }
1022+ adsr->next = adsr->rampPeak * LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart);
1023+ }
1024+
1025+ adsr->rampPhase += adsr->rampInc;
1026+ break;
1027+
1028+
1029+ case env_attack:
1030+
1031+ // If attack done, time to turn around.
1032+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1033+ {
1034+ adsr->whichStage = env_decay;
1035+ adsr->next = adsr->gain;
1036+ }
1037+ else
1038+ {
1039+ // do interpolation !
1040+ uint32_t intPart = (uint32_t)adsr->attackPhase;
1041+ float floatPart = adsr->attackPhase - intPart;
1042+ float secondValue;
1043+ if (adsr->attackPhase + 1.0f > adsr->buff_sizeMinusOne)
1044+ {
1045+ secondValue = 0.0f;
1046+ }
1047+ else
1048+ {
1049+ secondValue = adsr->exp_buff[(uint32_t)((adsr->attackPhase)+1)];
1050+ }
1051+
1052+ adsr->next = adsr->gain * (1.0f - LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart)); // inverted and backwards to get proper rising exponential shape/perception
1053+ }
1054+
1055+ // Increment ADSR attack.
1056+ adsr->attackPhase += adsr->attackInc;
1057+ break;
1058+
1059+ case env_decay:
1060+
1061+ // If decay done, sustain.
1062+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1063+ {
1064+ adsr->whichStage = env_sustain;
1065+ adsr->next = adsr->gain * adsr->sustain;
1066+ }
1067+
1068+ else
1069+ {
1070+ uint32_t intPart = (uint32_t)adsr->decayPhase;
1071+ float floatPart = adsr->decayPhase - intPart;
1072+ float secondValue;
1073+ if (adsr->decayPhase + 1.0f > adsr->buff_sizeMinusOne)
1074+ {
1075+ secondValue = 0.0f;
1076+ }
1077+ else
1078+ {
1079+ secondValue = adsr->exp_buff[(uint32_t)((adsr->decayPhase)+1)];
1080+ }
1081+ float interpValue = (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart));
1082+ adsr->next = (adsr->gain * (adsr->sustain + (interpValue * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
1083+ }
1084+
1085+ // Increment ADSR decay.
1086+ adsr->decayPhase += adsr->decayInc;
1087+ break;
1088+
1089+ case env_sustain:
1090+ adsr->next = adsr->next * adsr->leakFactor;
1091+ break;
1092+
1093+ case env_release:
1094+ // If release done, finish.
1095+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1096+ {
1097+ adsr->whichStage = env_idle;
1098+ adsr->next = 0.0f;
1099+ }
1100+ else {
1101+ uint32_t intPart = (uint32_t)adsr->releasePhase;
1102+ float floatPart = adsr->releasePhase - intPart;
1103+ float secondValue;
1104+ if (adsr->releasePhase + 1.0f > adsr->buff_sizeMinusOne)
1105+ {
1106+ secondValue = 0.0f;
1107+ }
1108+ else
1109+ {
1110+ secondValue = adsr->exp_buff[(uint32_t)((adsr->releasePhase)+1)];
1111+ }
1112+ adsr->next = adsr->releasePeak * (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart)); // do interpolation !
1113+ }
1114+
1115+ // Increment envelope release;
1116+ adsr->releasePhase += adsr->releaseInc;
1117+ break;
1118+ }
1119+ return adsr->next;
1120+}
1121+
1122+float tADSR4_tickNoInterp(tADSR4* const adsrenv)
1123+{
1124+ _tADSR4* adsr = *adsrenv;
1125+
1126+ switch (adsr->whichStage)
1127+ {
1128+ case env_ramp:
1129+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1130+ {
1131+ adsr->whichStage = env_attack;
1132+ adsr->next = 0.0f;
1133+ }
1134+ else
1135+ {
1136+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
1137+ }
1138+
1139+ adsr->rampPhase += adsr->rampInc;
1140+ break;
1141+
1142+
1143+ case env_attack:
1144+
1145+ // If attack done, time to turn around.
1146+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1147+ {
1148+ adsr->whichStage = env_decay;
1149+ adsr->next = adsr->gain;
1150+ }
1151+ else
1152+ {
1153+ adsr->next = adsr->gain * (1.0f - adsr->exp_buff[(uint32_t)adsr->attackPhase]); // inverted and backwards to get proper rising exponential shape/perception
1154+ }
1155+
1156+ // Increment ADSR attack.
1157+ adsr->attackPhase += adsr->attackInc;
1158+ break;
1159+
1160+ case env_decay:
1161+
1162+ // If decay done, sustain.
1163+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1164+ {
1165+ adsr->whichStage = env_sustain;
1166+ adsr->next = adsr->gain * adsr->sustain;
1167+ }
1168+
1169+ else
1170+ {
1171+ adsr->next = (adsr->gain * (adsr->sustain + (adsr->exp_buff[(uint32_t)adsr->decayPhase] * (1.0f - adsr->sustain)))) * adsr->leakFactor;
1172+ }
1173+
1174+ // Increment ADSR decay.
1175+ adsr->decayPhase += adsr->decayInc;
1176+ break;
1177+
1178+ case env_sustain:
1179+ adsr->next = adsr->next * adsr->leakFactor;
1180+ break;
1181+
1182+ case env_release:
1183+ // If release done, finish.
1184+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1185+ {
1186+ adsr->whichStage = env_idle;
1187+ adsr->next = 0.0f;
1188+ }
1189+ else {
1190+ adsr->next = adsr->releasePeak * adsr->exp_buff[(uint32_t)adsr->releasePhase];
1191+ }
1192+
1193+ // Increment envelope release;
1194+ adsr->releasePhase += adsr->releaseInc;
1195+ break;
1196+ }
1197+ return adsr->next;
1198+}
1199+
1200+
1201+
1202+/////-----------------
1203+/* Ramp */
1204+void tRamp_init(tRamp* const r, float time, int samples_per_tick)
1205+{
1206+ _tRamp* ramp = *r = (_tRamp*) leaf_alloc(sizeof(_tRamp));
1207+
1208+ ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f);
1209+ ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick;
1210+ ramp->curr = 0.0f;
1211+ ramp->dest = 0.0f;
1212+
1213+ if (time < ramp->minimum_time)
1214+ {
1215+ ramp->time = ramp->minimum_time;
1216+ }
1217+ else
1218+ {
1219+ ramp->time = time;
1220+ }
1221+ ramp->factor = (1.0f / ramp->time) * ramp->inv_sr_ms;
1222+ ramp->samples_per_tick = samples_per_tick;
1223+ ramp->inc = ((ramp->dest - ramp->curr) / ramp->time * ramp->inv_sr_ms) * (float)ramp->samples_per_tick;
1224+}
1225+
1226+void tRamp_free(tRamp* const r)
1227+{
1228+ _tRamp* ramp = *r;
1229+
1230+ leaf_free((char*)ramp);
1231+}
1232+
1233+void tRamp_initToPool (tRamp* const r, float time, int samples_per_tick, tMempool* const mp)
1234+{
1235+ _tMempool* m = *mp;
1236+ _tRamp* ramp = *r = (_tRamp*) mpool_alloc(sizeof(_tRamp), m);
1237+
1238+ ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f);
1239+ ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick;
1240+ ramp->curr = 0.0f;
1241+ ramp->dest = 0.0f;
1242+
1243+ if (time < ramp->minimum_time)
1244+ {
1245+ ramp->time = ramp->minimum_time;
1246+ }
1247+ else
1248+ {
1249+ ramp->time = time;
1250+ }
1251+ ramp->samples_per_tick = samples_per_tick;
1252+ ramp->factor = (1.0f / ramp->time) * ramp->inv_sr_ms * (float)ramp->samples_per_tick;
1253+ ramp->inc = (ramp->dest - ramp->curr) * ramp->factor;
1254+}
1255+
1256+void tRamp_freeFromPool (tRamp* const r, tMempool* const mp)
1257+{
1258+ _tMempool* m = *mp;
1259+ _tRamp* ramp = *r;
1260+
1261+ mpool_free((char*)ramp, m);
1262+}
1263+
1264+void tRamp_setTime(tRamp* const ramp, float time)
1265+{
1266+ _tRamp* r = *ramp;
1267+
1268+ if (time < r->minimum_time)
1269+ {
1270+ r->time = r->minimum_time;
1271+ }
1272+ else
1273+ {
1274+ r->time = time;
1275+ }
1276+ r->factor = (1.0f / r->time) * r->inv_sr_ms * (float)r->samples_per_tick;
1277+ r->inc = (r->dest - r->curr) * r->factor;
1278+
1279+}
1280+
1281+void tRamp_setDest(tRamp* const ramp, float dest)
1282+{
1283+ _tRamp* r = *ramp;
1284+ r->dest = dest;
1285+ r->inc = (r->dest - r->curr) * r->factor;
1286+}
1287+
1288+void tRamp_setVal(tRamp* const ramp, float val)
1289+{
1290+ _tRamp* r = *ramp;
1291+ r->curr = val;
1292+ r->inc = (r->dest - r->curr) * r->factor;
1293+}
1294+
1295+float tRamp_tick(tRamp* const ramp)
1296+{
1297+ _tRamp* r = *ramp;
1298+
1299+ r->curr += r->inc;
1300+
1301+ if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f)))
1302+ {
1303+ r->inc = 0.0f;
1304+ r->curr=r->dest;
1305+ }
1306+
1307+ return r->curr;
1308+}
1309+
1310+float tRamp_sample(tRamp* const ramp)
1311+{
1312+ _tRamp* r = *ramp;
1313+ return r->curr;
1314+}
1315+
1316+void tRampSampleRateChanged(tRamp* const ramp)
1317+{
1318+ _tRamp* r = *ramp;
1319+ r->inv_sr_ms = 1.0f / (leaf.sampleRate * 0.001f);
1320+ r->factor = (1.0f / r->time) * r->inv_sr_ms * (float)r->samples_per_tick;
1321+ r->inc = (r->dest - r->curr) * r->factor;
1322+}
1323+
1324+
1325+
1326+/* RampUpDown */
1327+void tRampUpDown_init(tRampUpDown* const r, float upTime, float downTime, int samples_per_tick)
1328+{
1329+ tRampUpDown_initToPool(r, upTime, downTime, samples_per_tick, &leaf.mempool);
1330+}
1331+
1332+void tRampUpDown_free(tRampUpDown* const r)
1333+{
1334+ tRampUpDown_freeFromPool(r, &leaf.mempool);
1335+}
1336+
1337+void tRampUpDown_initToPool(tRampUpDown* const r, float upTime, float downTime, int samples_per_tick, tMempool* const mp)
1338+{
1339+ _tMempool* m = *mp;
1340+ _tRampUpDown* ramp = *r = (_tRampUpDown*) mpool_alloc(sizeof(_tRampUpDown), m);
1341+
1342+ ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f);
1343+ ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick;
1344+ ramp->curr = 0.0f;
1345+ ramp->dest = 0.0f;
1346+
1347+ if (upTime < ramp->minimum_time)
1348+ {
1349+ ramp->upTime = ramp->minimum_time;
1350+ }
1351+ else
1352+ {
1353+ ramp->upTime = upTime;
1354+ }
1355+
1356+ if (downTime < ramp->minimum_time)
1357+ {
1358+ ramp->downTime = ramp->minimum_time;
1359+ }
1360+ else
1361+ {
1362+ ramp->downTime = downTime;
1363+ }
1364+
1365+ ramp->samples_per_tick = samples_per_tick;
1366+ ramp->upInc = ((ramp->dest - ramp->curr) / ramp->upTime * ramp->inv_sr_ms) * (float)ramp->samples_per_tick;
1367+ ramp->downInc = ((ramp->dest - ramp->curr) / ramp->downTime * ramp->inv_sr_ms) * (float)ramp->samples_per_tick;
1368+}
1369+
1370+void tRampUpDown_freeFromPool (tRampUpDown* const r, tMempool* const mp)
1371+{
1372+ _tMempool* m = *mp;
1373+ _tRampUpDown* ramp = *r;
1374+
1375+ mpool_free((char*)ramp, m);
1376+}
1377+
1378+void tRampUpDown_setUpTime(tRampUpDown* const ramp, float upTime)
1379+{
1380+ _tRampUpDown* r = *ramp;
1381+
1382+ if (upTime < r->minimum_time)
1383+ {
1384+ r->upTime = r->minimum_time;
1385+ }
1386+ else
1387+ {
1388+ r->upTime = upTime;
1389+ }
1390+ r->upInc = ((r->dest - r->curr) / r->upTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1391+}
1392+
1393+
1394+void tRampUpDown_setDownTime(tRampUpDown* const ramp, float downTime)
1395+{
1396+ _tRampUpDown* r = *ramp;
1397+
1398+ if (downTime < r->minimum_time)
1399+ {
1400+ r->downTime = r->minimum_time;
1401+ }
1402+ else
1403+ {
1404+ r->downTime = downTime;
1405+ }
1406+ r->downInc = ((r->dest - r->curr) / r->downTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1407+}
1408+
1409+void tRampUpDown_setDest(tRampUpDown* const ramp, float dest)
1410+{
1411+ _tRampUpDown* r = *ramp;
1412+ r->dest = dest;
1413+ r->upInc = ((r->dest - r->curr) / r->upTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1414+ r->downInc = ((r->dest - r->curr) / r->downTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1415+}
1416+
1417+void tRampUpDown_setVal(tRampUpDown* const ramp, float val)
1418+{
1419+ _tRampUpDown* r = *ramp;
1420+ r->curr = val;
1421+ r->upInc = ((r->dest - r->curr) / r->upTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1422+ r->downInc = ((r->dest - r->curr) / r->downTime * r->inv_sr_ms) * (float)r->samples_per_tick;
1423+}
1424+
1425+float tRampUpDown_tick(tRampUpDown* const ramp)
1426+{
1427+ _tRampUpDown* r = *ramp;
1428+ float test;
1429+
1430+ if (r->dest < r->curr)
1431+ {
1432+ test = r->curr + r->downInc;
1433+ if (test > r->dest)
1434+ {
1435+ r->curr = test;
1436+ }
1437+ else
1438+ {
1439+ r->downInc = 0.0f;
1440+ r->curr = r->dest;
1441+ }
1442+ }
1443+ else if (r->dest > r->curr)
1444+ {
1445+ test = r->curr + r->upInc;
1446+ if (test < r->dest)
1447+ {
1448+ r->curr = test;
1449+ }
1450+ else
1451+ {
1452+ r->upInc = 0.0f;
1453+ r->curr = r->dest;
1454+ }
1455+ }
1456+ return r->curr;
1457+}
1458+
1459+float tRampUpDown_sample(tRampUpDown* const ramp)
1460+{
1461+ _tRampUpDown* r = *ramp;
1462+ return r->curr;
1463+}
1464+
1465+
1466+
1467+
1468+
1469+
1470+/* Exponential Smoother */
1471+void tExpSmooth_init(tExpSmooth* const expsmooth, float val, float factor)
1472+{ // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms
1473+ _tExpSmooth* smooth = *expsmooth = (_tExpSmooth*) leaf_alloc(sizeof(_tExpSmooth));
1474+
1475+ smooth->curr=val;
1476+ smooth->dest=val;
1477+ if (factor<0) factor=0;
1478+ if (factor>1) factor=1;
1479+ smooth->factor=factor;
1480+ smooth->oneminusfactor=1.0f-factor;
1481+}
1482+
1483+void tExpSmooth_free(tExpSmooth* const expsmooth)
1484+{
1485+ _tExpSmooth* smooth = *expsmooth;
1486+
1487+ leaf_free((char*)smooth);
1488+}
1489+
1490+void tExpSmooth_initToPool (tExpSmooth* const expsmooth, float val, float factor, tMempool* const mp)
1491+{
1492+ _tMempool* m = *mp;
1493+ _tExpSmooth* smooth = *expsmooth = (_tExpSmooth*) mpool_alloc(sizeof(_tExpSmooth), m);
1494+
1495+ smooth->curr=val;
1496+ smooth->dest=val;
1497+ if (factor<0) factor=0;
1498+ if (factor>1) factor=1;
1499+ smooth->factor=factor;
1500+ smooth->oneminusfactor=1.0f-factor;
1501+}
1502+
1503+void tExpSmooth_freeFromPool (tExpSmooth* const expsmooth, tMempool* const mp)
1504+{
1505+ _tMempool* m = *mp;
1506+ _tExpSmooth* smooth = *expsmooth;
1507+
1508+ mpool_free((char*)smooth, m);
1509+}
1510+
1511+void tExpSmooth_setFactor(tExpSmooth* const expsmooth, float factor)
1512+{ // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms
1513+ _tExpSmooth* smooth = *expsmooth;
1514+
1515+ if (factor<0)
1516+ factor=0;
1517+ else
1518+ if (factor>1) factor=1;
1519+ smooth->factor=factor;
1520+ smooth->oneminusfactor=1.0f-factor;
1521+}
1522+
1523+void tExpSmooth_setDest(tExpSmooth* const expsmooth, float dest)
1524+{
1525+ _tExpSmooth* smooth = *expsmooth;
1526+ smooth->dest=dest;
1527+}
1528+
1529+void tExpSmooth_setVal(tExpSmooth* const expsmooth, float val)
1530+{
1531+ _tExpSmooth* smooth = *expsmooth;
1532+ smooth->curr=val;
1533+}
1534+
1535+void tExpSmooth_setValAndDest(tExpSmooth* const expsmooth, float val)
1536+{
1537+ _tExpSmooth* smooth = *expsmooth;
1538+ smooth->curr=val;
1539+ smooth->dest=val;
1540+}
1541+
1542+float tExpSmooth_tick(tExpSmooth* const expsmooth)
1543+{
1544+ _tExpSmooth* smooth = *expsmooth;
1545+ smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr;
1546+ return smooth->curr;
1547+}
1548+
1549+float tExpSmooth_sample(tExpSmooth* const expsmooth)
1550+{
1551+ _tExpSmooth* smooth = *expsmooth;
1552+ return smooth->curr;
1553+}
1554+
1555+//tSlide is based on the max/msp slide~ object
1556+////
1557+
1558+void tSlide_init (tSlide* const sl, float upSlide, float downSlide)
1559+{
1560+ tSlide_initToPool (sl, upSlide, downSlide, &leaf.mempool);
1561+}
1562+void tSlide_free (tSlide* const sl)
1563+{
1564+ tSlide_freeFromPool (sl, &leaf.mempool);
1565+}
1566+void tSlide_initToPool (tSlide* const sl, float upSlide, float downSlide, tMempool* const mp)
1567+{
1568+ _tMempool* m = *mp;
1569+ _tSlide* s = *sl = (_tSlide*) mpool_alloc(sizeof(_tSlide), m);
1570+ s->prevIn = 0.0f;
1571+ s->currentOut = 0.0f;
1572+ s->prevOut = 0.0f;
1573+ if (upSlide < 1.0f)
1574+ {
1575+ upSlide = 1.0f;
1576+ }
1577+
1578+ if (downSlide < 1.0f)
1579+ {
1580+ downSlide = 1.0f;
1581+ }
1582+ s->invUpSlide = 1.0f / upSlide;
1583+ s->invDownSlide = 1.0f / downSlide;
1584+}
1585+
1586+void tSlide_freeFromPool (tSlide* const sl, tMempool* const mp)
1587+{
1588+ _tMempool* m = *mp;
1589+ _tSlide* s = *sl;
1590+
1591+ mpool_free((char*)s, m);
1592+}
1593+
1594+float tSlide_tick(tSlide* const sl, float in)
1595+{
1596+ _tSlide* s = *sl;
1597+
1598+
1599+ if (in >= s->prevOut)
1600+ {
1601+ s->currentOut = s->prevOut + ((in - s->prevOut) * s->invUpSlide);
1602+ }
1603+ else
1604+ {
1605+ s->currentOut = s->prevOut + ((in - s->prevOut) * s->invDownSlide);
1606+ }
1607+ if (s->currentOut < VSF) s->currentOut = 0.0f;
1608+ s->prevIn = in;
1609+ s->prevOut = s->currentOut;
1610+ return s->currentOut;
1611+}
1612+
leaf/Src/leaf-filters.c+1802−0
@@ -0,0 +1,1802 @@
1+/*==============================================================================
2+
3+ leaf-filter.c
4+ Created: 20 Jan 2017 12:01:10pm
5+ Author: Michael R Mulshine
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-filters.h"
12+#include "..\Inc\leaf-tables.h"
13+#include "..\leaf.h"
14+
15+#else
16+
17+#include "../Inc/leaf-filters.h"
18+#include "../Inc/leaf-tables.h"
19+#include "../leaf.h"
20+//#include "tim.h"
21+#endif
22+
23+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
24+void tAllpass_init(tAllpass* const ft, float initDelay, uint32_t maxDelay)
25+{
26+ _tAllpass* f = *ft = (_tAllpass*) leaf_alloc(sizeof(_tAllpass));
27+
28+ f->gain = 0.7f;
29+
30+ f->lastOut = 0.0f;
31+
32+ tLinearDelay_init(&f->delay, initDelay, maxDelay);
33+}
34+
35+void tAllpass_free(tAllpass* const ft)
36+{
37+ _tAllpass* f = *ft;
38+
39+ tLinearDelay_free(&f->delay);
40+ leaf_free((char*)f);
41+}
42+
43+void tAllpass_initToPool (tAllpass* const ft, float initDelay, uint32_t maxDelay, tMempool* const mp)
44+{
45+ _tMempool* m = *mp;
46+ _tAllpass* f = *ft = (_tAllpass*) mpool_alloc(sizeof(_tAllpass), m);
47+
48+ f->gain = 0.7f;
49+
50+ f->lastOut = 0.0f;
51+
52+ tLinearDelay_initToPool(&f->delay, initDelay, maxDelay, mp);
53+}
54+
55+void tAllpass_freeFromPool (tAllpass* const ft, tMempool* const mp)
56+{
57+ _tMempool* m = *mp;
58+ _tAllpass* f = *ft;
59+
60+ tLinearDelay_freeFromPool(&f->delay, mp);
61+ mpool_free((char*)f, m);
62+}
63+
64+void tAllpass_setDelay(tAllpass* const ft, float delay)
65+{
66+ _tAllpass* f = *ft;
67+
68+ tLinearDelay_setDelay(&f->delay, delay);
69+}
70+
71+void tAllpass_setGain(tAllpass* const ft, float gain)
72+{
73+ _tAllpass* f = *ft;
74+
75+ f->gain = gain;
76+}
77+
78+float tAllpass_tick(tAllpass* const ft, float input)
79+{
80+ _tAllpass* f = *ft;
81+
82+ float s1 = (-f->gain) * f->lastOut + input;
83+
84+ float s2 = tLinearDelay_tick(&f->delay, s1) + (f->gain) * input;
85+
86+ f->lastOut = s2;
87+
88+ return f->lastOut;
89+}
90+
91+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
92+void tOnePole_init(tOnePole* const ft, float freq)
93+{
94+ _tOnePole* f = *ft = (_tOnePole*) leaf_alloc(sizeof(_tOnePole));
95+
96+ f->gain = 1.0f;
97+ f->a0 = 1.0;
98+
99+ tOnePole_setFreq(ft, freq);
100+
101+ f->lastIn = 0.0f;
102+ f->lastOut = 0.0f;
103+}
104+
105+void tOnePole_free(tOnePole* const ft)
106+{
107+ _tOnePole* f = *ft;
108+
109+ leaf_free((char*)f);
110+}
111+
112+void tOnePole_initToPool (tOnePole* const ft, float freq, tMempool* const mp)
113+{
114+ _tMempool* m = *mp;
115+ _tOnePole* f = *ft = (_tOnePole*) mpool_alloc(sizeof(_tOnePole), m);
116+
117+ f->gain = 1.0f;
118+ f->a0 = 1.0;
119+
120+ tOnePole_setFreq(ft, freq);
121+
122+ f->lastIn = 0.0f;
123+ f->lastOut = 0.0f;
124+}
125+
126+void tOnePole_freeFromPool (tOnePole* const ft, tMempool* const mp)
127+{
128+ _tMempool* m = *mp;
129+ _tOnePole* f = *ft;
130+
131+ mpool_free((char*)f, m);
132+}
133+
134+void tOnePole_setB0(tOnePole* const ft, float b0)
135+{
136+ _tOnePole* f = *ft;
137+ f->b0 = b0;
138+}
139+
140+void tOnePole_setA1(tOnePole* const ft, float a1)
141+{
142+ _tOnePole* f = *ft;
143+ if (a1 >= 1.0f) a1 = 0.999999f;
144+ f->a1 = a1;
145+}
146+
147+void tOnePole_setPole(tOnePole* const ft, float thePole)
148+{
149+ _tOnePole* f = *ft;
150+
151+ if (thePole >= 1.0f) thePole = 0.999999f;
152+
153+ // Normalize coefficients for peak unity gain.
154+ if (thePole > 0.0f) f->b0 = (1.0f - thePole);
155+ else f->b0 = (1.0f + thePole);
156+
157+ f->a1 = -thePole;
158+}
159+
160+void tOnePole_setFreq (tOnePole* const ft, float freq)
161+{
162+ _tOnePole* f = *ft;
163+ f->b0 = freq * leaf.twoPiTimesInvSampleRate;
164+ f->b0 = LEAF_clip(0.0f, f->b0, 1.0f);
165+ f->a1 = 1.0f - f->b0;
166+}
167+
168+void tOnePole_setCoefficients(tOnePole* const ft, float b0, float a1)
169+{
170+ _tOnePole* f = *ft;
171+ if (a1 >= 1.0f) a1 = 0.999999f;
172+ f->b0 = b0;
173+ f->a1 = a1;
174+}
175+
176+void tOnePole_setGain(tOnePole* const ft, float gain)
177+{
178+ _tOnePole* f = *ft;
179+ f->gain = gain;
180+}
181+
182+float tOnePole_tick(tOnePole* const ft, float input)
183+{
184+ _tOnePole* f = *ft;
185+
186+ float in = input * f->gain;
187+ float out = (f->b0 * in) + (f->a1 * f->lastOut);
188+
189+ f->lastIn = in;
190+ f->lastOut = out;
191+
192+ return out;
193+}
194+
195+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoPole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
196+void tTwoPole_init(tTwoPole* const ft)
197+{
198+ _tTwoPole* f = *ft = (_tTwoPole*) leaf_alloc(sizeof(_tTwoPole));
199+
200+ f->gain = 1.0f;
201+ f->a0 = 1.0;
202+ f->b0 = 1.0;
203+
204+ f->lastOut[0] = 0.0f;
205+ f->lastOut[1] = 0.0f;
206+}
207+
208+void tTwoPole_free(tTwoPole* const ft)
209+{
210+ _tTwoPole* f = *ft;
211+
212+ leaf_free((char*)f);
213+}
214+
215+void tTwoPole_initToPool (tTwoPole* const ft, tMempool* const mp)
216+{
217+ _tMempool* m = *mp;
218+ _tTwoPole* f = *ft = (_tTwoPole*) mpool_alloc(sizeof(_tTwoPole), m);
219+
220+ f->gain = 1.0f;
221+ f->a0 = 1.0;
222+ f->b0 = 1.0;
223+
224+ f->lastOut[0] = 0.0f;
225+ f->lastOut[1] = 0.0f;
226+}
227+
228+void tTwoPole_freeFromPool (tTwoPole* const ft, tMempool* const mp)
229+{
230+ _tMempool* m = *mp;
231+ _tTwoPole* f = *ft;
232+
233+ mpool_free((char*)f, m);
234+}
235+
236+float tTwoPole_tick(tTwoPole* const ft, float input)
237+{
238+ _tTwoPole* f = *ft;
239+
240+ float in = input * f->gain;
241+ float out = (f->b0 * in) - (f->a1 * f->lastOut[0]) - (f->a2 * f->lastOut[1]);
242+
243+ f->lastOut[1] = f->lastOut[0];
244+ f->lastOut[0] = out;
245+
246+ return out;
247+}
248+
249+void tTwoPole_setB0(tTwoPole* const ft, float b0)
250+{
251+ _tTwoPole* f = *ft;
252+ f->b0 = b0;
253+}
254+
255+void tTwoPole_setA1(tTwoPole* const ft, float a1)
256+{
257+ _tTwoPole* f = *ft;
258+ f->a1 = a1;
259+}
260+
261+void tTwoPole_setA2(tTwoPole* const ft, float a2)
262+{
263+ _tTwoPole* f = *ft;
264+ f->a2 = a2;
265+}
266+
267+
268+void tTwoPole_setResonance(tTwoPole* const ft, float frequency, float radius, oBool normalize)
269+{
270+ _tTwoPole* f = *ft;
271+
272+ if (frequency < 0.0f) frequency = 0.0f;
273+ if (frequency > (leaf.sampleRate * 0.49f)) frequency = leaf.sampleRate * 0.49f;
274+ if (radius < 0.0f) radius = 0.0f;
275+ if (radius >= 1.0f) radius = 0.999999f;
276+
277+ f->radius = radius;
278+ f->frequency = frequency;
279+ f->normalize = normalize;
280+
281+ f->a2 = radius * radius;
282+ f->a1 = -2.0f * radius * cosf(frequency * leaf.twoPiTimesInvSampleRate);
283+
284+ if ( normalize )
285+ {
286+ // Normalize the filter gain ... not terribly efficient.
287+ float real = 1 - radius + (f->a2 - radius) * cosf(2 * frequency * leaf.twoPiTimesInvSampleRate);
288+ float imag = (f->a2 - radius) * sinf(2 * frequency * leaf.twoPiTimesInvSampleRate);
289+ f->b0 = sqrtf( powf(real, 2) + powf(imag, 2) );
290+ }
291+}
292+
293+void tTwoPole_setCoefficients(tTwoPole* const ft, float b0, float a1, float a2)
294+{
295+ _tTwoPole* f = *ft;
296+ f->b0 = b0;
297+ f->a1 = a1;
298+ f->a2 = a2;
299+}
300+
301+void tTwoPole_setGain(tTwoPole* const ft, float gain)
302+{
303+ _tTwoPole* f = *ft;
304+ f->gain = gain;
305+}
306+
307+void tTwoPoleSampleRateChanged (tTwoPole* const ft)
308+{
309+ _tTwoPole* f = *ft;
310+
311+ f->a2 = f->radius * f->radius;
312+ f->a1 = -2.0f * f->radius * cosf(f->frequency * leaf.twoPiTimesInvSampleRate);
313+
314+ if ( f->normalize )
315+ {
316+ // Normalize the filter gain ... not terribly efficient.
317+ float real = 1 - f->radius + (f->a2 - f->radius) * cosf(2 * f->frequency * leaf.twoPiTimesInvSampleRate);
318+ float imag = (f->a2 - f->radius) * sinf(2 * f->frequency * leaf.twoPiTimesInvSampleRate);
319+ f->b0 = sqrtf( powf(real, 2) + powf(imag, 2) );
320+ }
321+}
322+
323+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OneZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
324+void tOneZero_init(tOneZero* const ft, float theZero)
325+{
326+ _tOneZero* f = *ft = (_tOneZero*) leaf_alloc(sizeof(_tOneZero));
327+
328+ f->gain = 1.0f;
329+ f->lastIn = 0.0f;
330+ f->lastOut = 0.0f;
331+ tOneZero_setZero(ft, theZero);
332+}
333+
334+void tOneZero_free(tOneZero* const ft)
335+{
336+ _tOneZero* f = *ft;
337+
338+ leaf_free((char*)f);
339+}
340+
341+void tOneZero_initToPool (tOneZero* const ft, float theZero, tMempool* const mp)
342+{
343+ _tMempool* m = *mp;
344+ _tOneZero* f = *ft = (_tOneZero*) mpool_alloc(sizeof(_tOneZero), m);
345+
346+ f->gain = 1.0f;
347+ f->lastIn = 0.0f;
348+ f->lastOut = 0.0f;
349+ tOneZero_setZero(ft, theZero);
350+}
351+
352+void tOneZero_freeFromPool (tOneZero* const ft, tMempool* const mp)
353+{
354+ _tMempool* m = *mp;
355+ _tOneZero* f = *ft;
356+
357+ mpool_free((char*)f, m);
358+}
359+
360+float tOneZero_tick(tOneZero* const ft, float input)
361+{
362+ _tOneZero* f = *ft;
363+
364+ float in = input * f->gain;
365+ float out = f->b1 * f->lastIn + f->b0 * in;
366+
367+ f->lastIn = in;
368+
369+ return out;
370+}
371+
372+void tOneZero_setZero(tOneZero* const ft, float theZero)
373+{
374+ _tOneZero* f = *ft;
375+
376+ if (theZero > 0.0f) f->b0 = 1.0f / (1.0f + theZero);
377+ else f->b0 = 1.0f / (1.0f - theZero);
378+
379+ f->b1 = -theZero * f->b0;
380+
381+}
382+
383+void tOneZero_setB0(tOneZero* const ft, float b0)
384+{
385+ _tOneZero* f = *ft;
386+
387+ f->b0 = b0;
388+}
389+
390+void tOneZero_setB1(tOneZero* const ft, float b1)
391+{
392+ _tOneZero* f = *ft;
393+ f->b1 = b1;
394+}
395+
396+void tOneZero_setCoefficients(tOneZero* const ft, float b0, float b1)
397+{
398+ _tOneZero* f = *ft;
399+ f->b0 = b0;
400+ f->b1 = b1;
401+}
402+
403+void tOneZero_setGain(tOneZero *ft, float gain)
404+{
405+ _tOneZero* f = *ft;
406+ f->gain = gain;
407+}
408+
409+float tOneZero_getPhaseDelay(tOneZero* const ft, float frequency )
410+{
411+ _tOneZero* f = *ft;
412+
413+ if ( frequency <= 0.0f) frequency = 0.05f;
414+
415+ f->frequency = frequency;
416+
417+ float omegaT = 2 * PI * frequency * leaf.invSampleRate;
418+ float real = 0.0, imag = 0.0;
419+
420+ real += f->b0;
421+
422+ real += f->b1 * cosf(omegaT);
423+ imag -= f->b1 * sinf(omegaT);
424+
425+ real *= f->gain;
426+ imag *= f->gain;
427+
428+ float phase = atan2f( imag, real );
429+
430+ real = 0.0; imag = 0.0;
431+
432+ phase -= atan2f( imag, real );
433+
434+ phase = fmodf( -phase, 2 * PI );
435+
436+ return phase / omegaT;
437+}
438+
439+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
440+void tTwoZero_init(tTwoZero* const ft)
441+{
442+ _tTwoZero* f = *ft = (_tTwoZero*) leaf_alloc(sizeof(_tTwoZero));
443+
444+ f->gain = 1.0f;
445+ f->lastIn[0] = 0.0f;
446+ f->lastIn[1] = 0.0f;
447+}
448+
449+void tTwoZero_free(tTwoZero* const ft)
450+{
451+ _tTwoZero* f = *ft;
452+
453+ leaf_free((char*)f);
454+}
455+
456+void tTwoZero_initToPool (tTwoZero* const ft, tMempool* const mp)
457+{
458+ _tMempool* m = *mp;
459+ _tTwoZero* f = *ft = (_tTwoZero*) mpool_alloc(sizeof(_tTwoZero), m);
460+
461+ f->gain = 1.0f;
462+ f->lastIn[0] = 0.0f;
463+ f->lastIn[1] = 0.0f;
464+}
465+
466+void tTwoZero_freeFromPool (tTwoZero* const ft, tMempool* const mp)
467+{
468+ _tMempool* m = *mp;
469+ _tTwoZero* f = *ft;
470+
471+ mpool_free((char*)f, m);
472+}
473+
474+float tTwoZero_tick(tTwoZero* const ft, float input)
475+{
476+ _tTwoZero* f = *ft;
477+
478+ float in = input * f->gain;
479+ float out = f->b2 * f->lastIn[1] + f->b1 * f->lastIn[0] + f->b0 * in;
480+
481+ f->lastIn[1] = f->lastIn[0];
482+ f->lastIn[0] = in;
483+
484+ return out;
485+}
486+
487+void tTwoZero_setNotch(tTwoZero* const ft, float freq, float radius)
488+{
489+ _tTwoZero* f = *ft;
490+
491+ // Should also deal with frequency being > half sample rate / nyquist. See STK
492+ if (freq < 0.0f) freq = 0.0f;
493+ if (radius < 0.0f) radius = 0.0f;
494+
495+ f->frequency = freq;
496+ f->radius = radius;
497+
498+ f->b2 = radius * radius;
499+ f->b1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
500+
501+ // Normalize the filter gain. From STK.
502+ if ( f->b1 > 0.0f ) // Maximum at z = 0.
503+ f->b0 = 1.0f / ( 1.0f + f->b1 + f->b2 );
504+ else // Maximum at z = -1.
505+ f->b0 = 1.0f / ( 1.0f - f->b1 + f->b2 );
506+ f->b1 *= f->b0;
507+ f->b2 *= f->b0;
508+
509+}
510+
511+void tTwoZero_setB0(tTwoZero* const ft, float b0)
512+{
513+ _tTwoZero* f = *ft;
514+ f->b0 = b0;
515+}
516+
517+void tTwoZero_setB1(tTwoZero* const ft, float b1)
518+{
519+ _tTwoZero* f = *ft;
520+ f->b1 = b1;
521+}
522+
523+void tTwoZero_setCoefficients(tTwoZero* const ft, float b0, float b1, float b2)
524+{
525+ _tTwoZero* f = *ft;
526+ f->b0 = b0;
527+ f->b1 = b1;
528+ f->b2 = b2;
529+}
530+
531+void tTwoZero_setGain(tTwoZero* const ft, float gain)
532+{
533+ _tTwoZero* f = *ft;
534+ f->gain = gain;
535+}
536+
537+void tTwoZeroSampleRateChanged(tTwoZero* const ft)
538+{
539+ _tTwoZero* f = *ft;
540+
541+ tTwoZero_setNotch(ft, f->frequency, f->radius);
542+}
543+
544+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PoleZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
545+void tPoleZero_init(tPoleZero* const pzf)
546+{
547+ _tPoleZero* f = *pzf = (_tPoleZero*) leaf_alloc(sizeof(_tPoleZero));
548+
549+ f->gain = 1.0f;
550+ f->b0 = 1.0;
551+ f->a0 = 1.0;
552+
553+ f->lastIn = 0.0f;
554+ f->lastOut = 0.0f;
555+}
556+
557+void tPoleZero_free(tPoleZero* const pzf)
558+{
559+ _tPoleZero* f = *pzf;
560+
561+ leaf_free((char*)f);
562+}
563+
564+void tPoleZero_initToPool (tPoleZero* const pzf, tMempool* const mp)
565+{
566+ _tMempool* m = *mp;
567+ _tPoleZero* f = *pzf = (_tPoleZero*) mpool_alloc(sizeof(_tPoleZero), m);
568+
569+ f->gain = 1.0f;
570+ f->b0 = 1.0;
571+ f->a0 = 1.0;
572+
573+ f->lastIn = 0.0f;
574+ f->lastOut = 0.0f;
575+}
576+
577+void tPoleZero_freeFromPool (tPoleZero* const pzf, tMempool* const mp)
578+{
579+ _tMempool* m = *mp;
580+ _tPoleZero* f = *pzf;
581+
582+ mpool_free((char*)f, m);
583+}
584+
585+void tPoleZero_setB0(tPoleZero* const pzf, float b0)
586+{
587+ _tPoleZero* f = *pzf;
588+ f->b0 = b0;
589+}
590+
591+void tPoleZero_setB1(tPoleZero* const pzf, float b1)
592+{
593+ _tPoleZero* f = *pzf;
594+ f->b1 = b1;
595+}
596+
597+void tPoleZero_setA1(tPoleZero* const pzf, float a1)
598+{
599+ _tPoleZero* f = *pzf;
600+
601+ if (a1 >= 1.0f) // a1 should be less than 1.0
602+ {
603+ a1 = 0.999999f;
604+ }
605+
606+ f->a1 = a1;
607+}
608+
609+void tPoleZero_setCoefficients(tPoleZero* const pzf, float b0, float b1, float a1)
610+{
611+ _tPoleZero* f = *pzf;
612+
613+ if (a1 >= 1.0f) // a1 should be less than 1.0
614+ {
615+ a1 = 0.999999f;
616+ }
617+
618+ f->b0 = b0;
619+ f->b1 = b1;
620+ f->a1 = a1;
621+}
622+
623+void tPoleZero_setAllpass(tPoleZero* const pzf, float coeff)
624+{
625+ _tPoleZero* f = *pzf;
626+
627+ if (coeff >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
628+ {
629+ coeff = 0.999999f;
630+ }
631+
632+ f->b0 = coeff;
633+ f->b1 = 1.0f;
634+ f->a0 = 1.0f;
635+ f->a1 = coeff;
636+}
637+
638+void tPoleZero_setBlockZero(tPoleZero* const pzf, float thePole)
639+{
640+ _tPoleZero* f = *pzf;
641+
642+ if (thePole >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
643+ {
644+ thePole = 0.999999f;
645+ }
646+
647+ f->b0 = 1.0f;
648+ f->b1 = -1.0f;
649+ f->a0 = 1.0f;
650+ f->a1 = -thePole;
651+}
652+
653+void tPoleZero_setGain(tPoleZero* const pzf, float gain)
654+{
655+ _tPoleZero* f = *pzf;
656+ f->gain = gain;
657+}
658+
659+float tPoleZero_tick(tPoleZero* const pzf, float input)
660+{
661+ _tPoleZero* f = *pzf;
662+
663+ float in = input * f->gain;
664+ float out = (f->b0 * in) + (f->b1 * f->lastIn) - (f->a1 * f->lastOut);
665+
666+ f->lastIn = in;
667+ f->lastOut = out;
668+
669+ return out;
670+}
671+
672+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ BiQuad Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
673+void tBiQuad_init(tBiQuad* const ft)
674+{
675+ _tBiQuad* f = *ft = (_tBiQuad*) leaf_alloc(sizeof(_tBiQuad));
676+
677+ f->gain = 1.0f;
678+
679+ f->b0 = 0.0f;
680+ f->a0 = 0.0f;
681+
682+ f->lastIn[0] = 0.0f;
683+ f->lastIn[1] = 0.0f;
684+ f->lastOut[0] = 0.0f;
685+ f->lastOut[1] = 0.0f;
686+}
687+
688+void tBiQuad_free(tBiQuad* const ft)
689+{
690+ _tBiQuad* f = *ft;
691+
692+ leaf_free((char*)f);
693+}
694+
695+void tBiQuad_initToPool (tBiQuad* const ft, tMempool* const mp)
696+{
697+ _tMempool* m = *mp;
698+ _tBiQuad* f = *ft = (_tBiQuad*) mpool_alloc(sizeof(_tBiQuad), m);
699+
700+ f->gain = 1.0f;
701+
702+ f->b0 = 0.0f;
703+ f->a0 = 0.0f;
704+
705+ f->lastIn[0] = 0.0f;
706+ f->lastIn[1] = 0.0f;
707+ f->lastOut[0] = 0.0f;
708+ f->lastOut[1] = 0.0f;
709+}
710+
711+void tBiQuad_freeFromPool (tBiQuad* const ft, tMempool* const mp)
712+{
713+ _tMempool* m = *mp;
714+ _tBiQuad* f = *ft;
715+
716+ mpool_free((char*)f, m);
717+}
718+
719+float tBiQuad_tick(tBiQuad* const ft, float input)
720+{
721+ _tBiQuad* f = *ft;
722+
723+ float in = input * f->gain;
724+ float out = f->b0 * in + f->b1 * f->lastIn[0] + f->b2 * f->lastIn[1];
725+ out -= f->a2 * f->lastOut[1] + f->a1 * f->lastOut[0];
726+
727+ f->lastIn[1] = f->lastIn[0];
728+ f->lastIn[0] = in;
729+
730+ f->lastOut[1] = f->lastOut[0];
731+ f->lastOut[0] = out;
732+
733+ return out;
734+}
735+
736+void tBiQuad_setResonance(tBiQuad* const ft, float freq, float radius, oBool normalize)
737+{
738+ _tBiQuad* f = *ft;
739+
740+ if (freq < 0.0f) freq = 0.0f;
741+ if (freq > (leaf.sampleRate * 0.49f)) freq = leaf.sampleRate * 0.49f;
742+ if (radius < 0.0f) radius = 0.0f;
743+ if (radius >= 1.0f) radius = 1.0f;
744+
745+ f->frequency = freq;
746+ f->radius = radius;
747+ f->normalize = normalize;
748+
749+ f->a2 = radius * radius;
750+ f->a1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate);
751+
752+ if (normalize)
753+ {
754+ f->b0 = 0.5f - 0.5f * f->a2;
755+ f->b1 = 0.0f;
756+ f->b2 = -f->b0;
757+ }
758+}
759+
760+void tBiQuad_setNotch(tBiQuad* const ft, float freq, float radius)
761+{
762+ _tBiQuad* f = *ft;
763+
764+ if (freq < 0.0f) freq = 0.0f;
765+ if (freq > (leaf.sampleRate * 0.49f)) freq = leaf.sampleRate * 0.49f;
766+ if (radius < 0.0f) radius = 0.0f;
767+
768+ f->b2 = radius * radius;
769+ f->b1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
770+
771+ // Does not attempt to normalize filter gain.
772+}
773+
774+void tBiQuad_setEqualGainZeros(tBiQuad* const ft)
775+{
776+ _tBiQuad* f = *ft;
777+ f->b0 = 1.0f;
778+ f->b1 = 0.0f;
779+ f->b2 = -1.0f;
780+}
781+
782+void tBiQuad_setB0(tBiQuad* const ft, float b0)
783+{
784+ _tBiQuad* f = *ft;
785+ f->b0 = b0;
786+}
787+
788+void tBiQuad_setB1(tBiQuad* const ft, float b1)
789+{
790+ _tBiQuad* f = *ft;
791+ f->b1 = b1;
792+}
793+
794+void tBiQuad_setB2(tBiQuad* const ft, float b2)
795+{
796+ _tBiQuad* f = *ft;
797+ f->b2 = b2;
798+}
799+
800+void tBiQuad_setA1(tBiQuad* const ft, float a1)
801+{
802+ _tBiQuad* f = *ft;
803+ f->a1 = a1;
804+}
805+
806+void tBiQuad_setA2(tBiQuad* const ft, float a2)
807+{
808+ _tBiQuad* f = *ft;
809+ f->a2 = a2;
810+}
811+
812+void tBiQuad_setCoefficients(tBiQuad* const ft, float b0, float b1, float b2, float a1, float a2)
813+{
814+ _tBiQuad* f = *ft;
815+ f->b0 = b0;
816+ f->b1 = b1;
817+ f->b2 = b2;
818+ f->a1 = a1;
819+ f->a2 = a2;
820+}
821+
822+void tBiQuad_setGain(tBiQuad* const ft, float gain)
823+{
824+ _tBiQuad* f = *ft;
825+ f->gain = gain;
826+}
827+
828+void tBiQuadSampleRateChanged(tBiQuad* const ft)
829+{
830+ _tBiQuad* f = *ft;
831+ f->a2 = f->radius * f->radius;
832+ f->a1 = -2.0f * f->radius * cosf(f->frequency * leaf.twoPiTimesInvSampleRate);
833+
834+ if (f->normalize)
835+ {
836+ f->b0 = 0.5f - 0.5f * f->a2;
837+ f->b1 = 0.0f;
838+ f->b2 = -f->b0;
839+ }
840+}
841+
842+// Less efficient, more accurate version of SVF, in which cutoff frequency is taken as floating point Hz value and tanf
843+// is calculated when frequency changes.
844+void tSVF_init(tSVF* const svff, SVFType type, float freq, float Q)
845+{
846+ tSVF_initToPool (svff, type, freq, Q, &leaf.mempool);
847+
848+ // or maybe this?
849+ /*
850+ * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1
851+ */
852+
853+}
854+
855+void tSVF_free(tSVF* const svff)
856+{
857+ tSVF_freeFromPool (svff, &leaf.mempool);
858+}
859+
860+void tSVF_initToPool (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp)
861+{
862+ _tMempool* m = *mp;
863+ _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m);
864+
865+ svf->type = type;
866+
867+ svf->ic1eq = 0;
868+ svf->ic2eq = 0;
869+ svf->Q = Q;
870+ svf->cutoff = freq;
871+ svf->g = tanf(PI * freq * leaf.invSampleRate);
872+ svf->k = 1.0f/Q;
873+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
874+ svf->a2 = svf->g*svf->a1;
875+ svf->a3 = svf->g*svf->a2;
876+ svf->cH = 0.0f;
877+ svf->cB = 0.0f;
878+ svf->cL = 1.0f;
879+
880+ if (type == SVFTypeLowpass)
881+ {
882+ svf->cH = 0.0f;
883+ svf->cB = 0.0f;
884+ svf->cBK = 0.0f;
885+ svf->cL = 1.0f;
886+ }
887+ else if (type == SVFTypeBandpass)
888+ {
889+ svf->cH = 0.0f;
890+ svf->cB = 1.0f;
891+ svf->cBK = 0.0f;
892+ svf->cL = 0.0f;
893+ }
894+
895+ else if (type == SVFTypeHighpass)
896+ {
897+ svf->cH = 1.0f;
898+ svf->cB = 0.0f;
899+ svf->cBK = -1.0f;
900+ svf->cL = -1.0f;
901+ }
902+
903+ else if (type == SVFTypeNotch)
904+ {
905+ svf->cH = 1.0f;
906+ svf->cB = 0.0f;
907+ svf->cBK = -1.0f;
908+ svf->cL = 0.0f;
909+ }
910+
911+
912+ else if (type == SVFTypePeak)
913+ {
914+ svf->cH = 1.0f;
915+ svf->cB = 0.0f;
916+ svf->cBK = -1.0f;
917+ svf->cL = -2.0f;
918+ }
919+}
920+
921+void tSVF_freeFromPool (tSVF* const svff, tMempool* const mp)
922+{
923+ _tMempool* m = *mp;
924+ _tSVF* svf = *svff;
925+
926+ mpool_free((char*)svf, m);
927+}
928+
929+float tSVF_tick(tSVF* const svff, float v0)
930+{
931+ _tSVF* svf = *svff;
932+
933+ float v1,v2,v3;
934+ v3 = v0 - svf->ic2eq;
935+ v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
936+ v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
937+ svf->ic1eq = (2.0f * v1) - svf->ic1eq;
938+ svf->ic2eq = (2.0f * v2) - svf->ic2eq;
939+
940+ return (v0 * svf->cH) + (v1 * svf->cB) + (svf->k * v1 * svf->cBK) + (v2 * svf->cL);
941+}
942+
943+void tSVF_setFreq(tSVF* const svff, float freq)
944+{
945+ _tSVF* svf = *svff;
946+ svf->cutoff = freq;
947+ svf->g = tanf(PI * freq * leaf.invSampleRate);
948+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
949+ svf->a2 = svf->g * svf->a1;
950+ svf->a3 = svf->g * svf->a2;
951+}
952+
953+void tSVF_setQ(tSVF* const svff, float Q)
954+{
955+ _tSVF* svf = *svff;
956+ svf->Q = Q;
957+ svf->k = 1.0f/Q;
958+
959+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
960+ svf->a2 = svf->g * svf->a1;
961+ svf->a3 = svf->g * svf->a2;
962+}
963+
964+void tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q)
965+{
966+ _tSVF* svf = *svff;
967+ svf->k = 1.0f/Q;
968+ svf->g = tanf(PI * freq * leaf.invSampleRate);
969+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
970+ svf->a2 = svf->g * svf->a1;
971+ svf->a3 = svf->g * svf->a2;
972+}
973+
974+// Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable.
975+void tEfficientSVF_init(tEfficientSVF* const svff, SVFType type, uint16_t input, float Q)
976+{
977+ _tEfficientSVF* svf = *svff = (_tEfficientSVF*) leaf_alloc(sizeof(_tEfficientSVF));
978+
979+ svf->type = type;
980+
981+ svf->ic1eq = 0;
982+ svf->ic2eq = 0;
983+
984+ svf->g = __leaf_table_filtertan[input];
985+ svf->k = 1.0f/Q;
986+ svf->a1 = 1.0f/(1.0f+svf->g*(svf->g+svf->k));
987+ svf->a2 = svf->g*svf->a1;
988+ svf->a3 = svf->g*svf->a2;
989+}
990+
991+void tEfficientSVF_free(tEfficientSVF* const svff)
992+{
993+ _tEfficientSVF* svf = *svff;
994+
995+ leaf_free((char*)svf);
996+}
997+
998+void tEfficientSVF_initToPool (tEfficientSVF* const svff, SVFType type, uint16_t input, float Q, tMempool* const mp)
999+{
1000+ _tMempool* m = *mp;
1001+ _tEfficientSVF* svf = *svff = (_tEfficientSVF*) mpool_alloc(sizeof(_tEfficientSVF), m);
1002+
1003+ svf->type = type;
1004+
1005+ svf->ic1eq = 0;
1006+ svf->ic2eq = 0;
1007+
1008+ svf->g = __leaf_table_filtertan[input];
1009+ svf->k = 1.0f/Q;
1010+ svf->a1 = 1.0f/(1.0f+svf->g*(svf->g+svf->k));
1011+ svf->a2 = svf->g*svf->a1;
1012+ svf->a3 = svf->g*svf->a2;
1013+}
1014+
1015+void tEfficientSVF_freeFromPool (tEfficientSVF* const svff, tMempool* const mp)
1016+{
1017+ _tMempool* m = *mp;
1018+ _tEfficientSVF* svf = *svff;
1019+
1020+ mpool_free((char*)svf, m);
1021+}
1022+
1023+float tEfficientSVF_tick(tEfficientSVF* const svff, float v0)
1024+{
1025+ _tEfficientSVF* svf = *svff;
1026+
1027+ float v1,v2,v3;
1028+ v3 = v0 - svf->ic2eq;
1029+ v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
1030+ v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
1031+ svf->ic1eq = (2.0f * v1) - svf->ic1eq;
1032+ svf->ic2eq = (2.0f * v2) - svf->ic2eq;
1033+
1034+ if (svf->type == SVFTypeLowpass) return v2;
1035+ else if (svf->type == SVFTypeBandpass) return v1;
1036+ else if (svf->type == SVFTypeHighpass) return v0 - (svf->k * v1) - v2;
1037+ else if (svf->type == SVFTypeNotch) return v0 - (svf->k * v1);
1038+ else if (svf->type == SVFTypePeak) return v0 - (svf->k * v1) - (2.0f * v2);
1039+ else return 0.0f;
1040+
1041+}
1042+
1043+void tEfficientSVF_setFreq(tEfficientSVF* const svff, uint16_t input)
1044+{
1045+ _tEfficientSVF* svf = *svff;
1046+
1047+ svf->g = __leaf_table_filtertan[input];
1048+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
1049+ svf->a2 = svf->g * svf->a1;
1050+ svf->a3 = svf->g * svf->a2;
1051+}
1052+
1053+void tEfficientSVF_setQ(tEfficientSVF* const svff, float Q)
1054+{
1055+ _tEfficientSVF* svf = *svff;
1056+
1057+ svf->k = 1.0f/Q;
1058+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
1059+ svf->a2 = svf->g * svf->a1;
1060+ svf->a3 = svf->g * svf->a2;
1061+}
1062+
1063+/* Highpass */
1064+void tHighpass_init(tHighpass* const ft, float freq)
1065+{
1066+ _tHighpass* f = *ft = (_tHighpass*) leaf_alloc(sizeof(_tHighpass));
1067+
1068+ f->R = (1.0f - (freq * leaf.twoPiTimesInvSampleRate));
1069+ f->ys = 0.0f;
1070+ f->xs = 0.0f;
1071+
1072+ f->frequency = freq;
1073+}
1074+
1075+void tHighpass_free(tHighpass* const ft)
1076+{
1077+ _tHighpass* f = *ft;
1078+
1079+ leaf_free((char*)f);
1080+}
1081+
1082+void tHighpass_initToPool (tHighpass* const ft, float freq, tMempool* const mp)
1083+{
1084+ _tMempool* m = *mp;
1085+ _tHighpass* f = *ft = (_tHighpass*) mpool_calloc(sizeof(_tHighpass), m);
1086+
1087+ f->R = (1.0f - (freq * leaf.twoPiTimesInvSampleRate));
1088+ f->ys = 0.0f;
1089+ f->xs = 0.0f;
1090+
1091+ f->frequency = freq;
1092+}
1093+
1094+void tHighpass_freeFromPool (tHighpass* const ft, tMempool* const mp)
1095+{
1096+ _tMempool* m = *mp;
1097+ _tHighpass* f = *ft;
1098+
1099+ mpool_free((char*)f, m);
1100+}
1101+
1102+void tHighpass_setFreq(tHighpass* const ft, float freq)
1103+{
1104+ _tHighpass* f = *ft;
1105+ f->frequency = freq;
1106+ f->R = (1.0f - (freq * leaf.twoPiTimesInvSampleRate));
1107+
1108+}
1109+
1110+float tHighpass_getFreq(tHighpass* const ft)
1111+{
1112+ _tHighpass* f = *ft;
1113+ return f->frequency;
1114+}
1115+
1116+// From JOS DC Blocker
1117+float tHighpass_tick(tHighpass* const ft, float x)
1118+{
1119+ _tHighpass* f = *ft;
1120+ f->ys = x - f->xs + f->R * f->ys;
1121+ f->xs = x;
1122+ return f->ys;
1123+}
1124+
1125+void tHighpassSampleRateChanged(tHighpass* const ft)
1126+{
1127+ _tHighpass* f = *ft;
1128+ f->R = (1.0f-((f->frequency * 2.0f * 3.14f) * leaf.invSampleRate));
1129+}
1130+
1131+void tButterworth_init(tButterworth* const ft, int N, float f1, float f2)
1132+{
1133+ _tButterworth* f = *ft = (_tButterworth*) leaf_alloc(sizeof(_tButterworth));
1134+
1135+ f->f1 = f1;
1136+ f->f2 = f2;
1137+ f->gain = 1.0f;
1138+
1139+ f->N = N;
1140+
1141+ if (f->N > NUM_SVF_BW) f->N = NUM_SVF_BW;
1142+
1143+ for(int i = 0; i < N/2; ++i)
1144+ {
1145+ tSVF_init(&f->low[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
1146+ tSVF_init(&f->high[i], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
1147+ }
1148+}
1149+
1150+void tButterworth_free(tButterworth* const ft)
1151+{
1152+ _tButterworth* f = *ft;
1153+
1154+ for(int i = 0; i < f->N/2; ++i)
1155+ {
1156+ tSVF_free(&f->low[i]);
1157+ tSVF_free(&f->high[i]);
1158+ }
1159+
1160+ leaf_free((char*)f);
1161+}
1162+
1163+void tButterworth_initToPool (tButterworth* const ft, int N, float f1, float f2, tMempool* const mp)
1164+{
1165+ _tMempool* m = *mp;
1166+ _tButterworth* f = *ft = (_tButterworth*) mpool_alloc(sizeof(_tButterworth), m);
1167+
1168+ f->f1 = f1;
1169+ f->f2 = f2;
1170+ f->gain = 1.0f;
1171+
1172+ f->N = N;
1173+
1174+ if (f->N > NUM_SVF_BW) f->N = NUM_SVF_BW;
1175+
1176+ for(int i = 0; i < N/2; ++i)
1177+ {
1178+ tSVF_initToPool(&f->low[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)), mp);
1179+ tSVF_initToPool(&f->high[i], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)), mp);
1180+ }
1181+}
1182+
1183+void tButterworth_freeFromPool (tButterworth* const ft, tMempool* const mp)
1184+{
1185+ _tMempool* m = *mp;
1186+ _tButterworth* f = *ft;
1187+
1188+ for(int i = 0; i < f->N/2; ++i)
1189+ {
1190+ tSVF_freeFromPool(&f->low[i], mp);
1191+ tSVF_freeFromPool(&f->high[i], mp);
1192+ }
1193+
1194+ mpool_free((char*)f, m);
1195+}
1196+
1197+float tButterworth_tick(tButterworth* const ft, float samp)
1198+{
1199+ _tButterworth* f = *ft;
1200+
1201+ for(int i = 0; i < ((f->N)/2); ++i)
1202+ {
1203+ samp = tSVF_tick(&f->low[i],samp);
1204+ samp = tSVF_tick(&f->high[i],samp);
1205+ }
1206+ return samp;
1207+}
1208+
1209+void tButterworth_setF1(tButterworth* const ft, float f1)
1210+{
1211+ _tButterworth* f = *ft;
1212+
1213+ f->f1 = f1;
1214+ for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->low[i], f1);
1215+}
1216+
1217+void tButterworth_setF2(tButterworth* const ft, float f2)
1218+{
1219+ _tButterworth* f = *ft;
1220+
1221+ f->f2 = f2;
1222+ for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->high[i], f2);
1223+}
1224+
1225+void tButterworth_setFreqs(tButterworth* const ft, float f1, float f2)
1226+{
1227+ _tButterworth* f = *ft;
1228+
1229+ f->f1 = f1;
1230+ f->f2 = f2;
1231+ for(int i = 0; i < ((f->N)/2); ++i)
1232+ {
1233+ tSVF_setFreq(&f->low[i], f1);
1234+ tSVF_setFreq(&f->high[i], f2);
1235+ }
1236+}
1237+
1238+void tFIR_init(tFIR* const firf, float* coeffs, int numTaps)
1239+{
1240+ _tFIR* fir = *firf = (_tFIR*) leaf_alloc(sizeof(_tFIR));
1241+
1242+ fir->numTaps = numTaps;
1243+ fir->coeff = coeffs;
1244+ fir->past = (float*)leaf_alloc(sizeof(float) * fir->numTaps);
1245+ for (int i = 0; i < fir->numTaps; ++i) fir->past[i] = 0.0f;
1246+}
1247+
1248+void tFIR_free(tFIR* const firf)
1249+{
1250+ _tFIR* fir = *firf;
1251+
1252+ leaf_free((char*)fir->past);
1253+ leaf_free((char*)fir);
1254+}
1255+
1256+void tFIR_initToPool (tFIR* const firf, float* coeffs, int numTaps, tMempool* const mp)
1257+{
1258+ _tMempool* m = *mp;
1259+ _tFIR* fir = *firf = (_tFIR*) mpool_alloc(sizeof(_tFIR), m);
1260+
1261+ fir->numTaps = numTaps;
1262+ fir->coeff = coeffs;
1263+ fir->past = (float*) mpool_alloc(sizeof(float) * fir->numTaps, m);
1264+ for (int i = 0; i < fir->numTaps; ++i) fir->past[i] = 0.0f;
1265+}
1266+
1267+void tFIR_freeFromPool (tFIR* const firf, tMempool* const mp)
1268+{
1269+ _tMempool* m = *mp;
1270+ _tFIR* fir = *firf;
1271+
1272+ mpool_free((char*)fir->past, m);
1273+ mpool_free((char*)fir, m);
1274+}
1275+
1276+float tFIR_tick(tFIR* const firf, float input)
1277+{
1278+ _tFIR* fir = *firf;
1279+
1280+ fir->past[0] = input;
1281+ float y = 0.0f;
1282+ for (int i = 0; i < fir->numTaps; ++i) y += fir->past[i]*fir->coeff[i];
1283+ for (int i = fir->numTaps-1; i > 0; --i) fir->past[i] = fir->past[i-1];
1284+ return y;
1285+}
1286+
1287+//---------------------------------------------
1288+////
1289+/// Median filter implemented based on James McCartney's median filter in Supercollider,
1290+/// translated from a Gen~ port of the Supercollider code that I believe was made by Rodrigo Costanzo and which I got from PA Tremblay - JS
1291+
1292+
1293+void tMedianFilter_init (tMedianFilter* const f, int size)
1294+{
1295+ tMedianFilter_initToPool(f, size, &leaf.mempool);
1296+}
1297+void tMedianFilter_free (tMedianFilter* const f)
1298+{
1299+ tMedianFilter_freeFromPool(f, &leaf.mempool);
1300+}
1301+void tMedianFilter_initToPool (tMedianFilter* const mf, int size, tMempool* const mp)
1302+{
1303+ _tMempool* m = *mp;
1304+ _tMedianFilter* f = *mf = (_tMedianFilter*) mpool_alloc(sizeof(_tMedianFilter), m);
1305+
1306+ f->size = size;
1307+ f->middlePosition = size / 2;
1308+ f->last = size - 1;
1309+ f->pos = -1;
1310+ f->val = (float*) mpool_alloc(sizeof(float) * size, m);
1311+ f->age = (int*) mpool_alloc(sizeof(int) * size, m);
1312+ for (int i = 0; i < f->size; ++i)
1313+ {
1314+ f->val[i] = 0.0f;
1315+ f->age[i] = i;
1316+ }
1317+
1318+}
1319+void tMedianFilter_freeFromPool (tMedianFilter* const mf, tMempool* const mp)
1320+{
1321+ _tMempool* m = *mp;
1322+ _tMedianFilter* f = *mf;
1323+
1324+ mpool_free((char*)f->val, m);
1325+ mpool_free((char*)f->age, m);
1326+ mpool_free((char*)f, m);
1327+}
1328+
1329+float tMedianFilter_tick (tMedianFilter* const mf, float input)
1330+{
1331+ _tMedianFilter* f = *mf;
1332+
1333+ for(int i=0; i<f->size; i++) {
1334+ int thisAge = f->age[i];
1335+ if(thisAge == f->last) {
1336+ f->pos = i;
1337+ }
1338+ else {
1339+ thisAge++;
1340+ f->age[i] = thisAge;
1341+ }
1342+ }
1343+
1344+ while( f->pos!=0 ) {
1345+ float test = f->val[f->pos-1];
1346+ if(input < test) {
1347+ f->val[f->pos]=test;
1348+ f->age[f->pos]=f->age[f->pos-1];
1349+ f->pos -= 1;
1350+ } else {break;}
1351+ }
1352+
1353+ while(f->pos != f->last) {
1354+ float test = f->val[f->pos+1];
1355+ if( input > test) {
1356+ f->val[f->pos] = test;
1357+ f->age[f->pos] = f->age[f->pos+1];
1358+ f->pos += 1;
1359+ } else {break;}
1360+ }
1361+
1362+ f->val[f->pos] = input;
1363+ f->age[f->pos] = 0;
1364+
1365+ return f->val[f->middlePosition];
1366+}
1367+
1368+/////
1369+
1370+void tVZFilter_init (tVZFilter* const vf, VZFilterType type, float freq, float bandWidth)
1371+{
1372+ tVZFilter_initToPool(vf, type, freq, bandWidth, &leaf.mempool);
1373+}
1374+
1375+void tVZFilter_free (tVZFilter* const vf)
1376+{
1377+ tVZFilter_freeFromPool(vf, &leaf.mempool);
1378+}
1379+void tVZFilter_initToPool (tVZFilter* const vf, VZFilterType type, float freq, float bandWidth, tMempool* const mp)
1380+{
1381+
1382+ _tMempool* m = *mp;
1383+ _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
1384+ f->fc = freq;
1385+ f->type = type;
1386+ f->G = ONE_OVER_SQRT2;
1387+ f->invG = 1.0f/ONE_OVER_SQRT2;
1388+ f->B = bandWidth;
1389+ f->m = 0.0f;
1390+ f->s1 = 0.0f;
1391+ f->s2 = 0.0f;
1392+ f->sr = leaf.sampleRate;
1393+ f->inv_sr = leaf.invSampleRate;
1394+ tVZFilter_calcCoeffs(vf);
1395+
1396+
1397+}
1398+void tVZFilter_freeFromPool (tVZFilter* const vf, tMempool* const mp)
1399+{
1400+ _tMempool* m = *mp;
1401+ _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
1402+ mpool_free((char*)f, m);
1403+}
1404+
1405+void tVZFilter_setSampleRate (tVZFilter* const vf, float sampleRate)
1406+{
1407+ _tVZFilter* f = *vf;
1408+ f->sr = sampleRate;
1409+ f->inv_sr = 1.0f/sampleRate;
1410+}
1411+
1412+float tVZFilter_tick (tVZFilter* const vf, float in)
1413+{
1414+ _tVZFilter* f = *vf;
1415+
1416+ float yL, yB, yH;
1417+
1418+ // compute highpass output via Eq. 5.1:
1419+ yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
1420+
1421+ // compute bandpass output by applying 1st integrator to highpass output:
1422+ yB = tanhf(f->g*yH) + f->s1;
1423+ f->s1 = f->g*yH + yB; // state update in 1st integrator
1424+
1425+ // compute lowpass output by applying 2nd integrator to bandpass output:
1426+ yL = tanhf(f->g*yB) + f->s2;
1427+ f->s2 = f->g*yB + yL; // state update in 2nd integrator
1428+
1429+ //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
1430+ //
1431+ //seems like that might look like this:
1432+ // y = tanh(g*x) + s; // output computation
1433+ // s = g*x + y; // state update
1434+
1435+ //instead of this:
1436+ // y = g*x + s; // output computation
1437+ // s = g*x + y; // state update
1438+
1439+ return f->cL*yL + f->cB*yB + f->cH*yH;
1440+
1441+}
1442+
1443+float tVZFilter_tickEfficient (tVZFilter* const vf, float in)
1444+{
1445+ _tVZFilter* f = *vf;
1446+
1447+ float yL, yB, yH;
1448+
1449+ // compute highpass output via Eq. 5.1:
1450+ yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
1451+
1452+ // compute bandpass output by applying 1st integrator to highpass output:
1453+ yB = (f->g*yH) + f->s1;
1454+ f->s1 = f->g*yH + yB; // state update in 1st integrator
1455+
1456+ // compute lowpass output by applying 2nd integrator to bandpass output:
1457+ yL = (f->g*yB) + f->s2;
1458+ f->s2 = f->g*yB + yL; // state update in 2nd integrator
1459+
1460+ //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
1461+ //
1462+ //seems like that might look like this:
1463+ // y = tanh(g*x) + s; // output computation
1464+ // s = g*x + y; // state update
1465+
1466+ //instead of this:
1467+ // y = g*x + s; // output computation
1468+ // s = g*x + y; // state update
1469+
1470+ return f->cL*yL + f->cB*yB + f->cH*yH;
1471+
1472+}
1473+
1474+float tVZFilter_tickEfficientBP (tVZFilter* const vf, float in)
1475+{
1476+ _tVZFilter* f = *vf;
1477+
1478+ float yL, yB, yH;
1479+
1480+ // compute highpass output via Eq. 5.1:
1481+ yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
1482+
1483+ // compute bandpass output by applying 1st integrator to highpass output:
1484+ yB = (f->g*yH) + f->s1;
1485+ f->s1 = f->g*yH + yB; // state update in 1st integrator
1486+
1487+ // compute lowpass output by applying 2nd integrator to bandpass output:
1488+ yL = (f->g*yB) + f->s2;
1489+ f->s2 = f->g*yB + yL; // state update in 2nd integrator
1490+
1491+ //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
1492+ //
1493+ //seems like that might look like this:
1494+ // y = tanh(g*x) + s; // output computation
1495+ // s = g*x + y; // state update
1496+
1497+ //instead of this:
1498+ // y = g*x + s; // output computation
1499+ // s = g*x + y; // state update
1500+
1501+ return f->cL*yL + f->cB*yB + f->cH*yH;
1502+
1503+}
1504+
1505+
1506+void tVZFilter_calcCoeffs (tVZFilter* const vf)
1507+{
1508+
1509+ _tVZFilter* f = *vf;
1510+ f->g = tanf(PI * f->fc * f->inv_sr); // embedded integrator gain (Fig 3.11)
1511+
1512+ switch( f->type )
1513+ {
1514+ case Bypass:
1515+ {
1516+ f->R2 = f->invG; // can we use an arbitrary value here, for example R2 = 1?
1517+ f->cL = 1.0f;
1518+ f->cB = f->R2;
1519+ f->cH = 1.0f;
1520+ }
1521+ break;
1522+ case Lowpass:
1523+ {
1524+ f->R2 = f->invG;
1525+ f->cL = 1.0f; f->cB = 0.0f; f->cH = 0.0f;
1526+ }
1527+ break;
1528+ case Highpass:
1529+ {
1530+ f->R2 = f->invG;
1531+ f->cL = 0.0f; f->cB = 0.0f; f->cH = 1.0f;
1532+ }
1533+ break;
1534+ case BandpassSkirt:
1535+ {
1536+ f->R2 = f->invG;
1537+ f->cL = 0.0f; f->cB = 1.0f; f->cH = 0.0f;
1538+ }
1539+ break;
1540+ case BandpassPeak:
1541+ {
1542+ f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
1543+ f->cL = 0.0f; f->cB = f->R2; f->cH = 0.0f;
1544+ }
1545+ break;
1546+ case BandReject:
1547+ {
1548+ f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
1549+ f->cL = 1.0f; f->cB = 0.0f; f->cH = 1.0f;
1550+ }
1551+ break;
1552+ case Bell:
1553+ {
1554+ float fl = f->fc*powf(2.0f, (-f->B)*0.5f); // lower bandedge frequency (in Hz)
1555+ float wl = tanf(PI*fl*f->inv_sr); // warped radian lower bandedge frequency /(2*fs)
1556+ float r = f->g/wl;
1557+ r *= r; // warped frequency ratio wu/wl == (wc/wl)^2 where wu is the
1558+ // warped upper bandedge, wc the center
1559+ f->R2 = 2.0f*sqrtf(((r*r+1.0f)/r-2.0f)/(4.0f*f->G));
1560+ f->cL = 1.0f; f->cB = f->R2*f->G; f->cH = 1.0f;
1561+ }
1562+ break;
1563+ case Lowshelf:
1564+ {
1565+ float A = sqrtf(f->G);
1566+ f->g /= sqrtf(A); // scale SVF-cutoff frequency for shelvers
1567+ f->R2 = 2*sinhf(f->B*logf(2.0f)*0.5f);
1568+ f->cL = f->G; f->cB = f->R2*A; f->cH = 1.0f;
1569+ }
1570+ break;
1571+ case Highshelf:
1572+ {
1573+ float A = sqrtf(f->G);
1574+ f->g *= sqrtf(A); // scale SVF-cutoff frequency for shelvers
1575+ f->R2 = 2.0f*sinhf(f->B*logf(2.0f)*0.5f);
1576+ f->cL = 1.0f; f->cB = f->R2*A; f->cH = f->G;
1577+ }
1578+ break;
1579+ case Allpass:
1580+ {
1581+ f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
1582+ f->cL = 1.0f; f->cB = -f->R2; f->cH = 1.0f;
1583+ }
1584+ break;
1585+
1586+ // experimental - maybe we must find better curves for cL, cB, cH:
1587+ case Morph:
1588+ {
1589+ f->R2 = f->invG;
1590+ float x = 2.0f*f->m-1.0f;
1591+
1592+ f->cL = maximum(-x, 0.0f); /*cL *= cL;*/
1593+ f->cH = minimum( x, 0.0f); /*cH *= cH;*/
1594+ f->cB = 1.0f-x*x;
1595+
1596+ // bottom line: we need to test different versions for how they feel when tweaking the
1597+ // morph parameter
1598+
1599+ // this scaling ensures constant magnitude at the cutoff point (we divide the coefficients by
1600+ // the magnitude response value at the cutoff frequency and scale back by the gain):
1601+ float s = f->G * sqrtf((f->R2*f->R2) / (f->cL*f->cL + f->cB*f->cB + f->cH*f->cH - 2.0f*f->cL*f->cH));
1602+ f->cL *= s; f->cB *= s; f->cH *= s;
1603+ }
1604+ break;
1605+
1606+ }
1607+
1608+ f->h = 1.0f / (1.0f + f->R2*f->g + f->g*f->g); // factor for feedback precomputation
1609+}
1610+
1611+
1612+void tVZFilter_setBandwidth (tVZFilter* const vf, float B)
1613+{
1614+ _tVZFilter* f = *vf;
1615+ f->B = LEAF_clip(0.0f, B, 100.0f);
1616+ tVZFilter_calcCoeffs(vf);
1617+}
1618+void tVZFilter_setFreq (tVZFilter* const vf, float freq)
1619+{
1620+ _tVZFilter* f = *vf;
1621+ f->fc = LEAF_clip(0.0f, freq, 0.5f*leaf.sampleRate);
1622+ tVZFilter_calcCoeffs(vf);
1623+}
1624+void tVZFilter_setFreqAndBandwidth (tVZFilter* const vf, float freq, float bw)
1625+{
1626+ _tVZFilter* f = *vf;
1627+ f->B = LEAF_clip(0.0f,bw, 100.0f);
1628+ f->fc = LEAF_clip(0.0f, freq, 0.5f*leaf.sampleRate);
1629+ tVZFilter_calcCoeffs(vf);
1630+}
1631+
1632+void tVZFilter_setGain (tVZFilter* const vf, float gain)
1633+{
1634+ _tVZFilter* f = *vf;
1635+ f->G = LEAF_clip(0.000001f, gain, 100.0f);
1636+ f->invG = 1.0f/f->G;
1637+ tVZFilter_calcCoeffs(vf);
1638+}
1639+
1640+void tVZFilter_setMorph (tVZFilter* const vf, float morph)
1641+{
1642+ _tVZFilter* f = *vf;
1643+ f->m = LEAF_clip(0.0f, morph, 1.0f);
1644+ tVZFilter_calcCoeffs(vf);
1645+}
1646+
1647+void tVZFilter_setType (tVZFilter* const vf, VZFilterType type)
1648+{
1649+ _tVZFilter* f = *vf;
1650+ f->type = type;
1651+ tVZFilter_calcCoeffs(vf);
1652+}
1653+
1654+float tVZFilter_BandwidthToR(tVZFilter* const vf, float B)
1655+{
1656+ _tVZFilter* f = *vf;
1657+ float fl = f->fc*powf(2.0f, -B*0.5f); // lower bandedge frequency (in Hz)
1658+ float gl = tanf(PI*fl*f->inv_sr); // warped radian lower bandedge frequency /(2*fs)
1659+ float r = gl/f->g; // ratio between warped lower bandedge- and center-frequencies
1660+ // unwarped: r = pow(2, -B/2) -> approximation for low
1661+ // center-frequencies
1662+ return sqrtf((1.0f-r*r)*(1.0f-r*r)/(4.0f*r*r));
1663+}
1664+
1665+
1666+
1667+void tDiodeFilter_init (tDiodeFilter* const vf, float cutoff, float resonance)
1668+{
1669+ tDiodeFilter_initToPool(vf, cutoff, resonance, &leaf.mempool);
1670+}
1671+
1672+void tDiodeFilter_free (tDiodeFilter* const vf)
1673+{
1674+ tDiodeFilter_freeFromPool(vf, &leaf.mempool);
1675+}
1676+void tDiodeFilter_initToPool (tDiodeFilter* const vf, float cutoff, float resonance, tMempool* const mp)
1677+{
1678+
1679+ _tMempool* m = *mp;
1680+ _tDiodeFilter* f = *vf = (_tDiodeFilter*) mpool_alloc(sizeof(_tDiodeFilter), m);
1681+ // initialization (the resonance factor is between 0 and 8 according to the article)
1682+ f->f = tan(PI * cutoff/leaf.sampleRate);
1683+ f->r = (7.f * resonance + 0.5f);
1684+ f->Vt = 0.5f;
1685+ f->n = 1.836f;
1686+ f->zi = 0.0f; //previous input value
1687+ f->gamma = f->Vt*f->n;
1688+ f->s0 = 0.01f;
1689+ f->s1 = 0.02f;
1690+ f->s2 = 0.03f;
1691+ f->s3 = 0.04f;
1692+ f->g0inv = 1.f/(2.f*f->Vt);
1693+ f->g1inv = 1.f/(2.f*f->gamma);
1694+ f->g2inv = 1.f/(6.f*f->gamma);
1695+
1696+
1697+}
1698+void tDiodeFilter_freeFromPool (tDiodeFilter* const vf, tMempool* const mp)
1699+{
1700+ _tMempool* m = *mp;
1701+ _tDiodeFilter* f = *vf = (_tDiodeFilter*) mpool_alloc(sizeof(_tDiodeFilter), m);
1702+ mpool_free((char*)f, m);
1703+}
1704+
1705+float tanhXdX(float x)
1706+{
1707+ float a = x*x;
1708+ // IIRC I got this as Pade-approx for tanh(sqrt(x))/sqrt(x)
1709+ return ((a + 105.0f)*a + 945.0f) / ((15.0f*a + 420.0f)*a + 945.0f);
1710+}
1711+
1712+float tDiodeFilter_tick (tDiodeFilter* const vf, float in)
1713+{
1714+ _tDiodeFilter* f = *vf;
1715+
1716+ // the input x[n+1] is given by 'in', and x[n] by zi
1717+ // input with half delay
1718+ float ih = 0.5f * (in + f->zi);
1719+
1720+ // evaluate the non-linear factors
1721+ float t0 = f->f*tanhXdX((ih - f->r * f->s3)*f->g0inv)*f->g0inv;
1722+ float t1 = f->f*tanhXdX((f->s1-f->s0)*f->g1inv)*f->g1inv;
1723+ float t2 = f->f*tanhXdX((f->s2-f->s1)*f->g1inv)*f->g1inv;
1724+ float t3 = f->f*tanhXdX((f->s3-f->s2)*f->g1inv)*f->g1inv;
1725+ float t4 = f->f*tanhXdX((f->s3)*f->g2inv)*f->g2inv;
1726+
1727+
1728+
1729+ // This formula gives the result for y3 thanks to MATLAB
1730+ float y3 = (f->s2 + f->s3 + t2*(f->s1 + f->s2 + f->s3 + t1*(f->s0 + f->s1 + f->s2 + f->s3 + t0*in)) + t1*(2.0f*f->s2 + 2.0f*f->s3))*t3 + f->s3 + 2.0f*f->s3*t1 + t2*(2.0f*f->s3 + 3.0f*f->s3*t1);
1731+// if (isnan(y3))
1732+// {
1733+// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
1734+// }
1735+ float tempy3denom = (t4 + t1*(2.0f*t4 + 4.0f) + t2*(t4 + t1*(t4 + f->r*t0 + 4.0f) + 3.0f) + 2.0f)*t3 + t4 + t1*(2.0f*t4 + 2.0f) + t2*(2.0f*t4 + t1*(3.0f*t4 + 3.0f) + 2.0f) + 1.0f;
1736+// if (isnan(tempy3denom))
1737+// {
1738+// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
1739+// }
1740+ if (tempy3denom == 0.0f)
1741+ {
1742+ tempy3denom = 0.000001f;
1743+ }
1744+ y3 = y3 / tempy3denom;
1745+// if (isnan(y3))
1746+// {
1747+// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
1748+// }
1749+ if (t1 == 0.0f)
1750+ {
1751+ t1 = 0.000001f;
1752+ }
1753+ if (t2 == 0.0f)
1754+ {
1755+ t2 = 0.000001f;
1756+ }
1757+ if (t3 == 0.0f)
1758+ {
1759+ t3 = 0.000001f;
1760+ }
1761+ // Other outputs
1762+ float y2 = (f->s3 - (1+t4+t3)*y3) / (-t3);
1763+ float y1 = (f->s2 - (1+t3+t2)*y2 + t3*y3) / (-t2);
1764+ float y0 = (f->s1 - (1+t2+t1)*y1 + t2*y2) / (-t1);
1765+ float xx = (in - f->r*y3);
1766+
1767+ // update state
1768+ f->s0 += 2.0f * (t0*xx + t1*(y1-y0));
1769+// if (isnan(f->s0))
1770+// {
1771+// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
1772+// }
1773+
1774+// if (isinf(f->s0))
1775+// {
1776+// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
1777+// }
1778+ f->s1 += 2.0f * (t2*(y2-y1) - t1*(y1-y0));
1779+ f->s2 += 2.0f * (t3*(y3-y2) - t2*(y2-y1));
1780+ f->s3 += 2.0f * (-t4*(y3) - t3*(y3-y2));
1781+
1782+ f->zi = in;
1783+ return y3*f->r;
1784+
1785+}
1786+
1787+
1788+
1789+void tDiodeFilter_setFreq (tDiodeFilter* const vf, float cutoff)
1790+{
1791+ _tDiodeFilter* f = *vf;
1792+ f->f = tanf(PI * LEAF_clip(10.0f, cutoff, 20000.0f)*leaf.invSampleRate);
1793+}
1794+
1795+
1796+void tDiodeFilter_setQ (tDiodeFilter* const vf, float resonance)
1797+{
1798+ _tDiodeFilter* f = *vf;
1799+ f->r = LEAF_clip(0.5, (7.f * resonance + 0.5f), 8.0f);
1800+
1801+}
1802+
leaf/Src/leaf-instruments.c+706−0
@@ -0,0 +1,706 @@
1+/*==============================================================================
2+
3+ leaf-instruments.c
4+ Created: 30 Nov 2018 10:24:21am
5+ Author: airship
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-instruments.h"
12+
13+#else
14+
15+#include "../Inc/leaf-instruments.h"
16+
17+#endif
18+
19+// ----------------- COWBELL ----------------------------//
20+
21+void t808Cowbell_init(t808Cowbell* const cowbellInst, int useStick)
22+{
23+ _t808Cowbell* cowbell = *cowbellInst = (_t808Cowbell*) leaf_alloc(sizeof(_t808Cowbell));
24+
25+ tSquare_init(&cowbell->p[0]);
26+ tSquare_setFreq(&cowbell->p[0], 540.0f);
27+
28+ tSquare_init(&cowbell->p[1]);
29+ tSquare_setFreq(&cowbell->p[1], 1.48148f * 540.0f);
30+
31+ cowbell->oscMix = 0.5f;
32+
33+ tSVF_init(&cowbell->bandpassOsc, SVFTypeBandpass, 2500, 1.0f);
34+
35+ tSVF_init(&cowbell->bandpassStick, SVFTypeBandpass, 1800, 1.0f);
36+
37+ tEnvelope_init(&cowbell->envGain, 5.0f, 100.0f, OFALSE);
38+
39+ tEnvelope_init(&cowbell->envFilter, 5.0, 100.0f, OFALSE);
40+
41+ tHighpass_init(&cowbell->highpass, 1000.0f);
42+
43+ tNoise_init(&cowbell->stick, WhiteNoise);
44+
45+ tEnvelope_init(&cowbell->envStick, 5.0f, 5.0f, 0);
46+
47+ cowbell->useStick = useStick;
48+}
49+
50+void t808Cowebell_free(t808Cowbell* const cowbellInst)
51+{
52+ _t808Cowbell* cowbell = *cowbellInst;
53+
54+ tSquare_free(&cowbell->p[0]);
55+ tSquare_free(&cowbell->p[1]);
56+ tSVF_free(&cowbell->bandpassOsc);
57+ tSVF_free(&cowbell->bandpassStick);
58+ tEnvelope_free(&cowbell->envGain);
59+ tEnvelope_free(&cowbell->envFilter);
60+ tHighpass_free(&cowbell->highpass);
61+ tNoise_free(&cowbell->stick);
62+ tEnvelope_free(&cowbell->envStick);
63+ leaf_free((char*)cowbell);
64+}
65+
66+void t808Cowbell_initToPool (t808Cowbell* const cowbellInst, int useStick, tMempool* const mp)
67+{
68+ _tMempool* m = *mp;
69+ _t808Cowbell* cowbell = *cowbellInst = (_t808Cowbell*) mpool_alloc(sizeof(_t808Cowbell), m);
70+
71+ tSquare_initToPool(&cowbell->p[0], mp);
72+ tSquare_setFreq(&cowbell->p[0], 540.0f);
73+
74+ tSquare_initToPool(&cowbell->p[1], mp);
75+ tSquare_setFreq(&cowbell->p[1], 1.48148f * 540.0f);
76+
77+ cowbell->oscMix = 0.5f;
78+
79+ tSVF_initToPool(&cowbell->bandpassOsc, SVFTypeBandpass, 2500, 1.0f, mp);
80+
81+ tSVF_initToPool(&cowbell->bandpassStick, SVFTypeBandpass, 1800, 1.0f, mp);
82+
83+ tEnvelope_initToPool(&cowbell->envGain, 5.0f, 100.0f, OFALSE, mp);
84+
85+ tEnvelope_initToPool(&cowbell->envFilter, 5.0, 100.0f, OFALSE, mp);
86+
87+ tHighpass_initToPool(&cowbell->highpass, 1000.0f, mp);
88+
89+ tNoise_initToPool(&cowbell->stick, WhiteNoise, mp);
90+
91+ tEnvelope_initToPool(&cowbell->envStick, 5.0f, 5.0f, 0, mp);
92+
93+ cowbell->useStick = useStick;
94+}
95+
96+void t808Cowbell_freeFromPool (t808Cowbell* const cowbellInst, tMempool* const mp)
97+{
98+ _tMempool* m = *mp;
99+ _t808Cowbell* cowbell = *cowbellInst;
100+
101+ tSquare_freeFromPool(&cowbell->p[0], mp);
102+ tSquare_freeFromPool(&cowbell->p[1], mp);
103+ tSVF_freeFromPool(&cowbell->bandpassOsc, mp);
104+ tSVF_freeFromPool(&cowbell->bandpassStick, mp);
105+ tEnvelope_freeFromPool(&cowbell->envGain, mp);
106+ tEnvelope_freeFromPool(&cowbell->envFilter, mp);
107+ tHighpass_freeFromPool(&cowbell->highpass, mp);
108+ tNoise_freeFromPool(&cowbell->stick, mp);
109+ tEnvelope_freeFromPool(&cowbell->envStick, mp);
110+ mpool_free((char*)cowbell, m);
111+}
112+
113+void t808Cowbell_on(t808Cowbell* const cowbellInst, float vel)
114+{
115+ _t808Cowbell* cowbell = *cowbellInst;
116+
117+ tEnvelope_on(&cowbell->envGain, vel);
118+
119+ if (cowbell->useStick)
120+ tEnvelope_on(&cowbell->envStick,vel);
121+}
122+
123+float t808Cowbell_tick(t808Cowbell* const cowbellInst)
124+{
125+ _t808Cowbell* cowbell = *cowbellInst;
126+
127+ float sample = 0.0f;
128+
129+ // Mix oscillators.
130+ sample = (cowbell->oscMix * tSquare_tick(&cowbell->p[0])) + ((1.0f-cowbell->oscMix) * tSquare_tick(&cowbell->p[1]));
131+
132+ // Filter dive and filter.
133+ tSVF_setFreq(&cowbell->bandpassOsc, cowbell->filterCutoff + 1000.0f * tEnvelope_tick(&cowbell->envFilter));
134+ sample = tSVF_tick(&cowbell->bandpassOsc,sample);
135+
136+ sample *= (0.9f * tEnvelope_tick(&cowbell->envGain));
137+
138+ if (cowbell->useStick)
139+ sample += (0.1f * tEnvelope_tick(&cowbell->envStick) * tSVF_tick(&cowbell->bandpassStick, tNoise_tick(&cowbell->stick)));
140+
141+
142+ sample = tHighpass_tick(&cowbell->highpass, sample);
143+
144+ return sample;
145+}
146+
147+void t808Cowbell_setDecay(t808Cowbell* const cowbellInst, float decay)
148+{
149+ _t808Cowbell* cowbell = *cowbellInst;
150+ tEnvelope_setDecay(&cowbell->envGain,decay);
151+}
152+
153+void t808Cowbell_setHighpassFreq(t808Cowbell *cowbellInst, float freq)
154+{
155+ _t808Cowbell* cowbell = *cowbellInst;
156+ tHighpass_setFreq(&cowbell->highpass,freq);
157+}
158+
159+void t808Cowbell_setBandpassFreq(t808Cowbell* const cowbellInst, float freq)
160+{
161+ _t808Cowbell* cowbell = *cowbellInst;
162+ cowbell->filterCutoff = freq;
163+}
164+
165+void t808Cowbell_setFreq(t808Cowbell* const cowbellInst, float freq)
166+{
167+ _t808Cowbell* cowbell = *cowbellInst;
168+ tSquare_setFreq(&cowbell->p[0],freq);
169+ tSquare_setFreq(&cowbell->p[1],1.48148f*freq);
170+}
171+
172+void t808Cowbell_setOscMix(t808Cowbell* const cowbellInst, float oscMix)
173+{
174+ _t808Cowbell* cowbell = *cowbellInst;
175+ cowbell->oscMix = oscMix;
176+}
177+
178+void t808Cowbell_setStick(t808Cowbell* const cowbellInst, int useStick)
179+{
180+ _t808Cowbell* cowbell = *cowbellInst;
181+ cowbell->useStick = useStick;
182+}
183+
184+// ----------------- HIHAT ----------------------------//
185+
186+void t808Hihat_init(t808Hihat* const hihatInst)
187+{
188+ _t808Hihat* hihat = *hihatInst = (_t808Hihat*) leaf_alloc(sizeof(_t808Hihat));
189+
190+ for (int i = 0; i < 6; i++)
191+ {
192+ tSquare_init(&hihat->p[i]);
193+ }
194+
195+ tNoise_init(&hihat->stick, PinkNoise);
196+ tNoise_init(&hihat->n, WhiteNoise);
197+
198+ // need to fix SVF to be generic
199+ tSVF_init(&hihat->bandpassStick, SVFTypeBandpass,2500.0f,1.2f);
200+ tSVF_init(&hihat->bandpassOsc, SVFTypeBandpass,3500.0f,0.3f);
201+
202+ tEnvelope_init(&hihat->envGain, 0.0f, 50.0f, OFALSE);
203+ tEnvelope_init(&hihat->envStick, 0.0f, 7.0f, OFALSE);
204+
205+
206+ tHighpass_init(&hihat->highpass, 7000.0f);
207+
208+ hihat->freq = 40.0f;
209+ hihat->stretch = 0.0f;
210+
211+ tSquare_setFreq(&hihat->p[0], 2.0f * hihat->freq);
212+ tSquare_setFreq(&hihat->p[1], 3.00f * hihat->freq);
213+ tSquare_setFreq(&hihat->p[2], 4.16f * hihat->freq);
214+ tSquare_setFreq(&hihat->p[3], 5.43f * hihat->freq);
215+ tSquare_setFreq(&hihat->p[4], 6.79f * hihat->freq);
216+ tSquare_setFreq(&hihat->p[5], 8.21f * hihat->freq);
217+}
218+
219+void t808Hihat_free(t808Hihat* const hihatInst)
220+{
221+ _t808Hihat* hihat = *hihatInst;
222+
223+ for (int i = 0; i < 6; i++)
224+ {
225+ tSquare_free(&hihat->p[i]);
226+ }
227+
228+ tNoise_free(&hihat->stick);
229+ tNoise_free(&hihat->n);
230+
231+ // need to fix SVF to be generic
232+ tSVF_free(&hihat->bandpassStick);
233+ tSVF_free(&hihat->bandpassOsc);
234+ tEnvelope_free(&hihat->envGain);
235+ tEnvelope_free(&hihat->envStick);
236+
237+ tHighpass_free(&hihat->highpass);
238+
239+ leaf_free((char*)hihat);
240+}
241+
242+void t808Hihat_initToPool (t808Hihat* const hihatInst, tMempool* const mp)
243+{
244+ _tMempool* m = *mp;
245+ _t808Hihat* hihat = *hihatInst = (_t808Hihat*) mpool_alloc(sizeof(_t808Hihat), m);
246+
247+ for (int i = 0; i < 6; i++)
248+ {
249+ tSquare_initToPool(&hihat->p[i], mp);
250+ }
251+
252+ tNoise_initToPool(&hihat->stick, PinkNoise, mp);
253+ tNoise_initToPool(&hihat->n, WhiteNoise, mp);
254+
255+ // need to fix SVF to be generic
256+ tSVF_initToPool(&hihat->bandpassStick, SVFTypeBandpass,2500.0f,1.2f, mp);
257+ tSVF_initToPool(&hihat->bandpassOsc, SVFTypeBandpass,3500.0f,0.3f, mp);
258+
259+ tEnvelope_initToPool(&hihat->envGain, 0.0f, 50.0f, OFALSE, mp);
260+ tEnvelope_initToPool(&hihat->envStick, 0.0f, 7.0f, OFALSE, mp);
261+
262+
263+ tHighpass_initToPool(&hihat->highpass, 7000.0f, mp);
264+
265+ hihat->freq = 40.0f;
266+ hihat->stretch = 0.0f;
267+
268+ tSquare_setFreq(&hihat->p[0], 2.0f * hihat->freq);
269+ tSquare_setFreq(&hihat->p[1], 3.00f * hihat->freq);
270+ tSquare_setFreq(&hihat->p[2], 4.16f * hihat->freq);
271+ tSquare_setFreq(&hihat->p[3], 5.43f * hihat->freq);
272+ tSquare_setFreq(&hihat->p[4], 6.79f * hihat->freq);
273+ tSquare_setFreq(&hihat->p[5], 8.21f * hihat->freq);
274+}
275+
276+void t808Hihat_freeFromPool (t808Hihat* const hihatInst, tMempool* const mp)
277+{
278+ _tMempool* m = *mp;
279+ _t808Hihat* hihat = *hihatInst;
280+
281+ for (int i = 0; i < 6; i++)
282+ {
283+ tSquare_freeFromPool(&hihat->p[i], mp);
284+ }
285+
286+ tNoise_freeFromPool(&hihat->stick, mp);
287+ tNoise_freeFromPool(&hihat->n, mp);
288+
289+ // need to fix SVF to be generic
290+ tSVF_freeFromPool(&hihat->bandpassStick, mp);
291+ tSVF_freeFromPool(&hihat->bandpassOsc, mp);
292+ tEnvelope_freeFromPool(&hihat->envGain, mp);
293+ tEnvelope_freeFromPool(&hihat->envStick, mp);
294+
295+ tHighpass_freeFromPool(&hihat->highpass, mp);
296+
297+ mpool_free((char*)hihat, m);
298+}
299+
300+void t808Hihat_on(t808Hihat* const hihatInst, float vel)
301+{
302+ _t808Hihat* hihat = *hihatInst;
303+ tEnvelope_on(&hihat->envGain, vel);
304+ tEnvelope_on(&hihat->envStick, vel);
305+}
306+
307+void t808Hihat_setOscNoiseMix(t808Hihat* const hihatInst, float oscNoiseMix)
308+{
309+ _t808Hihat* hihat = *hihatInst;
310+ hihat->oscNoiseMix = oscNoiseMix;
311+}
312+
313+float t808Hihat_tick(t808Hihat* const hihatInst)
314+{
315+ _t808Hihat* hihat = *hihatInst;
316+
317+ float sample = 0.0f;
318+ float gainScale = 0.1666f;
319+
320+ float myNoise = tNoise_tick(&hihat->n);
321+
322+ tSquare_setFreq(&hihat->p[0], ((2.0f + hihat->stretch) * hihat->freq));
323+ tSquare_setFreq(&hihat->p[1], ((3.00f + hihat->stretch) * hihat->freq));
324+ tSquare_setFreq(&hihat->p[2], ((4.16f + hihat->stretch) * hihat->freq));
325+ tSquare_setFreq(&hihat->p[3], ((5.43f + hihat->stretch) * hihat->freq));
326+ tSquare_setFreq(&hihat->p[4], ((6.79f + hihat->stretch) * hihat->freq));
327+ tSquare_setFreq(&hihat->p[5], ((8.21f + hihat->stretch) * hihat->freq));
328+
329+ for (int i = 0; i < 6; i++)
330+ {
331+ sample += tSquare_tick(&hihat->p[i]);
332+ }
333+
334+ sample *= gainScale;
335+
336+ sample = (hihat->oscNoiseMix * sample) + ((1.0f-hihat->oscNoiseMix) * myNoise);
337+
338+ sample = tSVF_tick(&hihat->bandpassOsc, sample);
339+
340+ float myGain = tEnvelope_tick(&hihat->envGain);
341+ sample *= (myGain*myGain);//square the output gain envelope
342+ sample = tHighpass_tick(&hihat->highpass, sample);
343+ sample += ((0.5f * tEnvelope_tick(&hihat->envStick)) * tSVF_tick(&hihat->bandpassStick, tNoise_tick(&hihat->stick)));
344+ sample = tanhf(sample * 2.0f);
345+
346+ return sample;
347+}
348+
349+void t808Hihat_setDecay(t808Hihat* const hihatInst, float decay)
350+{
351+ _t808Hihat* hihat = *hihatInst;
352+ tEnvelope_setDecay(&hihat->envGain,decay);
353+}
354+
355+void t808Hihat_setHighpassFreq(t808Hihat* const hihatInst, float freq)
356+{
357+ _t808Hihat* hihat = *hihatInst;
358+ tHighpass_setFreq(&hihat->highpass,freq);
359+}
360+
361+void t808Hihat_setStretch(t808Hihat* const hihatInst, float stretch)
362+{
363+ _t808Hihat* hihat = *hihatInst;
364+ hihat->stretch = stretch;
365+}
366+
367+void t808Hihat_setFM(t808Hihat* const hihatInst, float FM_amount)
368+{
369+ _t808Hihat* hihat = *hihatInst;
370+ hihat->FM_amount = FM_amount;
371+}
372+
373+void t808Hihat_setOscBandpassFreq(t808Hihat* const hihatInst, float freq)
374+{
375+ _t808Hihat* hihat = *hihatInst;
376+ tSVF_setFreq(&hihat->bandpassOsc,freq);
377+}
378+
379+void t808Hihat_setOscBandpassQ(t808Hihat* const hihatInst, float Q)
380+{
381+ _t808Hihat* hihat = *hihatInst;
382+ tSVF_setQ(&hihat->bandpassOsc,Q);
383+}
384+
385+void t808Hihat_setStickBandPassFreq(t808Hihat* const hihatInst, float freq)
386+{
387+ _t808Hihat* hihat = *hihatInst;
388+ tSVF_setFreq(&hihat->bandpassStick,freq);
389+}
390+
391+void t808Hihat_setStickBandPassQ(t808Hihat* const hihatInst, float Q)
392+{
393+ _t808Hihat* hihat = *hihatInst;
394+ tSVF_setQ(&hihat->bandpassStick,Q);
395+}
396+
397+void t808Hihat_setOscFreq(t808Hihat* const hihatInst, float freq)
398+{
399+ _t808Hihat* hihat = *hihatInst;
400+ hihat->freq = freq;
401+}
402+
403+// ----------------- SNARE ----------------------------//
404+
405+void t808Snare_init(t808Snare* const snareInst)
406+{
407+ _t808Snare* snare = *snareInst = (_t808Snare*) leaf_alloc(sizeof(_t808Snare));
408+
409+ float ratio[2] = {1.0, 1.5};
410+ for (int i = 0; i < 2; i++)
411+ {
412+ tTriangle_init(&snare->tone[i]);
413+
414+ tTriangle_setFreq(&snare->tone[i], ratio[i] * 400.0f);
415+ tSVF_init(&snare->toneLowpass[i], SVFTypeLowpass, 4000, 1.0f);
416+ tEnvelope_init(&snare->toneEnvOsc[i], 0.0f, 50.0f, OFALSE);
417+ tEnvelope_init(&snare->toneEnvGain[i], 1.0f, 150.0f, OFALSE);
418+ tEnvelope_init(&snare->toneEnvFilter[i], 1.0f, 2000.0f, OFALSE);
419+
420+ snare->toneGain[i] = 0.5f;
421+ }
422+
423+ snare->tone1Freq = ratio[0] * 100.0f;
424+ snare->tone2Freq = ratio[1] * 100.0f;
425+ snare->noiseFilterFreq = 3000.0f;
426+ tNoise_init(&snare->noiseOsc, WhiteNoise);
427+ tSVF_init(&snare->noiseLowpass, SVFTypeLowpass, 12000.0f, 0.8f);
428+ tEnvelope_init(&snare->noiseEnvGain, 0.0f, 100.0f, OFALSE);
429+ tEnvelope_init(&snare->noiseEnvFilter, 0.0f, 1000.0f, OFALSE);
430+ snare->noiseGain = 1.0f;
431+}
432+
433+void t808Snare_free (t808Snare* const snareInst)
434+{
435+ _t808Snare* snare = *snareInst;
436+
437+ for (int i = 0; i < 2; i++)
438+ {
439+ tTriangle_free(&snare->tone[i]);
440+ tSVF_free(&snare->toneLowpass[i]);
441+ tEnvelope_free(&snare->toneEnvOsc[i]);
442+ tEnvelope_free(&snare->toneEnvGain[i]);
443+ tEnvelope_free(&snare->toneEnvFilter[i]);
444+ }
445+
446+ tNoise_free(&snare->noiseOsc);
447+ tSVF_free(&snare->noiseLowpass);
448+ tEnvelope_free(&snare->noiseEnvGain);
449+ tEnvelope_free(&snare->noiseEnvFilter);
450+
451+ leaf_free((char*)snare);
452+}
453+
454+void t808Snare_initToPool (t808Snare* const snareInst, tMempool* const mp)
455+{
456+ _tMempool* m = *mp;
457+ _t808Snare* snare = *snareInst = (_t808Snare*) mpool_alloc(sizeof(_t808Snare), m);
458+
459+ float ratio[2] = {1.0, 1.5};
460+ for (int i = 0; i < 2; i++)
461+ {
462+ tTriangle_initToPool(&snare->tone[i], mp);
463+
464+ tTriangle_setFreq(&snare->tone[i], ratio[i] * 400.0f);
465+ tSVF_initToPool(&snare->toneLowpass[i], SVFTypeLowpass, 4000, 1.0f, mp);
466+ tEnvelope_initToPool(&snare->toneEnvOsc[i], 0.0f, 50.0f, OFALSE, mp);
467+ tEnvelope_initToPool(&snare->toneEnvGain[i], 1.0f, 150.0f, OFALSE, mp);
468+ tEnvelope_initToPool(&snare->toneEnvFilter[i], 1.0f, 2000.0f, OFALSE, mp);
469+
470+ snare->toneGain[i] = 0.5f;
471+ }
472+
473+ snare->tone1Freq = ratio[0] * 100.0f;
474+ snare->tone2Freq = ratio[1] * 100.0f;
475+ snare->noiseFilterFreq = 3000.0f;
476+ tNoise_initToPool(&snare->noiseOsc, WhiteNoise, mp);
477+ tSVF_initToPool(&snare->noiseLowpass, SVFTypeLowpass, 12000.0f, 0.8f, mp);
478+ tEnvelope_initToPool(&snare->noiseEnvGain, 0.0f, 100.0f, OFALSE, mp);
479+ tEnvelope_initToPool(&snare->noiseEnvFilter, 0.0f, 1000.0f, OFALSE, mp);
480+ snare->noiseGain = 1.0f;
481+}
482+
483+void t808Snare_freeFromPool (t808Snare* const snareInst, tMempool* const mp)
484+{
485+ _tMempool* m = *mp;
486+ _t808Snare* snare = *snareInst;
487+
488+ for (int i = 0; i < 2; i++)
489+ {
490+ tTriangle_freeFromPool(&snare->tone[i], mp);
491+ tSVF_freeFromPool(&snare->toneLowpass[i], mp);
492+ tEnvelope_freeFromPool(&snare->toneEnvOsc[i], mp);
493+ tEnvelope_freeFromPool(&snare->toneEnvGain[i], mp);
494+ tEnvelope_freeFromPool(&snare->toneEnvFilter[i], mp);
495+ }
496+
497+ tNoise_freeFromPool(&snare->noiseOsc, mp);
498+ tSVF_freeFromPool(&snare->noiseLowpass, mp);
499+ tEnvelope_freeFromPool(&snare->noiseEnvGain, mp);
500+ tEnvelope_freeFromPool(&snare->noiseEnvFilter, mp);
501+
502+ mpool_free((char*)snare, m);
503+}
504+
505+void t808Snare_on(t808Snare* const snareInst, float vel)
506+{
507+ _t808Snare* snare = *snareInst;
508+
509+ for (int i = 0; i < 2; i++)
510+ {
511+ tEnvelope_on(&snare->toneEnvOsc[i], vel);
512+ tEnvelope_on(&snare->toneEnvGain[i], vel);
513+ tEnvelope_on(&snare->toneEnvFilter[i], vel);
514+ }
515+
516+ tEnvelope_on(&snare->noiseEnvGain, vel);
517+ tEnvelope_on(&snare->noiseEnvFilter, vel);
518+}
519+
520+void t808Snare_setTone1Freq(t808Snare* const snareInst, float freq)
521+{
522+ _t808Snare* snare = *snareInst;
523+ snare->tone1Freq = freq;
524+ tTriangle_setFreq(&snare->tone[0], freq);
525+}
526+
527+void t808Snare_setTone2Freq(t808Snare* const snareInst, float freq)
528+{
529+ _t808Snare* snare = *snareInst;
530+ snare->tone2Freq = freq;
531+ tTriangle_setFreq(&snare->tone[1],freq);
532+}
533+
534+void t808Snare_setTone1Decay(t808Snare* const snareInst, float decay)
535+{
536+ _t808Snare* snare = *snareInst;
537+ tEnvelope_setDecay(&snare->toneEnvGain[0],decay);
538+}
539+
540+void t808Snare_setTone2Decay(t808Snare* const snareInst, float decay)
541+{
542+ _t808Snare* snare = *snareInst;
543+ tEnvelope_setDecay(&snare->toneEnvGain[1],decay);
544+}
545+
546+void t808Snare_setNoiseDecay(t808Snare* const snareInst, float decay)
547+{
548+ _t808Snare* snare = *snareInst;
549+ tEnvelope_setDecay(&snare->noiseEnvGain,decay);
550+}
551+
552+void t808Snare_setToneNoiseMix(t808Snare* const snareInst, float toneNoiseMix)
553+{
554+ _t808Snare* snare = *snareInst;
555+ snare->toneNoiseMix = toneNoiseMix;
556+}
557+
558+void t808Snare_setNoiseFilterFreq(t808Snare* const snareInst, float noiseFilterFreq)
559+{
560+ _t808Snare* snare = *snareInst;
561+ snare->noiseFilterFreq = noiseFilterFreq;
562+}
563+
564+void t808Snare_setNoiseFilterQ(t808Snare* const snareInst, float noiseFilterQ)
565+{
566+ _t808Snare* snare = *snareInst;
567+ tSVF_setQ(&snare->noiseLowpass, noiseFilterQ);
568+}
569+
570+static float tone[2];
571+
572+float t808Snare_tick(t808Snare* const snareInst)
573+{
574+ _t808Snare* snare = *snareInst;
575+
576+ for (int i = 0; i < 2; i++)
577+ {
578+ tTriangle_setFreq(&snare->tone[i], snare->tone1Freq + (20.0f * tEnvelope_tick(&snare->toneEnvOsc[i])));
579+ tone[i] = tTriangle_tick(&snare->tone[i]);
580+
581+ tSVF_setFreq(&snare->toneLowpass[i], 2000.0f + (500.0f * tEnvelope_tick(&snare->toneEnvFilter[i])));
582+ tone[i] = tSVF_tick(&snare->toneLowpass[i], tone[i]) * tEnvelope_tick(&snare->toneEnvGain[i]);
583+ }
584+
585+ float noise = tNoise_tick(&snare->noiseOsc);
586+ tSVF_setFreq(&snare->noiseLowpass, snare->noiseFilterFreq + (1000.0f * tEnvelope_tick(&snare->noiseEnvFilter)));
587+ noise = tSVF_tick(&snare->noiseLowpass, noise) * tEnvelope_tick(&snare->noiseEnvGain);
588+
589+ float sample = (snare->toneNoiseMix)*(tone[0] * snare->toneGain[0] + tone[1] * snare->toneGain[1]) + (1.0f-snare->toneNoiseMix) * (noise * snare->noiseGain);
590+ sample = tanhf(sample * 2.0f);
591+ return sample;
592+}
593+
594+// ----------------- KICK ----------------------------//
595+
596+void t808Kick_init (t808Kick* const kickInst)
597+{
598+ _t808Kick* kick = *kickInst = (_t808Kick*) leaf_alloc(sizeof(_t808Kick));
599+
600+ tCycle_init(&kick->tone);
601+ kick->toneInitialFreq = 40.0f;
602+ kick->sighAmountInHz = 7.0f;
603+ kick->chirpRatioMinusOne = 3.3f;
604+ tCycle_setFreq(&kick->tone, 50.0f);
605+ tSVF_init(&kick->toneLowpass, SVFTypeLowpass, 2000.0f, 0.5f);
606+ tEnvelope_init(&kick->toneEnvOscChirp, 0.0f, 20.0f, OFALSE);
607+ tEnvelope_init(&kick->toneEnvOscSigh, 0.0f, 2500.0f, OFALSE);
608+ tEnvelope_init(&kick->toneEnvGain, 0.0f, 800.0f, OFALSE);
609+ tNoise_init(&kick->noiseOsc, PinkNoise);
610+ tEnvelope_init(&kick->noiseEnvGain, 0.0f, 1.0f, OFALSE);
611+ kick->noiseGain = 0.3f;
612+}
613+
614+void t808Kick_free (t808Kick* const kickInst)
615+{
616+ _t808Kick* kick = *kickInst;
617+
618+ tCycle_free(&kick->tone);
619+ tSVF_free(&kick->toneLowpass);
620+ tEnvelope_free(&kick->toneEnvOscChirp);
621+ tEnvelope_free(&kick->toneEnvOscSigh);
622+ tEnvelope_free(&kick->toneEnvGain);
623+ tNoise_free(&kick->noiseOsc);
624+ tEnvelope_free(&kick->noiseEnvGain);
625+
626+ leaf_free((char*)kick);
627+}
628+
629+void t808Kick_initToPool (t808Kick* const kickInst, tMempool* const mp)
630+{
631+ _tMempool* m = *mp;
632+ _t808Kick* kick = *kickInst = (_t808Kick*) mpool_alloc(sizeof(_t808Kick), m);
633+
634+ tCycle_initToPool(&kick->tone, mp);
635+ kick->toneInitialFreq = 40.0f;
636+ kick->sighAmountInHz = 7.0f;
637+ kick->chirpRatioMinusOne = 3.3f;
638+ tCycle_setFreq(&kick->tone, 50.0f);
639+ tSVF_initToPool(&kick->toneLowpass, SVFTypeLowpass, 2000.0f, 0.5f, mp);
640+ tEnvelope_initToPool(&kick->toneEnvOscChirp, 0.0f, 20.0f, OFALSE, mp);
641+ tEnvelope_initToPool(&kick->toneEnvOscSigh, 0.0f, 2500.0f, OFALSE, mp);
642+ tEnvelope_initToPool(&kick->toneEnvGain, 0.0f, 800.0f, OFALSE, mp);
643+ tNoise_initToPool(&kick->noiseOsc, PinkNoise, mp);
644+ tEnvelope_initToPool(&kick->noiseEnvGain, 0.0f, 1.0f, OFALSE, mp);
645+ kick->noiseGain = 0.3f;
646+}
647+
648+void t808Kick_freeFromPool (t808Kick* const kickInst, tMempool* const mp)
649+{
650+ _tMempool* m = *mp;
651+ _t808Kick* kick = *kickInst;
652+
653+ tCycle_freeFromPool(&kick->tone, mp);
654+ tSVF_freeFromPool(&kick->toneLowpass, mp);
655+ tEnvelope_freeFromPool(&kick->toneEnvOscChirp, mp);
656+ tEnvelope_freeFromPool(&kick->toneEnvOscSigh, mp);
657+ tEnvelope_freeFromPool(&kick->toneEnvGain, mp);
658+ tNoise_freeFromPool(&kick->noiseOsc, mp);
659+ tEnvelope_freeFromPool(&kick->noiseEnvGain, mp);
660+
661+ mpool_free((char*)kick, m);
662+}
663+
664+float t808Kick_tick (t808Kick* const kickInst)
665+{
666+ _t808Kick* kick = *kickInst;
667+
668+ tCycle_setFreq(&kick->tone, (kick->toneInitialFreq * (1.0f + (kick->chirpRatioMinusOne * tEnvelope_tick(&kick->toneEnvOscChirp)))) + (kick->sighAmountInHz * tEnvelope_tick(&kick->toneEnvOscSigh)));
669+ float sample = tCycle_tick(&kick->tone) * tEnvelope_tick(&kick->toneEnvGain);
670+ sample+= tNoise_tick(&kick->noiseOsc) * tEnvelope_tick(&kick->noiseEnvGain);
671+ //add distortion here
672+ sample = tSVF_tick(&kick->toneLowpass, sample);
673+ return sample;
674+}
675+
676+void t808Kick_on (t808Kick* const kickInst, float vel)
677+{
678+ _t808Kick* kick = *kickInst;
679+ tEnvelope_on(&kick->toneEnvOscChirp, vel);
680+ tEnvelope_on(&kick->toneEnvOscSigh, vel);
681+ tEnvelope_on(&kick->toneEnvGain, vel);
682+ tEnvelope_on(&kick->noiseEnvGain, vel);
683+
684+}
685+void t808Kick_setToneFreq (t808Kick* const kickInst, float freq)
686+{
687+ _t808Kick* kick = *kickInst;
688+ kick->toneInitialFreq = freq;
689+
690+}
691+
692+void t808Kick_setToneDecay (t808Kick* const kickInst, float decay)
693+{
694+ _t808Kick* kick = *kickInst;
695+ tEnvelope_setDecay(&kick->toneEnvGain,decay);
696+ tEnvelope_setDecay(&kick->toneEnvGain,decay * 3.0f);
697+}
698+
699+void t808Kick_setNoiseDecay (t808Kick* const kickInst, float decay);
700+void t808Kick_setSighAmount (t808Kick* const kickInst, float sigh);
701+void t808Kick_setChirpAmount (t808Kick* const kickInst, float chirp);
702+void t808Kick_setToneNoiseMix (t808Kick* const kickInst, float toneNoiseMix);
703+void t808Kick_setNoiseFilterFreq (t808Kick* const kickInst, float noiseFilterFreq);
704+void t808Kick_setNoiseFilterQ (t808Kick* const kickInst, float noiseFilterQ);
705+
706+
leaf/Src/leaf-math.c+655−0
@@ -0,0 +1,655 @@
1+/*==============================================================================
2+
3+ leaf-math.c
4+ Created: 22 Jan 2017 7:02:56pm
5+ Author: Michael R Mulshine
6+
7+ ==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-math.h"
12+#include "..\Inc\leaf-tables.h"
13+
14+#else
15+
16+#include "../Inc/leaf-math.h"
17+#include "../Inc/leaf-tables.h"
18+
19+#endif
20+
21+
22+#define EXPONENTIAL_TABLE_SIZE 65536
23+
24+#define log10f_fast(x) (log2f_approx(x)*0.3010299956639812f)
25+
26+// This is a fast approximation to log2() found on http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html credited to this post https://community.arm.com/developer/tools-software/tools/f/armds-forum/4292/cmsis-dsp-new-functionality-proposal/22621#22621
27+// Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E;
28+float log2f_approx(float X) {
29+ float Y, F;
30+ int E;
31+ F = frexpf(fabsf(X), &E);
32+ Y = 1.23149591368684f;
33+ Y *= F;
34+ Y += -4.11852516267426f;
35+ Y *= F;
36+ Y += 6.02197014179219f;
37+ Y *= F;
38+ Y += -3.13396450166353f;
39+ Y += E;
40+ return(Y);
41+}
42+
43+float interpolate3max(float *buf, const int peakindex)
44+{
45+ float a = buf[peakindex-1];
46+ float b = buf[peakindex];
47+ float c = buf[peakindex+1];
48+ float realpeak;
49+
50+ realpeak = b + (float)0.125 * (c - a) * (c - a) / ((float)2. * b - a - c);
51+
52+ return(realpeak);
53+}
54+
55+float interpolate3phase(float *buf, const int peakindex)
56+{
57+ float a = buf[peakindex-1];
58+ float b = buf[peakindex];
59+ float c = buf[peakindex+1];
60+ float fraction;
61+
62+ fraction = ((float)0.5 * (c - a)) / ((float)2. * b - a - c);
63+
64+ return(fraction);
65+}
66+
67+// alternative implementation for abs()
68+// REQUIRES: 32 bit integers
69+int fastabs_int(int in){
70+ unsigned int r;
71+ int const mask = in >> 31;
72+
73+ r = (in ^ mask) - mask;
74+
75+ return (r);
76+}
77+
78+// alternative implementation for abs()
79+// REQUIRES: 32 bit floats
80+float fastabsf(float f)
81+{
82+ union
83+ {
84+ float f;
85+ unsigned int ui;
86+ }alias;
87+
88+ alias.f = f;
89+ alias.ui &= 0x7fffffff;
90+ return alias.f;
91+}
92+
93+double fastexp(double x) {
94+ x = 1.0 + (x * 0.0009765625);
95+ x *= x; x *= x; x *= x; x *= x;
96+ x *= x; x *= x; x *= x; x *= x;
97+ x *= x; x *= x;
98+ return x;
99+}
100+
101+float fastexpf(float x) {
102+ x = 1.0f + (x * 0.0009765625f);
103+ x *= x; x *= x; x *= x; x *= x;
104+ x *= x; x *= x; x *= x; x *= x;
105+ x *= x; x *= x;
106+ return x;
107+}
108+
109+double fasterexp(double x) {
110+ x = 1.0 + (x * 0.00390625);
111+ x *= x; x *= x; x *= x; x *= x;
112+ x *= x; x *= x; x *= x; x *= x;
113+ return x;
114+}
115+
116+float fasterexpf(float x) {
117+ x = 1.0f + (x * 0.00390625f);
118+ x *= x; x *= x; x *= x; x *= x;
119+ x *= x; x *= x; x *= x; x *= x;
120+ return x;
121+}
122+
123+// fast floating-point exp2 function taken from Robert Bristow Johnson's
124+// post in the music-dsp list on Date: Tue, 02 Sep 2014 16:50:11 -0400
125+float fastexp2f(float x)
126+{
127+ if (x >= -127.0)
128+ {
129+ float accumulator, xPower;
130+ union {float f; int32_t i;} xBits;
131+
132+ xBits.i = (int32_t)(x + 4096.0f) - 4096L; /* integer part */
133+ x -= (float)(xBits.i); /* fractional part */
134+
135+ accumulator = 1.0f + 0.69303212081966f*x;
136+ xPower = x*x;
137+ accumulator += 0.24137976293709f*xPower;
138+ xPower *= x;
139+ accumulator += 0.05203236900844f*xPower;
140+ xPower *= x;
141+ accumulator += 0.01355574723481f*xPower;
142+
143+ xBits.i += 127; /* bias integer part */
144+ xBits.i<<= 23; /* move biased int part into exponent bits */
145+
146+ return accumulator * xBits.f;
147+ }
148+ else
149+ {
150+ return 0.0f;
151+ }
152+}
153+
154+
155+float fastPowf(float a, float b) {
156+ union
157+ {
158+ float d; int x;
159+ }
160+ u = { a };
161+
162+ u.x = (int)(b * (u.x - 1064866805) + 1064866805);
163+ return u.d;
164+}
165+
166+
167+double fastPow(double a, double b) {
168+ union {
169+ double d;
170+ int x[2];
171+ } u = { a };
172+
173+ u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
174+
175+ u.x[0] = 0;
176+ return u.d;
177+}
178+
179+
180+
181+
182+
183+/*
184+ you pass in a float array to get back two indexes representing the volumes of the left (index 0) and right (index 1) channels
185+ when t is -1, volumes[0] = 0, volumes[1] = 1
186+ when t = 0, volumes[0] = 0.707, volumes[1] = 0.707 (equal-power cross fade)
187+ when t = 1, volumes[0] = 1, volumes[1] = 0
188+ */
189+
190+void LEAF_crossfade(float fade, float* volumes) {
191+ volumes[0] = sqrtf(0.5f * (1.0f + fade));
192+ volumes[1] = sqrtf(0.5f * (1.0f - fade));
193+}
194+
195+// dope af
196+float LEAF_chebyshevT(float in, int n){
197+ if (n == 0) return 1;
198+ else if (n == 1) return in;
199+ else return 2.0f * in * LEAF_chebyshevT(in, n-1) - LEAF_chebyshevT(in, n-2);
200+}
201+
202+#if !(_WIN32 || _WIN64)
203+float LEAF_CompoundChebyshevT(float in, int n, float* amps){
204+ float T[n+1];
205+ T[0] = 1.0f;
206+ T[1] = in;
207+ for (int i = 2; i <= n; ++i)
208+ T[i] = 2*in*T[i-1] - T[i-2];
209+ float out = 0;
210+ float amp = 0;
211+ for (int i = 0; i < n; ++i){
212+ out += amps[i]*T[i+1];
213+ amp += amps[i];
214+ }
215+ return out / amp ;
216+}
217+#endif
218+
219+float LEAF_frequencyToMidi(float f)
220+{
221+ return (69.0f + 12.0f * log2f(f * INV_440));
222+}
223+
224+// Jones shaper
225+float LEAF_shaper(float input, float m_drive)
226+{
227+ float fx = input * 2.0f; // prescale
228+ float w, c, xc, xc2, xc4;
229+
230+ xc = LEAF_clip(-SQRT8, fx, SQRT8);
231+ xc2 = xc*xc;
232+ c = 0.5f*fx*(3.0f - (xc2));
233+ xc4 = xc2 * xc2;
234+ w = (1.0f - xc2*0.25f + xc4*0.015625f) * WSCALE;
235+ float shaperOut = w*(c+ 0.05f*xc2)*(m_drive + 0.75f);
236+ shaperOut *= 0.5f; // post_scale
237+ return shaperOut;
238+}
239+
240+// round input to nearest rnd
241+float LEAF_round (float input, float rnd)
242+{
243+ rnd = fabsf(rnd);
244+
245+ if (rnd <= 0.0000001f) return input;
246+
247+ float scale = 1.f / rnd;
248+
249+ return roundf(input * scale) / scale;
250+}
251+
252+
253+
254+float LEAF_bitwise_xor(float input, uint32_t op)
255+{
256+ union unholy_t unholy;
257+ unholy.f = input;
258+ unholy.i = (unholy.i ^ op);
259+
260+ return unholy.f;
261+}
262+
263+float LEAF_reedTable(float input, float offset, float slope)
264+{
265+ float output = offset + (slope * input);
266+ if ( output > 1.0f) output = 1.0f;
267+ if ( output < -1.0f) output = -1.0f;
268+ return output;
269+}
270+
271+float LEAF_softClip(float val, float thresh)
272+{
273+ float x;
274+
275+ if(val > thresh)
276+ {
277+ x = thresh / val;
278+ return (1.0f - x) * (1.0f - thresh) + thresh;
279+ }
280+ else if(val < -thresh)
281+ {
282+ x = -thresh / val;
283+ return -((1.0f - x) * (1.0f - thresh) + thresh);
284+ }
285+ else
286+ {
287+ return val;
288+ }
289+}
290+
291+float LEAF_clip(float min, float val, float max)
292+{
293+ float tempmin = min;
294+ float tempmax = max;
295+ if (min > max)
296+ {
297+ tempmin = max;
298+ tempmax = min;
299+ }
300+ if (val < tempmin) {
301+ return tempmin;
302+ } else if (val > tempmax) {
303+ return tempmax;
304+ } else {
305+ return val;
306+ }
307+}
308+
309+int LEAF_clipInt(int min, int val, int max)
310+{
311+ int tempmin = min;
312+ int tempmax = max;
313+ if (min > max)
314+ {
315+ tempmin = max;
316+ tempmax = min;
317+ }
318+ if (val < tempmin) {
319+ return tempmin;
320+ } else if (val > tempmax) {
321+ return tempmax;
322+ } else {
323+ return val;
324+ }
325+}
326+
327+oBool LEAF_isPrime(uint64_t number )
328+{
329+ if ( number == 2 ) return OTRUE;
330+ if ( number & 1 ) {
331+ for ( int i=3; i<(int)sqrt((double)number)+1; i+=2 )
332+ if ( (number % i) == 0 ) return OFALSE;
333+ return OTRUE; // prime
334+ }
335+ else return OFALSE; // even
336+}
337+
338+// Adapted from MusicDSP: http://www.musicdsp.org/showone.php?id=238
339+float LEAF_tanh(float x)
340+{
341+
342+ if( x < -3.0f )
343+ return -1.0f;
344+ else if( x > 3.0f )
345+ return 1.0f;
346+ else
347+ return x * ( 27.0f + x * x ) / ( 27.0f + 9.0f * x * x );
348+}
349+
350+
351+void LEAF_generate_sine(float* buffer, int size)
352+{
353+ float phase;
354+ for (int i = 0; i < size; i++)
355+ {
356+ phase = (float) i / (float) size;
357+ buffer[i] = sinf(phase * TWO_PI);
358+ }
359+}
360+
361+void LEAF_generate_sawtooth(float* buffer, float basefreq, int size)
362+{
363+ int harmonic = 1;
364+ float phase = 0.0f;
365+ float freq = harmonic * basefreq;
366+ float amp;
367+
368+ while (freq < (leaf.sampleRate * 0.5))
369+ {
370+ amp = 1.0f / harmonic;
371+ for (int i = 0; i < size; i++)
372+ {
373+ phase = (float) i / (float) size;
374+ buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
375+ }
376+
377+ harmonic++;
378+ freq = harmonic * basefreq;
379+ }
380+}
381+
382+
383+void LEAF_generate_triangle(float* buffer, float basefreq, int size)
384+{
385+ int harmonic = 1;
386+ float phase = 0.0f;
387+ float freq = harmonic * basefreq;
388+ float amp = 1.0f;
389+
390+ int count = 0;
391+ float mult = 1.0f;
392+
393+ while (freq < (leaf.sampleRate * 0.5))
394+ {
395+ amp = 1.0f / (float)(harmonic * harmonic);
396+
397+ if (count % 2) mult = -1.0f;
398+ else mult = 1.0f;
399+
400+ for (int i = 0; i < size; i++)
401+ {
402+ phase = (float) i / (float) size;
403+ buffer[i] += (mult * amp * sinf(harmonic * phase * TWO_PI));
404+ }
405+
406+ count++;
407+ harmonic += 2;
408+ freq = harmonic * basefreq;
409+ }
410+}
411+
412+void LEAF_generate_square(float* buffer, float basefreq, int size)
413+{
414+ int harmonic = 1;
415+ float phase = 0.0f;
416+ float freq = harmonic * basefreq;
417+ float amp = 1.0f;
418+
419+ while (freq < (leaf.sampleRate * 0.5))
420+ {
421+ amp = 1.0f / (float)(harmonic);
422+
423+ for (int i = 0; i < size; i++)
424+ {
425+ phase = (float) i / (float) size;
426+ buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
427+ }
428+
429+ harmonic += 2;
430+ freq = harmonic * basefreq;
431+ }
432+}
433+
434+
435+//0.001 base gives a good curve that goes from 1 to near zero
436+void LEAF_generate_exp(float* buffer, float base, float start, float end, float offset, int size)
437+{
438+ float increment = (end - start) / (float)size;
439+ float x = start;
440+ for (int i = 0; i < size; i++)
441+ {
442+ buffer[i] = powf(base, x) + offset;
443+ x += increment;
444+ }
445+}
446+
447+
448+// http://www.martin-finke.de/blog/articles/audio-plugins-018-polyblep-oscillator/
449+// http://www.kvraudio.com/forum/viewtopic.php?t=375517
450+// t = phase, dt = inc, assuming 0-1 phase
451+// assumes discontinuity at 0, so offset inputs as needed
452+float LEAF_poly_blep(float t, float dt)
453+{
454+ // 0 <= t < 1
455+ if (t < dt) {
456+ t /= dt;
457+ return t+t - t*t - 1.0f;
458+ }
459+ // -1 < t < 0
460+ else if (t > 1.0f - dt) {
461+ t = (t - 1.0f) / dt;
462+ return t*t + t+t + 1.0f;
463+ }
464+ // 0 otherwise
465+ else return 0.0f;
466+
467+//
468+// float y = 0.0f;
469+// if (t < 2.0f * dt)
470+// {
471+// float x = t / dt;
472+// float u = 2.0f - x;
473+// u *= u;
474+// u *= u;
475+// y += u;
476+// if (t < dt) {
477+// float v = 1.0f - x;
478+// v *= v;
479+// v *= v;
480+// y -= 4.0f * v;
481+// }
482+// }
483+// else if (t > 1.0f - (2.0f * dt))
484+// {
485+// float x = (t - 1.0f) / dt;
486+// float u = 2.0f - x;
487+// u *= u;
488+// u *= u;
489+// y += u;
490+// if (t > 1.0f - dt) {
491+// float v = 1.0f - x;
492+// v *= v;
493+// v *= v;
494+// y += 4.0f * v;
495+// }
496+// }
497+// return y / 12.0f;
498+}
499+
500+
501+//-----------------------------------------------------------------------------
502+// name: mtof()
503+// desc: midi to freq, from PD source
504+//-----------------------------------------------------------------------------
505+float LEAF_midiToFrequency(float f)
506+{
507+ if( f <= -1500.0f ) return (0);
508+ else if( f > 1499.0f ) return (LEAF_midiToFrequency(1499.0f));
509+ else return ( powf(2.0f, (f - 69.0f) * 0.083333333333333f) * 440.0f );
510+}
511+
512+
513+// alpha, [0.0, 1.0]
514+float LEAF_interpolate_hermite (float A, float B, float C, float D, float alpha)
515+{
516+ alpha = LEAF_clip(0.0f, alpha, 1.0f);
517+
518+ float a = -A*0.5f + (3.0f*B)*0.5f - (3.0f*C)*0.5f + D*0.5f;
519+ float b = A - (5.0f*B)*0.5f + 2.0f*C - D * 0.5f;
520+ float c = -A*0.5f + C*0.5f;
521+ float d = B;
522+
523+ return a*alpha*alpha*alpha + b*alpha*alpha + c*alpha + d;
524+}
525+
526+
527+// from http://www.musicdsp.org/archive.php?classid=5#93
528+//xx is alpha (fractional part of sample value)
529+//grabbed this from Tom Erbe's Delay pd code
530+float LEAF_interpolate_hermite_x(float yy0, float yy1, float yy2, float yy3, float xx)
531+{
532+ // 4-point, 3rd-order Hermite (x-form)
533+ float c0 = yy1;
534+ float c1 = 0.5f * (yy2 - yy0);
535+ float y0my1 = yy0 - yy1;
536+ float c3 = (yy1 - yy2) + 0.5f * (yy3 - y0my1 - yy2);
537+ float c2 = y0my1 + c1 - c3;
538+
539+ return ((c3 * xx + c2) * xx + c1) * xx + c0;
540+}
541+
542+// alpha, [0.0, 1.0]
543+float LEAF_interpolation_linear (float A, float B, float alpha)
544+{
545+ alpha = LEAF_clip(0.0f, alpha, 1.0f);
546+
547+ float omAlpha = 1.0f - alpha;
548+
549+ // First 1/2 of interpolation
550+ float out = A * omAlpha;
551+
552+ out += B * alpha;
553+
554+ return out;
555+}
556+
557+#define LOGTEN 2.302585092994
558+
559+float mtof(float f)
560+{
561+ if (f <= -1500.0f) return(0);
562+ else if (f > 1499.0f) return(mtof(1499.0f));
563+ else return (8.17579891564f * expf(0.0577622650f * f));
564+}
565+
566+float fast_mtof(float f)
567+{
568+ return (8.17579891564f * fastexpf(0.0577622650f * f));
569+}
570+
571+float faster_mtof(float f)
572+{
573+ return (8.17579891564f * fastexpf(0.0577622650f * f));
574+}
575+
576+float ftom(float f)
577+{
578+ return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
579+}
580+
581+float powtodb(float f)
582+{
583+ if (f <= 0) return (0);
584+ else
585+ {
586+ float val = 100.0f + 10.0f/LOGTEN * logf(f);
587+ return (val < 0.0f ? 0.0f : val);
588+ }
589+}
590+
591+float rmstodb(float f)
592+{
593+ if (f <= 0) return (0);
594+ else
595+ {
596+ float val = 100 + 20.f/LOGTEN * log(f);
597+ return (val < 0 ? 0 : val);
598+ }
599+}
600+
601+float dbtopow(float f)
602+{
603+ if (f <= 0)
604+ return(0);
605+ else
606+ {
607+ if (f > 870.0f)
608+ f = 870.0f;
609+ return (expf((LOGTEN * 0.1f) * (f-100.0f)));
610+ }
611+}
612+
613+float dbtorms(float f)
614+{
615+ if (f <= 0)
616+ return(0);
617+ else
618+ {
619+ if (f > 485.0f)
620+ f = 485.0f;
621+ }
622+ return (expf((LOGTEN * 0.05f) * (f-100.0f)));
623+}
624+
625+
626+float atodb(float a)
627+{
628+ return 20.0f*log10f(a);
629+}
630+
631+float dbtoa(float db)
632+{
633+ return powf(10.0f, db * 0.05f);
634+ //return expf(0.115129254649702f * db); //faster version from http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html
635+}
636+
637+
638+float fastdbtoa(float db)
639+{
640+ //return powf(10.0f, db * 0.05f);
641+ return expf(0.115129254649702f * db); //faster version from http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html
642+}
643+
644+
645+float maximum (float num1, float num2)
646+{
647+ return (num1 > num2 ) ? num1 : num2;
648+}
649+
650+float minimum (float num1, float num2)
651+{
652+ return (num1 < num2 ) ? num1 : num2;
653+}
654+
655+
leaf/Src/leaf-mempool.c+412−0
@@ -0,0 +1,412 @@
1+
2+/** mpool source significantly modified by Mike Mulshine, Jeff Snyder, et al., Princeton University Music Department **/
3+
4+/**
5+ In short, mpool is distributed under so called "BSD license",
6+
7+ Copyright (c) 2009-2010 Tatsuhiko Kubo <cubicdaiya@gmail.com>
8+ All rights reserved.
9+
10+ Redistribution and use in source and binary forms, with or without modification,
11+ are permitted provided that the following conditions are met:
12+
13+ * Redistributions of source code must retain the above copyright notice,
14+ this list of conditions and the following disclaimer.
15+
16+ * Redistributions in binary form must reproduce the above copyright notice,
17+ this list of conditions and the following disclaimer in the documentation
18+ and/or other materials provided with the distribution.
19+
20+ * Neither the name of the authors nor the names of its contributors
21+ may be used to endorse or promote products derived from this software
22+ without specific prior written permission.
23+
24+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35+ */
36+
37+/* written with C99 style */
38+
39+#if _WIN32 || _WIN64
40+
41+#include "..\Inc\leaf-mempool.h"
42+#include "..\leaf.h"
43+
44+#else
45+
46+#include "../Inc/leaf-mempool.h"
47+#include "../leaf.h"
48+
49+#endif
50+
51+/**
52+ * private function
53+ */
54+static inline size_t mpool_align(size_t size);
55+static inline mpool_node_t* create_node(char* block_location, mpool_node_t* next, mpool_node_t* prev, size_t size);
56+static inline void delink_node(mpool_node_t* node);
57+
58+/**
59+ * create memory pool
60+ */
61+void mpool_create (char* memory, size_t size, _tMempool* pool)
62+{
63+ leaf.header_size = mpool_align(sizeof(mpool_node_t));
64+
65+ pool->mpool = (char*)memory;
66+ pool->usize = 0;
67+ pool->msize = size;
68+
69+ pool->head = create_node(pool->mpool, NULL, NULL, pool->msize-leaf.header_size);
70+
71+ /*
72+ for (int i = 0; i < pool->head->size; i++)
73+ {
74+ memory[i+leaf.header_size]=0;
75+ }
76+ */
77+ //is zeroing out the memory necessary? This takes a long time on large pools - JS
78+}
79+
80+void leaf_pool_init(char* memory, size_t size)
81+{
82+ mpool_create(memory, size, &leaf._mempool);
83+
84+ leaf.mempool = &leaf._mempool;
85+}
86+
87+/**
88+ * allocate memory from memory pool
89+ */
90+char* mpool_alloc(size_t asize, _tMempool* pool)
91+{
92+ // If the head is NULL, the mempool is full
93+ if (pool->head == NULL)
94+ {
95+ leaf_mempool_overrun();
96+ return NULL;
97+ }
98+
99+ // Should we alloc the first block large enough or check all blocks and pick the one closest in size?
100+ size_t size_to_alloc = mpool_align(asize);
101+ mpool_node_t* node_to_alloc = pool->head;
102+
103+ // Traverse the free list for a large enough block
104+ while (node_to_alloc->size < size_to_alloc)
105+ {
106+ node_to_alloc = node_to_alloc->next;
107+
108+ // If we reach the end of the free list, there
109+ // are no blocks large enough, return NULL
110+ if (node_to_alloc == NULL)
111+ {
112+ leaf_mempool_overrun();
113+ return NULL;
114+ }
115+ }
116+
117+ // Create a new node after the node to be allocated if there is enough space
118+ mpool_node_t* new_node;
119+ size_t leftover = node_to_alloc->size - size_to_alloc;
120+ node_to_alloc->size = size_to_alloc;
121+ if (leftover > leaf.header_size)
122+ {
123+ long offset = (char*) node_to_alloc - (char*) pool->mpool;
124+ offset += leaf.header_size + node_to_alloc->size;
125+ new_node = create_node(&pool->mpool[offset],
126+ node_to_alloc->next,
127+ node_to_alloc->prev,
128+ leftover - leaf.header_size);
129+ }
130+ else
131+ {
132+ // Add any leftover space to the allocated node to avoid fragmentation
133+ node_to_alloc->size += leftover;
134+
135+ new_node = node_to_alloc->next;
136+ }
137+
138+ // Update the head if we are allocating the first node of the free list
139+ // The head will be NULL if there is no space left
140+ if (pool->head == node_to_alloc)
141+ {
142+ pool->head = new_node;
143+ }
144+
145+ // Remove the allocated node from the free list
146+ delink_node(node_to_alloc);
147+
148+ pool->usize += leaf.header_size + node_to_alloc->size;
149+
150+ if (leaf.clearOnAllocation > 0)
151+ {
152+ char* new_pool = (char*)node_to_alloc->pool;
153+ for (int i = 0; i < node_to_alloc->size; i++) new_pool[i] = 0;
154+ }
155+
156+ // Return the pool of the allocated node;
157+ return node_to_alloc->pool;
158+}
159+
160+
161+/**
162+ * allocate memory from memory pool and also clear that memory to be blank
163+ */
164+char* mpool_calloc(size_t asize, _tMempool* pool)
165+{
166+ // If the head is NULL, the mempool is full
167+ if (pool->head == NULL)
168+ {
169+ leaf_mempool_overrun();
170+ return NULL;
171+ }
172+
173+ // Should we alloc the first block large enough or check all blocks and pick the one closest in size?
174+ size_t size_to_alloc = mpool_align(asize);
175+ mpool_node_t* node_to_alloc = pool->head;
176+
177+ // Traverse the free list for a large enough block
178+ while (node_to_alloc->size < size_to_alloc)
179+ {
180+ node_to_alloc = node_to_alloc->next;
181+
182+ // If we reach the end of the free list, there
183+ // are no blocks large enough, return NULL
184+ if (node_to_alloc == NULL)
185+ {
186+ leaf_mempool_overrun();
187+ return NULL;
188+ }
189+ }
190+
191+ // Create a new node after the node to be allocated if there is enough space
192+ mpool_node_t* new_node;
193+ size_t leftover = node_to_alloc->size - size_to_alloc;
194+ node_to_alloc->size = size_to_alloc;
195+ if (leftover > leaf.header_size)
196+ {
197+ long offset = (char*) node_to_alloc - (char*) pool->mpool;
198+ offset += leaf.header_size + node_to_alloc->size;
199+ new_node = create_node(&pool->mpool[offset],
200+ node_to_alloc->next,
201+ node_to_alloc->prev,
202+ leftover - leaf.header_size);
203+ }
204+ else
205+ {
206+ // Add any leftover space to the allocated node to avoid fragmentation
207+ node_to_alloc->size += leftover;
208+
209+ new_node = node_to_alloc->next;
210+ }
211+
212+ // Update the head if we are allocating the first node of the free list
213+ // The head will be NULL if there is no space left
214+ if (pool->head == node_to_alloc)
215+ {
216+ pool->head = new_node;
217+ }
218+
219+ // Remove the allocated node from the free list
220+ delink_node(node_to_alloc);
221+
222+ pool->usize += leaf.header_size + node_to_alloc->size;
223+ // Format the new pool
224+ char* new_pool = (char*)node_to_alloc->pool;
225+ for (int i = 0; i < node_to_alloc->size; i++) new_pool[i] = 0;
226+ // Return the pool of the allocated node;
227+ return node_to_alloc->pool;
228+}
229+
230+char* leaf_alloc(size_t size)
231+{
232+ //printf("alloc %i\n", size);
233+ char* block = mpool_alloc(size, &leaf._mempool);
234+
235+ if (block == NULL) leaf_mempool_overrun();
236+
237+ return block;
238+}
239+
240+char* leaf_calloc(size_t size)
241+{
242+ //printf("alloc %i\n", size);
243+ char* block = mpool_calloc(size, &leaf._mempool);
244+
245+ if (block == NULL) leaf_mempool_overrun();
246+
247+
248+ return block;
249+}
250+
251+void mpool_free(char* ptr, _tMempool* pool)
252+{
253+ //if (ptr < pool->mpool || ptr >= pool->mpool + pool->msize)
254+ // Get the node at the freed space
255+ mpool_node_t* freed_node = (mpool_node_t*) (ptr - leaf.header_size);
256+
257+ pool->usize -= leaf.header_size + freed_node->size;
258+
259+ // Check each node in the list against the newly freed one to see if it's adjacent in memory
260+ mpool_node_t* other_node = pool->head;
261+ mpool_node_t* next_node;
262+ while (other_node != NULL)
263+ {
264+ next_node = other_node->next;
265+ // Check if a node is directly after the freed node
266+ if ((long) freed_node + (leaf.header_size + freed_node->size) == (long) other_node)
267+ {
268+ // Increase freed node's size
269+ freed_node->size += leaf.header_size + other_node->size;
270+ // If we are merging with the head, move the head forward
271+ if (other_node == pool->head) pool->head = pool->head->next;
272+ // Delink the merged node
273+ delink_node(other_node);
274+ }
275+
276+ // Check if a node is directly before the freed node
277+ else if ((long) other_node + (leaf.header_size + other_node->size) == (long) freed_node)
278+ {
279+ // Increase the merging node's size
280+ other_node->size += leaf.header_size + freed_node->size;
281+
282+ if (other_node != pool->head)
283+ {
284+ // Delink the merging node
285+ delink_node(other_node);
286+ // Attach the merging node to the head
287+ other_node->next = pool->head;
288+ // Merge
289+ freed_node = other_node;
290+ }
291+ else
292+ {
293+ // If we are merging with the head, move the head forward
294+ pool->head = pool->head->next;
295+ // Merge
296+ freed_node = other_node;
297+ }
298+ }
299+
300+ other_node = next_node;
301+ }
302+
303+ // Ensure the freed node is attached to the head
304+ freed_node->next = pool->head;
305+ if (pool->head != NULL) pool->head->prev = freed_node;
306+ pool->head = freed_node;
307+
308+ // Format the freed pool
309+ // char* freed_pool = (char*)freed_node->pool;
310+ // for (int i = 0; i < freed_node->size; i++) freed_pool[i] = 0;
311+}
312+
313+void leaf_free(char* ptr)
314+{
315+ mpool_free(ptr, &leaf._mempool);
316+}
317+
318+size_t mpool_get_size(_tMempool* pool)
319+{
320+ return pool->msize;
321+}
322+
323+size_t mpool_get_used(_tMempool* pool)
324+{
325+ return pool->usize;
326+}
327+
328+size_t leaf_pool_get_size(void)
329+{
330+ return mpool_get_size(&leaf._mempool);
331+}
332+
333+size_t leaf_pool_get_used(void)
334+{
335+ return mpool_get_used(&leaf._mempool);
336+}
337+
338+char* leaf_pool_get_pool(void)
339+{
340+ char* buff = leaf._mempool.mpool;
341+
342+ return buff;
343+}
344+
345+/**
346+ * align byte boundary
347+ */
348+static inline size_t mpool_align(size_t size) {
349+ return (size + (MPOOL_ALIGN_SIZE - 1)) & ~(MPOOL_ALIGN_SIZE - 1);
350+}
351+
352+static inline mpool_node_t* create_node(char* block_location, mpool_node_t* next, mpool_node_t* prev, size_t size)
353+{
354+ mpool_node_t* node = (mpool_node_t*)block_location;
355+ node->pool = block_location + leaf.header_size;
356+ node->next = next;
357+ node->prev = prev;
358+ node->size = size;
359+
360+ return node;
361+}
362+
363+static inline void delink_node(mpool_node_t* node)
364+{
365+ // If there is a node after the node to remove
366+ if (node->next != NULL)
367+ {
368+ // Close the link
369+ node->next->prev = node->prev;
370+ }
371+ // If there is a node before the node to remove
372+ if (node->prev != NULL)
373+ {
374+ // Close the link
375+ node->prev->next = node->next;
376+ }
377+
378+ node->next = NULL;
379+ node->prev = NULL;
380+}
381+
382+void leaf_mempool_overrun(void)
383+{
384+ LEAF_error(1);
385+ //TODO: we should make a set of real error codes that are in an enum type
386+}
387+
388+void tMempool_init(tMempool* const mp, char* memory, size_t size)
389+{
390+ tMempool_initToPool(mp, memory, size, &leaf.mempool);
391+}
392+
393+void tMempool_free(tMempool* const mp)
394+{
395+ tMempool_freeFromPool(mp, &leaf.mempool);
396+}
397+
398+void tMempool_initToPool (tMempool* const mp, char* memory, size_t size, tMempool* const mem)
399+{
400+ _tMempool* mm = *mem;
401+ _tMempool* m = *mp = (_tMempool*) mpool_alloc(sizeof(_tMempool), mm);
402+
403+ mpool_create (memory, size, m);
404+}
405+
406+void tMempool_freeFromPool (tMempool* const mp, tMempool* const mem)
407+{
408+ _tMempool* mm = *mem;
409+ _tMempool* m = *mp;
410+
411+ mpool_free((char*)m, mm);
412+}
leaf/Src/leaf-midi.c+980−0
@@ -0,0 +1,980 @@
1+/*==============================================================================
2+
3+ leaf-midi.c
4+ Created: 30 Nov 2018 11:29:16am
5+ Author: airship
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-midi.h"
12+
13+#else
14+
15+#include "../Inc/leaf-midi.h"
16+
17+#endif
18+
19+//====================================================================================
20+/* Stack */
21+//====================================================================================
22+
23+void tStack_init(tStack* const stack)
24+{
25+ _tStack* ns = *stack = (_tStack*) leaf_alloc(sizeof(_tStack));
26+
27+ ns->ordered = OFALSE;
28+ ns->size = 0;
29+ ns->pos = 0;
30+ ns->capacity = STACK_SIZE;
31+
32+ for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1;
33+}
34+
35+void tStack_free(tStack* const stack)
36+{
37+ _tStack* ns = *stack;
38+
39+ leaf_free((char*)ns);
40+}
41+
42+void tStack_initToPool (tStack* const stack, tMempool* const mp)
43+{
44+ _tMempool* m = *mp;
45+ _tStack* ns = *stack = (_tStack*) mpool_alloc(sizeof(_tStack), m);
46+
47+ ns->ordered = OFALSE;
48+ ns->size = 0;
49+ ns->pos = 0;
50+ ns->capacity = STACK_SIZE;
51+
52+ for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1;
53+}
54+
55+void tStack_freeFromPool (tStack* const stack, tMempool* const mp)
56+{
57+ _tMempool* m = *mp;
58+ _tStack* ns = *stack;
59+
60+ mpool_free((char*)ns, m);
61+}
62+
63+// If stack contains note, returns index. Else returns -1;
64+int tStack_contains(tStack* const stack, uint16_t noteVal)
65+{
66+ _tStack* ns = *stack;
67+ for (int i = 0; i < ns->size; i++)
68+ {
69+ if (ns->data[i] == noteVal) return i;
70+ }
71+ return -1;
72+}
73+
74+void tStack_add(tStack* const stack, uint16_t noteVal)
75+{
76+ _tStack* ns = *stack;
77+
78+ uint8_t j;
79+
80+ int whereToInsert = 0;
81+ if (ns->ordered)
82+ {
83+ for (j = 0; j < ns->size; j++)
84+ {
85+ if (noteVal > ns->data[j])
86+ {
87+ if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
88+ {
89+ whereToInsert = j+1;
90+ break;
91+ }
92+ }
93+ }
94+ }
95+
96+ //first move notes that are already in the stack one position to the right
97+ for (j = ns->size; j > whereToInsert; j--)
98+ {
99+ ns->data[j] = ns->data[(j - 1)];
100+ }
101+
102+ //then, insert the new note into the front of the stack
103+ ns->data[whereToInsert] = noteVal;
104+
105+ ns->size++;
106+}
107+
108+int tStack_addIfNotAlreadyThere(tStack* const stack, uint16_t noteVal)
109+{
110+ _tStack* ns = *stack;
111+
112+ uint8_t j;
113+
114+ int added = 0;
115+
116+ if (tStack_contains(stack, noteVal) == -1)
117+ {
118+ int whereToInsert = 0;
119+ if (ns->ordered)
120+ {
121+ for (j = 0; j < ns->size; j++)
122+ {
123+ if (noteVal > ns->data[j])
124+ {
125+ if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
126+ {
127+ whereToInsert = j+1;
128+ break;
129+ }
130+ }
131+ }
132+ }
133+
134+ //first move notes that are already in the stack one position to the right
135+ for (j = ns->size; j > whereToInsert; j--)
136+ {
137+ ns->data[j] = ns->data[(j - 1)];
138+ }
139+
140+ //then, insert the new note into the front of the stack
141+ ns->data[whereToInsert] = noteVal;
142+
143+ ns->size++;
144+
145+ added = 1;
146+ }
147+
148+ return added;
149+}
150+
151+// Remove noteVal. return 1 if removed, 0 if not
152+int tStack_remove(tStack* const stack, uint16_t noteVal)
153+{
154+ _tStack* ns = *stack;
155+
156+ uint8_t k;
157+ int foundIndex = tStack_contains(stack, noteVal);
158+ int removed = 0;
159+
160+ if (foundIndex >= 0)
161+ {
162+ for (k = 0; k < (ns->size - foundIndex); k++)
163+ {
164+ if ((k+foundIndex) >= (ns->capacity - 1))
165+ {
166+ ns->data[k + foundIndex] = -1;
167+ }
168+ else
169+ {
170+ ns->data[k + foundIndex] = ns->data[k + foundIndex + 1];
171+ if ((k + foundIndex) == (ns->size - 1))
172+ {
173+ ns->data[k + foundIndex + 1] = -1;
174+ }
175+ }
176+
177+ }
178+ // in case it got put on the stack multiple times
179+ foundIndex--;
180+ ns->size--;
181+ removed = 1;
182+ }
183+
184+ return removed;
185+}
186+
187+// Doesn't change size of data types
188+void tStack_setCapacity(tStack* const stack, uint16_t cap)
189+{
190+ _tStack* ns = *stack;
191+
192+ if (cap <= 0)
193+ ns->capacity = 1;
194+ else if (cap <= STACK_SIZE)
195+ ns->capacity = cap;
196+ else
197+ ns->capacity = STACK_SIZE;
198+
199+ for (int i = cap; i < STACK_SIZE; i++)
200+ {
201+ if ((int)ns->data[i] != -1)
202+ {
203+ ns->data[i] = -1;
204+ ns->size -= 1;
205+ }
206+ }
207+
208+ if (ns->pos >= cap)
209+ {
210+ ns->pos = 0;
211+ }
212+}
213+
214+int tStack_getSize(tStack* const stack)
215+{
216+ _tStack* ns = *stack;
217+
218+ return ns->size;
219+}
220+
221+void tStack_clear(tStack* const stack)
222+{
223+ _tStack* ns = *stack;
224+
225+ for (int i = 0; i < STACK_SIZE; i++)
226+ {
227+ ns->data[i] = -1;
228+ }
229+ ns->pos = 0;
230+ ns->size = 0;
231+}
232+
233+// Next item in order of addition to stack. Return 0-31 if there is a next item to move to. Returns -1 otherwise.
234+int tStack_next(tStack* const stack)
235+{
236+ _tStack* ns = *stack;
237+
238+ int step = 0;
239+ if (ns->size != 0) // if there is at least one note in the stack
240+ {
241+ if (ns->pos > 0) // if you're not at the most recent note (first one), then go backward in the array (moving from earliest to latest)
242+ {
243+ ns->pos--;
244+ }
245+ else
246+ {
247+ ns->pos = (ns->size - 1); // if you are the most recent note, go back to the earliest note in the array
248+ }
249+
250+ step = ns->data[ns->pos];
251+ return step;
252+ }
253+ else
254+ {
255+ return -1;
256+ }
257+}
258+
259+int tStack_get(tStack* const stack, int which)
260+{
261+ _tStack* ns = *stack;
262+ return ns->data[which];
263+}
264+
265+int tStack_first(tStack* const stack)
266+{
267+ _tStack* ns = *stack;
268+ return ns->data[0];
269+}
270+
271+
272+// POLY
273+void tPoly_init(tPoly* const polyh, int maxNumVoices)
274+{
275+ _tPoly* poly = *polyh = (_tPoly*) leaf_alloc(sizeof(_tPoly));
276+
277+ poly->numVoices = maxNumVoices;
278+ poly->maxNumVoices = maxNumVoices;
279+ poly->lastVoiceToChange = 0;
280+
281+ // Arp mode stuff
282+ poly->currentVoice = 0;
283+ poly->maxLength = 128;
284+ poly->currentNote = -1;
285+
286+ //default learned CCs and notes are just the CCs 1-128 - notes are skipped
287+ for (int i = 0; i < 128; i++)
288+ {
289+ poly->notes[i][0] = 0;
290+ poly->notes[i][1] = -1;
291+ }
292+
293+ poly->glideTime = 5.0f;
294+
295+ poly->ramps = (tRamp*) leaf_alloc(sizeof(tRamp) * poly->maxNumVoices);
296+ poly->rampVals = (float*) leaf_alloc(sizeof(float) * poly->maxNumVoices);
297+ poly->firstReceived = (oBool*) leaf_alloc(sizeof(oBool) * poly->maxNumVoices);
298+ poly->voices = (int**) leaf_alloc(sizeof(int*) * poly->maxNumVoices);
299+
300+ for (int i = 0; i < poly->maxNumVoices; ++i)
301+ {
302+ poly->voices[i] = (int*) leaf_alloc(sizeof(int) * 2);
303+ poly->voices[i][0] = -1;
304+ poly->firstReceived[i] = OFALSE;
305+
306+ tRamp_init(&poly->ramps[i], poly->glideTime, 1);
307+ }
308+
309+ poly->pitchBend = 0.0f;
310+
311+ tRamp_init(&poly->pitchBendRamp, 1.0f, 1);
312+ tStack_init(&poly->stack);
313+ tStack_init(&poly->orderStack);
314+
315+ poly->pitchGlideIsActive = OFALSE;
316+}
317+
318+void tPoly_free(tPoly* const polyh)
319+{
320+ _tPoly* poly = *polyh;
321+
322+ for (int i = 0; i < poly->maxNumVoices; i++)
323+ {
324+ tRamp_free(&poly->ramps[i]);
325+ leaf_free((char*)poly->voices[i]);
326+ }
327+ tRamp_free(&poly->pitchBendRamp);
328+ tStack_free(&poly->stack);
329+ tStack_free(&poly->orderStack);
330+
331+ leaf_free((char*)poly->voices);
332+ leaf_free((char*)poly->ramps);
333+ leaf_free((char*)poly->rampVals);
334+ leaf_free((char*)poly->firstReceived);
335+
336+ leaf_free((char*)poly);
337+}
338+
339+void tPoly_initToPool (tPoly* const polyh, int maxNumVoices, tMempool* const mp)
340+{
341+ _tMempool* m = *mp;
342+ _tPoly* poly = *polyh = (_tPoly*) mpool_alloc(sizeof(_tPoly), m);
343+
344+ poly->numVoices = maxNumVoices;
345+ poly->maxNumVoices = maxNumVoices;
346+ poly->lastVoiceToChange = 0;
347+
348+ // Arp mode stuff
349+ poly->currentVoice = 0;
350+ poly->maxLength = 128;
351+ poly->currentNote = -1;
352+
353+ //default learned CCs and notes are just the CCs 1-128 - notes are skipped
354+ for (int i = 0; i < 128; i++)
355+ {
356+ poly->notes[i][0] = 0;
357+ poly->notes[i][1] = -1;
358+ }
359+
360+ poly->glideTime = 5.0f;
361+
362+ poly->ramps = (tRamp*) mpool_alloc(sizeof(tRamp) * poly->maxNumVoices, m);
363+ poly->rampVals = (float*) mpool_alloc(sizeof(float) * poly->maxNumVoices, m);
364+ poly->firstReceived = (oBool*) mpool_alloc(sizeof(oBool) * poly->maxNumVoices, m);
365+ poly->voices = (int**) mpool_alloc(sizeof(int*) * poly->maxNumVoices, m);
366+
367+ for (int i = 0; i < poly->maxNumVoices; ++i)
368+ {
369+ poly->voices[i] = (int*) mpool_alloc(sizeof(int) * 2, m);
370+ poly->voices[i][0] = -1;
371+ poly->firstReceived[i] = OFALSE;
372+
373+ tRamp_initToPool(&poly->ramps[i], poly->glideTime, 1, mp);
374+ }
375+
376+ poly->pitchBend = 0.0f;
377+
378+ tRamp_initToPool(&poly->pitchBendRamp, 1.0f, 1, mp);
379+ tStack_initToPool(&poly->stack, mp);
380+ tStack_initToPool(&poly->orderStack, mp);
381+
382+ poly->pitchGlideIsActive = OFALSE;
383+}
384+
385+void tPoly_freeFromPool (tPoly* const polyh, tMempool* const mp)
386+{
387+ _tMempool* m = *mp;
388+ _tPoly* poly = *polyh;
389+
390+ for (int i = 0; i < poly->maxNumVoices; i++)
391+ {
392+ tRamp_freeFromPool(&poly->ramps[i], mp);
393+ mpool_free((char*)poly->voices[i], m);
394+ }
395+ tRamp_freeFromPool(&poly->pitchBendRamp, mp);
396+ tStack_freeFromPool(&poly->stack, mp);
397+ tStack_freeFromPool(&poly->orderStack, mp);
398+
399+ mpool_free((char*)poly->voices, m);
400+ mpool_free((char*)poly->ramps, m);
401+ mpool_free((char*)poly->rampVals, m);
402+ mpool_free((char*)poly->firstReceived, m);
403+
404+ mpool_free((char*)poly, m);
405+}
406+
407+void tPoly_tickPitch(tPoly* polyh)
408+{
409+ tPoly_tickPitchGlide(polyh);
410+ tPoly_tickPitchBend(polyh);
411+}
412+
413+void tPoly_tickPitchGlide(tPoly* polyh)
414+{
415+ _tPoly* poly = *polyh;
416+ for (int i = 0; i < poly->maxNumVoices; ++i)
417+ {
418+ tRamp_tick(&poly->ramps[i]);
419+ }
420+}
421+
422+void tPoly_tickPitchBend(tPoly* polyh)
423+{
424+ _tPoly* poly = *polyh;
425+ tRamp_tick(&poly->pitchBendRamp);
426+}
427+
428+void tPoly_setPitchBend(tPoly* const polyh, float pitchBend)
429+{
430+ _tPoly* poly = *polyh;
431+ poly->pitchBend = pitchBend;
432+ tRamp_setDest(&poly->pitchBendRamp, poly->pitchBend);
433+}
434+
435+int tPoly_noteOn(tPoly* const polyh, int note, uint8_t vel)
436+{
437+ _tPoly* poly = *polyh;
438+
439+ // if not in keymap or already on stack, dont do anything. else, add that note.
440+ if (tStack_contains(&poly->stack, note) >= 0) return -1;
441+ else
442+ {
443+ tPoly_orderedAddToStack(polyh, note);
444+ tStack_add(&poly->stack, note);
445+
446+ int alteredVoice = -1;
447+ oBool found = OFALSE;
448+ for (int i = 0; i < poly->numVoices; i++)
449+ {
450+ if (poly->voices[i][0] < 0) // if inactive voice, give this note to voice
451+ {
452+ if (!poly->firstReceived[i] || !poly->pitchGlideIsActive)
453+ {
454+ tRamp_setVal(&poly->ramps[i], note);
455+ poly->firstReceived[i] = OTRUE;
456+ }
457+
458+ found = OTRUE;
459+
460+ poly->voices[i][0] = note;
461+ poly->voices[i][1] = vel;
462+ poly->lastVoiceToChange = i;
463+ poly->notes[note][0] = vel;
464+ poly->notes[note][1] = i;
465+
466+ tRamp_setDest(&poly->ramps[i], poly->voices[i][0]);
467+
468+ alteredVoice = i;
469+ break;
470+ }
471+ }
472+
473+ if (!found) //steal
474+ {
475+ int whichVoice, whichNote;
476+ for (int j = tStack_getSize(&poly->stack) - 1; j >= 0; j--)
477+ {
478+ whichNote = tStack_get(&poly->stack, j);
479+ whichVoice = poly->notes[whichNote][1];
480+ if (whichVoice >= 0)
481+ {
482+ poly->lastVoiceToChange = whichVoice;
483+ int oldNote = poly->voices[whichVoice][0];
484+ poly->voices[whichVoice][0] = note;
485+ poly->voices[whichVoice][1] = vel;
486+ poly->notes[oldNote][1] = -1; //mark the stolen voice as inactive (in the second dimension of the notes array)
487+ poly->notes[note][0] = vel;
488+ poly->notes[note][1] = whichVoice;
489+
490+ if (poly->pitchGlideIsActive)
491+ {
492+ tRamp_setTime(&poly->ramps[whichVoice], poly->glideTime);
493+ }
494+ else
495+ {
496+ tRamp_setVal(&poly->ramps[whichVoice], note);
497+ }
498+ tRamp_setDest(&poly->ramps[whichVoice], poly->voices[whichVoice][0]);
499+
500+ alteredVoice = whichVoice;
501+
502+ break;
503+ }
504+ }
505+ }
506+ return alteredVoice;
507+ }
508+}
509+
510+
511+int16_t noteToTest = -1;
512+
513+int tPoly_noteOff(tPoly* const polyh, uint8_t note)
514+{
515+ _tPoly* poly = *polyh;
516+
517+ tStack_remove(&poly->stack, note);
518+ tStack_remove(&poly->orderStack, note);
519+ poly->notes[note][0] = 0;
520+ poly->notes[note][1] = -1;
521+
522+ int deactivatedVoice = -1;
523+ for (int i = 0; i < poly->maxNumVoices; i++)
524+ {
525+ if (poly->voices[i][0] == note)
526+ {
527+ poly->voices[i][0] = -1;
528+ poly->voices[i][1] = 0;
529+ poly->lastVoiceToChange = i;
530+ deactivatedVoice = i;
531+ break;
532+ }
533+ }
534+ /*
535+ //monophonic handling
536+ if ((poly->numVoices == 1) && (tStack_getSize(poly->stack) > 0))
537+ {
538+ int oldNote = tStack_first(poly->stack);
539+ poly->voices[0][0] = oldNote;
540+ poly->voices[0][1] = poly->notes[oldNote][0];
541+ poly->lastVoiceToChange = 0;
542+ }
543+ */
544+
545+ //grab old notes off the stack if there are notes waiting to replace the free voice
546+ if (deactivatedVoice >= 0)
547+ {
548+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
549+ {
550+ noteToTest = tStack_get(&poly->stack, j);
551+
552+ if (poly->notes[noteToTest][1] < 0) //if there is a stolen note waiting (marked inactive but on the stack)
553+ {
554+ poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
555+ if (poly->pitchGlideIsActive)
556+ {
557+ tRamp_setTime(&poly->ramps[deactivatedVoice], poly->glideTime);
558+ }
559+ else
560+ {
561+ tRamp_setVal(&poly->ramps[deactivatedVoice], noteToTest);
562+ }
563+ tRamp_setDest(&poly->ramps[deactivatedVoice], poly->voices[deactivatedVoice][0]);
564+ poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][0]; // set the velocity of the voice to be the velocity of that note
565+ poly->notes[noteToTest][1] = deactivatedVoice; //mark that it is no longer stolen and is now active
566+ return -1;
567+ }
568+ }
569+ }
570+ return deactivatedVoice;
571+}
572+
573+void tPoly_orderedAddToStack(tPoly* const polyh, uint8_t noteVal)
574+{
575+ _tPoly* poly = *polyh;
576+
577+ uint8_t j;
578+ int myPitch, thisPitch, nextPitch;
579+
580+ tStack ns = poly->orderStack;
581+
582+ int whereToInsert = 0;
583+
584+ for (j = 0; j < ns->size; j++)
585+ {
586+ myPitch = noteVal;
587+ thisPitch = ns->data[j];
588+ nextPitch = ns->data[j+1];
589+
590+ if (myPitch > thisPitch)
591+ {
592+ if ((myPitch < nextPitch) || (nextPitch == -1))
593+ {
594+ whereToInsert = j+1;
595+ break;
596+ }
597+ }
598+ }
599+
600+ //first move notes that are already in the stack one position to the right
601+ for (j = ns->size; j > whereToInsert; j--)
602+ {
603+ ns->data[j] = ns->data[(j - 1)];
604+ }
605+
606+ //then, insert the new note into the front of the stack
607+ ns->data[whereToInsert] = noteVal;
608+
609+ ns->size++;
610+
611+}
612+
613+void tPoly_setNumVoices(tPoly* const polyh, uint8_t numVoices)
614+{
615+ _tPoly* poly = *polyh;
616+ poly->numVoices = (numVoices > poly->maxNumVoices) ? poly->maxNumVoices : numVoices;
617+}
618+
619+void tPoly_setPitchGlideActive(tPoly* const polyh, oBool isActive)
620+{
621+ _tPoly* poly = *polyh;
622+ poly->pitchGlideIsActive = isActive;
623+}
624+
625+void tPoly_setPitchGlideTime(tPoly* const polyh, float t)
626+{
627+ _tPoly* poly = *polyh;
628+ poly->glideTime = t;
629+ for (int i = 0; i < poly->maxNumVoices; ++i)
630+ {
631+ tRamp_setTime(&poly->ramps[i], poly->glideTime);
632+ }
633+}
634+
635+void tPoly_setBendGlideTime(tPoly* const polyh, float t)
636+{
637+ _tPoly* poly = *polyh;
638+ tRamp_setTime(&poly->pitchBendRamp, t);
639+}
640+
641+void tPoly_setBendSamplesPerTick(tPoly* const polyh, float t)
642+{
643+ _tPoly* poly = *polyh;
644+ poly->pitchBendRamp->samples_per_tick = t;
645+}
646+
647+int tPoly_getNumVoices(tPoly* const polyh)
648+{
649+ _tPoly* poly = *polyh;
650+ return poly->numVoices;
651+}
652+
653+int tPoly_getNumActiveVoices(tPoly* const polyh)
654+{
655+ _tPoly* poly = *polyh;
656+ return LEAF_clip(0, tStack_getSize(&poly->stack), poly->numVoices);
657+}
658+
659+float tPoly_getPitch(tPoly* const polyh, uint8_t voice)
660+{
661+ _tPoly* poly = *polyh;
662+ return tRamp_sample(&poly->ramps[voice]) + tRamp_sample(&poly->pitchBendRamp);
663+}
664+
665+int tPoly_getKey(tPoly* const polyh, uint8_t voice)
666+{
667+ _tPoly* poly = *polyh;
668+ return poly->voices[voice][0];
669+}
670+
671+int tPoly_getVelocity(tPoly* const polyh, uint8_t voice)
672+{
673+ _tPoly* poly = *polyh;
674+ return poly->voices[voice][1];
675+}
676+
677+int tPoly_isOn(tPoly* const polyh, uint8_t voice)
678+{
679+ _tPoly* poly = *polyh;
680+ return (poly->voices[voice][0] > 0) ? 1 : 0;
681+}
682+
683+
684+
685+
686+//tSimplePoly = much more efficient implementation without ramps and glide
687+
688+
689+// SIMPLE POLY
690+void tSimplePoly_init(tSimplePoly* const polyh, int maxNumVoices)
691+{
692+ tSimplePoly_initToPool(polyh, maxNumVoices, &leaf.mempool);
693+}
694+
695+void tSimplePoly_free(tSimplePoly* const polyh)
696+{
697+ tSimplePoly_freeFromPool(polyh, &leaf.mempool);
698+}
699+
700+void tSimplePoly_initToPool (tSimplePoly* const polyh, int maxNumVoices, tMempool* const mp)
701+{
702+ _tMempool* m = *mp;
703+ _tSimplePoly* poly = *polyh = (_tSimplePoly*) mpool_alloc(sizeof(_tSimplePoly), m);
704+
705+ poly->numVoices = maxNumVoices;
706+ poly->maxNumVoices = maxNumVoices;
707+
708+ for (int i = 0; i < 128; i++)
709+ {
710+ poly->notes[i][0] = -1;
711+ poly->notes[i][1] = 0;
712+ }
713+ poly->stealing_on = 1;
714+ poly->recover_stolen = 1;
715+ poly->voices = (int**) mpool_alloc(sizeof(int*) * poly->maxNumVoices, m);
716+
717+ for (int i = 0; i < poly->maxNumVoices; ++i)
718+ {
719+ poly->voices[i] = (int*) mpool_alloc(sizeof(int) * 3, m);
720+ poly->voices[i][0] = -1;
721+ }
722+ tStack_initToPool(&poly->stack, mp);
723+
724+}
725+
726+void tSimplePoly_freeFromPool (tSimplePoly* const polyh, tMempool* const mp)
727+{
728+ _tMempool* m = *mp;
729+ _tSimplePoly* poly = *polyh;
730+
731+ for (int i = 0; i < poly->maxNumVoices; i++)
732+ {
733+ mpool_free((char*)poly->voices[i], m);
734+ }
735+ tStack_freeFromPool(&poly->stack, mp);
736+ mpool_free((char*)poly->voices, m);
737+ mpool_free((char*)poly, m);
738+}
739+
740+int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel)
741+{
742+ _tSimplePoly* poly = *polyh;
743+ int whichVoice, whichNote, oldNote, alteredVoice;
744+ // if not in keymap or already on stack, dont do anything. else, add that note.
745+ if (tStack_contains(&poly->stack, note) >= 0) return -1;
746+ else
747+ {
748+ alteredVoice = -1;
749+ oBool found = OFALSE;
750+ for (int i = 0; i < poly->numVoices; i++)
751+ {
752+ if (poly->voices[i][0] == -1) // if inactive voice, give this note to voice
753+ {
754+
755+ found = OTRUE;
756+
757+ poly->voices[i][0] = note;
758+ poly->voices[i][1] = vel;
759+ poly->notes[note][0] = i;
760+ poly->notes[note][1] = vel;
761+ poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
762+
763+ alteredVoice = i;
764+ tStack_add(&poly->stack, note);
765+ break;
766+ }
767+ }
768+ if (!found)
769+ {
770+ //second preference is grabbing one that is in release phase but not finished sounding yet
771+ for (int i = 0 ; i < poly->numVoices; i++)
772+ {
773+ if (poly->voices[i][0] == -2) // if voice is released but still sounding, take over this voice
774+ {
775+
776+ found = OTRUE;
777+
778+ poly->voices[i][0] = note;
779+ poly->voices[i][1] = vel;
780+ poly->notes[note][0] = i;
781+ poly->notes[note][1] = vel;
782+ poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
783+
784+ alteredVoice = i;
785+ tStack_add(&poly->stack, note);
786+ break;
787+ }
788+ }
789+ }
790+ if ((!found) && (poly->stealing_on)) //steal
791+ {
792+ for (int j = tStack_getSize(&poly->stack) - 1; j >= 0; j--)
793+ {
794+ whichNote = tStack_get(&poly->stack, j);
795+ whichVoice = poly->notes[whichNote][0];
796+ if (whichVoice >= 0)
797+ {
798+ oldNote = poly->voices[whichVoice][0];
799+ poly->voices[whichVoice][0] = note;
800+ poly->voices[whichVoice][1] = vel;
801+ poly->notes[oldNote][0] = -3; //mark the stolen voice as stolen (in the second dimension of the notes array)
802+ poly->notes[note][0] = whichVoice;
803+ poly->notes[note][1] = vel;
804+
805+ poly->voices[whichVoice][2] = note;
806+
807+ alteredVoice = whichVoice;
808+ tStack_add(&poly->stack, note);
809+ break;
810+ }
811+ }
812+ }
813+ return alteredVoice;
814+ }
815+}
816+
817+
818+
819+int tSimplePoly_noteOff(tSimplePoly* const polyh, uint8_t note)
820+{
821+ _tSimplePoly* poly = *polyh;
822+ int16_t noteToTest = -1;
823+
824+ tStack_remove(&poly->stack, note);
825+ poly->notes[note][0] = -1;
826+
827+ int deactivatedVoice = -1;
828+ for (int i = 0; i < poly->maxNumVoices; i++)
829+ {
830+ if (poly->voices[i][0] == note)
831+ {
832+ poly->voices[i][0] = -1;
833+ poly->voices[i][1] = 0;
834+ deactivatedVoice = i;
835+ break;
836+ }
837+ }
838+
839+ if (poly->recover_stolen)
840+ {
841+ //grab old notes off the stack if there are notes waiting to replace the free voice
842+ if (deactivatedVoice >= 0)
843+ {
844+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
845+ {
846+ noteToTest = tStack_get(&poly->stack, j);
847+
848+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
849+ {
850+ poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
851+ poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
852+ poly->voices[deactivatedVoice][2] = noteToTest;
853+ poly->notes[noteToTest][0] = deactivatedVoice; //mark that it is no longer stolen and is now active
854+ return -1;
855+ }
856+ }
857+ }
858+ }
859+ return deactivatedVoice;
860+}
861+
862+
863+void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice)
864+{
865+ _tSimplePoly* poly = *polyh;
866+
867+ if (poly->voices[voice][0] == -2) //only do this if the voice is waiting for deactivation (not already reassigned while waiting)
868+ {
869+ poly->voices[voice][0] = -1;
870+ poly->voices[voice][1] = 0;
871+ if (poly->recover_stolen)
872+ {
873+ //grab old notes off the stack if there are notes waiting to replace the free voice
874+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
875+ {
876+ noteToTest = tStack_get(&poly->stack, j);
877+
878+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
879+ {
880+ poly->voices[voice][0] = noteToTest; //set the newly free voice to use the old stolen note
881+ poly->voices[voice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
882+ poly->voices[voice][2] = noteToTest;
883+ poly->notes[noteToTest][0] = voice; //mark that it is no longer stolen and is now active
884+ }
885+ }
886+ }
887+ }
888+}
889+
890+int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note)
891+{
892+ _tSimplePoly* poly = *polyh;
893+
894+
895+ int voiceWithThatNote = -1;
896+ for (int i = 0; i < poly->maxNumVoices; i++)
897+ {
898+ if (poly->voices[i][0] == note)
899+ {
900+ voiceWithThatNote = i;
901+ break;
902+ }
903+ }
904+ return voiceWithThatNote;
905+}
906+
907+
908+int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note)
909+{
910+ _tSimplePoly* poly = *polyh;
911+ int deactivatedVoice = -1;
912+
913+ if (tStack_remove(&poly->stack, note))
914+
915+ {
916+
917+ poly->notes[note][0] = -2;
918+
919+
920+
921+ for (int i = 0; i < poly->maxNumVoices; i++)
922+ {
923+ if (poly->voices[i][0] == note)
924+ {
925+ poly->voices[i][0] = -2;
926+ poly->voices[i][1] = 0;
927+ deactivatedVoice = i;
928+ break;
929+ }
930+ }
931+
932+
933+ }
934+ return deactivatedVoice;
935+}
936+
937+void tSimplePoly_setNumVoices(tSimplePoly* const polyh, uint8_t numVoices)
938+{
939+ _tSimplePoly* poly = *polyh;
940+ poly->numVoices = (numVoices > poly->maxNumVoices) ? poly->maxNumVoices : numVoices;
941+}
942+
943+
944+int tSimplePoly_getNumVoices(tSimplePoly* const polyh)
945+{
946+ _tSimplePoly* poly = *polyh;
947+ return poly->numVoices;
948+}
949+
950+int tSimplePoly_getNumActiveVoices(tSimplePoly* const polyh)
951+{
952+ _tSimplePoly* poly = *polyh;
953+ return LEAF_clip(0, tStack_getSize(&poly->stack), poly->numVoices);
954+}
955+
956+
957+int tSimplePoly_getPitch(tSimplePoly* const polyh, uint8_t voice)
958+{
959+ _tSimplePoly* poly = *polyh;
960+ return poly->voices[voice][2];
961+}
962+
963+//this one returns negative one if the voice is inactive
964+int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice)
965+{
966+ _tSimplePoly* poly = *polyh;
967+ return poly->voices[voice][0];
968+}
969+
970+int tSimplePoly_getVelocity(tSimplePoly* const polyh, uint8_t voice)
971+{
972+ _tSimplePoly* poly = *polyh;
973+ return poly->voices[voice][1];
974+}
975+
976+int tSimplePoly_isOn(tSimplePoly* const polyh, uint8_t voice)
977+{
978+ _tSimplePoly* poly = *polyh;
979+ return (poly->voices[voice][0] > 0) ? 1 : 0;
980+}
leaf/Src/leaf-oscillators.c+1660−0
@@ -0,0 +1,1660 @@
1+/*==============================================================================
2+ leaf-oscillators.c
3+ Created: 20 Jan 2017 12:00:58pm
4+ Author: Michael R Mulshine
5+ ==============================================================================*/
6+
7+#if _WIN32 || _WIN64
8+
9+#include "..\Inc\leaf-oscillators.h"
10+#include "..\leaf.h"
11+
12+#else
13+
14+#include "../Inc/leaf-oscillators.h"
15+#include "../leaf.h"
16+
17+#endif
18+
19+// Cycle
20+void tCycle_init(tCycle* const cy)
21+{
22+ tCycle_initToPool(cy, &leaf.mempool);
23+}
24+
25+void tCycle_free(tCycle* const cy)
26+{
27+ tCycle_freeFromPool(cy, &leaf.mempool);
28+}
29+
30+void tCycle_initToPool (tCycle* const cy, tMempool* const mp)
31+{
32+ _tMempool* m = *mp;
33+ _tCycle* c = *cy = (_tCycle*) mpool_alloc(sizeof(_tCycle), m);
34+
35+ c->inc = 0.0f;
36+ c->phase = 0.0f;
37+
38+}
39+
40+void tCycle_freeFromPool (tCycle* const cy, tMempool* const mp)
41+{
42+ _tMempool* m = *mp;
43+ _tCycle* c = *cy;
44+
45+ mpool_free((char*)c, m);
46+}
47+
48+void tCycle_setFreq(tCycle* const cy, float freq)
49+{
50+ _tCycle* c = *cy;
51+
52+ c->freq = freq;
53+
54+ c->inc = freq * leaf.invSampleRate;
55+}
56+
57+//need to check bounds and wrap table properly to allow through-zero FM
58+float tCycle_tick(tCycle* const cy)
59+{
60+ _tCycle* c = *cy;
61+ float temp;;
62+ int intPart;;
63+ float fracPart;
64+ float samp0;
65+ float samp1;
66+
67+ // Phasor increment
68+ c->phase += c->inc;
69+ while (c->phase >= 1.0f) c->phase -= 1.0f;
70+ while (c->phase < 0.0f) c->phase += 1.0f;
71+
72+ // Wavetable synthesis
73+
74+ temp = SINE_TABLE_SIZE * c->phase;
75+ intPart = (int)temp;
76+ fracPart = temp - (float)intPart;
77+ samp0 = __leaf_table_sinewave[intPart];
78+ if (++intPart >= SINE_TABLE_SIZE) intPart = 0;
79+ samp1 = __leaf_table_sinewave[intPart];
80+
81+ return (samp0 + (samp1 - samp0) * fracPart);
82+
83+}
84+
85+void tCycleSampleRateChanged (tCycle* const cy)
86+{
87+ _tCycle* c = *cy;
88+
89+ c->inc = c->freq * leaf.invSampleRate;
90+}
91+
92+//========================================================================
93+/* Triangle */
94+void tTriangle_init(tTriangle* const cy)
95+{
96+ tTriangle_initToPool(cy, &leaf.mempool);
97+}
98+
99+void tTriangle_free(tTriangle* const cy)
100+{
101+ tTriangle_freeFromPool(cy, &leaf.mempool);
102+}
103+
104+void tTriangle_initToPool (tTriangle* const cy, tMempool* const mp)
105+{
106+ _tMempool* m = *mp;
107+ _tTriangle* c = *cy = (_tTriangle*) mpool_alloc(sizeof(_tTriangle), m);
108+
109+ c->inc = 0.0f;
110+ c->phase = 0.0f;
111+ tTriangle_setFreq(cy, 220);
112+}
113+
114+void tTriangle_freeFromPool (tTriangle* const cy, tMempool* const mp)
115+{
116+ _tMempool* m = *mp;
117+ _tTriangle* c = *cy;
118+
119+ mpool_free((char*)c, m);
120+}
121+
122+void tTriangle_setFreq(tTriangle* const cy, float freq)
123+{
124+ _tTriangle* c = *cy;
125+
126+ c->freq = freq;
127+
128+ c->inc = c->freq * leaf.invSampleRate;
129+
130+ c->w = c->freq * INV_20;
131+ for (c->oct = 0; c->w > 2.0f; c->oct++)
132+ {
133+ c->w = 0.5f * c->w;
134+ }
135+ c->w = 2.0f - c->w;
136+}
137+
138+
139+float tTriangle_tick(tTriangle* const cy)
140+{
141+ _tTriangle* c = *cy;
142+
143+ // Phasor increment
144+ c->phase += c->inc;
145+ while (c->phase >= 1.0f) c->phase -= 1.0f;
146+ while (c->phase < 0.0f) c->phase += 1.0f;
147+
148+ float out = 0.0f;
149+
150+ int idx = (int)(c->phase * TRI_TABLE_SIZE);
151+
152+ // Wavetable synthesis
153+ out = __leaf_table_triangle[c->oct+1][idx] +
154+ (__leaf_table_triangle[c->oct][idx] - __leaf_table_triangle[c->oct+1][idx]) * c->w;
155+
156+ return out;
157+}
158+
159+void tTriangleSampleRateChanged (tTriangle* const cy)
160+{
161+ _tTriangle* c = *cy;
162+
163+ c->inc = c->freq * leaf.invSampleRate;
164+}
165+
166+//========================================================================
167+/* Square */
168+void tSquare_init(tSquare* const cy)
169+{
170+ tSquare_initToPool(cy, &leaf.mempool);
171+}
172+
173+void tSquare_free(tSquare* const cy)
174+{
175+ tSquare_freeFromPool(cy, &leaf.mempool);
176+}
177+
178+void tSquare_initToPool (tSquare* const cy, tMempool* const mp)
179+{
180+ _tMempool* m = *mp;
181+ _tSquare* c = *cy = (_tSquare*) mpool_alloc(sizeof(_tSquare), m);
182+
183+ c->inc = 0.0f;
184+ c->phase = 0.0f;
185+ tSquare_setFreq(cy, 220);
186+}
187+
188+void tSquare_freeFromPool(tSquare* const cy, tMempool* const mp)
189+{
190+ _tMempool* m = *mp;
191+ _tSquare* c = *cy;
192+
193+ mpool_free((char*)c, m);
194+}
195+
196+void tSquare_setFreq(tSquare* const cy, float freq)
197+{
198+ _tSquare* c = *cy;
199+
200+ c->freq = freq;
201+
202+ c->inc = c->freq * leaf.invSampleRate;
203+
204+ c->w = c->freq * INV_20;
205+ for (c->oct = 0; c->w > 2.0f; c->oct++)
206+ {
207+ c->w = 0.5f * c->w;
208+ }
209+ c->w = 2.0f - c->w;
210+}
211+
212+float tSquare_tick(tSquare* const cy)
213+{
214+ _tSquare* c = *cy;
215+
216+ // Phasor increment
217+ c->phase += c->inc;
218+ while (c->phase >= 1.0f) c->phase -= 1.0f;
219+ while (c->phase < 0.0f) c->phase += 1.0f;
220+
221+ float out = 0.0f;
222+
223+ int idx = (int)(c->phase * SQR_TABLE_SIZE);
224+
225+ // Wavetable synthesis
226+ out = __leaf_table_squarewave[c->oct+1][idx] +
227+ (__leaf_table_squarewave[c->oct][idx] - __leaf_table_squarewave[c->oct+1][idx]) * c->w;
228+
229+ return out;
230+}
231+
232+void tSquareSampleRateChanged (tSquare* const cy)
233+{
234+ _tSquare* c = *cy;
235+
236+ c->inc = c->freq * leaf.invSampleRate;
237+}
238+
239+//=====================================================================
240+// Sawtooth
241+void tSawtooth_init(tSawtooth* const cy)
242+{
243+ tSawtooth_initToPool(cy, &leaf.mempool);
244+}
245+
246+void tSawtooth_free(tSawtooth* const cy)
247+{
248+ tSawtooth_freeFromPool(cy, &leaf.mempool);
249+}
250+
251+void tSawtooth_initToPool (tSawtooth* const cy, tMempool* const mp)
252+{
253+ _tMempool* m = *mp;
254+ _tSawtooth* c = *cy = (_tSawtooth*) mpool_alloc(sizeof(_tSawtooth), m);
255+
256+ c->inc = 0.0f;
257+ c->phase = 0.0f;
258+ tSawtooth_setFreq(cy, 220);
259+}
260+
261+void tSawtooth_freeFromPool (tSawtooth* const cy, tMempool* const mp)
262+{
263+ _tMempool* m = *mp;
264+ _tSawtooth* c = *cy;
265+
266+ mpool_free((char*)c, m);
267+}
268+
269+void tSawtooth_setFreq(tSawtooth* const cy, float freq)
270+{
271+ _tSawtooth* c = *cy;
272+
273+ c->freq = freq;
274+
275+ c->inc = c->freq * leaf.invSampleRate;
276+
277+ c->w = c->freq * INV_20;
278+ for (c->oct = 0; c->w > 2.0f; c->oct++)
279+ {
280+ c->w = 0.5f * c->w;
281+ }
282+ c->w = 2.0f - c->w;
283+}
284+
285+float tSawtooth_tick(tSawtooth* const cy)
286+{
287+ _tSawtooth* c = *cy;
288+
289+ // Phasor increment
290+ c->phase += c->inc;
291+ while (c->phase >= 1.0f) c->phase -= 1.0f;
292+ while (c->phase < 0.0f) c->phase += 1.0f;
293+
294+ float out = 0.0f;
295+
296+ int idx = (int)(c->phase * SAW_TABLE_SIZE);
297+
298+ // Wavetable synthesis
299+ out = __leaf_table_sawtooth[c->oct+1][idx] +
300+ (__leaf_table_sawtooth[c->oct][idx] - __leaf_table_sawtooth[c->oct+1][idx]) * c->w;
301+
302+ return out;
303+}
304+
305+void tSawtoothSampleRateChanged (tSawtooth* const cy)
306+{
307+ _tSawtooth* c = *cy;
308+
309+ c->inc = c->freq * leaf.invSampleRate;
310+}
311+
312+//========================================================================
313+// Sine
314+void tSine_init(tSine* const cy, int size)
315+{
316+ tSine_initToPool(cy, size, &leaf.mempool);
317+}
318+
319+void tSine_free(tSine* const cy)
320+{
321+ tSine_freeFromPool(cy, &leaf.mempool);
322+}
323+
324+void tSine_initToPool (tSine* const cy, int size, tMempool* const mp)
325+{
326+ _tMempool* m = *mp;
327+ _tSine* c = *cy = (_tSine*) mpool_alloc(sizeof(_tSine), m);
328+
329+ c->size = size;
330+ c->sine = (float*) mpool_alloc(sizeof(float) * c->size, m);
331+ LEAF_generate_sine(c->sine, size);
332+ c->inc = 0.0f;
333+ c->phase = 0.0f;
334+}
335+
336+void tSine_freeFromPool (tSine* const cy, tMempool* const mp)
337+{
338+ _tMempool* m = *mp;
339+ _tSine* c = *cy;
340+
341+ mpool_free((char*)c->sine, m);
342+ mpool_free((char*)c, m);
343+}
344+
345+void tSine_setFreq(tSine* const cy, float freq)
346+{
347+ _tSine* c = *cy;
348+
349+ c->freq = freq;
350+ c->inc = freq * leaf.invSampleRate;
351+}
352+
353+float tSine_tick(tSine* const cy)
354+{
355+ _tSine* c = *cy;
356+ float temp;
357+ int intPart;
358+ float fracPart;
359+ float samp0;
360+ float samp1;
361+
362+ // Phasor increment
363+ c->phase += c->inc;
364+ while (c->phase >= 1.0f) c->phase -= 1.0f;
365+ while (c->phase < 0.0f) c->phase += 1.0f;
366+
367+ // Wavetable synthesis
368+
369+ temp = c->size * c->phase;
370+ intPart = (int)temp;
371+ fracPart = temp - (float)intPart;
372+ samp0 = c->sine[intPart];
373+ if (++intPart >= c->size) intPart = 0;
374+ samp1 = c->sine[intPart];
375+
376+ return (samp0 + (samp1 - samp0) * fracPart);
377+
378+}
379+
380+void tSineSampleRateChanged (tSine* const cy)
381+{
382+ _tSine* c = *cy;
383+
384+ c->inc = c->freq * leaf.invSampleRate;
385+}
386+
387+//==============================================================================
388+
389+/* tTri: Anti-aliased Triangle waveform. */
390+void tTri_init (tTri* const osc)
391+{
392+ tTri_initToPool(osc, &leaf.mempool);
393+}
394+
395+void tTri_free (tTri* const osc)
396+{
397+ tTri_freeFromPool(osc, &leaf.mempool);
398+}
399+
400+void tTri_initToPool (tTri* const osc, tMempool* const mp)
401+{
402+ _tMempool* m = *mp;
403+ _tTri* c = *osc = (_tTri*) mpool_alloc(sizeof(_tTri), m);
404+
405+ c->inc = 0.0f;
406+ c->phase = 0.0f;
407+ c->skew = 0.5f;
408+ c->lastOut = 0.0f;
409+}
410+
411+void tTri_freeFromPool (tTri* const cy, tMempool* const mp)
412+{
413+ _tMempool* m = *mp;
414+ _tTri* c = *cy;
415+
416+ mpool_free((char*)c, m);
417+}
418+
419+float tTri_tick (tTri* const osc)
420+{
421+ _tTri* c = *osc;
422+
423+ float out;
424+ float skew;
425+
426+ if (c->phase < c->skew)
427+ {
428+ out = 1.0f;
429+ skew = (1.0f - c->skew) * 2.0f;
430+ }
431+ else
432+ {
433+ out = -1.0f;
434+ skew = c->skew * 2.0f;
435+ }
436+
437+ out += LEAF_poly_blep(c->phase, c->inc);
438+ out -= LEAF_poly_blep(fmod(c->phase + (1.0f - c->skew), 1.0f), c->inc);
439+
440+ out = (skew * c->inc * out) + ((1 - c->inc) * c->lastOut);
441+ c->lastOut = out;
442+
443+ c->phase += c->inc;
444+ if (c->phase >= 1.0f)
445+ {
446+ c->phase -= 1.0f;
447+ }
448+
449+ return out;
450+}
451+
452+void tTri_setFreq (tTri* const osc, float freq)
453+{
454+ _tTri* c = *osc;
455+
456+ c->freq = freq;
457+ c->inc = freq * leaf.invSampleRate;
458+}
459+
460+void tTri_setSkew (tTri* const osc, float skew)
461+{
462+ _tTri* c = *osc;
463+ c->skew = (skew + 1.0f) * 0.5f;
464+}
465+
466+
467+//==============================================================================
468+
469+/* tPulse: Anti-aliased pulse waveform. */
470+void tPulse_init (tPulse* const osc)
471+{
472+ tPulse_initToPool(osc, &leaf.mempool);
473+}
474+
475+void tPulse_free (tPulse* const osc)
476+{
477+ tPulse_freeFromPool(osc, &leaf.mempool);
478+}
479+
480+void tPulse_initToPool (tPulse* const osc, tMempool* const mp)
481+{
482+ _tMempool* m = *mp;
483+ _tPulse* c = *osc = (_tPulse*) mpool_alloc(sizeof(_tPulse), m);
484+
485+ c->inc = 0.0f;
486+ c->phase = 0.0f;
487+ c->width = 0.5f;
488+}
489+
490+void tPulse_freeFromPool(tPulse* const osc, tMempool* const mp)
491+{
492+ _tMempool* m = *mp;
493+ _tPulse* c = *osc;
494+
495+ mpool_free((char*)c, m);
496+}
497+
498+float tPulse_tick (tPulse* const osc)
499+{
500+ _tPulse* c = *osc;
501+
502+ float out;
503+ if (c->phase < c->width) out = 1.0f;
504+ else out = -1.0f;
505+ out += LEAF_poly_blep(c->phase, c->inc);
506+ out -= LEAF_poly_blep(fmod(c->phase + (1.0f - c->width), 1.0f), c->inc);
507+
508+ c->phase += c->inc;
509+ if (c->phase >= 1.0f)
510+ {
511+ c->phase -= 1.0f;
512+ }
513+
514+ return out;
515+}
516+
517+void tPulse_setFreq (tPulse* const osc, float freq)
518+{
519+ _tPulse* c = *osc;
520+
521+ c->freq = freq;
522+ c->inc = freq * leaf.invSampleRate;
523+}
524+
525+void tPulse_setWidth (tPulse* const osc, float width)
526+{
527+ _tPulse* c = *osc;
528+ c->width = width;
529+}
530+
531+
532+//==============================================================================
533+
534+/* tSawtooth: Anti-aliased Sawtooth waveform. */
535+void tSaw_init (tSaw* const osc)
536+{
537+ tSaw_initToPool(osc, &leaf.mempool);
538+}
539+
540+void tSaw_free (tSaw* const osc)
541+{
542+ tSaw_freeFromPool(osc, &leaf.mempool);
543+}
544+
545+void tSaw_initToPool (tSaw* const osc, tMempool* const mp)
546+{
547+ _tMempool* m = *mp;
548+ _tSaw* c = *osc = (_tSaw*) mpool_alloc(sizeof(_tSaw), m);
549+
550+ c->inc = 0.0f;
551+ c->phase = 0.0f;
552+}
553+
554+void tSaw_freeFromPool (tSaw* const osc, tMempool* const mp)
555+{
556+ _tMempool* m = *mp;
557+ _tSaw* c = *osc;
558+
559+ mpool_free((char*)c, m);
560+}
561+
562+float tSaw_tick (tSaw* const osc)
563+{
564+ _tSaw* c = *osc;
565+
566+ float out = (c->phase * 2.0f) - 1.0f;
567+ out -= LEAF_poly_blep(c->phase, c->inc);
568+
569+ c->phase += c->inc;
570+ if (c->phase >= 1.0f)
571+ {
572+ c->phase -= 1.0f;
573+ }
574+
575+ return out;
576+}
577+
578+void tSaw_setFreq (tSaw* const osc, float freq)
579+{
580+ _tSaw* c = *osc;
581+
582+ c->freq = freq;
583+
584+ c->inc = freq * leaf.invSampleRate;
585+}
586+
587+//========================================================================
588+/* Phasor */
589+void tPhasorSampleRateChanged (tPhasor* const ph)
590+{
591+ _tPhasor* p = *ph;
592+
593+ p->inc = p->freq * leaf.invSampleRate;
594+};
595+
596+void tPhasor_init(tPhasor* const ph)
597+{
598+ tPhasor_initToPool(ph, &leaf.mempool);
599+}
600+
601+void tPhasor_free(tPhasor* const ph)
602+{
603+ tPhasor_freeFromPool(ph, &leaf.mempool);
604+}
605+
606+void tPhasor_initToPool (tPhasor* const ph, tMempool* const mp)
607+{
608+ _tMempool* m = *mp;
609+ _tPhasor* p = *ph = (_tPhasor*) mpool_alloc(sizeof(_tPhasor), m);
610+
611+ p->phase = 0.0f;
612+ p->inc = 0.0f;
613+ p->phaseDidReset = 0;
614+}
615+
616+void tPhasor_freeFromPool(tPhasor* const ph, tMempool* const mp)
617+{
618+ _tMempool* m = *mp;
619+ _tPhasor* p = *ph;
620+
621+ mpool_free((char*)p, m);
622+}
623+
624+void tPhasor_setFreq(tPhasor* const ph, float freq)
625+{
626+ _tPhasor* p = *ph;
627+
628+ p->freq = freq;
629+
630+ p->inc = freq * leaf.invSampleRate;
631+}
632+
633+float tPhasor_tick(tPhasor* const ph)
634+{
635+ _tPhasor* p = *ph;
636+
637+ p->phase += p->inc;
638+
639+
640+ p->phaseDidReset = 0;
641+ if (p->phase >= 1.0f)
642+ {
643+ p->phaseDidReset = 1;
644+ p->phase -= 1.0f;
645+ }
646+
647+ return p->phase;
648+}
649+
650+/* Noise */
651+void tNoise_init(tNoise* const ns, NoiseType type)
652+{
653+ tNoise_initToPool(ns, type, &leaf.mempool);
654+}
655+
656+void tNoise_free(tNoise* const ns)
657+{
658+ tNoise_freeFromPool(ns, &leaf.mempool);
659+}
660+
661+void tNoise_initToPool (tNoise* const ns, NoiseType type, tMempool* const mp)
662+{
663+ _tMempool* m = *mp;
664+ _tNoise* n = *ns = (_tNoise*) mpool_alloc(sizeof(_tNoise), m);
665+
666+ n->type = type;
667+ n->rand = leaf.random;
668+}
669+
670+void tNoise_freeFromPool (tNoise* const ns, tMempool* const mp)
671+{
672+ _tMempool* m = *mp;
673+ _tNoise* n = *ns;
674+
675+ mpool_free((char*)n, m);
676+}
677+
678+float tNoise_tick(tNoise* const ns)
679+{
680+ _tNoise* n = *ns;
681+
682+ float rand = (n->rand() * 2.0f) - 1.0f;
683+
684+ if (n->type == PinkNoise)
685+ {
686+ float tmp;
687+ n->pinkb0 = 0.99765f * n->pinkb0 + rand * 0.0990460f;
688+ n->pinkb1 = 0.96300f * n->pinkb1 + rand * 0.2965164f;
689+ n->pinkb2 = 0.57000f * n->pinkb2 + rand * 1.0526913f;
690+ tmp = n->pinkb0 + n->pinkb1 + n->pinkb2 + rand * 0.1848f;
691+ return (tmp * 0.05f);
692+ }
693+ else // WhiteNoise
694+ {
695+ return rand;
696+ }
697+}
698+
699+//=================================================================================
700+/* Neuron */
701+
702+void tNeuronSampleRateChanged(tNeuron* nr)
703+{
704+
705+}
706+
707+void tNeuron_init(tNeuron* const nr)
708+{
709+ tNeuron_initToPool(nr, &leaf.mempool);
710+}
711+
712+void tNeuron_free(tNeuron* const nr)
713+{
714+ tNeuron_freeFromPool(nr, &leaf.mempool);
715+}
716+
717+void tNeuron_initToPool (tNeuron* const nr, tMempool* const mp)
718+{
719+ _tMempool* m = *mp;
720+ _tNeuron* n = *nr = (_tNeuron*) mpool_alloc(sizeof(_tNeuron), m);
721+
722+ tPoleZero_initToPool(&n->f, mp);
723+
724+ tPoleZero_setBlockZero(&n->f, 0.99f);
725+
726+ n->timeStep = 1.0f / 50.0f;
727+
728+ n->current = 0.0f; // 100.0f for sound
729+ n->voltage = 0.0f;
730+
731+ n->mode = NeuronNormal;
732+
733+ n->P[0] = 0.0f;
734+ n->P[1] = 0.0f;
735+ n->P[2] = 1.0f;
736+
737+ n->V[0] = -12.0f;
738+ n->V[1] = 115.0f;
739+ n->V[2] = 10.613f;
740+
741+ n->gK = 36.0f;
742+ n->gN = 120.0f;
743+ n->gL = 0.3f;
744+ n->C = 1.0f;
745+
746+ n->rate[2] = n->gL/n->C;
747+}
748+
749+void tNeuron_freeFromPool(tNeuron* const nr, tMempool* const mp)
750+{
751+ _tMempool* m = *mp;
752+ _tNeuron* n = *nr;
753+
754+ tPoleZero_free(&n->f);
755+ mpool_free((char*)n, m);
756+}
757+
758+void tNeuron_reset(tNeuron* const nr)
759+{
760+ _tNeuron* n = *nr;
761+
762+ tPoleZero_setBlockZero(&n->f, 0.99f);
763+
764+ n->timeStep = 1.0f / 50.0f;
765+
766+ n->current = 0.0f; // 100.0f for sound
767+ n->voltage = 0.0f;
768+
769+ n->mode = NeuronNormal;
770+
771+ n->P[0] = 0.0f;
772+ n->P[1] = 0.0f;
773+ n->P[2] = 1.0f;
774+
775+ n->V[0] = -12.0f;
776+ n->V[1] = 115.0f;
777+ n->V[2] = 10.613f;
778+
779+ n->gK = 36.0f;
780+ n->gN = 120.0f;
781+ n->gL = 0.3f;
782+ n->C = 1.0f;
783+
784+ n->rate[2] = n->gL/n->C;
785+}
786+
787+void tNeuron_setV1(tNeuron* const nr, float V1)
788+{
789+ _tNeuron* n = *nr;
790+ n->V[0] = V1;
791+}
792+
793+
794+void tNeuron_setV2(tNeuron* const nr, float V2)
795+{
796+ _tNeuron* n = *nr;
797+ n->V[1] = V2;
798+}
799+
800+void tNeuron_setV3(tNeuron* const nr, float V3)
801+{
802+ _tNeuron* n = *nr;
803+ n->V[2] = V3;
804+}
805+
806+void tNeuron_setTimeStep(tNeuron* const nr, float timeStep)
807+{
808+ _tNeuron* n = *nr;
809+ n->timeStep = timeStep;
810+}
811+
812+void tNeuron_setK(tNeuron* const nr, float K)
813+{
814+ _tNeuron* n = *nr;
815+ n->gK = K;
816+}
817+
818+void tNeuron_setL(tNeuron* const nr, float L)
819+{
820+ _tNeuron* n = *nr;
821+ n->gL = L;
822+ n->rate[2] = n->gL/n->C;
823+}
824+
825+void tNeuron_setN(tNeuron* const nr, float N)
826+{
827+ _tNeuron* n = *nr;
828+ n->gN = N;
829+}
830+
831+void tNeuron_setC(tNeuron* const nr, float C)
832+{
833+ _tNeuron* n = *nr;
834+ n->C = C;
835+ n->rate[2] = n->gL/n->C;
836+}
837+
838+float tNeuron_tick(tNeuron* const nr)
839+{
840+ _tNeuron* n = *nr;
841+
842+ float output = 0.0f;
843+ float voltage = n->voltage;
844+
845+ n->alpha[0] = (0.01f * (10.0f - voltage)) / (expf((10.0f - voltage)/10.0f) - 1.0f);
846+ n->alpha[1] = (0.1f * (25.0f-voltage)) / (expf((25.0f-voltage)/10.0f) - 1.0f);
847+ n->alpha[2] = (0.07f * expf((-1.0f * voltage)/20.0f));
848+
849+ n->beta[0] = (0.125f * expf((-1.0f* voltage)/80.0f));
850+ n->beta[1] = (4.0f * expf((-1.0f * voltage)/18.0f));
851+ n->beta[2] = (1.0f / (expf((30.0f-voltage)/10.0f) + 1.0f));
852+
853+ for (int i = 0; i < 3; i++)
854+ {
855+ n->P[i] = (n->alpha[i] * n->timeStep) + ((1.0f - ((n->alpha[i] + n->beta[i]) * n->timeStep)) * n->P[i]);
856+
857+ if (n->P[i] > 1.0f) n->P[i] = 0.0f;
858+ else if (n->P[i] < -1.0f) n->P[i] = 0.0f;
859+ }
860+ // rate[0]= k ; rate[1] = Na ; rate[2] = l
861+ n->rate[0] = ((n->gK * powf(n->P[0], 4.0f)) / n->C);
862+ n->rate[1] = ((n->gN * powf(n->P[1], 3.0f) * n->P[2]) / n->C);
863+
864+ //calculate the final membrane voltage based on the computed variables
865+ n->voltage = voltage +
866+ (n->timeStep * n->current / n->C) -
867+ (n->timeStep * ( n->rate[0] * (voltage - n->V[0]) + n->rate[1] * (voltage - n->V[1]) + n->rate[2] * (voltage - n->V[2])));
868+
869+ if (n->mode == NeuronTanh)
870+ {
871+ n->voltage = 100.0f * tanhf(0.01f * n->voltage);
872+ }
873+ else if (n->mode == NeuronAaltoShaper)
874+ {
875+ float shapeVoltage = 0.01f * n->voltage;
876+
877+ float w, c, xc, xc2, xc4;
878+
879+ float sqrt8 = 2.82842712475f;
880+
881+ float wscale = 1.30612244898f;
882+ float m_drive = 1.0f;
883+
884+ xc = LEAF_clip(-sqrt8, shapeVoltage, sqrt8);
885+
886+ xc2 = xc*xc;
887+
888+ c = 0.5f * shapeVoltage * (3.0f - (xc2));
889+
890+ xc4 = xc2 * xc2;
891+
892+ w = (1.0f - xc2 * 0.25f + xc4 * 0.015625f) * wscale;
893+
894+ shapeVoltage = w * (c + 0.05f * xc2) * (m_drive + 0.75f);
895+
896+ n->voltage = 100.0f * shapeVoltage;
897+ }
898+
899+
900+ if (n->voltage > 100.0f) n->voltage = 100.0f;
901+ else if (n->voltage < -100.) n->voltage = -100.0f;
902+
903+ //(inputCurrent + (voltage - ((voltage * timeStep) / timeConstant)) + P[0] + P[1] + P[2]) => voltage;
904+ // now we should have a result
905+ //set the output voltage to the "step" ugen, which controls the DAC.
906+ output = n->voltage * 0.01f; // volts
907+
908+ output = tPoleZero_tick(&n->f, output);
909+
910+ return output;
911+
912+}
913+
914+void tNeuron_setMode (tNeuron* const nr, NeuronMode mode)
915+{
916+ _tNeuron* n = *nr;
917+ n->mode = mode;
918+}
919+
920+void tNeuron_setCurrent (tNeuron* const nr, float current)
921+{
922+ _tNeuron* n = *nr;
923+ n->current = current;
924+}
925+
926+
927+
928+void tMinBLEP_init (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio)
929+{
930+ tMinBLEP_initToPool(minblep, zeroCrossings, oversamplerRatio, &leaf.mempool);
931+}
932+
933+void tMinBLEP_free (tMinBLEP* const minblep)
934+{
935+ tMinBLEP_freeFromPool(minblep, &leaf.mempool);
936+}
937+
938+void tMinBLEP_initToPool (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio, tMempool* const mp)
939+{
940+ _tMempool* m = *mp;
941+ _tMinBLEP* mb = *minblep = (_tMinBLEP*) mpool_alloc(sizeof(_tMinBLEP), m);
942+
943+ mb->overSamplingRatio = zeroCrossings;
944+ mb->zeroCrossings = oversamplerRatio;
945+ mb->returnDerivative = 0;
946+ mb->proportionalBlepFreq = (float) mb->zeroCrossings / (float) mb->overSamplingRatio; // defaults to NyQuist ....
947+
948+ mb->lastValue = 0;
949+ mb->lastDelta = 0;
950+
951+// float* x1, x2, y1, y2;
952+ // AA FILTER
953+// zeromem (coefficients, sizeof (coefficients));
954+
955+ mb->minBlepSize = (mb->zeroCrossings * 2 * mb->overSamplingRatio) + 1;
956+
957+ mb->ratio = 1;
958+ mb->lastRatio = 1;
959+
960+// createLowPass (ratio);
961+// resetFilters();
962+
963+ mb->blepIndex = 0;
964+ mb->numActiveBleps = 0;
965+ //currentActiveBlepOffsets;
966+
967+ // These probably don't need to be this large
968+ mb->offset = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
969+// mb->freqMultiple = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
970+ mb->pos_change_magnitude = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
971+ mb->vel_change_magnitude = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
972+
973+ mb->minBlepArray = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
974+ mb->minBlepDerivArray = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
975+
976+ tMinBLEP_buildBLEP(minblep);
977+}
978+
979+void tMinBLEP_freeFromPool (tMinBLEP* const minblep, tMempool* const mp)
980+{
981+ _tMempool* m = *mp;
982+ _tMinBLEP* mb = *minblep;
983+
984+ mpool_free((char*)mb->offset, m);
985+// mpool_free(mb->freqMultiple, m);
986+ mpool_free((char*)mb->pos_change_magnitude, m);
987+ mpool_free((char*)mb->vel_change_magnitude, m);
988+
989+ mpool_free((char*)mb->minBlepArray, m);
990+ mpool_free((char*)mb->minBlepDerivArray, m);
991+
992+ mpool_free((char*)mb, m);
993+}
994+
995+// SINC Function
996+static float SINC(float x)
997+{
998+ float pix;
999+
1000+ if(x == 0.0f)
1001+ return 1.0f;
1002+ else
1003+ {
1004+ pix = PI * x;
1005+ return sinf(pix) / pix;
1006+ }
1007+}
1008+
1009+// Generate Blackman Window
1010+static void BlackmanWindow(int n, float *w)
1011+{
1012+ int m = n - 1;
1013+ int i;
1014+ float f1, f2, fm;
1015+
1016+ fm = (float)m;
1017+ for(i = 0; i <= m; i++)
1018+ {
1019+ f1 = (2.0f * PI * (float)i) / fm;
1020+ f2 = 2.0f * f1;
1021+ w[i] = 0.42f - (0.5f * cosf(f1)) + (0.08f * cosf(f2));
1022+ }
1023+}
1024+
1025+// Discrete Fourier Transform
1026+static void DFT(int n, float *realTime, float *imagTime, float *realFreq, float *imagFreq)
1027+{
1028+ int k, i;
1029+ float sr, si, p;
1030+
1031+ for(k = 0; k < n; k++)
1032+ {
1033+ realFreq[k] = 0.0f;
1034+ imagFreq[k] = 0.0f;
1035+ }
1036+
1037+ for(k = 0; k < n; k++)
1038+ for(i = 0; i < n; i++)
1039+ {
1040+ p = (2.0f * PI * (float)(k * i)) / n;
1041+ sr = cosf(p);
1042+ si = -sinf(p);
1043+ realFreq[k] += (realTime[i] * sr) - (imagTime[i] * si);
1044+ imagFreq[k] += (realTime[i] * si) + (imagTime[i] * sr);
1045+ }
1046+}
1047+
1048+// Inverse Discrete Fourier Transform
1049+static void InverseDFT(int n, float *realTime, float *imagTime, float *realFreq, float *imagFreq)
1050+{
1051+ int k, i;
1052+ float sr, si, p;
1053+
1054+ for(k = 0; k < n; k++)
1055+ {
1056+ realTime[k] = 0.0f;
1057+ imagTime[k] = 0.0f;
1058+ }
1059+
1060+ for(k = 0; k < n; k++)
1061+ {
1062+ for(i = 0; i < n; i++)
1063+ {
1064+ p = (2.0f * PI * (float)(k * i)) / n;
1065+ sr = cosf(p);
1066+ si = -sinf(p);
1067+ realTime[k] += (realFreq[i] * sr) + (imagFreq[i] * si);
1068+ imagTime[k] += (realFreq[i] * si) - (imagFreq[i] * sr);
1069+ }
1070+ realTime[k] /= n;
1071+ imagTime[k] /= n;
1072+ }
1073+}
1074+
1075+// Complex Absolute Value
1076+static float complexabs(float x, float y)
1077+{
1078+ return sqrtf((x * x) + (y * y));
1079+}
1080+
1081+// Complex Exponential
1082+static void complexexp(float x, float y, float *zx, float *zy)
1083+{
1084+ float expx;
1085+
1086+ expx = expf(x);
1087+ *zx = expx * cosf(y);
1088+ *zy = expx * sinf(y);
1089+}
1090+
1091+// Compute Real Cepstrum Of Signal
1092+static void RealCepstrum(int n, float *signal, float *realCepstrum)
1093+{
1094+ int i;
1095+
1096+ float realTime[n];
1097+ float imagTime[n];
1098+ float realFreq[n];
1099+ float imagFreq[n];
1100+
1101+ // Compose Complex FFT Input
1102+
1103+ for(i = 0; i < n; i++)
1104+ {
1105+ realTime[i] = signal[i];
1106+ imagTime[i] = 0.0f;
1107+ }
1108+
1109+ // Perform DFT
1110+
1111+ DFT(n, realTime, imagTime, realFreq, imagFreq);
1112+
1113+ // Calculate Log Of Absolute Value
1114+
1115+ for(i = 0; i < n; i++)
1116+ {
1117+ realFreq[i] = logf(complexabs(realFreq[i], imagFreq[i]));
1118+ imagFreq[i] = 0.0f;
1119+ }
1120+
1121+ // Perform Inverse FFT
1122+
1123+ InverseDFT(n, realTime, imagTime, realFreq, imagFreq);
1124+
1125+ // Output Real Part Of FFT
1126+ for(i = 0; i < n; i++)
1127+ realCepstrum[i] = realTime[i];
1128+}
1129+
1130+// Compute Minimum Phase Reconstruction Of Signal
1131+static void MinimumPhase(int n, float *realCepstrum, float *minimumPhase)
1132+{
1133+ int i, nd2;
1134+ float realTime[n];
1135+ float imagTime[n];
1136+ float realFreq[n];
1137+ float imagFreq[n];
1138+
1139+ nd2 = n / 2;
1140+
1141+ if((n % 2) == 1)
1142+ {
1143+ realTime[0] = realCepstrum[0];
1144+ for(i = 1; i < nd2; i++)
1145+ realTime[i] = 2.0f * realCepstrum[i];
1146+ for(i = nd2; i < n; i++)
1147+ realTime[i] = 0.0f;
1148+ }
1149+ else
1150+ {
1151+ realTime[0] = realCepstrum[0];
1152+ for(i = 1; i < nd2; i++)
1153+ realTime[i] = 2.0f * realCepstrum[i];
1154+ realTime[nd2] = realCepstrum[nd2];
1155+ for(i = nd2 + 1; i < n; i++)
1156+ realTime[i] = 0.0f;
1157+ }
1158+
1159+ for(i = 0; i < n; i++)
1160+ imagTime[i] = 0.0f;
1161+
1162+ DFT(n, realTime, imagTime, realFreq, imagFreq);
1163+
1164+ for(i = 0; i < n; i++)
1165+ complexexp(realFreq[i], imagFreq[i], &realFreq[i], &imagFreq[i]);
1166+
1167+ InverseDFT(n, realTime, imagTime, realFreq, imagFreq);
1168+
1169+ for(i = 0; i < n; i++)
1170+ minimumPhase[i] = realTime[i];
1171+}
1172+
1173+
1174+// Generate the MinBLEP
1175+void tMinBLEP_buildBLEP(tMinBLEP* const minblep)
1176+{
1177+ _tMinBLEP* m = *minblep;
1178+
1179+ int i, n;
1180+ float r, a, b;
1181+
1182+ n = m->minBlepSize;
1183+
1184+ // Generate Sinc
1185+
1186+ a = -m->overSamplingRatio;
1187+ b = m->overSamplingRatio;
1188+ for(i = 0; i < n; i++)
1189+ {
1190+ r = ((float)i) / ((float)(n - 1));
1191+ m->minBlepArray[i] = SINC(a + (r * (b - a)));
1192+ m->minBlepDerivArray[i] = 0;
1193+ }
1194+
1195+ // Window Sinc
1196+
1197+ BlackmanWindow(n, m->minBlepDerivArray);
1198+ for(i = 0; i < n; i++)
1199+ m->minBlepArray[i] *= m->minBlepDerivArray[i];
1200+
1201+ // Minimum Phase Reconstruction
1202+
1203+ RealCepstrum(n, m->minBlepArray, m->minBlepDerivArray);
1204+ MinimumPhase(n, m->minBlepDerivArray, m->minBlepArray);
1205+
1206+ // Integrate Into MinBLEP
1207+ a = 0.0f;
1208+ float secondInt = 0.0f;
1209+ for(i = 0; i < n; i++)
1210+ {
1211+ a += m->minBlepArray[i];
1212+ m->minBlepArray[i] = a;
1213+
1214+ secondInt += a;
1215+ m->minBlepDerivArray[i] = secondInt;
1216+ }
1217+
1218+ // Normalize
1219+ a = m->minBlepArray[n - 1];
1220+ a = 1.0f / a;
1221+ b = 0.0f;
1222+ for(i = 0; i < n; i++)
1223+ {
1224+ m->minBlepArray[i] *= a;
1225+ b = fmaxf(b, m->minBlepDerivArray[i]);
1226+ }
1227+
1228+ // Normalize ...
1229+ b = 1.0f/b;
1230+ for (i = 0; i < n; i++)
1231+ {
1232+ m->minBlepDerivArray[i] *= b;
1233+ m->minBlepDerivArray[i] -= ((float)i) / ((float) n-1);
1234+
1235+ // SUBTRACT 1 and invert so the signal (so it goes 1->0)
1236+ m->minBlepArray[i] -= 1.0f;
1237+ m->minBlepArray[i] = -m->minBlepArray[i];
1238+ }
1239+}
1240+
1241+void tMinBLEP_addBLEP (tMinBLEP* const minblep, float offset, float posChange, float velChange)
1242+{
1243+ _tMinBLEP* m = *minblep;
1244+
1245+ int n = m->minBlepSize;
1246+
1247+ m->offset[m->blepIndex] = offset;
1248+// m->freqMultiple[m->blepIndex] = m->overSamplingRatio*m->proportionalBlepFreq;
1249+ m->pos_change_magnitude[m->blepIndex] = posChange;
1250+ m->vel_change_magnitude[m->blepIndex] = velChange;
1251+
1252+ m->blepIndex++;
1253+ if (m->blepIndex >= n) m->blepIndex = 0;
1254+
1255+ m->numActiveBleps++;
1256+}
1257+
1258+float tMinBLEP_tick (tMinBLEP* const minblep, float input)
1259+{
1260+ _tMinBLEP* m = *minblep;
1261+ // PROCESS ALL BLEPS -
1262+ /// for each offset, copy a portion of the blep array to the output ....
1263+
1264+ float sample = input;
1265+
1266+ int n = m->minBlepSize;
1267+
1268+ for (int blep = 1; blep <= m->numActiveBleps; blep++)
1269+ {
1270+ int i = (m->blepIndex - blep + n) % n;
1271+ float adjusted_Freq = m->overSamplingRatio*m->proportionalBlepFreq;//m->freqMultiple[i];
1272+ float exactPosition = m->offset[i];
1273+
1274+ float blepPosExact = adjusted_Freq*(exactPosition + 1); // +1 because this needs to trigger on the LOW SAMPLE
1275+ float blepPosSample = 0;
1276+ float fraction = modff(blepPosExact, &blepPosSample);
1277+
1278+ // LIMIT the scaling on the derivative array
1279+ // otherwise, it can get TOO large
1280+ float depthLimited = m->proportionalBlepFreq; //jlimit<double>(.1, 1, proportionalBlepFreq);
1281+ float blepDeriv_PosExact = depthLimited*m->overSamplingRatio*(exactPosition + 1);
1282+ float blepDeriv_Sample = 0;
1283+ float fraction_Deriv = modff(blepDeriv_PosExact, &blepDeriv_Sample);
1284+
1285+
1286+ // DONE ... we reached the end ...
1287+ if (((int) blepPosExact > n) && ((int) blepDeriv_PosExact > n))
1288+ break;
1289+
1290+ // BLEP has not yet occurred ...
1291+ if (blepPosExact < 0)
1292+ continue;
1293+
1294+
1295+ // 0TH ORDER COMPENSATION ::::
1296+ /// add the BLEP to compensate for discontinuties in the POSITION
1297+ if ( fabs(m->pos_change_magnitude[i]) > 0 && blepPosSample < n)
1298+ {
1299+ // LINEAR INTERPOLATION ::::
1300+ float lowValue = m->minBlepArray[(int) blepPosSample];
1301+ float hiValue = lowValue;
1302+
1303+ if ((int) blepPosSample + 1 < n)
1304+ hiValue = m->minBlepArray[(int) blepPosSample + 1];
1305+
1306+ float delta = hiValue - lowValue;
1307+ float exactValue = lowValue + fraction*delta;
1308+
1309+ // SCALE by the discontinuity magnitude
1310+ exactValue *= m->pos_change_magnitude[i];
1311+
1312+ // ADD to the thruput
1313+ sample += exactValue;
1314+ }
1315+
1316+
1317+ // 1ST ORDER COMPENSATION ::::
1318+ /// add the BLEP DERIVATIVE to compensate for discontinuties in the VELOCITY
1319+ if ( fabs(m->vel_change_magnitude[i]) > 0 && blepDeriv_PosExact < n)
1320+ {
1321+
1322+ // LINEAR INTERPOLATION ::::
1323+ double lowValue = m->minBlepDerivArray[(int) blepDeriv_PosExact];
1324+ double hiValue = lowValue;
1325+
1326+ if ((int) blepDeriv_PosExact + 1 < n)
1327+ hiValue = m->minBlepDerivArray[(int) blepDeriv_PosExact + 1];
1328+
1329+ double delta = hiValue - lowValue;
1330+ double exactValue = lowValue + fraction_Deriv*delta;
1331+
1332+ // SCALE by the discontinuity magnitude`
1333+ exactValue *= m->vel_change_magnitude[i];
1334+
1335+ // ADD to the thruput
1336+ sample += exactValue;
1337+
1338+ }
1339+
1340+ // UPDATE ::::
1341+ m->offset[i] += 1.0f;
1342+ if (m->offset[i] * adjusted_Freq > n)
1343+ {
1344+ m->numActiveBleps--;
1345+ }
1346+ }
1347+ return sample;
1348+}
1349+
1350+//==============================================================================
1351+
1352+/* tMBTriangle: Anti-aliased Triangle waveform. */
1353+void tMBTriangle_init (tMBTriangle* const osc)
1354+{
1355+ tMBTriangle_initToPool(osc, &leaf.mempool);
1356+}
1357+
1358+void tMBTriangle_free (tMBTriangle* const osc)
1359+{
1360+ tMBTriangle_freeFromPool(osc, &leaf.mempool);
1361+}
1362+
1363+void tMBTriangle_initToPool (tMBTriangle* const osc, tMempool* const mp)
1364+{
1365+ _tMempool* m = *mp;
1366+ _tMBTriangle* c = *osc = (_tMBTriangle*) mpool_alloc(sizeof(_tMBTriangle), m);
1367+
1368+ c->inc = 0.0f;
1369+ c->phase = 0.0f;
1370+ c->skew = 0.5f;
1371+ c->lastOut = 0.0f;
1372+
1373+ tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
1374+ tHighpass_initToPool(&c->dcBlock, 5.0f, mp);
1375+}
1376+
1377+void tMBTriangle_freeFromPool (tMBTriangle* const cy, tMempool* const mp)
1378+{
1379+ _tMempool* m = *mp;
1380+ _tMBTriangle* c = *cy;
1381+
1382+ tMinBLEP_freeFromPool(&c->minBlep, mp);
1383+ tHighpass_freeFromPool(&c->dcBlock, mp);
1384+
1385+ mpool_free((char*)c, m);
1386+}
1387+
1388+float tMBTriangle_tick (tMBTriangle* const osc)
1389+{
1390+ _tMBTriangle* c = *osc;
1391+
1392+ float out;
1393+
1394+ c->phase += c->inc;
1395+ if (c->phase >= 1.0f)
1396+ {
1397+ c->phase -= 1.0f;
1398+ float offset = 1.0f - ((c->inc - c->phase) / c->inc);
1399+ tMinBLEP_addBLEP(&c->minBlep, offset, -2, 0.0f);
1400+ }
1401+ if (c->skew <= c->phase && c->phase < c->skew + c->inc)
1402+ {
1403+ float offset = 1.0f - ((c->inc - c->phase + c->skew) / c->inc);
1404+ tMinBLEP_addBLEP(&c->minBlep, offset, 2, 0.0f);
1405+ }
1406+
1407+ if (c->phase < c->skew)
1408+ {
1409+ out = (1.0f - c->skew) * 2.0f;
1410+ }
1411+ else
1412+ {
1413+ out = -c->skew * 2.0f;
1414+ }
1415+
1416+ out = tMinBLEP_tick(&c->minBlep, out);// - phasor->inc * 2.0f;
1417+
1418+ out = (c->inc * out) + ((1 - c->inc) * c->lastOut);
1419+ c->lastOut = out;
1420+
1421+ return tHighpass_tick(&c->dcBlock, out * 4.0f);
1422+
1423+// float offset;
1424+// float vel = 2;
1425+// c->phase += c->inc;
1426+// if (c->phase >= 1.0f)
1427+// {
1428+// c->phase -= 1.0f;
1429+// offset = 1.0f - ((c->inc - c->phase) / c->inc);
1430+// tMinBLEP_addBLEP(&c->minBlep, offset, 0.0f, -vel);
1431+// }
1432+// if (c->skew <= c->phase && c->phase < c->skew + c->inc)
1433+// {
1434+// offset = 1.0f - ((c->inc - c->phase + c->skew) / c->inc);
1435+// tMinBLEP_addBLEP(&c->minBlep, offset, 0.0f, vel);
1436+// }
1437+//
1438+// float out;
1439+// if (c->phase < c->skew) out = 1.0f - (c->phase / c->skew);
1440+// else out = (c->phase - c->skew) / (1 - c->skew);
1441+//
1442+// out = (out - 0.5f) * 2.0f;
1443+//
1444+//// return tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));
1445+// return tMinBLEP_tick(&c->minBlep, out);
1446+}
1447+
1448+void tMBTriangle_setFreq (tMBTriangle* const osc, float freq)
1449+{
1450+ _tMBTriangle* c = *osc;
1451+
1452+ c->freq = freq;
1453+ c->inc = freq * leaf.invSampleRate;
1454+
1455+// tHighpass_setFreq(&c->dcBlock, freq*0.5);
1456+}
1457+
1458+void tMBTriangle_setSkew (tMBTriangle* const osc, float skew)
1459+{
1460+ _tMBTriangle* c = *osc;
1461+ c->skew = (skew + 1.0f) * 0.5f;
1462+}
1463+
1464+void tMBTriangle_sync (tMBTriangle* const osc, float phase)
1465+{
1466+ _tMBTriangle* c = *osc;
1467+
1468+ phase += 0.5f;
1469+
1470+ int intPart = (int) phase;
1471+ phase = phase - (float) intPart;
1472+
1473+ float before, after;
1474+
1475+ if (c->phase < c->skew) before = (1.0f - c->skew - c->phase) * 2.0f;
1476+ else before = -(c->skew - c->phase) * 2.0f;
1477+
1478+ if (phase < c->skew) after = (1.0f - c->skew - c->phase) * 2.0f;
1479+ else after = -(c->skew - c->phase) * 2.0f;
1480+
1481+ c->phase = phase;
1482+
1483+ float offset = 0.0f;//1.0f - ((c->inc - c->phase) / c->inc);
1484+ tMinBLEP_addBLEP(&c->minBlep, offset, before - after, 0.0f);
1485+
1486+ if (c->phase < c->skew) c->lastOut = 1.0f - (c->phase / c->skew);
1487+ else c->lastOut = (c->phase - c->skew) / (1.0f - c->skew);
1488+}
1489+
1490+//==============================================================================
1491+
1492+/* tMBPulse: Anti-aliased pulse waveform. */
1493+void tMBPulse_init (tMBPulse* const osc)
1494+{
1495+ tMBPulse_initToPool(osc, &leaf.mempool);
1496+}
1497+
1498+void tMBPulse_free (tMBPulse* const osc)
1499+{
1500+ tMBPulse_freeFromPool(osc, &leaf.mempool);
1501+}
1502+
1503+void tMBPulse_initToPool (tMBPulse* const osc, tMempool* const mp)
1504+{
1505+ _tMempool* m = *mp;
1506+ _tMBPulse* c = *osc = (_tMBPulse*) mpool_alloc(sizeof(_tMBPulse), m);
1507+
1508+ c->inc = 0.0f;
1509+ c->phase = 0.0f;
1510+ c->width = 0.5f;
1511+
1512+ tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
1513+ tHighpass_initToPool(&c->dcBlock, 10.0f, mp);
1514+}
1515+
1516+void tMBPulse_freeFromPool(tMBPulse* const osc, tMempool* const mp)
1517+{
1518+ _tMempool* m = *mp;
1519+ _tMBPulse* c = *osc;
1520+
1521+ tMinBLEP_freeFromPool(&c->minBlep, mp);
1522+ tHighpass_freeFromPool(&c->dcBlock, mp);
1523+
1524+ mpool_free((char*)c, m);
1525+}
1526+
1527+float tMBPulse_tick (tMBPulse* const osc)
1528+{
1529+ _tMBPulse* c = *osc;
1530+
1531+
1532+
1533+ c->phase += c->inc;
1534+ if (c->phase >= 1.0f)
1535+ {
1536+ c->phase -= 1.0f;
1537+ float offset = 1.0f - ((c->inc - c->phase) / c->inc);
1538+ tMinBLEP_addBLEP(&c->minBlep, offset, -2.0f, 0.0f);
1539+ }
1540+ if (c->width <= c->phase && c->phase < c->width + c->inc)
1541+ {
1542+ float offset = 1.0f - ((c->inc - c->phase + c->width) / c->inc);
1543+ tMinBLEP_addBLEP(&c->minBlep, offset, 2.0f, 0.0f);
1544+ }
1545+
1546+ float out;
1547+ if (c->phase < c->width) out = 1.0f;
1548+ else out = -1.0f;
1549+
1550+ return tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));
1551+}
1552+
1553+void tMBPulse_setFreq (tMBPulse* const osc, float freq)
1554+{
1555+ _tMBPulse* c = *osc;
1556+
1557+ c->freq = freq;
1558+ c->inc = freq * leaf.invSampleRate;
1559+}
1560+
1561+void tMBPulse_setWidth (tMBPulse* const osc, float width)
1562+{
1563+ _tMBPulse* c = *osc;
1564+ c->width = width;
1565+}
1566+
1567+void tMBPulse_sync (tMBPulse* const osc, float phase)
1568+{
1569+ _tMBPulse* c = *osc;
1570+ int intPart = (int) phase;
1571+ phase = phase - (float) intPart;
1572+
1573+ float before, after;
1574+
1575+ if (c->phase < c->width) before = 1.0f;
1576+ else before = -1.0f;
1577+
1578+ if (phase < c->width) after = 1.0;
1579+ else after = -1.0f;
1580+
1581+ float offset = 0.0f;//1.0f - ((c->inc - c->phase) / c->inc);
1582+ tMinBLEP_addBLEP(&c->minBlep, offset, before - after, 0.0f);
1583+
1584+ c->phase = phase;
1585+}
1586+
1587+
1588+//==============================================================================
1589+
1590+/* tMBSawtooth: Anti-aliased Sawtooth waveform. */
1591+void tMBSaw_init (tMBSaw* const osc)
1592+{
1593+ tMBSaw_initToPool(osc, &leaf.mempool);
1594+}
1595+
1596+void tMBSaw_free (tMBSaw* const osc)
1597+{
1598+ tMBSaw_freeFromPool(osc, &leaf.mempool);
1599+}
1600+
1601+void tMBSaw_initToPool (tMBSaw* const osc, tMempool* const mp)
1602+{
1603+ _tMempool* m = *mp;
1604+ _tMBSaw* c = *osc = (_tMBSaw*) mpool_alloc(sizeof(_tMBSaw), m);
1605+
1606+ c->inc = 0.0f;
1607+ c->phase = 0.0f;
1608+
1609+ tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
1610+ tHighpass_initToPool(&c->dcBlock, 10.0f, mp);
1611+}
1612+
1613+void tMBSaw_freeFromPool (tMBSaw* const osc, tMempool* const mp)
1614+{
1615+ _tMempool* m = *mp;
1616+ _tMBSaw* c = *osc;
1617+
1618+ tMinBLEP_freeFromPool(&c->minBlep, mp);
1619+ tHighpass_freeFromPool(&c->dcBlock, mp);
1620+
1621+ mpool_free((char*)c, m);
1622+}
1623+
1624+float tMBSaw_tick (tMBSaw* const osc)
1625+{
1626+ _tMBSaw* c = *osc;
1627+
1628+ c->phase += c->inc;
1629+ if (c->phase >= 1.0f)
1630+ {
1631+ c->phase -= 1.0f;
1632+ float offset = 1.0f - ((c->inc - c->phase) / c->inc);
1633+ tMinBLEP_addBLEP(&c->minBlep, offset, 2.0f, 0.0f);
1634+ }
1635+
1636+ float out = (c->phase * 2.0f) - 1.0f;
1637+
1638+ return tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));
1639+}
1640+
1641+void tMBSaw_setFreq (tMBSaw* const osc, float freq)
1642+{
1643+ _tMBSaw* c = *osc;
1644+
1645+ c->freq = freq;
1646+
1647+ c->inc = freq * leaf.invSampleRate;
1648+}
1649+
1650+void tMBSaw_sync (tMBSaw* const osc, float phase)
1651+{
1652+ _tMBSaw* c = *osc;
1653+ int intPart = (int) phase;
1654+ phase = phase - (float) intPart;
1655+
1656+ float offset = 0.0f;//1.0f - ((c->inc - phase +) / c->inc);
1657+ tMinBLEP_addBLEP(&c->minBlep, offset, (c->phase - phase) * 2.0f, 0.0f);
1658+
1659+ c->phase = phase;
1660+}
leaf/Src/leaf-physical.c+747−0
@@ -0,0 +1,747 @@
1+/*==============================================================================
2+
3+ leaf-string.c
4+ Created: 30 Nov 2018 10:41:42am
5+ Author: airship
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-physical.h"
12+
13+#else
14+
15+#include "../Inc/leaf-physical.h"
16+
17+#endif
18+
19+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tPluck ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
20+void tPluck_init (tPluck* const pl, float lowestFrequency)
21+{
22+ tPluck_initToPool(pl, lowestFrequency, &leaf.mempool);
23+}
24+
25+void tPluck_free (tPluck* const pl)
26+{
27+ tPluck_freeFromPool(pl, &leaf.mempool);
28+}
29+
30+void tPluck_initToPool (tPluck* const pl, float lowestFrequency, tMempool* const mp)
31+{
32+ _tMempool* m = *mp;
33+ _tPluck* p = *pl = (_tPluck*) mpool_alloc(sizeof(_tPluck), m);
34+
35+ if ( lowestFrequency <= 0.0f ) lowestFrequency = 10.0f;
36+
37+ tNoise_initToPool(&p->noise, WhiteNoise, mp);
38+
39+ tOnePole_initToPool(&p->pickFilter, 0.0f, mp);
40+
41+ tOneZero_initToPool(&p->loopFilter, 0.0f, mp);
42+
43+ tAllpassDelay_initToPool(&p->delayLine, 0.0f, leaf.sampleRate * 2, mp);
44+ tAllpassDelay_clear(&p->delayLine);
45+
46+ tPluck_setFrequency(pl, 220.0f);
47+}
48+
49+void tPluck_freeFromPool (tPluck* const pl, tMempool* const mp)
50+{
51+ _tMempool* m = *mp;
52+ _tPluck* p = *pl;
53+
54+ tNoise_freeFromPool(&p->noise, mp);
55+ tOnePole_freeFromPool(&p->pickFilter, mp);
56+ tOneZero_freeFromPool(&p->loopFilter, mp);
57+ tAllpassDelay_freeFromPool(&p->delayLine, mp);
58+
59+ mpool_free((char*)p, m);
60+}
61+
62+float tPluck_getLastOut (tPluck* const pl)
63+{
64+ _tPluck* p = *pl;
65+ return p->lastOut;
66+}
67+
68+float tPluck_tick (tPluck* const pl)
69+{
70+ _tPluck* p = *pl;
71+ return (p->lastOut = 3.0f * tAllpassDelay_tick(&p->delayLine, tOneZero_tick(&p->loopFilter, tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain ) ));
72+}
73+
74+void tPluck_pluck (tPluck* const pl, float amplitude)
75+{
76+ _tPluck* p = *pl;
77+
78+ if ( amplitude < 0.0f) amplitude = 0.0f;
79+ else if (amplitude > 1.0f) amplitude = 1.0f;
80+
81+ tOnePole_setPole(&p->pickFilter, 0.999f - (amplitude * 0.15f));
82+ tOnePole_setGain(&p->pickFilter, amplitude * 0.5f );
83+
84+ // Fill delay with noise additively with current contents.
85+ for ( uint32_t i = 0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ )
86+ tAllpassDelay_tick(&p->delayLine, 0.6f * tAllpassDelay_getLastOut(&p->delayLine) + tOnePole_tick(&p->pickFilter, tNoise_tick(&p->noise) ) );
87+}
88+
89+// Start a note with the given frequency and amplitude.;
90+void tPluck_noteOn (tPluck* const pl, float frequency, float amplitude )
91+{
92+ _tPluck* p = *pl;
93+ p->lastFreq = frequency;
94+ tPluck_setFrequency( pl, frequency );
95+ tPluck_pluck( pl, amplitude );
96+}
97+
98+// Stop a note with the given amplitude (speed of decay).
99+void tPluck_noteOff (tPluck* const pl, float amplitude )
100+{
101+ _tPluck* p = *pl;
102+
103+ if ( amplitude < 0.0f) amplitude = 0.0f;
104+ else if (amplitude > 1.0f) amplitude = 1.0f;
105+
106+ p->loopGain = 1.0f - amplitude;
107+}
108+
109+// Set instrument parameters for a particular frequency.
110+void tPluck_setFrequency (tPluck* const pl, float frequency )
111+{
112+ _tPluck* p = *pl;
113+
114+ if ( frequency <= 0.0f ) frequency = 0.001f;
115+
116+ // Delay = length - filter delay.
117+ float delay = ( leaf.sampleRate / frequency ) - tOneZero_getPhaseDelay(&p->loopFilter, frequency );
118+
119+ tAllpassDelay_setDelay(&p->delayLine, delay );
120+
121+ p->loopGain = 0.99f + (frequency * 0.000005f);
122+
123+ if ( p->loopGain >= 0.999f ) p->loopGain = 0.999f;
124+
125+}
126+
127+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
128+void tPluck_controlChange (tPluck* const pl, int number, float value)
129+{
130+ return;
131+}
132+
133+void tPluckSampleRateChanged(tPluck* const pl)
134+{
135+ _tPluck* p = *pl;
136+ tPluck_setFrequency(pl, p->lastFreq);
137+}
138+
139+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tKarplusStrong ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
140+void tKarplusStrong_init (tKarplusStrong* const pl, float lowestFrequency)
141+{
142+ tKarplusStrong_initToPool(pl, lowestFrequency, &leaf.mempool);
143+}
144+
145+void tKarplusStrong_free (tKarplusStrong* const pl)
146+{
147+ tKarplusStrong_freeFromPool(pl, &leaf.mempool);
148+}
149+
150+void tKarplusStrong_initToPool (tKarplusStrong* const pl, float lowestFrequency, tMempool* const mp)
151+{
152+ _tMempool* m = *mp;
153+ _tKarplusStrong* p = *pl = (_tKarplusStrong*) mpool_alloc(sizeof(_tKarplusStrong), m);
154+
155+ if ( lowestFrequency <= 0.0f ) lowestFrequency = 8.0f;
156+
157+ tAllpassDelay_initToPool(&p->delayLine, 0.0f, leaf.sampleRate * 2, mp);
158+ tAllpassDelay_clear(&p->delayLine);
159+
160+ tLinearDelay_initToPool(&p->combDelay, 0.0f, leaf.sampleRate * 2, mp);
161+ tLinearDelay_clear(&p->combDelay);
162+
163+ tOneZero_initToPool(&p->filter, 0.0f, mp);
164+
165+ tNoise_initToPool(&p->noise, WhiteNoise, mp);
166+
167+ for (int i = 0; i < 4; i++)
168+ {
169+ tBiQuad_initToPool(&p->biquad[i], mp);
170+ }
171+
172+ p->pluckAmplitude = 0.3f;
173+ p->pickupPosition = 0.4f;
174+
175+ p->stretching = 0.9999f;
176+ p->baseLoopGain = 0.995f;
177+ p->loopGain = 0.999f;
178+
179+ tKarplusStrong_setFrequency( pl, 220.0f );
180+}
181+
182+void tKarplusStrong_freeFromPool (tKarplusStrong* const pl, tMempool* const mp)
183+{
184+ _tMempool* m = *mp;
185+ _tKarplusStrong* p = *pl;
186+
187+ tAllpassDelay_freeFromPool(&p->delayLine, mp);
188+ tLinearDelay_freeFromPool(&p->combDelay, mp);
189+ tOneZero_freeFromPool(&p->filter, mp);
190+ tNoise_freeFromPool(&p->noise, mp);
191+
192+ for (int i = 0; i < 4; i++)
193+ {
194+ tBiQuad_freeFromPool(&p->biquad[i], mp);
195+ }
196+
197+ mpool_free((char*)p, m);
198+}
199+
200+float tKarplusStrong_getLastOut (tKarplusStrong* const pl)
201+{
202+ _tKarplusStrong* p = *pl;
203+ return p->lastOut;
204+}
205+
206+float tKarplusStrong_tick (tKarplusStrong* const pl)
207+{
208+ _tKarplusStrong* p = *pl;
209+
210+ float temp = tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain;
211+
212+ // Calculate allpass stretching.
213+ for (int i=0; i<4; i++) temp = tBiQuad_tick(&p->biquad[i],temp);
214+
215+ // Moving average filter.
216+ temp = tOneZero_tick(&p->filter, temp);
217+
218+ float out = tAllpassDelay_tick(&p->delayLine, temp);
219+ out = out - tLinearDelay_tick(&p->combDelay, out);
220+ p->lastOut = out;
221+
222+ return p->lastOut;
223+}
224+
225+void tKarplusStrong_pluck (tKarplusStrong* const pl, float amplitude)
226+{
227+ _tKarplusStrong* p = *pl;
228+
229+ if ( amplitude < 0.0f) amplitude = 0.0f;
230+ else if (amplitude > 1.0f) amplitude = 1.0f;
231+
232+ p->pluckAmplitude = amplitude;
233+
234+ for ( uint32_t i=0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ )
235+ {
236+ // Fill delay with noise additively with current contents.
237+ tAllpassDelay_tick(&p->delayLine, (tAllpassDelay_getLastOut(&p->delayLine) * 0.6f) + 0.4f * tNoise_tick(&p->noise) * p->pluckAmplitude );
238+ //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) );
239+ }
240+}
241+
242+// Start a note with the given frequency and amplitude.;
243+void tKarplusStrong_noteOn (tKarplusStrong* const pl, float frequency, float amplitude )
244+{
245+ tKarplusStrong_setFrequency( pl, frequency );
246+ tKarplusStrong_pluck( pl, amplitude );
247+}
248+
249+// Stop a note with the given amplitude (speed of decay).
250+void tKarplusStrong_noteOff (tKarplusStrong* const pl, float amplitude )
251+{
252+ _tKarplusStrong* p = *pl;
253+
254+ if ( amplitude < 0.0f) amplitude = 0.0f;
255+ else if (amplitude > 1.0f) amplitude = 1.0f;
256+
257+ p->loopGain = 1.0f - amplitude;
258+}
259+
260+// Set instrument parameters for a particular frequency.
261+void tKarplusStrong_setFrequency (tKarplusStrong* const pl, float frequency )
262+{
263+ _tKarplusStrong* p = *pl;
264+
265+ if ( frequency <= 0.0f ) frequency = 0.001f;
266+
267+ p->lastFrequency = frequency;
268+ p->lastLength = leaf.sampleRate / p->lastFrequency;
269+ float delay = p->lastLength - 0.5f;
270+ tAllpassDelay_setDelay(&p->delayLine, delay);
271+
272+ // MAYBE MODIFY LOOP GAINS
273+ p->loopGain = p->baseLoopGain + (frequency * 0.000005f);
274+ if (p->loopGain >= 1.0f) p->loopGain = 0.99999f;
275+
276+ tKarplusStrong_setStretch(pl, p->stretching);
277+
278+ tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength );
279+
280+}
281+
282+// Set the stretch "factor" of the string (0.0 - 1.0).
283+void tKarplusStrong_setStretch (tKarplusStrong* const pl, float stretch )
284+{
285+ _tKarplusStrong* p = *pl;
286+
287+ p->stretching = stretch;
288+ float coefficient;
289+ float freq = p->lastFrequency * 2.0f;
290+ float dFreq = ( (0.5f * leaf.sampleRate) - freq ) * 0.25f;
291+ float temp = 0.5f + (stretch * 0.5f);
292+ if ( temp > 0.9999f ) temp = 0.9999f;
293+
294+ for ( int i=0; i<4; i++ )
295+ {
296+ coefficient = temp * temp;
297+ tBiQuad_setA2(&p->biquad[i], coefficient);
298+ tBiQuad_setB0(&p->biquad[i], coefficient);
299+ tBiQuad_setB2(&p->biquad[i], 1.0f);
300+
301+ coefficient = -2.0f * temp * cos(TWO_PI * freq / leaf.sampleRate);
302+ tBiQuad_setA1(&p->biquad[i], coefficient);
303+ tBiQuad_setB1(&p->biquad[i], coefficient);
304+
305+ freq += dFreq;
306+ }
307+}
308+
309+// Set the pluck or "excitation" position along the string (0.0 - 1.0).
310+void tKarplusStrong_setPickupPosition (tKarplusStrong* const pl, float position )
311+{
312+ _tKarplusStrong* p = *pl;
313+
314+ if (position < 0.0f) p->pickupPosition = 0.0f;
315+ else if (position <= 1.0f) p->pickupPosition = position;
316+ else p->pickupPosition = 1.0f;
317+
318+ tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength);
319+}
320+
321+// Set the base loop gain.
322+void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const pl, float aGain )
323+{
324+ _tKarplusStrong* p = *pl;
325+
326+ p->baseLoopGain = aGain;
327+ p->loopGain = p->baseLoopGain + (p->lastFrequency * 0.000005f);
328+ if ( p->loopGain > 0.99999f ) p->loopGain = 0.99999f;
329+}
330+
331+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
332+void tKarplusStrong_controlChange (tKarplusStrong* const pl, SKControlType type, float value)
333+{
334+ if ( value < 0.0f ) value = 0.0f;
335+ else if (value > 128.0f) value = 128.0f;
336+
337+ float normalizedValue = value * INV_128;
338+
339+ if (type == SKPickPosition) // 4
340+ tKarplusStrong_setPickupPosition( pl, normalizedValue );
341+ else if (type == SKStringDamping) // 11
342+ tKarplusStrong_setBaseLoopGain( pl, 0.97f + (normalizedValue * 0.03f) );
343+ else if (type == SKDetune) // 1
344+ tKarplusStrong_setStretch( pl, 0.91f + (0.09f * (1.0f - normalizedValue)) );
345+}
346+
347+void tKarplusStrongSampleRateChanged (tKarplusStrong* const pl)
348+{
349+ _tKarplusStrong* p = *pl;
350+
351+ tKarplusStrong_setFrequency(pl, p->lastFrequency);
352+ tKarplusStrong_setStretch(pl, p->stretching);
353+}
354+
355+/* Simple Living String*/
356+
357+void tSimpleLivingString_init(tSimpleLivingString* const pl, float freq, float dampFreq,
358+ float decay, float targetLev, float levSmoothFactor,
359+ float levStrength, int levMode)
360+{
361+ tSimpleLivingString_initToPool(pl, freq, dampFreq, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf.mempool);
362+}
363+
364+void tSimpleLivingString_free(tSimpleLivingString* const pl)
365+{
366+ tSimpleLivingString_freeFromPool(pl, &leaf.mempool);
367+}
368+
369+void tSimpleLivingString_initToPool (tSimpleLivingString* const pl, float freq, float dampFreq,
370+ float decay, float targetLev, float levSmoothFactor,
371+ float levStrength, int levMode, tMempool* const mp)
372+{
373+ _tMempool* m = *mp;
374+ _tSimpleLivingString* p = *pl = (_tSimpleLivingString*) mpool_alloc(sizeof(_tSimpleLivingString), m);
375+
376+ p->curr=0.0f;
377+ tExpSmooth_initToPool(&p->wlSmooth, leaf.sampleRate/freq, 0.01, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
378+ tSimpleLivingString_setFreq(pl, freq);
379+ tLinearDelay_initToPool(&p->delayLine,p->waveLengthInSamples, 2400, mp);
380+ tLinearDelay_clear(&p->delayLine);
381+ tOnePole_initToPool(&p->bridgeFilter, dampFreq, mp);
382+ tHighpass_initToPool(&p->DCblocker,13, mp);
383+ p->decay=decay;
384+ tFeedbackLeveler_initToPool(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode, mp);
385+ p->levMode=levMode;
386+}
387+
388+void tSimpleLivingString_freeFromPool (tSimpleLivingString* const pl, tMempool* const mp)
389+{
390+ _tMempool* m = *mp;
391+ _tSimpleLivingString* p = *pl;
392+
393+ tExpSmooth_freeFromPool(&p->wlSmooth, mp);
394+ tLinearDelay_freeFromPool(&p->delayLine, mp);
395+ tOnePole_freeFromPool(&p->bridgeFilter, mp);
396+ tHighpass_freeFromPool(&p->DCblocker, mp);
397+ tFeedbackLeveler_freeFromPool(&p->fbLev, mp);
398+
399+ mpool_free((char*)p, m);
400+}
401+
402+void tSimpleLivingString_setFreq(tSimpleLivingString* const pl, float freq)
403+{
404+ _tSimpleLivingString* p = *pl;
405+
406+ if (freq<20) freq=20;
407+ else if (freq>10000) freq=10000;
408+ p->waveLengthInSamples = leaf.sampleRate/freq;
409+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
410+}
411+
412+void tSimpleLivingString_setWaveLength(tSimpleLivingString* const pl, float waveLength)
413+{
414+ _tSimpleLivingString* p = *pl;
415+
416+ if (waveLength<4.8) waveLength=4.8;
417+ else if (waveLength>2400) waveLength=2400;
418+ p->waveLengthInSamples = waveLength;
419+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
420+}
421+
422+void tSimpleLivingString_setDampFreq(tSimpleLivingString* const pl, float dampFreq)
423+{
424+ _tSimpleLivingString* p = *pl;
425+ tOnePole_setFreq(&p->bridgeFilter, dampFreq);
426+}
427+
428+void tSimpleLivingString_setDecay(tSimpleLivingString* const pl, float decay)
429+{
430+ _tSimpleLivingString* p = *pl;
431+ p->decay=decay;
432+}
433+
434+void tSimpleLivingString_setTargetLev(tSimpleLivingString* const pl, float targetLev)
435+{
436+ _tSimpleLivingString* p = *pl;
437+ tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev);
438+}
439+
440+void tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const pl, float levSmoothFactor)
441+{
442+ _tSimpleLivingString* p = *pl;
443+ tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor);
444+}
445+
446+void tSimpleLivingString_setLevStrength(tSimpleLivingString* const pl, float levStrength)
447+{
448+ _tSimpleLivingString* p = *pl;
449+ tFeedbackLeveler_setStrength(&p->fbLev, levStrength);
450+}
451+
452+void tSimpleLivingString_setLevMode(tSimpleLivingString* const pl, int levMode)
453+{
454+ _tSimpleLivingString* p = *pl;
455+ tFeedbackLeveler_setMode(&p->fbLev, levMode);
456+ p->levMode=levMode;
457+}
458+
459+float tSimpleLivingString_tick(tSimpleLivingString* const pl, float input)
460+{
461+ _tSimpleLivingString* p = *pl;
462+
463+ float stringOut=tOnePole_tick(&p->bridgeFilter,tLinearDelay_tickOut(&p->delayLine));
464+ float stringInput=tHighpass_tick(&p->DCblocker, tFeedbackLeveler_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input));
465+ tLinearDelay_tickIn(&p->delayLine, stringInput);
466+ tLinearDelay_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth));
467+ p->curr = stringOut;
468+ return p->curr;
469+}
470+
471+float tSimpleLivingString_sample(tSimpleLivingString* const pl)
472+{
473+ _tSimpleLivingString* p = *pl;
474+ return p->curr;
475+}
476+
477+/* Living String*/
478+
479+void tLivingString_init(tLivingString* const pl, float freq, float pickPos, float prepIndex,
480+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
481+ float levStrength, int levMode)
482+{
483+ tLivingString_initToPool(pl, freq, pickPos, prepIndex, dampFreq, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf.mempool);
484+}
485+
486+void tLivingString_free(tLivingString* const pl)
487+{
488+ tLivingString_freeFromPool(pl, &leaf.mempool);
489+}
490+
491+void tLivingString_initToPool (tLivingString* const pl, float freq, float pickPos, float prepIndex,
492+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
493+ float levStrength, int levMode, tMempool* const mp)
494+{
495+ _tMempool* m = *mp;
496+ _tLivingString* p = *pl = (_tLivingString*) mpool_alloc(sizeof(_tLivingString), m);
497+
498+ p->curr=0.0f;
499+ tExpSmooth_initToPool(&p->wlSmooth, leaf.sampleRate/freq, 0.01, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
500+ tLivingString_setFreq(pl, freq);
501+ p->freq = freq;
502+ tExpSmooth_initToPool(&p->ppSmooth, pickPos, 0.01, mp); // smoother for pick position
503+ tLivingString_setPickPos(pl, pickPos);
504+ p->prepIndex=prepIndex;
505+ tLinearDelay_initToPool(&p->delLF,p->waveLengthInSamples, 2400, mp);
506+ tLinearDelay_initToPool(&p->delUF,p->waveLengthInSamples, 2400, mp);
507+ tLinearDelay_initToPool(&p->delUB,p->waveLengthInSamples, 2400, mp);
508+ tLinearDelay_initToPool(&p->delLB,p->waveLengthInSamples, 2400, mp);
509+ tLinearDelay_clear(&p->delLF);
510+ tLinearDelay_clear(&p->delUF);
511+ tLinearDelay_clear(&p->delUB);
512+ tLinearDelay_clear(&p->delLB);
513+ p->dampFreq = dampFreq;
514+ tOnePole_initToPool(&p->bridgeFilter, dampFreq, mp);
515+ tOnePole_initToPool(&p->nutFilter, dampFreq, mp);
516+ tOnePole_initToPool(&p->prepFilterU, dampFreq, mp);
517+ tOnePole_initToPool(&p->prepFilterL, dampFreq, mp);
518+ tHighpass_initToPool(&p->DCblockerU,13, mp);
519+ tHighpass_initToPool(&p->DCblockerL,13, mp);
520+ p->decay=decay;
521+ p->prepIndex = prepIndex;
522+ tFeedbackLeveler_initToPool(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode, mp);
523+ tFeedbackLeveler_initToPool(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode, mp);
524+ p->levMode=levMode;
525+}
526+
527+void tLivingString_freeFromPool (tLivingString* const pl, tMempool* const mp)
528+{
529+ _tMempool* m = *mp;
530+ _tLivingString* p = *pl;
531+
532+ tExpSmooth_freeFromPool(&p->wlSmooth, mp);
533+ tExpSmooth_freeFromPool(&p->ppSmooth, mp);
534+ tLinearDelay_freeFromPool(&p->delLF, mp);
535+ tLinearDelay_freeFromPool(&p->delUF, mp);
536+ tLinearDelay_freeFromPool(&p->delUB, mp);
537+ tLinearDelay_freeFromPool(&p->delLB, mp);
538+ tOnePole_freeFromPool(&p->bridgeFilter, mp);
539+ tOnePole_freeFromPool(&p->nutFilter, mp);
540+ tOnePole_freeFromPool(&p->prepFilterU, mp);
541+ tOnePole_freeFromPool(&p->prepFilterL, mp);
542+ tHighpass_freeFromPool(&p->DCblockerU, mp);
543+ tHighpass_freeFromPool(&p->DCblockerL, mp);
544+ tFeedbackLeveler_freeFromPool(&p->fbLevU, mp);
545+ tFeedbackLeveler_freeFromPool(&p->fbLevL, mp);
546+
547+ mpool_free((char*)p, m);
548+}
549+
550+void tLivingString_setFreq(tLivingString* const pl, float freq)
551+{ // NOTE: It is faster to set wavelength in samples directly
552+ _tLivingString* p = *pl;
553+ if (freq<20) freq=20;
554+ else if (freq>10000) freq=10000;
555+ p->waveLengthInSamples = leaf.sampleRate/freq;
556+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
557+}
558+
559+void tLivingString_setWaveLength(tLivingString* const pl, float waveLength)
560+{
561+ _tLivingString* p = *pl;
562+ if (waveLength<4.8) waveLength=4.8;
563+ else if (waveLength>2400) waveLength=2400;
564+ p->waveLengthInSamples = waveLength;
565+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
566+}
567+
568+void tLivingString_setPickPos(tLivingString* const pl, float pickPos)
569+{ // between 0 and 1
570+ _tLivingString* p = *pl;
571+ if (pickPos<0.f) pickPos=0.f;
572+ else if (pickPos>1.f) pickPos=1.f;
573+ p->pickPos = pickPos;
574+ tExpSmooth_setDest(&p->ppSmooth, p->pickPos);
575+}
576+
577+void tLivingString_setPrepIndex(tLivingString* const pl, float prepIndex)
578+{ // between 0 and 1
579+ _tLivingString* p = *pl;
580+ if (prepIndex<0.f) prepIndex=0.f;
581+ else if (prepIndex>1.f) prepIndex=1.f;
582+ p->prepIndex = prepIndex;
583+}
584+
585+void tLivingString_setDampFreq(tLivingString* const pl, float dampFreq)
586+{
587+ _tLivingString* p = *pl;
588+ tOnePole_setFreq(&p->bridgeFilter, dampFreq);
589+ tOnePole_setFreq(&p->nutFilter, dampFreq);
590+ tOnePole_setFreq(&p->prepFilterU, dampFreq);
591+ tOnePole_setFreq(&p->prepFilterL, dampFreq);
592+}
593+
594+void tLivingString_setDecay(tLivingString* const pl, float decay)
595+{
596+ _tLivingString* p = *pl;
597+ p->decay=decay;
598+}
599+
600+void tLivingString_setTargetLev(tLivingString* const pl, float targetLev)
601+{
602+ _tLivingString* p = *pl;
603+ tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev);
604+ tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev);
605+}
606+
607+void tLivingString_setLevSmoothFactor(tLivingString* const pl, float levSmoothFactor)
608+{
609+ _tLivingString* p = *pl;
610+ tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor);
611+ tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor);
612+}
613+
614+void tLivingString_setLevStrength(tLivingString* const pl, float levStrength)
615+{
616+ _tLivingString* p = *pl;
617+ tFeedbackLeveler_setStrength(&p->fbLevU, levStrength);
618+ tFeedbackLeveler_setStrength(&p->fbLevL, levStrength);
619+}
620+
621+void tLivingString_setLevMode(tLivingString* const pl, int levMode)
622+{
623+ _tLivingString* p = *pl;
624+ tFeedbackLeveler_setMode(&p->fbLevU, levMode);
625+ tFeedbackLeveler_setMode(&p->fbLevL, levMode);
626+ p->levMode=levMode;
627+}
628+
629+float tLivingString_tick(tLivingString* const pl, float input)
630+{
631+ _tLivingString* p = *pl;
632+
633+ // from pickPos upwards=forwards
634+ float fromLF=tLinearDelay_tickOut(&p->delLF);
635+ float fromUF=tLinearDelay_tickOut(&p->delUF);
636+ float fromUB=tLinearDelay_tickOut(&p->delUB);
637+ float fromLB=tLinearDelay_tickOut(&p->delLB);
638+ // into upper half of string, from nut, going backwards
639+ float fromNut=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF)));
640+ tLinearDelay_tickIn(&p->delUB, fromNut);
641+ // into lower half of string, from pickpoint, going backwards
642+ float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF);
643+ float intoLower=p->prepIndex*fromLowerPrep+(1.0f - p->prepIndex)*fromUB+input;
644+ tLinearDelay_tickIn(&p->delLB, intoLower);
645+ // into lower half of string, from bridge
646+ float fromBridge=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1.0f)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB)));
647+ tLinearDelay_tickIn(&p->delLF, fromBridge);
648+ // into upper half of string, from pickpoint, going forwards/upwards
649+ float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB);
650+ float intoUpper=p->prepIndex*fromUpperPrep+(1.0f - p->prepIndex)*fromLF+input;
651+ tLinearDelay_tickIn(&p->delUF, intoUpper);
652+ // update all delay lengths
653+ float pickP=tExpSmooth_tick(&p->ppSmooth);
654+ float wLen=tExpSmooth_tick(&p->wlSmooth);
655+ float lowLen=pickP*wLen;
656+ float upLen=(1.0f-pickP)*wLen;
657+ tLinearDelay_setDelay(&p->delLF, lowLen);
658+ tLinearDelay_setDelay(&p->delLB, lowLen);
659+ tLinearDelay_setDelay(&p->delUF, upLen);
660+ tLinearDelay_setDelay(&p->delUB, upLen);
661+ p->curr = fromBridge;
662+ return p->curr;
663+}
664+
665+float tLivingString_sample(tLivingString* const pl)
666+{
667+ _tLivingString* p = *pl;
668+ return p->curr;
669+}
670+
671+///Reed Table model
672+//default values from STK are 0.6 offset and -0.8 slope
673+
674+void tReedTable_init (tReedTable* const pm, float offset, float slope)
675+{
676+ _tReedTable* p = *pm = (_tReedTable*) leaf_alloc(sizeof(_tReedTable));
677+
678+ p->offset = offset;
679+ p->slope = slope;
680+}
681+
682+void tReedTable_free (tReedTable* const pm)
683+{
684+ _tReedTable* p = *pm;
685+
686+ leaf_free((char*)p);
687+}
688+
689+void tReedTable_initToPool (tReedTable* const pm, float offset, float slope, tMempool* const mp)
690+{
691+ _tMempool* m = *mp;
692+ _tReedTable* p = *pm = (_tReedTable*) mpool_alloc(sizeof(_tReedTable), m);
693+
694+ p->offset = offset;
695+ p->slope = slope;
696+}
697+
698+void tReedTable_freeFromPool (tReedTable* const pm, tMempool* const mp)
699+{
700+ _tMempool* m = *mp;
701+ _tReedTable* p = *pm;
702+
703+ mpool_free((char*)p, m);
704+}
705+
706+float tReedTable_tick (tReedTable* const pm, float input)
707+{
708+ _tReedTable* p = *pm;
709+
710+ // The input is differential pressure across the reed.
711+ float output = p->offset + (p->slope * input);
712+
713+ // If output is > 1, the reed has slammed shut and the
714+ // reflection function value saturates at 1.0.
715+ if ( output > 1.0f) output = 1.0f;
716+
717+ // This is nearly impossible in a physical system, but
718+ // a reflection function value of -1.0 corresponds to
719+ // an open end (and no discontinuity in bore profile).
720+ if ( output < -1.0f) output = -1.0f;
721+
722+ return output;
723+}
724+
725+float tReedTable_tanh_tick (tReedTable* const pm, float input)
726+{
727+ _tReedTable* p = *pm;
728+
729+ // The input is differential pressure across the reed.
730+ float output = p->offset + (p->slope * input);
731+
732+ // If output is > 1, the reed has slammed shut and the
733+ // reflection function value saturates at 1.0.
734+ return tanhf(output);
735+}
736+
737+void tReedTable_setOffset (tReedTable* const pm, float offset)
738+{
739+ _tReedTable* p = *pm;
740+ p->offset = offset;
741+}
742+
743+void tReedTable_setSlope (tReedTable* const pm, float slope)
744+{
745+ _tReedTable* p = *pm;
746+ p->slope = slope;
747+}
leaf/Src/leaf-reverb.c+925−0
@@ -0,0 +1,925 @@
1+/*==============================================================================
2+
3+ leaf-reverb.c
4+ Created: 20 Jan 2017 12:02:04pm
5+ Author: Michael R Mulshine
6+
7+==============================================================================*/
8+
9+#if _WIN32 || _WIN64
10+
11+#include "..\Inc\leaf-reverb.h"
12+#include "..\leaf.h"
13+
14+#else
15+
16+#include "../Inc/leaf-reverb.h"
17+#include "../leaf.h"
18+
19+#endif
20+
21+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
22+void tPRCReverb_init(tPRCReverb* const rev, float t60)
23+{
24+ _tPRCReverb* r = *rev = (_tPRCReverb*) leaf_alloc(sizeof(_tPRCReverb));
25+
26+ if (t60 <= 0.0f) t60 = 0.001f;
27+
28+ r->inv_441 = 1.0f/44100.0f;
29+
30+ int lengths[4] = { 341, 613, 1557, 2137 }; // Delay lengths for 44100 Hz sample rate.
31+ double scaler = leaf.sampleRate * r->inv_441;
32+
33+ int delay, i;
34+ if (scaler != 1.0f)
35+ {
36+ for (i=0; i<4; i++)
37+ {
38+ delay = (int) scaler * lengths[i];
39+
40+ if ( (delay & 1) == 0) delay++;
41+
42+ while ( !LEAF_isPrime(delay) ) delay += 2;
43+
44+ lengths[i] = delay;
45+ }
46+ }
47+
48+ tDelay_init(&r->allpassDelays[0], lengths[0], lengths[0] * 2);
49+ tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2);
50+ tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2);
51+
52+ tPRCReverb_setT60(rev, t60);
53+
54+ r->allpassCoeff = 0.7f;
55+ r->mix = 0.5f;
56+}
57+
58+void tPRCReverb_free(tPRCReverb* const rev)
59+{
60+ _tPRCReverb* r = *rev;
61+
62+ tDelay_free(&r->allpassDelays[0]);
63+ tDelay_free(&r->allpassDelays[1]);
64+ tDelay_free(&r->combDelay);
65+ leaf_free((char*)r);
66+}
67+
68+void tPRCReverb_initToPool (tPRCReverb* const rev, float t60, tMempool* const mp)
69+{
70+ _tMempool* m = *mp;
71+ _tPRCReverb* r = *rev = (_tPRCReverb*) mpool_alloc(sizeof(_tPRCReverb), m);
72+
73+ if (t60 <= 0.0f) t60 = 0.001f;
74+
75+ r->inv_441 = 1.0f/44100.0f;
76+
77+ int lengths[4] = { 341, 613, 1557, 2137 }; // Delay lengths for 44100 Hz sample rate.
78+ double scaler = leaf.sampleRate * r->inv_441;
79+
80+ int delay, i;
81+ if (scaler != 1.0f)
82+ {
83+ for (i=0; i<4; i++)
84+ {
85+ delay = (int) scaler * lengths[i];
86+
87+ if ( (delay & 1) == 0) delay++;
88+
89+ while ( !LEAF_isPrime(delay) ) delay += 2;
90+
91+ lengths[i] = delay;
92+ }
93+ }
94+
95+ tDelay_initToPool(&r->allpassDelays[0], lengths[0], lengths[0] * 2, mp);
96+ tDelay_initToPool(&r->allpassDelays[1], lengths[1], lengths[1] * 2, mp);
97+ tDelay_initToPool(&r->combDelay, lengths[2], lengths[2] * 2, mp);
98+
99+ tPRCReverb_setT60(rev, t60);
100+
101+ r->allpassCoeff = 0.7f;
102+ r->mix = 0.5f;
103+}
104+
105+void tPRCReverb_freeFromPool (tPRCReverb* const rev, tMempool* const mp)
106+{
107+ _tMempool* m = *mp;
108+ _tPRCReverb* r = *rev;
109+
110+ tDelay_freeFromPool(&r->allpassDelays[0], mp);
111+ tDelay_freeFromPool(&r->allpassDelays[1], mp);
112+ tDelay_freeFromPool(&r->combDelay, mp);
113+ mpool_free((char*)r, m);
114+}
115+
116+void tPRCRevert_clear(tPRCReverb* const rev)
117+{
118+ _tPRCReverb* r = *rev;
119+
120+ tDelay_clear(&r->allpassDelays[0]);
121+ tDelay_clear(&r->allpassDelays[1]);
122+ tDelay_clear(&r->combDelay);
123+}
124+
125+void tPRCReverb_setT60(tPRCReverb* const rev, float t60)
126+{
127+ _tPRCReverb* r = *rev;
128+
129+ if ( t60 <= 0.0f ) t60 = 0.001f;
130+
131+ r->t60 = t60;
132+
133+ r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / t60 ));
134+
135+}
136+
137+void tPRCReverb_setMix(tPRCReverb* const rev, float mix)
138+{
139+ _tPRCReverb* r = *rev;
140+ r->mix = mix;
141+}
142+
143+float tPRCReverb_tick(tPRCReverb* const rev, float input)
144+{
145+ _tPRCReverb* r = *rev;
146+
147+ float temp, temp0, temp1, temp2;
148+ float out;
149+
150+ r->lastIn = input;
151+
152+ temp = tDelay_getLastOut(&r->allpassDelays[0]);
153+ temp0 = r->allpassCoeff * temp;
154+ temp0 += input;
155+ tDelay_tick(&r->allpassDelays[0], temp0);
156+ temp0 = -( r->allpassCoeff * temp0) + temp;
157+
158+ temp = tDelay_getLastOut(&r->allpassDelays[1]);
159+ temp1 = r->allpassCoeff * temp;
160+ temp1 += temp0;
161+ tDelay_tick(&r->allpassDelays[1], temp1);
162+ temp1 = -(r->allpassCoeff * temp1) + temp;
163+
164+ temp2 = temp1 + ( r->combCoeff * tDelay_getLastOut(&r->combDelay));
165+
166+ out = r->mix * tDelay_tick(&r->combDelay, temp2);
167+
168+ temp = (1.0f - r->mix) * input;
169+
170+ out += temp;
171+
172+ r->lastOut = out;
173+
174+ return out;
175+}
176+
177+void tPRCReverbSampleRateChanged (tPRCReverb* const rev)
178+{
179+ _tPRCReverb* r = *rev;
180+ r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 ));
181+}
182+
183+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
184+void tNReverb_init(tNReverb* const rev, float t60)
185+{
186+ _tNReverb* r = *rev = (_tNReverb*) leaf_alloc(sizeof(_tNReverb));
187+
188+ if (t60 <= 0.0f) t60 = 0.001f;
189+
190+ r->inv_441 = 1.0f/44100.0f;
191+
192+ int lengths[15] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 53, 43, 37, 29, 19}; // Delay lengths for 44100 Hz sample rate.
193+ double scaler = leaf.sampleRate / 25641.0f;
194+
195+ int delay, i;
196+
197+ for (i=0; i < 15; i++)
198+ {
199+ delay = (int) scaler * lengths[i];
200+ if ( (delay & 1) == 0)
201+ delay++;
202+ while ( !LEAF_isPrime(delay) )
203+ delay += 2;
204+ lengths[i] = delay;
205+ }
206+
207+ for ( i=0; i<6; i++ )
208+ {
209+ tLinearDelay_init(&r->combDelays[i], lengths[i], lengths[i] * 2.0f);
210+ tLinearDelay_clear(&r->combDelays[i]);
211+ r->combCoeffs[i] = pow(10.0, (-3 * lengths[i] * leaf.invSampleRate / t60));
212+ }
213+
214+ for ( i=0; i<8; i++ )
215+ {
216+ tLinearDelay_init(&r->allpassDelays[i], lengths[i+6], lengths[i+6] * 2.0f);
217+ tLinearDelay_clear(&r->allpassDelays[i]);
218+ }
219+
220+
221+ tNReverb_setT60(rev, t60);
222+ r->allpassCoeff = 0.7f;
223+ r->mix = 0.3f;
224+}
225+
226+void tNReverb_free(tNReverb* const rev)
227+{
228+ _tNReverb* r = *rev;
229+
230+ for (int i = 0; i < 6; i++)
231+ {
232+ tLinearDelay_free(&r->combDelays[i]);
233+ }
234+
235+ for (int i = 0; i < 8; i++)
236+ {
237+ tLinearDelay_free(&r->allpassDelays[i]);
238+ }
239+
240+ leaf_free((char*)r);
241+}
242+
243+void tNReverb_initToPool (tNReverb* const rev, float t60, tMempool* const mp)
244+{
245+ _tMempool* m = *mp;
246+ _tNReverb* r = *rev = (_tNReverb*) mpool_alloc(sizeof(_tNReverb), m);
247+
248+ if (t60 <= 0.0f) t60 = 0.001f;
249+
250+ r->inv_441 = 1.0f/44100.0f;
251+
252+ int lengths[15] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 53, 43, 37, 29, 19}; // Delay lengths for 44100 Hz sample rate.

673 more lines aren’t shown here.

leaf/Src/leaf-sampling.c+866−0

This diff is large: its 867 lines aren’t shown here.

leaf/Src/leaf-tables.c+14061−0

This diff is large: its 14062 lines aren’t shown here.

leaf/Src/leaf.c+60−0

This diff is large: its 61 lines aren’t shown here.

leaf/leaf.cpp+45−0

This diff is large: its 46 lines aren’t shown here.

leaf/leaf.h+154−0

This diff is large: its 155 lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t