Unified · Split
Binary file not shown.
| @@ -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 | ||
Binary file not shown.
| @@ -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 | } | ||
| @@ -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_ */ | ||
| @@ -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 | ||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | //============================================================================== | ||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | //============================================================================== | ||
| @@ -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 | //============================================================================== | ||
| @@ -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 | } | ||
| @@ -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 | |||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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 | } | ||
| @@ -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.
This diff is large: its 867 lines aren’t shown here.
This diff is large: its 14062 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.