@grame/faustwasm 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/standalone/faust-ui/index.js +0 -2
- package/assets/standalone/faust-ui/index.js.map +1 -1
- package/dist/cjs-bundle/index.js +1 -1
- package/dist/esm-bundle/index.js +1 -1
- package/libfaust-wasm/libfaust-wasm.wasm +0 -0
- package/package.json +2 -2
- package/test/compost_library.lib +630 -0
- package/test/compost_networks.dsp +104 -0
- package/test/faustlive-wasm/faust-ui/index.js +0 -2
- package/test/faustlive-wasm/faust-ui/index.js.map +1 -1
- package/test/prime_numbers.dsp +198 -0
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grame/faustwasm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"description": "WebAssembly version of Faust Compiler",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"homepage": "https://github.com/grame-cncm/faustwasm#readme",
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@aws-crypto/sha256-js": "^2.0.1",
|
|
37
|
-
"@shren/faust-ui": "^1.1.
|
|
37
|
+
"@shren/faust-ui": "^1.1.5",
|
|
38
38
|
"@types/emscripten": "^1.39.5",
|
|
39
39
|
"@types/node": "^16.11.7",
|
|
40
40
|
"@types/webmidi": "^2.0.6",
|
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
declare name "WKR Compost Library";
|
|
2
|
+
declare author "Luca Spanedda";
|
|
3
|
+
declare author "Dario Sanfilippo";
|
|
4
|
+
declare version "1.0";
|
|
5
|
+
declare description "2023";
|
|
6
|
+
declare copyright "Copyright (C) 2023 Luca Spanedda <lucaspanedda1995@gmail.com>";
|
|
7
|
+
declare license "MIT license";
|
|
8
|
+
// Import the standard Faust Libraries
|
|
9
|
+
import("stdfaust.lib");
|
|
10
|
+
// Import Lists
|
|
11
|
+
primes = component("prime_numbers.dsp").primes;
|
|
12
|
+
primesThousands = component("prime_numbers.dsp").primesThousands;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/************************************************************************
|
|
16
|
+
************************************************************************
|
|
17
|
+
- BASIC -
|
|
18
|
+
************************************************************************
|
|
19
|
+
************************************************************************/
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// constants values
|
|
23
|
+
PI = ma.PI;
|
|
24
|
+
TWOPI = 2.0 * PI;
|
|
25
|
+
SR = ma.SR;
|
|
26
|
+
EPS = ma.EPSILON;
|
|
27
|
+
NY = SR / 2.0;
|
|
28
|
+
T = 1.0 / SR;
|
|
29
|
+
PIT = PI * T;
|
|
30
|
+
TWOPIT = TWOPI * T;
|
|
31
|
+
MS2T(t) = (t / 1000) * ma.SR;
|
|
32
|
+
|
|
33
|
+
// limit function for library and system
|
|
34
|
+
limit(maxl, minl, x) = max(minl, min(maxl, x));
|
|
35
|
+
|
|
36
|
+
info(i, lower, upper) =
|
|
37
|
+
_ <: _, vbargraph(" %i [style:numerical]", lower, upper) : attach;
|
|
38
|
+
infoScale(i, lower, upper) =
|
|
39
|
+
_ <: _, (_ * 1000 : vbargraph(" %i [style:numerical]", lower * 1000, upper * 1000)) : attach;
|
|
40
|
+
|
|
41
|
+
// binary selector 0 - 1
|
|
42
|
+
selector(sel, x, y) = ( x * (1 - sel) + y * (sel) );
|
|
43
|
+
|
|
44
|
+
// index of the primes numbers
|
|
45
|
+
primeNumbers(index) = ba.take(index , list)
|
|
46
|
+
with{
|
|
47
|
+
list = primes;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
/************************************************************************
|
|
52
|
+
************************************************************************
|
|
53
|
+
- MAPPING -
|
|
54
|
+
************************************************************************
|
|
55
|
+
************************************************************************/
|
|
56
|
+
|
|
57
|
+
// bipolar -1/+1 to unipolar 0/1
|
|
58
|
+
biToUni(x) = (x + 1) / 2;
|
|
59
|
+
|
|
60
|
+
// accept 0/1
|
|
61
|
+
map(minL, maxL, x) = x * (maxL - minL) + minL;
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/************************************************************************
|
|
65
|
+
************************************************************************
|
|
66
|
+
- SIGNALS GENERATION -
|
|
67
|
+
************************************************************************
|
|
68
|
+
************************************************************************/
|
|
69
|
+
|
|
70
|
+
// pseudo-random noise with linear congruential generator (LCG)
|
|
71
|
+
noise(initSeed) = LCG ~ _ : (_ / m)
|
|
72
|
+
with{
|
|
73
|
+
// initSeed = an initial seed value
|
|
74
|
+
a = 18446744073709551557; // a large prime number,
|
|
75
|
+
// such as 18446744073709551557
|
|
76
|
+
c = 12345; // a small prime number, such as 12345
|
|
77
|
+
m = 2 ^ 31; // 2.1 billion
|
|
78
|
+
// linear_congruential_generator
|
|
79
|
+
LCG(seed) = ((a * seed + c) + (initSeed - initSeed') % m);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
multinoise(N) = par(i, N, noise(ba.take(i + 1, primes)));
|
|
83
|
+
|
|
84
|
+
// Letrec Phasor
|
|
85
|
+
phasorLetrec(f) = Xn
|
|
86
|
+
letrec{
|
|
87
|
+
'Xn = (Xn + (f / ma.SR)) : frac;
|
|
88
|
+
}
|
|
89
|
+
with{
|
|
90
|
+
frac(x) = x-floor(x);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
/************************************************************************
|
|
95
|
+
************************************************************************
|
|
96
|
+
- FILTERS -
|
|
97
|
+
************************************************************************
|
|
98
|
+
************************************************************************/
|
|
99
|
+
|
|
100
|
+
//--------------------------------------------- ONEZERO FILTER (FIR of I° Order)
|
|
101
|
+
// (g) = give amplitude 0-1(open-close) to the delayed signal
|
|
102
|
+
// (g) = +1 lowpass, (g) = -1 highpass
|
|
103
|
+
ozf(g, x) = (x' * g), x :> +;
|
|
104
|
+
|
|
105
|
+
//--------------------------------------- ONEPOLE FILTER (IIR of 1 sample delay)
|
|
106
|
+
// only the pole section
|
|
107
|
+
pole(g) = + ~ * (g);
|
|
108
|
+
|
|
109
|
+
//--------------------------------------------------------------- ALLPASS FILTER
|
|
110
|
+
// (t, g) = give: delay in samples, feedback gain 0-1
|
|
111
|
+
apf(del, g, x) = x : (+ : _ <: @(del - 1), *(g))~ *(-g) : mem, _ : + : _;
|
|
112
|
+
|
|
113
|
+
// APF Time Variant
|
|
114
|
+
sdelay(maxDelay, interpolationLen, delayLen, x) =
|
|
115
|
+
loop ~ si.bus(4) : (! , ! , ! , ! , _)
|
|
116
|
+
with {
|
|
117
|
+
loop(lineState, incrState, lowerDelayState, upperDelayState) =
|
|
118
|
+
line , incr , lowerDelay , upperDelay , output
|
|
119
|
+
with {
|
|
120
|
+
lowerReach = lineState == 0;
|
|
121
|
+
upperReach = lineState == 1;
|
|
122
|
+
lowerDelayChange = delayLen != lowerDelayState;
|
|
123
|
+
upperDelayChange = delayLen != upperDelayState;
|
|
124
|
+
incr = ba.if( upperReach & upperDelayChange,
|
|
125
|
+
-1.0 / interpolationLen,
|
|
126
|
+
ba.if( lowerReach & lowerDelayChange),
|
|
127
|
+
1.0 / interpolationLen,
|
|
128
|
+
incrState);
|
|
129
|
+
line = max(.0, min(1.0, lineState + incr));
|
|
130
|
+
lowerDelay = ba.if(upperReach, delayLen, lowerDelayState);
|
|
131
|
+
upperDelay = ba.if(lowerReach, delayLen, upperDelayState);
|
|
132
|
+
lowerDelayline = de.delay(maxDelay, lowerDelay, x) * (1.0 - line);
|
|
133
|
+
upperDelayline = de.delay(maxDelay, upperDelay, x) * line;
|
|
134
|
+
output = lowerDelayline + upperDelayline;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
allpassWerner(maxDel, intTime, del, g, x) = (loop : sdelay(maxDel, intTime, del - 1)) ~ _ : mem * D_g + x * g
|
|
139
|
+
with {
|
|
140
|
+
D_g = sqrt(1 - g * g);
|
|
141
|
+
loop(fb) = x * D_g - g * fb;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
AllpassWernerCascade(M, maxDel, intTime, d, g, x) = x : seq(i, M, allpassWerner(maxDel, intTime, d * (sqrt((i + 1) / M) - sqrt(i / M)), g));
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
//---------------------------------------------------------------------- SVF TPT
|
|
148
|
+
// SVFTPT filter function
|
|
149
|
+
// TPT version of the SVF Filter by Vadim Zavalishin
|
|
150
|
+
// reference : (by Will Pirkle)
|
|
151
|
+
// http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.2.0.pdf
|
|
152
|
+
SVFTPT(Q, cf, x) = loop ~ si.bus(2) : (! , ! , _ , _ , _ , _ , _)
|
|
153
|
+
with {
|
|
154
|
+
g = tan(cf * ma.PI * ma.T);
|
|
155
|
+
R = 1.0 / (2.0 * Q);
|
|
156
|
+
G1 = 1.0 / (1.0 + 2.0 * R * g + g * g);
|
|
157
|
+
G2 = 2.0 * R + g;
|
|
158
|
+
loop(s1, s2) = u1 , u2 , lp , hp , bp * 2.0 * R , x - bp * 4.0 * R , bp
|
|
159
|
+
with {
|
|
160
|
+
hp = (x - s1 * G2 - s2) * G1;
|
|
161
|
+
v1 = hp * g;
|
|
162
|
+
bp = s1 + v1;
|
|
163
|
+
v2 = bp * g;
|
|
164
|
+
lp = s2 + v2;
|
|
165
|
+
u1 = v1 + bp;
|
|
166
|
+
u2 = v2 + lp;
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
LPSVF(Q, cf, x) = SVFTPT(Q, cf, x) : (_ , ! , ! , ! , !);
|
|
171
|
+
|
|
172
|
+
HPSVF(Q, cf, x) = SVFTPT(Q, cf, x) : (! , _ , ! , ! , !);
|
|
173
|
+
|
|
174
|
+
BPSVF(Q, cf, x) = SVFTPT(Q, limit(20000, 20, cf), x) : (! , ! , _ , ! , !);
|
|
175
|
+
|
|
176
|
+
NotchSVF(Q, cf, x) = x - BPSVF(Q, limit(20000, 20, cf), x);
|
|
177
|
+
|
|
178
|
+
APSVF(Q, cf, x) = SVFTPT(Q, cf, x) : (! , ! , ! , _ , !);
|
|
179
|
+
|
|
180
|
+
PeakingSVF(Q, cf, x) = LPSVF(Q, cf, x) - HPSVF(Q, cf, x);
|
|
181
|
+
|
|
182
|
+
BP2SVF(Q, cf, x) = SVFTPT(Q, cf, x) : (! , ! , ! , ! , _);
|
|
183
|
+
|
|
184
|
+
BPBWSVF(BW, CF, x) = BPSVF(limit(20000, minimum, (CF / BW)), CF, x);
|
|
185
|
+
|
|
186
|
+
// Zavalishin's SVF BP FILTER
|
|
187
|
+
// optimized BP from the TPT version of the SVF Filter by Vadim Zavalishin
|
|
188
|
+
// reference : (by Will Pirkle)
|
|
189
|
+
// http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.2.0.pdf
|
|
190
|
+
BPSVFTPT(glin, bw, cf, x) = loop ~ si.bus(2) : (! , ! , _)
|
|
191
|
+
with {
|
|
192
|
+
g = tan(cf * ma.PI * (1.0/ma.SR));
|
|
193
|
+
Q = cf / max(EPS, bw);
|
|
194
|
+
R = 1.0 / (Q + Q);
|
|
195
|
+
G = 1.0 / (1.0 + 2.0 * R * g + g * g);
|
|
196
|
+
loop(s1, s2) = u1 , u2 , bp * glin
|
|
197
|
+
with {
|
|
198
|
+
bp = (g * (x - s2) + s1) * G;
|
|
199
|
+
bp2 = bp + bp;
|
|
200
|
+
v2 = bp2 * g;
|
|
201
|
+
u1 = bp2 - s1;
|
|
202
|
+
u2 = v2 + s2;
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
//------------------------------------------------------------------ ONEPOLE TPT
|
|
207
|
+
// Zavalishin Onepole TPT Filter
|
|
208
|
+
// TPT version of the One-Pole Filter by Vadim Zavalishin
|
|
209
|
+
// reference : (by Will Pirkle)
|
|
210
|
+
// http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.2.0.pdf
|
|
211
|
+
onePoleTPT(cf, x) = loop ~ _ : ! , si.bus(3)
|
|
212
|
+
with {
|
|
213
|
+
g = tan(cf * ma.PI * ma.T);
|
|
214
|
+
G = g / (1.0 + g);
|
|
215
|
+
loop(s) = u , lp , hp , ap
|
|
216
|
+
with {
|
|
217
|
+
v = (x - s) * G; u = v + lp; lp = v + s; hp = x - lp; ap = lp - hp;
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Lowpass TPT
|
|
222
|
+
LPTPT(cf, x) = onePoleTPT(cf, x) : (_ , ! , !);
|
|
223
|
+
|
|
224
|
+
// Highpass TPT
|
|
225
|
+
HPTPT(cf, x) = onePoleTPT(cf, x) : (! , _ , !);
|
|
226
|
+
|
|
227
|
+
// Allpass TPT
|
|
228
|
+
APTPT(cf, x) = onePoleTPT(cf, x) : (!, !, _);
|
|
229
|
+
|
|
230
|
+
//-------------------------------------------------------------- BUTTERWORTH ---
|
|
231
|
+
butterworthQ(order, stage) = qFactor(order % 2)
|
|
232
|
+
with {
|
|
233
|
+
qFactor(0) = 1.0 / (2.0 * cos(((2.0 * stage + 1) *
|
|
234
|
+
(ma.PI / (order * 2.0)))));
|
|
235
|
+
qFactor(1) = 1.0 / (2.0 * cos(((stage + 1) * (ma.PI / order))));
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
LPButterworthN(1, cf, x) = LPTPT(cf, x);
|
|
239
|
+
LPButterworthN(N, cf, x) = cascade(N % 2)
|
|
240
|
+
with {
|
|
241
|
+
cascade(0) = x : seq(i, N / 2, LPSVF(butterworthQ(N, i), cf));
|
|
242
|
+
cascade(1) = x : LPTPT(cf) : seq(i, (N - 1) / 2,
|
|
243
|
+
LPSVF(butterworthQ(N, i), cf));
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
HPButterworthN(1, cf, x) = HPTPT(cf, x);
|
|
247
|
+
HPButterworthN(N, cf, x) = cascade(N % 2)
|
|
248
|
+
with {
|
|
249
|
+
cascade(0) = x : seq(i, N / 2, HPSVF(butterworthQ(N, i), cf));
|
|
250
|
+
cascade(1) = x : HPTPT(cf) : seq(i, (N - 1) /
|
|
251
|
+
2, HPSVF(butterworthQ(N, i), cf));
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
//------------------------------------------------------------------- DC BLOCKER
|
|
255
|
+
// https://ccrma.stanford.edu/~jos/fp/DC_Blocker.html
|
|
256
|
+
dcblocker(ozfc, polefc, x) = x : ozf(ozfc) : pole(polefc);
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
/************************************************************************
|
|
260
|
+
************************************************************************
|
|
261
|
+
- AUDIO INFORMATION PROCESSING -
|
|
262
|
+
************************************************************************
|
|
263
|
+
************************************************************************/
|
|
264
|
+
|
|
265
|
+
//----------------------------------------------------------------- MAX PEAK ---
|
|
266
|
+
// references: 1, 2
|
|
267
|
+
// Peak Max with IIR filter and max comparison
|
|
268
|
+
peakmax(x) = loop ~_
|
|
269
|
+
with{
|
|
270
|
+
loop(y) = abs(x) , y : max;
|
|
271
|
+
};
|
|
272
|
+
//process = _ : peakmax;
|
|
273
|
+
|
|
274
|
+
//--------------------------------------------------- MAX PEAK NORMALIZATION ---
|
|
275
|
+
// references: 5
|
|
276
|
+
// Peak Max Normalization
|
|
277
|
+
fixedNorm(x) = 1 / (x : loop ~ _) * x
|
|
278
|
+
with{
|
|
279
|
+
loop(y,z) = ( (y, abs(z) ) : max);
|
|
280
|
+
};
|
|
281
|
+
//process = _ * .2 : fixedNorm;
|
|
282
|
+
|
|
283
|
+
//--------------------------------------------------- PEAK ENVELOPE FOLLOWER ---
|
|
284
|
+
peakenvelope(period, x) = loop ~ _
|
|
285
|
+
with {
|
|
286
|
+
loop(y) = max(abs(x), y * coeff);
|
|
287
|
+
twoPIforT = (2.0 * ma.PI) * (1.0 / ma.SR);
|
|
288
|
+
coeff = exp(-twoPIforT / max(EPS, period));
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Peak envelope. with attack and decay
|
|
292
|
+
peakEnvAttRel(att, rel, x) = peakenvelope(rel - att, x) :
|
|
293
|
+
LPTPT(1.0 / max(EPS, att));
|
|
294
|
+
|
|
295
|
+
//----------------------------------------- MOVING AVERAGE ENVELOPE FOLLOWER ---
|
|
296
|
+
movingAverage(seconds, x) = x - x@(seconds * ma.SR) :
|
|
297
|
+
fi.pole(1.0) / (seconds * ma.SR);
|
|
298
|
+
//process = _ * 10 : movingAverage(1);
|
|
299
|
+
|
|
300
|
+
//------------------------------------------------------- MOVING AVERAGE RMS ---
|
|
301
|
+
movingAverageRMS(seconds, x) = sqrt(max(0, movingAverage(seconds, x ^ 2)));
|
|
302
|
+
//process = movingAverageRMS(1);
|
|
303
|
+
|
|
304
|
+
//-------------------------------------------------------------- PEAK HOLDER ---
|
|
305
|
+
// holdTime in Seconds
|
|
306
|
+
peakHolder(holdTime, x) = loop ~ si.bus(2) : ! , _
|
|
307
|
+
with {
|
|
308
|
+
loop(timerState, outState) = timer , output
|
|
309
|
+
with {
|
|
310
|
+
isNewPeak = abs(x) >= outState;
|
|
311
|
+
isTimeOut = timerState >= (holdTime * ma.SR - 1);
|
|
312
|
+
bypass = isNewPeak | isTimeOut;
|
|
313
|
+
timer = ba.if(bypass, 0, timerState + 1);
|
|
314
|
+
output = ba.if(bypass, abs(x), outState);
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
//----------------------------------------------- ATTACK DECAY - RMS AVERAGE ---
|
|
320
|
+
// references: 3
|
|
321
|
+
RMS(att, rel, x) = loop ~ _ : sqrt
|
|
322
|
+
with {
|
|
323
|
+
loop(y) = (1.0 - coeff) * x * x + coeff * y
|
|
324
|
+
with {
|
|
325
|
+
attCoeff = exp(-2.0 * ma.PI * ma.T / att);
|
|
326
|
+
relCoeff = exp(-2.0 * ma.PI * ma.T / rel);
|
|
327
|
+
coeff = ba.if(abs(x) > y, attCoeff, relCoeff);
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
//--------------------------------------------------------- DYNAMIC LIMITERS ---
|
|
333
|
+
// lookahead limiter with: peakHolder, lowpass & peakenvelope
|
|
334
|
+
// All the credits of the original version goes to Dario Sanfilippo
|
|
335
|
+
LookaheadLimiter(threshold, holdSec, decaySec, x) =
|
|
336
|
+
(x : peakHolder(holdSec) : LPTPT(1/holdSec) : peakenvelope(decaySec)) :
|
|
337
|
+
(min(1, threshold) / max(1, _)) *
|
|
338
|
+
(x @ (holdSec * ma.SR));
|
|
339
|
+
|
|
340
|
+
//------------------------------------------------------ DYNAMIC COMPRESSION ---
|
|
341
|
+
dynamiComp(i, k, att, rel, exponent, x) =
|
|
342
|
+
vgroup("dynaComp %i", (x * scaling) : hgroup("out %i", infoScale(k, -100, 100)))
|
|
343
|
+
with {
|
|
344
|
+
complement(x) = 1.0 - x;
|
|
345
|
+
clipUni(x) = max(0.0, min(1.0, x));
|
|
346
|
+
scaling = ma.tanh(x) : peakEnvAttRel(att, rel) :
|
|
347
|
+
clipUni : complement : pow(exponent : hgroup("exp %i", infoScale(k, -100, 100)));
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
//------------------------------------------------------------ PITCH TRACKER ---
|
|
352
|
+
// averaging function with 2pi time constant; t is the averaging time in seconds
|
|
353
|
+
avg(t, x) = y
|
|
354
|
+
letrec {
|
|
355
|
+
'y = x + alpha * (y - x);
|
|
356
|
+
}
|
|
357
|
+
with {
|
|
358
|
+
alpha = exp((-2.0 * ma.PI * ma.T) / t);
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// zero-crossing indicator function
|
|
362
|
+
zeroCrossing(x) = (x * x') < 0;
|
|
363
|
+
|
|
364
|
+
// zero-crossing rate
|
|
365
|
+
zeroCrossingRate(t, x) = zeroCrossing(x) : avg(t);
|
|
366
|
+
|
|
367
|
+
// pitch tracker as zero-crossing rate of self-regulating lowpassed inputs
|
|
368
|
+
// we highpass the input to avoid infrasonic
|
|
369
|
+
// components to affect the measurements
|
|
370
|
+
// we then clip the lowpass cutoff to improve stability
|
|
371
|
+
pitchTracker(t, x) = loop ~ _
|
|
372
|
+
with {
|
|
373
|
+
loop(y) = fi.lowpass(4, max(80, y), xHighpassed) :
|
|
374
|
+
(zeroCrossingRate(t) * ma.SR * .5)
|
|
375
|
+
with {
|
|
376
|
+
xHighpassed = fi.highpass(1, 20, x);
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// Resonant Frequency Suppressor
|
|
381
|
+
resonKill(bypass, T, Q, x) = out
|
|
382
|
+
with{
|
|
383
|
+
FC = pitchTracker(T, x);
|
|
384
|
+
filter = x - BPSVF(Q, FC, x);
|
|
385
|
+
out = filter * (1 - bypass) + x * bypass;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
//---------------------------------------------------------------- LOCAL MAX ---
|
|
390
|
+
localMax(seconds, x) = loop ~ si.bus(4) : _ , ! , ! , !
|
|
391
|
+
with {
|
|
392
|
+
loop(yState, timerState, peakState, timeInSamplesState) =
|
|
393
|
+
y , timer , peak , timeInSamples
|
|
394
|
+
with {
|
|
395
|
+
timeInSamples = ba.if(reset + 1 - 1', limit(1000, 0, seconds) *
|
|
396
|
+
ma.SR, timeInSamplesState);
|
|
397
|
+
reset = timerState >= (timeInSamplesState - 1);
|
|
398
|
+
timer = ba.if(reset, 1, timerState + 1);
|
|
399
|
+
peak = max(abs(x), peakState * (1.0 - reset));
|
|
400
|
+
y = ba.if(reset, peak', yState);
|
|
401
|
+
};
|
|
402
|
+
};
|
|
403
|
+
// process = localMax(4);
|
|
404
|
+
|
|
405
|
+
//---------------------------------------------------------- SAMPLE AND HOLD ---
|
|
406
|
+
// SAH circuit
|
|
407
|
+
SAH(ph, y) = \(FB).( selector( ph : \(x).(x < x'), FB, y ) )~ _ ;
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
/************************************************************************
|
|
411
|
+
************************************************************************
|
|
412
|
+
- READ & WRITE TABLES -
|
|
413
|
+
************************************************************************
|
|
414
|
+
************************************************************************/
|
|
415
|
+
|
|
416
|
+
//-------------------------------------------- TIMESTRETCHING2 (OLA 2 HEADS) ---
|
|
417
|
+
// Timestretcher - sum of the 2 Head Reads
|
|
418
|
+
// Bufpos = 0 to 1 signals for the reads
|
|
419
|
+
Stretcher(bufferMax, bufferSec, record, readSection, readOffset, readStretch, grainDims, i, jittin, freqShift, x) =
|
|
420
|
+
x <: head1 + head2
|
|
421
|
+
with{
|
|
422
|
+
offset = 2;
|
|
423
|
+
// tableMax = table Max Dimension - 10 Seconds
|
|
424
|
+
tableMax = 192000 * bufferMax + offset;
|
|
425
|
+
frac(x) = x-floor(x);
|
|
426
|
+
// read section
|
|
427
|
+
// stretchFactor - 0 Normal / 1 Extreme stretch (Freeze)
|
|
428
|
+
stretch = phasorLetrec( (1/bufferSec) - readStretch)
|
|
429
|
+
* readSection;
|
|
430
|
+
// Jitter Amount in the position for the reads
|
|
431
|
+
rnd = abs(noise((10667 * i) + 10667));
|
|
432
|
+
jitter = jittin * rnd;
|
|
433
|
+
// position in the Buffer for the Reads
|
|
434
|
+
cntrlRead = (readOffset + stretch) - jitter : frac;
|
|
435
|
+
// L = buffer dimension in seconds
|
|
436
|
+
L = ma.SR * bufferSec;
|
|
437
|
+
// Write index - ramp 0 to L
|
|
438
|
+
wIdx = offset + ((+(1) : %(L)) ~ _) * record : int;
|
|
439
|
+
// <: vgroup("Write", attach(_, _/L : hbargraph(" %i [style:numerical]",0,1)));
|
|
440
|
+
buffer(p, x) = it.frwtable(3, tableMax, .0, wIdx, x, p);
|
|
441
|
+
// Hanning window Equation
|
|
442
|
+
hann(x) = sin(frac(x) * ma.PI) ^ 2.0;
|
|
443
|
+
// Grain in Milliseconds
|
|
444
|
+
grainms = 1 / grainDims : si.smoo;
|
|
445
|
+
// Position of the grain in the Buffer
|
|
446
|
+
bufPos = cntrlRead;
|
|
447
|
+
// <: vgroup("Read", attach(_, _ : hbargraph(" %i [style:numerical]",0,1)));
|
|
448
|
+
timePhase = offset + (bufPos * L);
|
|
449
|
+
// two Heads for the read
|
|
450
|
+
// 0°
|
|
451
|
+
ph1 = phasorLetrec(grainms * freqShift);
|
|
452
|
+
// 180*
|
|
453
|
+
ph2 = ma.frac(.5 + ph1);
|
|
454
|
+
// Buffer positions = Position in the Buffer + Grain Read
|
|
455
|
+
pos1 = SAH(ph1, timePhase) + ph1*(ma.SR/grainms);
|
|
456
|
+
pos2 = SAH(ph2, timePhase) + ph2*(ma.SR/grainms);
|
|
457
|
+
// Windows + Buffer Reads
|
|
458
|
+
head1 = hann(ph1) * buffer(pos1);
|
|
459
|
+
head2 = hann(ph2) * buffer(pos2);
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
/************************************************************************
|
|
464
|
+
************************************************************************
|
|
465
|
+
- NETWORKS -
|
|
466
|
+
************************************************************************
|
|
467
|
+
************************************************************************/
|
|
468
|
+
|
|
469
|
+
//----------------------------------------------------- VECTORIAL OPERATIONS ---
|
|
470
|
+
// perform operations on an arbitrary number of vectors
|
|
471
|
+
vecOp(vectorsList, op) =
|
|
472
|
+
vectorsList : seq(i, vecDim - 1, vecOp2D , vecBus(vecDim - 2 - i))
|
|
473
|
+
with {
|
|
474
|
+
vecBus(0) = par(i, vecLen, 0 : !);
|
|
475
|
+
vecBus(dim) = par(i, dim, si.bus(vecLen));
|
|
476
|
+
vecOp2D = ro.interleave(vecLen, 2) : par(i, vecLen, op);
|
|
477
|
+
vecDim = outputs(vectorsList) / vecLen;
|
|
478
|
+
vecLen = outputs(ba.take(1, vectorsList));
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
//----------------------------------------------------------------- MATRIXES ---
|
|
482
|
+
// vector FDN Matrix
|
|
483
|
+
vecMx(N, list) = si.bus(N) <: par(i, N, (vecOp((si.bus(N), list), *) :> +));
|
|
484
|
+
|
|
485
|
+
vecMatrix(N) = si.bus(N) <: par(i, N, (vecOp((si.bus(N), list(i+1)), *) :> +))
|
|
486
|
+
with{
|
|
487
|
+
list(1) = 1, 0, 0, 0;
|
|
488
|
+
list(2) = 0, 1, 0, 0;
|
|
489
|
+
list(3) = 0, 0, 1, 0;
|
|
490
|
+
list(4) = 0, 0, 0, 1;
|
|
491
|
+
list(5) = 1, 0, 0, 0;
|
|
492
|
+
list(6) = 0, 1, 0, 0;
|
|
493
|
+
list(7) = 0, 0, 1, 0;
|
|
494
|
+
list(8) = 0, 0, 0, 1;
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// fully connected FDN Matrix
|
|
498
|
+
fullyconnectedMx(N) = vecMx(N, par(i, N, 1));
|
|
499
|
+
fullyconnectedMxNormalized(N) = vecMx(N, par(i, N, 1/N));
|
|
500
|
+
|
|
501
|
+
// hadamard FDN Matrix
|
|
502
|
+
butterfly(2) = si.bus(2) <: +, -;
|
|
503
|
+
butterfly(N) = si.bus(N) <: ro.interleave(N/2,2), ro.interleave(N/2,2) : par(i, N/2, +), par(i, N/2, -);
|
|
504
|
+
hadamard(2) = butterfly(2);
|
|
505
|
+
hadamard(N) = butterfly(N) : (hadamard(N/2), hadamard(N/2));
|
|
506
|
+
|
|
507
|
+
// Normalized hadamard FDN Matrix
|
|
508
|
+
hadamardcoeff(N) = par(i, N, 1.0 / sqrt(N));
|
|
509
|
+
hadamardNormalized(N) = vecOp((hadamard(N) , hadamardcoeff(N)), *);
|
|
510
|
+
|
|
511
|
+
//----------------------------------------------------------------- NETWORKS ---
|
|
512
|
+
FDNfullyconnected(N, D, G) = (vecOp((si.bus(N) , si.bus(N)), +) :
|
|
513
|
+
vecOp((si.bus(N), par(i, N, D * ma.SR - 1)), @)) ~
|
|
514
|
+
(fullyconnectedMxNormalized(N));
|
|
515
|
+
|
|
516
|
+
FDNhadamard(N, D, G) = (vecOp((si.bus(N) , si.bus(N)), +) :
|
|
517
|
+
vecOp((si.bus(N), par(i, N, D * ma.SR - 1)), @)) ~
|
|
518
|
+
(hadamardNormalized(N));
|
|
519
|
+
|
|
520
|
+
FDNsingleLoop(N, D, G) = (vecOp((si.bus(N) , si.bus(N)), +) :
|
|
521
|
+
vecOp((si.bus(N), par(i, N, D * ma.SR - 1)), @)) ~ ro.crossNM(N-1, 1);
|
|
522
|
+
|
|
523
|
+
FDNmatrix(N, D, G) = (vecOp((si.bus(N) , si.bus(N)), +) :
|
|
524
|
+
vecOp((si.bus(N), par(i, N, D * ma.SR - 1)), @)) ~ (vectorMatrix(N))
|
|
525
|
+
with{
|
|
526
|
+
vectorMatrix(N) = si.bus(N) <:
|
|
527
|
+
par(i, N, (vecOp((si.bus(N), list(i+1)), *) :> +))
|
|
528
|
+
with{
|
|
529
|
+
list(1) = 1, 0, 0, 0;
|
|
530
|
+
list(2) = 0, 1, 0, 0;
|
|
531
|
+
list(3) = 0, 0, 1, 0;
|
|
532
|
+
list(4) = 0, 0, 0, 1;
|
|
533
|
+
list(5) = 1, 0, 0, 0;
|
|
534
|
+
list(6) = 0, 1, 0, 0;
|
|
535
|
+
list(7) = 0, 0, 1, 0;
|
|
536
|
+
list(8) = 0, 0, 0, 1;
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
/************************************************************************
|
|
542
|
+
************************************************************************
|
|
543
|
+
- NONLINEARITIES -
|
|
544
|
+
************************************************************************
|
|
545
|
+
************************************************************************/
|
|
546
|
+
|
|
547
|
+
//----------------------------------------------------------- NONLINEARITIES ---
|
|
548
|
+
controlSignalProcessing(i, k, exponent, responseTime, x) = vgroup("cntrlSig %i",
|
|
549
|
+
xAverageSign * pow(abs(xAverageNormalisedSaturated) * .9, exponent) : hgroup("cntrl %i", infoScale(k, -1, 1)) :
|
|
550
|
+
os.osc : hgroup("cntrl Osc %i", infoScale(k, -1, 1))
|
|
551
|
+
: SAHDiffInvertion : si.smoo : hgroup("cntrl Sah %i", infoScale(k, -1, 1))
|
|
552
|
+
)
|
|
553
|
+
with {
|
|
554
|
+
xAverage = x : seq(i, 4, LPTPT(1.0 / responseTime));
|
|
555
|
+
xAverageRMS = xAverage * xAverage : seq(i, 4, LPTPT(1.0 / (10.0 * responseTime))) : sqrt;
|
|
556
|
+
xAverageNormalised = xAverage / max(EPS, xAverageRMS);
|
|
557
|
+
xAverageNormalisedSaturated = ma.tanh(xAverageNormalised);
|
|
558
|
+
xAverageSign = ma.signum(xAverage);
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
//------------------------------------------------------- SAH DIFF INVERSION ---
|
|
562
|
+
/* Sample-and-hold signals whose slope changes sign over a certain
|
|
563
|
+
period/ */
|
|
564
|
+
SAHDiffInvertion(x) = loop ~ _
|
|
565
|
+
with {
|
|
566
|
+
loop(y) = ba.if(nonZeroDiff * nonZeroDiff' < .0, x, y);
|
|
567
|
+
nonZeroDiff = ba.sAndH(abs(diff(x)) > EPS, diff(x));
|
|
568
|
+
diff(x) = x - x';
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
//----------------------------------------------------------- RELAY HYSTERON ---
|
|
572
|
+
hysteron(alpha, beta, x) = loop ~ _
|
|
573
|
+
with {
|
|
574
|
+
loop(y) = ba.if(x < alpha, .0, ba.if(x > beta, 1.0, y));
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
/************************************************************************
|
|
579
|
+
************************************************************************
|
|
580
|
+
- POPULATION GROWTH MODEL (termic model) -
|
|
581
|
+
************************************************************************
|
|
582
|
+
************************************************************************/
|
|
583
|
+
|
|
584
|
+
//----------------------------------------------------------- ENERGY AVERAGE ---
|
|
585
|
+
energy(xg, t, x) = avg(t, x * x * xg)
|
|
586
|
+
with {
|
|
587
|
+
avg(t, x) = onepole(1.0 / t, x) : ba.selectn(3, 0);
|
|
588
|
+
onepole(cf, x) = loop ~ _ : ! , si.bus(3)
|
|
589
|
+
with {
|
|
590
|
+
g = tan(cf * PI * T);
|
|
591
|
+
G = g / (1.0 + g);
|
|
592
|
+
Ghp = 1.0 - G;
|
|
593
|
+
Gap = G + G - 1.0;
|
|
594
|
+
loop(s) = u , lp , hp , ap
|
|
595
|
+
with {
|
|
596
|
+
u = v + v + s;
|
|
597
|
+
v0 = x - s;
|
|
598
|
+
hp = Ghp * v0;
|
|
599
|
+
v = G * v0;
|
|
600
|
+
lp = v + s;
|
|
601
|
+
ap = lp - hp;
|
|
602
|
+
};
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
//---------------------------------------------------- COMPOST TERMIC CURVES ---
|
|
607
|
+
warpedSine(a, b, c, d, x) = a * pow((1.0 + sin(ph)) / 2.0, b)
|
|
608
|
+
with {
|
|
609
|
+
ph = TWOPI * (min(1.0, x + d) ^ c + .75);
|
|
610
|
+
};
|
|
611
|
+
// show windows
|
|
612
|
+
//process = os.phasor(1, 4) <: warpedSine(3, 2, 5, 0) , warpedSine(2, 1.2, 4, .24) , warpedSine(1, 1, 6, .55);
|
|
613
|
+
|
|
614
|
+
//-------------------------------------------------------- POPULATION GROWTH ---
|
|
615
|
+
populationGrowth(i, G, E) = _ * a0Activation, _ * a1Activation, _ * a2Activation, _ * a3Activation
|
|
616
|
+
with {
|
|
617
|
+
curve(0) = warpedSine(3, 2, 5, 0);
|
|
618
|
+
curve(1) = warpedSine(2, 1.2, 4, .24);
|
|
619
|
+
curve(2) = warpedSine(1, 1, 6, .55);
|
|
620
|
+
Temp = hgroup("Energy Average", E : ma.tanh : info(i, -1, 1));
|
|
621
|
+
generationIndex = Temp : curve(i);
|
|
622
|
+
isInReproductionCondition =
|
|
623
|
+
hysteron(.001, .1, generationIndex) * 2.0 - 1.0;
|
|
624
|
+
reproductionClock = isInReproductionCondition :
|
|
625
|
+
\(state).(max(0, +(state))) ~ _;
|
|
626
|
+
a0Activation = 1 : hgroup("Active 0", info(i, 0, 1));
|
|
627
|
+
a1Activation = hysteron(SR, SR * 2, reproductionClock) : hgroup("Active 1", info(i, 0, 1));
|
|
628
|
+
a2Activation = hysteron(SR * 2, SR * 3, reproductionClock) : hgroup("Active 2", info(i, 0, 1));
|
|
629
|
+
a3Activation = hysteron(SR * 3, SR * 4, reproductionClock) : hgroup("Active 3", info(i, 0, 1));
|
|
630
|
+
};
|