@grame/faustwasm 0.7.3 → 0.7.4

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.
@@ -0,0 +1,4646 @@
1
+ var __accessCheck = (obj, member, msg) => {
2
+ if (!member.has(obj))
3
+ throw TypeError("Cannot " + msg);
4
+ };
5
+ var __privateGet = (obj, member, getter) => {
6
+ __accessCheck(obj, member, "read from private field");
7
+ return getter ? getter.call(obj) : member.get(obj);
8
+ };
9
+ var __privateAdd = (obj, member, value) => {
10
+ if (member.has(obj))
11
+ throw TypeError("Cannot add the same private member more than once");
12
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
13
+ };
14
+ var __privateSet = (obj, member, value, setter) => {
15
+ __accessCheck(obj, member, "write to private field");
16
+ setter ? setter.call(obj, value) : member.set(obj, value);
17
+ return value;
18
+ };
19
+
20
+ // src/instantiateFaustModuleFromFile.ts
21
+ var instantiateFaustModuleFromFile = async (jsFile, dataFile = jsFile.replace(/c?js$/, "data"), wasmFile = jsFile.replace(/c?js$/, "wasm")) => {
22
+ var _a, _b;
23
+ let FaustModule;
24
+ let dataBinary;
25
+ let wasmBinary;
26
+ const jsCodeHead = /var (.+) = \(/;
27
+ if (typeof window === "object") {
28
+ let jsCode = await (await fetch(jsFile)).text();
29
+ jsCode = `${jsCode}
30
+ export default ${(_a = jsCode.match(jsCodeHead)) == null ? void 0 : _a[1]};
31
+ `;
32
+ const jsFileMod = URL.createObjectURL(new Blob([jsCode], { type: "text/javascript" }));
33
+ FaustModule = (await import(
34
+ /* webpackIgnore: true */
35
+ jsFileMod
36
+ )).default;
37
+ dataBinary = await (await fetch(dataFile)).arrayBuffer();
38
+ wasmBinary = new Uint8Array(await (await fetch(wasmFile)).arrayBuffer());
39
+ } else {
40
+ const { promises: fs } = await import("fs");
41
+ const { pathToFileURL } = await import("url");
42
+ let jsCode = await fs.readFile(jsFile, { encoding: "utf-8" });
43
+ jsCode = `
44
+ import process from "process";
45
+ import * as path from "path";
46
+ import { createRequire } from "module";
47
+ import { fileURLToPath } from "url";
48
+
49
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
50
+ const __filename = fileURLToPath(import.meta.url);
51
+ const require = createRequire(import.meta.url);
52
+
53
+ ${jsCode}
54
+
55
+ export default ${(_b = jsCode.match(jsCodeHead)) == null ? void 0 : _b[1]};
56
+ `;
57
+ const jsFileMod = jsFile.replace(/c?js$/, "mjs");
58
+ await fs.writeFile(jsFileMod, jsCode);
59
+ FaustModule = (await import(
60
+ /* webpackIgnore: true */
61
+ pathToFileURL(jsFileMod).href
62
+ )).default;
63
+ await fs.unlink(jsFileMod);
64
+ dataBinary = (await fs.readFile(dataFile)).buffer;
65
+ wasmBinary = (await fs.readFile(wasmFile)).buffer;
66
+ }
67
+ const faustModule = await FaustModule({
68
+ wasmBinary,
69
+ getPreloadedPackage: (remotePackageName, remotePackageSize) => {
70
+ if (remotePackageName === "libfaust-wasm.data")
71
+ return dataBinary;
72
+ return new ArrayBuffer(0);
73
+ }
74
+ });
75
+ return faustModule;
76
+ };
77
+ var instantiateFaustModuleFromFile_default = instantiateFaustModuleFromFile;
78
+
79
+ // src/FaustAudioWorkletProcessor.ts
80
+ var getFaustAudioWorkletProcessor = (dependencies, faustData, register = true) => {
81
+ const { registerProcessor, AudioWorkletProcessor, sampleRate } = globalThis;
82
+ const {
83
+ FaustBaseWebAudioDsp: FaustBaseWebAudioDsp2,
84
+ FaustWasmInstantiator: FaustWasmInstantiator2
85
+ } = dependencies;
86
+ const {
87
+ processorName,
88
+ dspName,
89
+ dspMeta,
90
+ effectMeta,
91
+ poly
92
+ } = faustData;
93
+ const analysePolyParameters = (item) => {
94
+ const polyKeywords = ["/gate", "/freq", "/gain", "/key", "/vel", "/velocity"];
95
+ const isPolyReserved = "address" in item && !!polyKeywords.find((k) => item.address.endsWith(k));
96
+ if (poly && isPolyReserved)
97
+ return null;
98
+ if (item.type === "vslider" || item.type === "hslider" || item.type === "nentry") {
99
+ return { name: item.address, defaultValue: item.init || 0, minValue: item.min || 0, maxValue: item.max || 0 };
100
+ } else if (item.type === "button" || item.type === "checkbox") {
101
+ return { name: item.address, defaultValue: item.init || 0, minValue: 0, maxValue: 1 };
102
+ }
103
+ return null;
104
+ };
105
+ class FaustAudioWorkletProcessor extends AudioWorkletProcessor {
106
+ constructor(options) {
107
+ super(options);
108
+ this.paramValuesCache = {};
109
+ this.port.onmessage = (e) => this.handleMessageAux(e);
110
+ const { parameterDescriptors } = this.constructor;
111
+ parameterDescriptors.forEach((pd) => {
112
+ this.paramValuesCache[pd.name] = pd.defaultValue || 0;
113
+ });
114
+ const { moduleId, instanceId } = options.processorOptions;
115
+ if (!moduleId || !instanceId)
116
+ return;
117
+ this.wamInfo = { moduleId, instanceId };
118
+ }
119
+ static get parameterDescriptors() {
120
+ const params = [];
121
+ const callback = (item) => {
122
+ const param = analysePolyParameters(item);
123
+ if (param)
124
+ params.push(param);
125
+ };
126
+ FaustBaseWebAudioDsp2.parseUI(dspMeta.ui, callback);
127
+ if (effectMeta)
128
+ FaustBaseWebAudioDsp2.parseUI(effectMeta.ui, callback);
129
+ return params;
130
+ }
131
+ setupWamEventHandler() {
132
+ var _a;
133
+ if (!this.wamInfo)
134
+ return;
135
+ const { moduleId, instanceId } = this.wamInfo;
136
+ const { webAudioModules } = globalThis;
137
+ const ModuleScope = webAudioModules.getModuleScope(moduleId);
138
+ const paramMgrProcessor = (_a = ModuleScope == null ? void 0 : ModuleScope.paramMgrProcessors) == null ? void 0 : _a[instanceId];
139
+ if (!paramMgrProcessor)
140
+ return;
141
+ if (paramMgrProcessor.handleEvent)
142
+ return;
143
+ paramMgrProcessor.handleEvent = (event) => {
144
+ if (event.type === "wam-midi")
145
+ this.midiMessage(event.data.bytes);
146
+ };
147
+ }
148
+ process(inputs, outputs, parameters) {
149
+ for (const path in parameters) {
150
+ const [paramValue] = parameters[path];
151
+ if (paramValue !== this.paramValuesCache[path]) {
152
+ this.fDSPCode.setParamValue(path, paramValue);
153
+ this.paramValuesCache[path] = paramValue;
154
+ }
155
+ }
156
+ return this.fDSPCode.compute(inputs[0], outputs[0]);
157
+ }
158
+ handleMessageAux(e) {
159
+ const msg = e.data;
160
+ switch (msg.type) {
161
+ case "acc": {
162
+ this.propagateAcc(msg.data, msg.invert);
163
+ break;
164
+ }
165
+ case "gyr": {
166
+ this.propagateGyr(msg.data);
167
+ break;
168
+ }
169
+ case "midi": {
170
+ this.midiMessage(msg.data);
171
+ break;
172
+ }
173
+ case "ctrlChange": {
174
+ this.ctrlChange(msg.data[0], msg.data[1], msg.data[2]);
175
+ break;
176
+ }
177
+ case "pitchWheel": {
178
+ this.pitchWheel(msg.data[0], msg.data[1]);
179
+ break;
180
+ }
181
+ case "param": {
182
+ this.setParamValue(msg.data.path, msg.data.value);
183
+ break;
184
+ }
185
+ case "setPlotHandler": {
186
+ if (msg.data) {
187
+ this.fDSPCode.setPlotHandler((output, index, events) => this.port.postMessage({ type: "plot", value: output, index, events }));
188
+ } else {
189
+ this.fDSPCode.setPlotHandler(null);
190
+ }
191
+ break;
192
+ }
193
+ case "setupWamEventHandler": {
194
+ this.setupWamEventHandler();
195
+ break;
196
+ }
197
+ case "start": {
198
+ this.fDSPCode.start();
199
+ break;
200
+ }
201
+ case "stop": {
202
+ this.fDSPCode.stop();
203
+ break;
204
+ }
205
+ case "destroy": {
206
+ this.port.close();
207
+ this.fDSPCode.destroy();
208
+ break;
209
+ }
210
+ default:
211
+ break;
212
+ }
213
+ }
214
+ setParamValue(path, value) {
215
+ this.fDSPCode.setParamValue(path, value);
216
+ this.paramValuesCache[path] = value;
217
+ }
218
+ midiMessage(data) {
219
+ this.fDSPCode.midiMessage(data);
220
+ }
221
+ ctrlChange(channel, ctrl, value) {
222
+ this.fDSPCode.ctrlChange(channel, ctrl, value);
223
+ }
224
+ pitchWheel(channel, wheel) {
225
+ this.fDSPCode.pitchWheel(channel, wheel);
226
+ }
227
+ propagateAcc(accelerationIncludingGravity, invert = false) {
228
+ this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
229
+ }
230
+ propagateGyr(event) {
231
+ this.fDSPCode.propagateGyr(event);
232
+ }
233
+ }
234
+ class FaustMonoAudioWorkletProcessor extends FaustAudioWorkletProcessor {
235
+ constructor(options) {
236
+ super(options);
237
+ const { FaustMonoWebAudioDsp: FaustMonoWebAudioDsp2 } = dependencies;
238
+ const { factory, sampleSize } = options.processorOptions;
239
+ const instance = FaustWasmInstantiator2.createSyncMonoDSPInstance(factory);
240
+ this.fDSPCode = new FaustMonoWebAudioDsp2(instance, sampleRate, sampleSize, 128, factory.soundfiles);
241
+ this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
242
+ this.fDSPCode.start();
243
+ }
244
+ }
245
+ class FaustPolyAudioWorkletProcessor extends FaustAudioWorkletProcessor {
246
+ constructor(options) {
247
+ super(options);
248
+ this.handleMessageAux = (e) => {
249
+ const msg = e.data;
250
+ switch (msg.type) {
251
+ case "keyOn":
252
+ this.keyOn(msg.data[0], msg.data[1], msg.data[2]);
253
+ break;
254
+ case "keyOff":
255
+ this.keyOff(msg.data[0], msg.data[1], msg.data[2]);
256
+ break;
257
+ default:
258
+ super.handleMessageAux(e);
259
+ break;
260
+ }
261
+ };
262
+ const { FaustPolyWebAudioDsp: FaustPolyWebAudioDsp3 } = dependencies;
263
+ const { voiceFactory, mixerModule, voices, effectFactory, sampleSize } = options.processorOptions;
264
+ const instance = FaustWasmInstantiator2.createSyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory);
265
+ const soundfiles = { ...effectFactory == null ? void 0 : effectFactory.soundfiles, ...voiceFactory.soundfiles };
266
+ this.fDSPCode = new FaustPolyWebAudioDsp3(instance, sampleRate, sampleSize, 128, soundfiles);
267
+ this.port.onmessage = (e) => this.handleMessageAux(e);
268
+ this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
269
+ this.fDSPCode.start();
270
+ }
271
+ midiMessage(data) {
272
+ const cmd = data[0] >> 4;
273
+ const channel = data[0] & 15;
274
+ const data1 = data[1];
275
+ const data2 = data[2];
276
+ if (cmd === 8 || cmd === 9 && data2 === 0)
277
+ this.keyOff(channel, data1, data2);
278
+ else if (cmd === 9)
279
+ this.keyOn(channel, data1, data2);
280
+ else
281
+ super.midiMessage(data);
282
+ }
283
+ // Public API
284
+ keyOn(channel, pitch, velocity) {
285
+ this.fDSPCode.keyOn(channel, pitch, velocity);
286
+ }
287
+ keyOff(channel, pitch, velocity) {
288
+ this.fDSPCode.keyOff(channel, pitch, velocity);
289
+ }
290
+ allNotesOff(hard) {
291
+ this.fDSPCode.allNotesOff(hard);
292
+ }
293
+ }
294
+ const Processor = poly ? FaustPolyAudioWorkletProcessor : FaustMonoAudioWorkletProcessor;
295
+ if (register) {
296
+ try {
297
+ registerProcessor(processorName || dspName || (poly ? "mydsp_poly" : "mydsp"), Processor);
298
+ } catch (error) {
299
+ console.warn(error);
300
+ }
301
+ }
302
+ return poly ? FaustPolyAudioWorkletProcessor : FaustMonoAudioWorkletProcessor;
303
+ };
304
+ var FaustAudioWorkletProcessor_default = getFaustAudioWorkletProcessor;
305
+
306
+ // src/FaustFFTAudioWorkletProcessor.ts
307
+ var getFaustFFTAudioWorkletProcessor = (dependencies, faustData, register = true) => {
308
+ const { registerProcessor, AudioWorkletProcessor, sampleRate } = globalThis;
309
+ const {
310
+ FaustBaseWebAudioDsp: FaustBaseWebAudioDsp2,
311
+ FaustWasmInstantiator: FaustWasmInstantiator2,
312
+ FaustMonoWebAudioDsp: FaustMonoWebAudioDsp2,
313
+ FFTUtils
314
+ } = dependencies;
315
+ const {
316
+ processorName,
317
+ dspName,
318
+ dspMeta,
319
+ fftOptions
320
+ } = faustData;
321
+ const {
322
+ windowFunctions,
323
+ getFFT,
324
+ fftToSignal,
325
+ signalToFFT,
326
+ signalToNoFFT
327
+ } = FFTUtils;
328
+ const ceil = (x, to) => Math.abs(to) < 1 ? Math.ceil(x * (1 / to)) / (1 / to) : Math.ceil(x / to) * to;
329
+ const mod = (x, y) => (x % y + y) % y;
330
+ const apply = (array, windowFunction) => {
331
+ for (let i = 0; i < array.length; i++) {
332
+ array[i] *= windowFunction(i, array.length);
333
+ }
334
+ };
335
+ const fftParamKeywords = ["/fftSize", "/fftHopSize", "/fftOverlap", "/windowFunction", "/noIFFT"];
336
+ const setTypedArray = (to, from, offsetTo = 0, offsetFrom = 0) => {
337
+ const toLength = to.length;
338
+ const fromLength = from.length;
339
+ const spillLength = Math.min(toLength, fromLength);
340
+ let spilled = 0;
341
+ let $to = mod(offsetTo, toLength) || 0;
342
+ let $from = mod(offsetFrom, fromLength) || 0;
343
+ while (spilled < spillLength) {
344
+ const $spillLength = Math.min(spillLength - spilled, toLength - $to, fromLength - $from);
345
+ const $fromEnd = $from + $spillLength;
346
+ if ($from === 0 && $fromEnd === fromLength)
347
+ to.set(from, $to);
348
+ else
349
+ to.set(from.subarray($from, $fromEnd), $to);
350
+ $to = ($to + $spillLength) % toLength;
351
+ $from = $fromEnd % fromLength;
352
+ spilled += $spillLength;
353
+ }
354
+ return $to;
355
+ };
356
+ const analyseParameters = (item) => {
357
+ const isFFTReserved = "address" in item && !!fftParamKeywords.find((k) => item.address.endsWith(k));
358
+ if (isFFTReserved)
359
+ return null;
360
+ if (item.type === "vslider" || item.type === "hslider" || item.type === "nentry") {
361
+ return { name: item.address, defaultValue: item.init || 0, minValue: item.min || 0, maxValue: item.max || 0 };
362
+ } else if (item.type === "button" || item.type === "checkbox") {
363
+ return { name: item.address, defaultValue: item.init || 0, minValue: 0, maxValue: 1 };
364
+ }
365
+ return null;
366
+ };
367
+ class FaustFFTAudioWorkletProcessor extends AudioWorkletProcessor {
368
+ constructor(options) {
369
+ super(options);
370
+ this.paramValuesCache = {};
371
+ this.destroyed = false;
372
+ /** Pointer of next start sample to write of the FFT input window */
373
+ this.$inputWrite = 0;
374
+ /** Pointer of next start sample to read of the FFT input window */
375
+ this.$inputRead = 0;
376
+ /** Pointer of next start sample to write of the FFT output window */
377
+ this.$outputWrite = 0;
378
+ /** Pointer of next start sample to read of the FFT output window */
379
+ this.$outputRead = 0;
380
+ /** Not perform in IFFT when reconstruct the audio signal */
381
+ this.noIFFT = false;
382
+ /** audio data from input, array of channels */
383
+ this.fftInput = [];
384
+ /** audio data for output, array of channels */
385
+ this.fftOutput = [];
386
+ /** FFT Overlaps, 1 means no overlap */
387
+ this.fftOverlap = 0;
388
+ this.fftHopSize = 0;
389
+ this.fftSize = 0;
390
+ this.fftBufferSize = 0;
391
+ this.fPlotHandler = null;
392
+ this.fCachedEvents = [];
393
+ this.fBufferNum = 0;
394
+ this.soundfiles = {};
395
+ this.windowFunction = null;
396
+ this.port.onmessage = (e) => this.handleMessageAux(e);
397
+ const { parameterDescriptors } = this.constructor;
398
+ parameterDescriptors.forEach((pd) => {
399
+ this.paramValuesCache[pd.name] = pd.defaultValue || 0;
400
+ });
401
+ const { factory, sampleSize } = options.processorOptions;
402
+ this.dspInstance = FaustWasmInstantiator2.createSyncMonoDSPInstance(factory);
403
+ this.sampleSize = sampleSize;
404
+ this.soundfiles = factory.soundfiles;
405
+ this.initFFT();
406
+ const { moduleId, instanceId } = options.processorOptions;
407
+ if (!moduleId || !instanceId)
408
+ return;
409
+ this.wamInfo = { moduleId, instanceId };
410
+ }
411
+ get fftProcessorBufferSize() {
412
+ return this.fftSize / 2 + 1;
413
+ }
414
+ async initFFT() {
415
+ this.FFT = await getFFT();
416
+ await this.createFFTProcessor();
417
+ return true;
418
+ }
419
+ static get parameterDescriptors() {
420
+ const params = [];
421
+ const callback = (item) => {
422
+ const param = analyseParameters(item);
423
+ if (param)
424
+ params.push(param);
425
+ };
426
+ FaustBaseWebAudioDsp2.parseUI(dspMeta.ui, callback);
427
+ return [
428
+ ...params,
429
+ {
430
+ defaultValue: (fftOptions == null ? void 0 : fftOptions.fftSize) || 1024,
431
+ maxValue: 2 ** 32,
432
+ minValue: 2,
433
+ name: "fftSize"
434
+ },
435
+ {
436
+ defaultValue: (fftOptions == null ? void 0 : fftOptions.fftOverlap) || 2,
437
+ maxValue: 32,
438
+ minValue: 1,
439
+ name: "fftOverlap"
440
+ },
441
+ {
442
+ defaultValue: typeof (fftOptions == null ? void 0 : fftOptions.defaultWindowFunction) === "number" ? fftOptions.defaultWindowFunction + 1 : 0,
443
+ maxValue: (windowFunctions == null ? void 0 : windowFunctions.length) || 0,
444
+ minValue: 0,
445
+ name: "windowFunction"
446
+ },
447
+ {
448
+ defaultValue: +!!(fftOptions == null ? void 0 : fftOptions.noIFFT) || 0,
449
+ maxValue: 1,
450
+ minValue: 0,
451
+ name: "noIFFT"
452
+ }
453
+ ];
454
+ }
455
+ setupWamEventHandler() {
456
+ var _a;
457
+ if (!this.wamInfo)
458
+ return;
459
+ const { moduleId, instanceId } = this.wamInfo;
460
+ const { webAudioModules } = globalThis;
461
+ const ModuleScope = webAudioModules.getModuleScope(moduleId);
462
+ const paramMgrProcessor = (_a = ModuleScope == null ? void 0 : ModuleScope.paramMgrProcessors) == null ? void 0 : _a[instanceId];
463
+ if (!paramMgrProcessor)
464
+ return;
465
+ if (paramMgrProcessor.handleEvent)
466
+ return;
467
+ paramMgrProcessor.handleEvent = (event) => {
468
+ if (event.type === "wam-midi")
469
+ this.midiMessage(event.data.bytes);
470
+ };
471
+ }
472
+ processFFT() {
473
+ let samplesForFFT = mod(this.$inputWrite - this.$inputRead, this.fftBufferSize) || this.fftBufferSize;
474
+ while (samplesForFFT >= this.fftSize) {
475
+ let fftProcessorOutputs = [];
476
+ this.fDSPCode.compute((inputs) => {
477
+ for (let i = 0; i < Math.min(this.fftInput.length, Math.ceil(inputs.length / 3)); i++) {
478
+ const ffted = this.rfft.forward((fftBuffer) => {
479
+ setTypedArray(fftBuffer, this.fftInput[i], 0, this.$inputRead);
480
+ for (let j = 0; j < fftBuffer.length; j++) {
481
+ fftBuffer[j] *= this.window[j];
482
+ }
483
+ });
484
+ fftToSignal(ffted, inputs[i * 3], inputs[i * 3 + 1], inputs[i * 3 + 2]);
485
+ }
486
+ for (let i = this.fftInput.length * 3; i < inputs.length; i++) {
487
+ if (i % 3 === 2)
488
+ inputs[i].forEach((v, j) => inputs[i][j] = j);
489
+ else
490
+ inputs[i].fill(0);
491
+ }
492
+ }, (outputs) => {
493
+ fftProcessorOutputs = outputs;
494
+ });
495
+ this.$inputRead += this.fftHopSize;
496
+ this.$inputRead %= this.fftBufferSize;
497
+ samplesForFFT -= this.fftHopSize;
498
+ for (let i = 0; i < this.fftOutput.length; i++) {
499
+ let iffted;
500
+ if (this.noIFFT) {
501
+ iffted = this.noIFFTBuffer;
502
+ signalToNoFFT(fftProcessorOutputs[i * 2] || this.fftProcessorZeros, fftProcessorOutputs[i * 2 + 1] || this.fftProcessorZeros, iffted);
503
+ } else {
504
+ iffted = this.rfft.inverse((ifftBuffer) => {
505
+ signalToFFT(fftProcessorOutputs[i * 2] || this.fftProcessorZeros, fftProcessorOutputs[i * 2 + 1] || this.fftProcessorZeros, ifftBuffer);
506
+ });
507
+ }
508
+ for (let j = 0; j < iffted.length; j++) {
509
+ iffted[j] *= this.window[j];
510
+ }
511
+ let $;
512
+ for (let j = 0; j < iffted.length - this.fftHopSize; j++) {
513
+ $ = mod(this.$outputWrite + j, this.fftBufferSize);
514
+ this.fftOutput[i][$] += iffted[j];
515
+ if (i === 0)
516
+ this.windowSumSquare[$] += this.noIFFT ? this.window[j] : this.window[j] ** 2;
517
+ }
518
+ for (let j = iffted.length - this.fftHopSize; j < iffted.length; j++) {
519
+ $ = mod(this.$outputWrite + j, this.fftBufferSize);
520
+ this.fftOutput[i][$] = iffted[j];
521
+ if (i === 0)
522
+ this.windowSumSquare[$] = this.noIFFT ? this.window[j] : this.window[j] ** 2;
523
+ }
524
+ }
525
+ this.$outputWrite += this.fftHopSize;
526
+ this.$outputWrite %= this.fftBufferSize;
527
+ }
528
+ }
529
+ process(inputs, outputs, parameters) {
530
+ if (this.destroyed)
531
+ return false;
532
+ if (!this.FFT)
533
+ return true;
534
+ const input = inputs[0];
535
+ const output = outputs[0];
536
+ const inputChannels = (input == null ? void 0 : input.length) || 0;
537
+ const outputChannels = (output == null ? void 0 : output.length) || 0;
538
+ const bufferSize = (input == null ? void 0 : input.length) ? Math.max(...input.map((c) => c.length)) || 128 : 128;
539
+ this.noIFFT = !!parameters.noIFFT[0];
540
+ this.resetFFT(~~parameters.fftSize[0], ~~parameters.fftOverlap[0], ~~parameters.windowFunction[0], inputChannels, outputChannels, bufferSize);
541
+ if (!this.fDSPCode)
542
+ return true;
543
+ for (const path in parameters) {
544
+ if (!!fftParamKeywords.find((k) => `/${path}`.endsWith(k)))
545
+ continue;
546
+ const [paramValue] = parameters[path];
547
+ if (paramValue !== this.paramValuesCache[path]) {
548
+ this.fDSPCode.setParamValue(path, paramValue);
549
+ this.paramValuesCache[path] = paramValue;
550
+ }
551
+ }
552
+ if (input == null ? void 0 : input.length) {
553
+ let $inputWrite = 0;
554
+ for (let i = 0; i < input.length; i++) {
555
+ const inputWindow = this.fftInput[i];
556
+ const channel = input[i].length ? input[i] : new Float32Array(bufferSize);
557
+ $inputWrite = setTypedArray(inputWindow, channel, this.$inputWrite);
558
+ }
559
+ this.$inputWrite = $inputWrite;
560
+ } else {
561
+ this.$inputWrite += bufferSize;
562
+ this.$inputWrite %= this.fftBufferSize;
563
+ }
564
+ this.processFFT();
565
+ for (let i = 0; i < output.length; i++) {
566
+ setTypedArray(output[i], this.fftOutput[i], 0, this.$outputRead);
567
+ let div = 0;
568
+ for (let j = 0; j < bufferSize; j++) {
569
+ div = this.windowSumSquare[mod(this.$outputRead + j, this.fftBufferSize)];
570
+ output[i][j] /= div < 1e-8 ? 1 : div;
571
+ }
572
+ }
573
+ this.$outputRead += bufferSize;
574
+ this.$outputRead %= this.fftBufferSize;
575
+ if (this.fPlotHandler) {
576
+ this.port.postMessage({ type: "plot", value: output, index: this.fBufferNum++, events: this.fCachedEvents });
577
+ this.fCachedEvents = [];
578
+ }
579
+ return true;
580
+ }
581
+ handleMessageAux(e) {
582
+ var _a, _b, _c;
583
+ const msg = e.data;
584
+ switch (msg.type) {
585
+ case "midi":
586
+ this.midiMessage(msg.data);
587
+ break;
588
+ case "ctrlChange":
589
+ this.ctrlChange(msg.data[0], msg.data[1], msg.data[2]);
590
+ break;
591
+ case "pitchWheel":
592
+ this.pitchWheel(msg.data[0], msg.data[1]);
593
+ break;
594
+ case "param":
595
+ this.setParamValue(msg.data.path, msg.data.value);
596
+ break;
597
+ case "setPlotHandler": {
598
+ if (msg.data) {
599
+ this.fPlotHandler = (output, index, events) => {
600
+ if (events)
601
+ this.fCachedEvents.push(...events);
602
+ };
603
+ } else {
604
+ this.fPlotHandler = null;
605
+ }
606
+ (_a = this.fDSPCode) == null ? void 0 : _a.setPlotHandler(this.fPlotHandler);
607
+ break;
608
+ }
609
+ case "setupWamEventHandler": {
610
+ this.setupWamEventHandler();
611
+ break;
612
+ }
613
+ case "start": {
614
+ (_b = this.fDSPCode) == null ? void 0 : _b.start();
615
+ break;
616
+ }
617
+ case "stop": {
618
+ (_c = this.fDSPCode) == null ? void 0 : _c.stop();
619
+ break;
620
+ }
621
+ case "destroy": {
622
+ this.port.close();
623
+ this.destroy();
624
+ break;
625
+ }
626
+ default:
627
+ break;
628
+ }
629
+ }
630
+ setParamValue(path, value) {
631
+ var _a;
632
+ (_a = this.fDSPCode) == null ? void 0 : _a.setParamValue(path, value);
633
+ this.paramValuesCache[path] = value;
634
+ }
635
+ midiMessage(data) {
636
+ var _a;
637
+ (_a = this.fDSPCode) == null ? void 0 : _a.midiMessage(data);
638
+ }
639
+ ctrlChange(channel, ctrl, value) {
640
+ var _a;
641
+ (_a = this.fDSPCode) == null ? void 0 : _a.ctrlChange(channel, ctrl, value);
642
+ }
643
+ pitchWheel(channel, wheel) {
644
+ var _a;
645
+ (_a = this.fDSPCode) == null ? void 0 : _a.pitchWheel(channel, wheel);
646
+ }
647
+ resetFFT(sizeIn, overlapIn, windowFunctionIn, inputChannels, outputChannels, bufferSize) {
648
+ var _a, _b;
649
+ const fftSize = ~~ceil(Math.max(2, sizeIn || 1024), 2);
650
+ const fftOverlap = ~~Math.min(fftSize, Math.max(1, overlapIn));
651
+ const fftHopSize = ~~Math.max(1, fftSize / fftOverlap);
652
+ const latency = fftSize - Math.min(fftHopSize, bufferSize);
653
+ let windowFunction = null;
654
+ if (windowFunctionIn !== 0) {
655
+ windowFunction = typeof windowFunctions === "object" ? windowFunctions[~~windowFunctionIn - 1] || null : null;
656
+ }
657
+ const fftSizeChanged = fftSize !== this.fftSize;
658
+ const fftOverlapChanged = fftOverlap !== this.fftOverlap;
659
+ if (fftSizeChanged || fftOverlapChanged) {
660
+ this.fftSize = fftSize;
661
+ this.fftOverlap = fftOverlap;
662
+ this.fftHopSize = fftHopSize;
663
+ this.$inputWrite = 0;
664
+ this.$inputRead = 0;
665
+ this.$outputWrite = 0;
666
+ this.$outputRead = -latency;
667
+ this.fftBufferSize = Math.max(fftSize * 2 - this.fftHopSize, bufferSize * 2);
668
+ if (!fftSizeChanged && this.fftHopSizeParam)
669
+ (_a = this.fDSPCode) == null ? void 0 : _a.setParamValue(this.fftHopSizeParam, this.fftHopSize);
670
+ }
671
+ if (fftSizeChanged) {
672
+ (_b = this.rfft) == null ? void 0 : _b.dispose();
673
+ this.rfft = new this.FFT(fftSize);
674
+ this.noIFFTBuffer = new Float32Array(this.fftSize);
675
+ this.createFFTProcessor();
676
+ }
677
+ if (fftSizeChanged || fftOverlapChanged || windowFunction !== this.windowFunction) {
678
+ this.windowFunction = windowFunction;
679
+ this.window = new Float32Array(fftSize);
680
+ this.window.fill(1);
681
+ if (windowFunction)
682
+ apply(this.window, windowFunction);
683
+ this.windowSumSquare = new Float32Array(this.fftBufferSize);
684
+ }
685
+ if (this.fftInput.length > inputChannels) {
686
+ this.fftInput.splice(inputChannels);
687
+ }
688
+ if (this.fftOutput.length > outputChannels) {
689
+ this.fftOutput.splice(outputChannels);
690
+ }
691
+ if (fftSizeChanged || fftOverlapChanged) {
692
+ for (let i = 0; i < inputChannels; i++) {
693
+ this.fftInput[i] = new Float32Array(this.fftBufferSize);
694
+ }
695
+ for (let i = 0; i < outputChannels; i++) {
696
+ this.fftOutput[i] = new Float32Array(this.fftBufferSize);
697
+ }
698
+ } else {
699
+ if (this.fftInput.length < inputChannels) {
700
+ for (let i = this.fftInput.length; i < inputChannels; i++) {
701
+ this.fftInput[i] = new Float32Array(this.fftBufferSize);
702
+ }
703
+ }
704
+ if (this.fftOutput.length < outputChannels) {
705
+ for (let i = this.fftOutput.length; i < outputChannels; i++) {
706
+ this.fftOutput[i] = new Float32Array(this.fftBufferSize);
707
+ }
708
+ }
709
+ }
710
+ }
711
+ async createFFTProcessor() {
712
+ var _a, _b;
713
+ (_a = this.fDSPCode) == null ? void 0 : _a.stop();
714
+ (_b = this.fDSPCode) == null ? void 0 : _b.destroy();
715
+ this.fDSPCode = new FaustMonoWebAudioDsp2(this.dspInstance, sampleRate, this.sampleSize, this.fftProcessorBufferSize, this.soundfiles);
716
+ this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
717
+ this.fDSPCode.setPlotHandler(this.fPlotHandler);
718
+ const params = this.fDSPCode.getParams();
719
+ this.fDSPCode.start();
720
+ for (const path in this.paramValuesCache) {
721
+ if (!!fftParamKeywords.find((k) => `/${path}`.endsWith(k)))
722
+ continue;
723
+ this.fDSPCode.setParamValue(path, this.paramValuesCache[path]);
724
+ }
725
+ const fftSizeParam = params.find((s) => s.endsWith("/fftSize"));
726
+ if (fftSizeParam)
727
+ this.fDSPCode.setParamValue(fftSizeParam, this.fftSize);
728
+ this.fftHopSizeParam = params.find((s) => s.endsWith("/fftHopSize"));
729
+ if (this.fftHopSizeParam)
730
+ this.fDSPCode.setParamValue(this.fftHopSizeParam, this.fftHopSize);
731
+ this.fftProcessorZeros = new Float32Array(this.fftProcessorBufferSize);
732
+ }
733
+ destroy() {
734
+ var _a, _b, _c;
735
+ (_a = this.fDSPCode) == null ? void 0 : _a.stop();
736
+ (_b = this.fDSPCode) == null ? void 0 : _b.destroy();
737
+ (_c = this.rfft) == null ? void 0 : _c.dispose();
738
+ this.destroyed = true;
739
+ }
740
+ }
741
+ const Processor = FaustFFTAudioWorkletProcessor;
742
+ if (register) {
743
+ try {
744
+ registerProcessor(processorName || dspName || "myfftdsp", Processor);
745
+ } catch (error) {
746
+ console.warn(error);
747
+ }
748
+ }
749
+ return FaustFFTAudioWorkletProcessor;
750
+ };
751
+ var FaustFFTAudioWorkletProcessor_default = getFaustFFTAudioWorkletProcessor;
752
+
753
+ // node_modules/tslib/tslib.es6.mjs
754
+ function __awaiter(thisArg, _arguments, P, generator) {
755
+ function adopt(value) {
756
+ return value instanceof P ? value : new P(function(resolve) {
757
+ resolve(value);
758
+ });
759
+ }
760
+ return new (P || (P = Promise))(function(resolve, reject) {
761
+ function fulfilled(value) {
762
+ try {
763
+ step(generator.next(value));
764
+ } catch (e) {
765
+ reject(e);
766
+ }
767
+ }
768
+ function rejected(value) {
769
+ try {
770
+ step(generator["throw"](value));
771
+ } catch (e) {
772
+ reject(e);
773
+ }
774
+ }
775
+ function step(result) {
776
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
777
+ }
778
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
779
+ });
780
+ }
781
+ function __generator(thisArg, body) {
782
+ var _ = { label: 0, sent: function() {
783
+ if (t[0] & 1)
784
+ throw t[1];
785
+ return t[1];
786
+ }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
787
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
788
+ return this;
789
+ }), g;
790
+ function verb(n) {
791
+ return function(v) {
792
+ return step([n, v]);
793
+ };
794
+ }
795
+ function step(op) {
796
+ if (f)
797
+ throw new TypeError("Generator is already executing.");
798
+ while (g && (g = 0, op[0] && (_ = 0)), _)
799
+ try {
800
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
801
+ return t;
802
+ if (y = 0, t)
803
+ op = [op[0] & 2, t.value];
804
+ switch (op[0]) {
805
+ case 0:
806
+ case 1:
807
+ t = op;
808
+ break;
809
+ case 4:
810
+ _.label++;
811
+ return { value: op[1], done: false };
812
+ case 5:
813
+ _.label++;
814
+ y = op[1];
815
+ op = [0];
816
+ continue;
817
+ case 7:
818
+ op = _.ops.pop();
819
+ _.trys.pop();
820
+ continue;
821
+ default:
822
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
823
+ _ = 0;
824
+ continue;
825
+ }
826
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
827
+ _.label = op[1];
828
+ break;
829
+ }
830
+ if (op[0] === 6 && _.label < t[1]) {
831
+ _.label = t[1];
832
+ t = op;
833
+ break;
834
+ }
835
+ if (t && _.label < t[2]) {
836
+ _.label = t[2];
837
+ _.ops.push(op);
838
+ break;
839
+ }
840
+ if (t[2])
841
+ _.ops.pop();
842
+ _.trys.pop();
843
+ continue;
844
+ }
845
+ op = body.call(thisArg, _);
846
+ } catch (e) {
847
+ op = [6, e];
848
+ y = 0;
849
+ } finally {
850
+ f = t = 0;
851
+ }
852
+ if (op[0] & 5)
853
+ throw op[1];
854
+ return { value: op[0] ? op[1] : void 0, done: true };
855
+ }
856
+ }
857
+
858
+ // node_modules/@aws-crypto/sha256-js/build/module/constants.js
859
+ var BLOCK_SIZE = 64;
860
+ var DIGEST_LENGTH = 32;
861
+ var KEY = new Uint32Array([
862
+ 1116352408,
863
+ 1899447441,
864
+ 3049323471,
865
+ 3921009573,
866
+ 961987163,
867
+ 1508970993,
868
+ 2453635748,
869
+ 2870763221,
870
+ 3624381080,
871
+ 310598401,
872
+ 607225278,
873
+ 1426881987,
874
+ 1925078388,
875
+ 2162078206,
876
+ 2614888103,
877
+ 3248222580,
878
+ 3835390401,
879
+ 4022224774,
880
+ 264347078,
881
+ 604807628,
882
+ 770255983,
883
+ 1249150122,
884
+ 1555081692,
885
+ 1996064986,
886
+ 2554220882,
887
+ 2821834349,
888
+ 2952996808,
889
+ 3210313671,
890
+ 3336571891,
891
+ 3584528711,
892
+ 113926993,
893
+ 338241895,
894
+ 666307205,
895
+ 773529912,
896
+ 1294757372,
897
+ 1396182291,
898
+ 1695183700,
899
+ 1986661051,
900
+ 2177026350,
901
+ 2456956037,
902
+ 2730485921,
903
+ 2820302411,
904
+ 3259730800,
905
+ 3345764771,
906
+ 3516065817,
907
+ 3600352804,
908
+ 4094571909,
909
+ 275423344,
910
+ 430227734,
911
+ 506948616,
912
+ 659060556,
913
+ 883997877,
914
+ 958139571,
915
+ 1322822218,
916
+ 1537002063,
917
+ 1747873779,
918
+ 1955562222,
919
+ 2024104815,
920
+ 2227730452,
921
+ 2361852424,
922
+ 2428436474,
923
+ 2756734187,
924
+ 3204031479,
925
+ 3329325298
926
+ ]);
927
+ var INIT = [
928
+ 1779033703,
929
+ 3144134277,
930
+ 1013904242,
931
+ 2773480762,
932
+ 1359893119,
933
+ 2600822924,
934
+ 528734635,
935
+ 1541459225
936
+ ];
937
+ var MAX_HASHABLE_LENGTH = Math.pow(2, 53) - 1;
938
+
939
+ // node_modules/@aws-crypto/sha256-js/build/module/RawSha256.js
940
+ var RawSha256 = (
941
+ /** @class */
942
+ function() {
943
+ function RawSha2562() {
944
+ this.state = Int32Array.from(INIT);
945
+ this.temp = new Int32Array(64);
946
+ this.buffer = new Uint8Array(64);
947
+ this.bufferLength = 0;
948
+ this.bytesHashed = 0;
949
+ this.finished = false;
950
+ }
951
+ RawSha2562.prototype.update = function(data) {
952
+ if (this.finished) {
953
+ throw new Error("Attempted to update an already finished hash.");
954
+ }
955
+ var position = 0;
956
+ var byteLength = data.byteLength;
957
+ this.bytesHashed += byteLength;
958
+ if (this.bytesHashed * 8 > MAX_HASHABLE_LENGTH) {
959
+ throw new Error("Cannot hash more than 2^53 - 1 bits");
960
+ }
961
+ while (byteLength > 0) {
962
+ this.buffer[this.bufferLength++] = data[position++];
963
+ byteLength--;
964
+ if (this.bufferLength === BLOCK_SIZE) {
965
+ this.hashBuffer();
966
+ this.bufferLength = 0;
967
+ }
968
+ }
969
+ };
970
+ RawSha2562.prototype.digest = function() {
971
+ if (!this.finished) {
972
+ var bitsHashed = this.bytesHashed * 8;
973
+ var bufferView = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength);
974
+ var undecoratedLength = this.bufferLength;
975
+ bufferView.setUint8(this.bufferLength++, 128);
976
+ if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
977
+ for (var i = this.bufferLength; i < BLOCK_SIZE; i++) {
978
+ bufferView.setUint8(i, 0);
979
+ }
980
+ this.hashBuffer();
981
+ this.bufferLength = 0;
982
+ }
983
+ for (var i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
984
+ bufferView.setUint8(i, 0);
985
+ }
986
+ bufferView.setUint32(BLOCK_SIZE - 8, Math.floor(bitsHashed / 4294967296), true);
987
+ bufferView.setUint32(BLOCK_SIZE - 4, bitsHashed);
988
+ this.hashBuffer();
989
+ this.finished = true;
990
+ }
991
+ var out = new Uint8Array(DIGEST_LENGTH);
992
+ for (var i = 0; i < 8; i++) {
993
+ out[i * 4] = this.state[i] >>> 24 & 255;
994
+ out[i * 4 + 1] = this.state[i] >>> 16 & 255;
995
+ out[i * 4 + 2] = this.state[i] >>> 8 & 255;
996
+ out[i * 4 + 3] = this.state[i] >>> 0 & 255;
997
+ }
998
+ return out;
999
+ };
1000
+ RawSha2562.prototype.hashBuffer = function() {
1001
+ var _a = this, buffer = _a.buffer, state = _a.state;
1002
+ var state0 = state[0], state1 = state[1], state2 = state[2], state3 = state[3], state4 = state[4], state5 = state[5], state6 = state[6], state7 = state[7];
1003
+ for (var i = 0; i < BLOCK_SIZE; i++) {
1004
+ if (i < 16) {
1005
+ this.temp[i] = (buffer[i * 4] & 255) << 24 | (buffer[i * 4 + 1] & 255) << 16 | (buffer[i * 4 + 2] & 255) << 8 | buffer[i * 4 + 3] & 255;
1006
+ } else {
1007
+ var u = this.temp[i - 2];
1008
+ var t1_1 = (u >>> 17 | u << 15) ^ (u >>> 19 | u << 13) ^ u >>> 10;
1009
+ u = this.temp[i - 15];
1010
+ var t2_1 = (u >>> 7 | u << 25) ^ (u >>> 18 | u << 14) ^ u >>> 3;
1011
+ this.temp[i] = (t1_1 + this.temp[i - 7] | 0) + (t2_1 + this.temp[i - 16] | 0);
1012
+ }
1013
+ var t1 = (((state4 >>> 6 | state4 << 26) ^ (state4 >>> 11 | state4 << 21) ^ (state4 >>> 25 | state4 << 7)) + (state4 & state5 ^ ~state4 & state6) | 0) + (state7 + (KEY[i] + this.temp[i] | 0) | 0) | 0;
1014
+ var t2 = ((state0 >>> 2 | state0 << 30) ^ (state0 >>> 13 | state0 << 19) ^ (state0 >>> 22 | state0 << 10)) + (state0 & state1 ^ state0 & state2 ^ state1 & state2) | 0;
1015
+ state7 = state6;
1016
+ state6 = state5;
1017
+ state5 = state4;
1018
+ state4 = state3 + t1 | 0;
1019
+ state3 = state2;
1020
+ state2 = state1;
1021
+ state1 = state0;
1022
+ state0 = t1 + t2 | 0;
1023
+ }
1024
+ state[0] += state0;
1025
+ state[1] += state1;
1026
+ state[2] += state2;
1027
+ state[3] += state3;
1028
+ state[4] += state4;
1029
+ state[5] += state5;
1030
+ state[6] += state6;
1031
+ state[7] += state7;
1032
+ };
1033
+ return RawSha2562;
1034
+ }()
1035
+ );
1036
+
1037
+ // node_modules/@smithy/util-utf8/dist-es/fromUtf8.browser.js
1038
+ var fromUtf8 = (input) => new TextEncoder().encode(input);
1039
+
1040
+ // node_modules/@aws-crypto/util/build/module/convertToBuffer.js
1041
+ var fromUtf82 = typeof Buffer !== "undefined" && Buffer.from ? function(input) {
1042
+ return Buffer.from(input, "utf8");
1043
+ } : fromUtf8;
1044
+ function convertToBuffer(data) {
1045
+ if (data instanceof Uint8Array)
1046
+ return data;
1047
+ if (typeof data === "string") {
1048
+ return fromUtf82(data);
1049
+ }
1050
+ if (ArrayBuffer.isView(data)) {
1051
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
1052
+ }
1053
+ return new Uint8Array(data);
1054
+ }
1055
+
1056
+ // node_modules/@aws-crypto/util/build/module/isEmptyData.js
1057
+ function isEmptyData(data) {
1058
+ if (typeof data === "string") {
1059
+ return data.length === 0;
1060
+ }
1061
+ return data.byteLength === 0;
1062
+ }
1063
+
1064
+ // node_modules/@aws-crypto/sha256-js/build/module/jsSha256.js
1065
+ var Sha256 = (
1066
+ /** @class */
1067
+ function() {
1068
+ function Sha2562(secret) {
1069
+ this.secret = secret;
1070
+ this.hash = new RawSha256();
1071
+ this.reset();
1072
+ }
1073
+ Sha2562.prototype.update = function(toHash) {
1074
+ if (isEmptyData(toHash) || this.error) {
1075
+ return;
1076
+ }
1077
+ try {
1078
+ this.hash.update(convertToBuffer(toHash));
1079
+ } catch (e) {
1080
+ this.error = e;
1081
+ }
1082
+ };
1083
+ Sha2562.prototype.digestSync = function() {
1084
+ if (this.error) {
1085
+ throw this.error;
1086
+ }
1087
+ if (this.outer) {
1088
+ if (!this.outer.finished) {
1089
+ this.outer.update(this.hash.digest());
1090
+ }
1091
+ return this.outer.digest();
1092
+ }
1093
+ return this.hash.digest();
1094
+ };
1095
+ Sha2562.prototype.digest = function() {
1096
+ return __awaiter(this, void 0, void 0, function() {
1097
+ return __generator(this, function(_a) {
1098
+ return [2, this.digestSync()];
1099
+ });
1100
+ });
1101
+ };
1102
+ Sha2562.prototype.reset = function() {
1103
+ this.hash = new RawSha256();
1104
+ if (this.secret) {
1105
+ this.outer = new RawSha256();
1106
+ var inner = bufferFromSecret(this.secret);
1107
+ var outer = new Uint8Array(BLOCK_SIZE);
1108
+ outer.set(inner);
1109
+ for (var i = 0; i < BLOCK_SIZE; i++) {
1110
+ inner[i] ^= 54;
1111
+ outer[i] ^= 92;
1112
+ }
1113
+ this.hash.update(inner);
1114
+ this.outer.update(outer);
1115
+ for (var i = 0; i < inner.byteLength; i++) {
1116
+ inner[i] = 0;
1117
+ }
1118
+ }
1119
+ };
1120
+ return Sha2562;
1121
+ }()
1122
+ );
1123
+ function bufferFromSecret(secret) {
1124
+ var input = convertToBuffer(secret);
1125
+ if (input.byteLength > BLOCK_SIZE) {
1126
+ var bufferHash = new RawSha256();
1127
+ bufferHash.update(input);
1128
+ input = bufferHash.digest();
1129
+ }
1130
+ var buffer = new Uint8Array(BLOCK_SIZE);
1131
+ buffer.set(input);
1132
+ return buffer;
1133
+ }
1134
+
1135
+ // src/FaustCompiler.ts
1136
+ var ab2str = (buf) => String.fromCharCode.apply(null, buf);
1137
+ var str2ab = (str) => {
1138
+ const buf = new ArrayBuffer(str.length);
1139
+ const bufView = new Uint8Array(buf);
1140
+ for (let i = 0, strLen = str.length; i < strLen; i++) {
1141
+ bufView[i] = str.charCodeAt(i);
1142
+ }
1143
+ return bufView;
1144
+ };
1145
+ var sha256 = async (str) => {
1146
+ const sha2562 = new Sha256();
1147
+ sha2562.update(str);
1148
+ const hashArray = Array.from(await sha2562.digest());
1149
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1150
+ return hashHex;
1151
+ };
1152
+ var _FaustCompiler = class _FaustCompiler {
1153
+ /**
1154
+ * Get a stringified DSP factories table
1155
+ */
1156
+ static serializeDSPFactories() {
1157
+ const table = {};
1158
+ this.gFactories.forEach((factory, shaKey) => {
1159
+ const { code, json, poly } = factory;
1160
+ table[shaKey] = { code: btoa(ab2str(code)), json: JSON.parse(json), poly };
1161
+ });
1162
+ return table;
1163
+ }
1164
+ /**
1165
+ * Get a stringified DSP factories table as string
1166
+ */
1167
+ static stringifyDSPFactories() {
1168
+ return JSON.stringify(this.serializeDSPFactories());
1169
+ }
1170
+ /**
1171
+ * Import a DSP factories table
1172
+ */
1173
+ static deserializeDSPFactories(table) {
1174
+ const awaited = [];
1175
+ for (const shaKey in table) {
1176
+ const factory = table[shaKey];
1177
+ const { code, json, poly } = factory;
1178
+ const ab = str2ab(atob(code));
1179
+ awaited.push(WebAssembly.compile(ab).then((module) => this.gFactories.set(shaKey, { shaKey, cfactory: 0, code: ab, module, json: JSON.stringify(json), poly, soundfiles: {} })));
1180
+ }
1181
+ return Promise.all(awaited);
1182
+ }
1183
+ /**
1184
+ * Import a stringified DSP factories table
1185
+ */
1186
+ static importDSPFactories(tableStr) {
1187
+ const table = JSON.parse(tableStr);
1188
+ return this.deserializeDSPFactories(table);
1189
+ }
1190
+ constructor(libFaust) {
1191
+ this.fLibFaust = libFaust;
1192
+ this.fErrorMessage = "";
1193
+ }
1194
+ intVec2intArray(vec) {
1195
+ const size = vec.size();
1196
+ const ui8Code = new Uint8Array(size);
1197
+ for (let i = 0; i < size; i++) {
1198
+ ui8Code[i] = vec.get(i);
1199
+ }
1200
+ return ui8Code;
1201
+ }
1202
+ async createDSPFactory(name, code, args, poly) {
1203
+ if (_FaustCompiler.gFactories.size > 10) {
1204
+ _FaustCompiler.gFactories.clear();
1205
+ }
1206
+ let shaKey = await sha256(name + code + args + (poly ? "poly" : "mono"));
1207
+ if (_FaustCompiler.gFactories.has(shaKey)) {
1208
+ return _FaustCompiler.gFactories.get(shaKey) || null;
1209
+ } else {
1210
+ try {
1211
+ const faustDspWasm = this.fLibFaust.createDSPFactory(name, code, args, !poly);
1212
+ const ui8Code = this.intVec2intArray(faustDspWasm.data);
1213
+ faustDspWasm.data.delete();
1214
+ const module = await WebAssembly.compile(ui8Code);
1215
+ const factory = { shaKey, cfactory: faustDspWasm.cfactory, code: ui8Code, module, json: faustDspWasm.json, poly, soundfiles: {} };
1216
+ this.deleteDSPFactory(factory);
1217
+ _FaustCompiler.gFactories.set(shaKey, factory);
1218
+ return factory;
1219
+ } catch (e) {
1220
+ this.fErrorMessage = this.fLibFaust.getErrorAfterException();
1221
+ this.fLibFaust.cleanupAfterException();
1222
+ throw this.fErrorMessage ? new Error(this.fErrorMessage) : e;
1223
+ }
1224
+ }
1225
+ }
1226
+ version() {
1227
+ return this.fLibFaust.version();
1228
+ }
1229
+ getErrorMessage() {
1230
+ return this.fErrorMessage;
1231
+ }
1232
+ async createMonoDSPFactory(name, code, args) {
1233
+ return this.createDSPFactory(name, code, args, false);
1234
+ }
1235
+ async createPolyDSPFactory(name, code, args) {
1236
+ return this.createDSPFactory(name, code, args, true);
1237
+ }
1238
+ deleteDSPFactory(factory) {
1239
+ this.fLibFaust.deleteDSPFactory(factory.cfactory);
1240
+ factory.cfactory = 0;
1241
+ }
1242
+ expandDSP(code, args) {
1243
+ try {
1244
+ return this.fLibFaust.expandDSP("FaustDSP", code, args);
1245
+ } catch (e) {
1246
+ this.fErrorMessage = this.fLibFaust.getErrorAfterException();
1247
+ this.fLibFaust.cleanupAfterException();
1248
+ throw this.fErrorMessage ? new Error(this.fErrorMessage) : e;
1249
+ }
1250
+ }
1251
+ generateAuxFiles(name, code, args) {
1252
+ try {
1253
+ return this.fLibFaust.generateAuxFiles(name, code, args);
1254
+ } catch (e) {
1255
+ this.fErrorMessage = this.fLibFaust.getErrorAfterException();
1256
+ this.fLibFaust.cleanupAfterException();
1257
+ throw this.fErrorMessage ? new Error(this.fErrorMessage) : e;
1258
+ }
1259
+ }
1260
+ deleteAllDSPFactories() {
1261
+ this.fLibFaust.deleteAllDSPFactories();
1262
+ }
1263
+ fs() {
1264
+ return this.fLibFaust.fs();
1265
+ }
1266
+ async getAsyncInternalMixerModule(isDouble = false) {
1267
+ const bufferKey = isDouble ? "mixer64Buffer" : "mixer32Buffer";
1268
+ const moduleKey = isDouble ? "mixer64Module" : "mixer32Module";
1269
+ if (this[moduleKey])
1270
+ return { mixerBuffer: this[bufferKey], mixerModule: this[moduleKey] };
1271
+ const path = isDouble ? "/usr/rsrc/mixer64.wasm" : "/usr/rsrc/mixer32.wasm";
1272
+ const mixerBuffer = this.fs().readFile(path, { encoding: "binary" });
1273
+ this[bufferKey] = mixerBuffer;
1274
+ const mixerModule = await WebAssembly.compile(mixerBuffer);
1275
+ this[moduleKey] = mixerModule;
1276
+ return { mixerBuffer, mixerModule };
1277
+ }
1278
+ getSyncInternalMixerModule(isDouble = false) {
1279
+ const bufferKey = isDouble ? "mixer64Buffer" : "mixer32Buffer";
1280
+ const moduleKey = isDouble ? "mixer64Module" : "mixer32Module";
1281
+ if (this[moduleKey])
1282
+ return { mixerBuffer: this[bufferKey], mixerModule: this[moduleKey] };
1283
+ const path = isDouble ? "/usr/rsrc/mixer64.wasm" : "/usr/rsrc/mixer32.wasm";
1284
+ const mixerBuffer = this.fs().readFile(path, { encoding: "binary" });
1285
+ this[bufferKey] = mixerBuffer;
1286
+ const mixerModule = new WebAssembly.Module(mixerBuffer);
1287
+ this[moduleKey] = mixerModule;
1288
+ return { mixerBuffer, mixerModule };
1289
+ }
1290
+ };
1291
+ _FaustCompiler.gFactories = /* @__PURE__ */ new Map();
1292
+ var FaustCompiler = _FaustCompiler;
1293
+ var FaustCompiler_default = FaustCompiler;
1294
+
1295
+ // src/FaustDspInstance.ts
1296
+ var FaustDspInstance = class {
1297
+ constructor(exports) {
1298
+ this.fExports = exports;
1299
+ }
1300
+ compute($dsp, count, $input, $output) {
1301
+ this.fExports.compute($dsp, count, $input, $output);
1302
+ }
1303
+ getNumInputs($dsp) {
1304
+ return this.fExports.getNumInputs($dsp);
1305
+ }
1306
+ getNumOutputs($dsp) {
1307
+ return this.fExports.getNumOutputs($dsp);
1308
+ }
1309
+ getParamValue($dsp, index) {
1310
+ return this.fExports.getParamValue($dsp, index);
1311
+ }
1312
+ getSampleRate($dsp) {
1313
+ return this.fExports.getSampleRate($dsp);
1314
+ }
1315
+ init($dsp, sampleRate) {
1316
+ this.fExports.init($dsp, sampleRate);
1317
+ }
1318
+ instanceClear($dsp) {
1319
+ this.fExports.instanceClear($dsp);
1320
+ }
1321
+ instanceConstants($dsp, sampleRate) {
1322
+ this.fExports.instanceConstants($dsp, sampleRate);
1323
+ }
1324
+ instanceInit($dsp, sampleRate) {
1325
+ this.fExports.instanceInit($dsp, sampleRate);
1326
+ }
1327
+ instanceResetUserInterface($dsp) {
1328
+ this.fExports.instanceResetUserInterface($dsp);
1329
+ }
1330
+ setParamValue($dsp, index, value) {
1331
+ this.fExports.setParamValue($dsp, index, value);
1332
+ }
1333
+ };
1334
+
1335
+ // src/FaustWasmInstantiator.ts
1336
+ var FaustWasmInstantiator = class {
1337
+ static createWasmImport(memory) {
1338
+ return {
1339
+ env: {
1340
+ memory: memory || new WebAssembly.Memory({ initial: 100 }),
1341
+ memoryBase: 0,
1342
+ tableBase: 0,
1343
+ // Integer version
1344
+ _abs: Math.abs,
1345
+ // Float version
1346
+ _acosf: Math.acos,
1347
+ _asinf: Math.asin,
1348
+ _atanf: Math.atan,
1349
+ _atan2f: Math.atan2,
1350
+ _ceilf: Math.ceil,
1351
+ _cosf: Math.cos,
1352
+ _expf: Math.exp,
1353
+ _floorf: Math.floor,
1354
+ _fmodf: (x, y) => x % y,
1355
+ _logf: Math.log,
1356
+ _log10f: Math.log10,
1357
+ _max_f: Math.max,
1358
+ _min_f: Math.min,
1359
+ _remainderf: (x, y) => x - Math.round(x / y) * y,
1360
+ _powf: Math.pow,
1361
+ _roundf: Math.round,
1362
+ _sinf: Math.sin,
1363
+ _sqrtf: Math.sqrt,
1364
+ _tanf: Math.tan,
1365
+ _acoshf: Math.acosh,
1366
+ _asinhf: Math.asinh,
1367
+ _atanhf: Math.atanh,
1368
+ _coshf: Math.cosh,
1369
+ _sinhf: Math.sinh,
1370
+ _tanhf: Math.tanh,
1371
+ _isnanf: Number.isNaN,
1372
+ _isinff: (x) => !isFinite(x),
1373
+ _copysignf: (x, y) => Math.sign(x) === Math.sign(y) ? x : -x,
1374
+ // Double version
1375
+ _acos: Math.acos,
1376
+ _asin: Math.asin,
1377
+ _atan: Math.atan,
1378
+ _atan2: Math.atan2,
1379
+ _ceil: Math.ceil,
1380
+ _cos: Math.cos,
1381
+ _exp: Math.exp,
1382
+ _floor: Math.floor,
1383
+ _fmod: (x, y) => x % y,
1384
+ _log: Math.log,
1385
+ _log10: Math.log10,
1386
+ _max_: Math.max,
1387
+ _min_: Math.min,
1388
+ _remainder: (x, y) => x - Math.round(x / y) * y,
1389
+ _pow: Math.pow,
1390
+ _round: Math.round,
1391
+ _sin: Math.sin,
1392
+ _sqrt: Math.sqrt,
1393
+ _tan: Math.tan,
1394
+ _acosh: Math.acosh,
1395
+ _asinh: Math.asinh,
1396
+ _atanh: Math.atanh,
1397
+ _cosh: Math.cosh,
1398
+ _sinh: Math.sinh,
1399
+ _tanh: Math.tanh,
1400
+ _isnan: Number.isNaN,
1401
+ _isinf: (x) => !isFinite(x),
1402
+ _copysign: (x, y) => Math.sign(x) === Math.sign(y) ? x : -x,
1403
+ table: new WebAssembly.Table({ initial: 0, element: "anyfunc" })
1404
+ }
1405
+ };
1406
+ }
1407
+ static createWasmMemoryPoly(voicesIn, sampleSize, dspMeta, effectMeta, bufferSize) {
1408
+ const voices = Math.max(4, voicesIn);
1409
+ const ptrSize = sampleSize;
1410
+ const pow2limit = (x) => {
1411
+ let n = 65536;
1412
+ while (n < x) {
1413
+ n *= 2;
1414
+ }
1415
+ return n;
1416
+ };
1417
+ const effectSize = effectMeta ? effectMeta.size : 0;
1418
+ let memorySize = pow2limit(
1419
+ effectSize + dspMeta.size * voices + (dspMeta.inputs + dspMeta.outputs * 2) * (ptrSize + bufferSize * sampleSize)
1420
+ ) / 65536;
1421
+ memorySize = Math.max(2, memorySize);
1422
+ return new WebAssembly.Memory({ initial: memorySize });
1423
+ }
1424
+ static createWasmMemoryMono(sampleSize, dspMeta, bufferSize) {
1425
+ const ptrSize = sampleSize;
1426
+ const memorySize = (dspMeta.size + (dspMeta.inputs + dspMeta.outputs) * (ptrSize + bufferSize * sampleSize)) / 65536;
1427
+ return new WebAssembly.Memory({ initial: memorySize * 2 });
1428
+ }
1429
+ static createMonoDSPInstanceAux(instance, json, mem = null) {
1430
+ const functions = instance.exports;
1431
+ const api = new FaustDspInstance(functions);
1432
+ const memory = mem ? mem : instance.exports.memory;
1433
+ return { memory, api, json };
1434
+ }
1435
+ static createMemoryMono(monoFactory) {
1436
+ const monoMeta = JSON.parse(monoFactory.json);
1437
+ const sampleSize = monoMeta.compile_options.match("-double") ? 8 : 4;
1438
+ return this.createWasmMemoryMono(sampleSize, monoMeta, 8192);
1439
+ }
1440
+ static createMemoryPoly(voices, voiceFactory, effectFactory) {
1441
+ const voiceMeta = JSON.parse(voiceFactory.json);
1442
+ const effectMeta = effectFactory && effectFactory.json ? JSON.parse(effectFactory.json) : null;
1443
+ const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
1444
+ return this.createWasmMemoryPoly(voices, sampleSize, voiceMeta, effectMeta, 8192);
1445
+ }
1446
+ static createMixerAux(mixerModule, memory) {
1447
+ const mixerImport = {
1448
+ imports: { print: console.log },
1449
+ memory: { memory }
1450
+ };
1451
+ const mixerInstance = new WebAssembly.Instance(mixerModule, mixerImport);
1452
+ const mixerFunctions = mixerInstance.exports;
1453
+ return mixerFunctions;
1454
+ }
1455
+ // Public API
1456
+ static async loadDSPFactory(wasmPath, jsonPath) {
1457
+ const wasmFile = await fetch(wasmPath);
1458
+ if (!wasmFile.ok) {
1459
+ throw new Error(`=> exception raised while running loadDSPFactory, file not found: ${wasmPath}`);
1460
+ }
1461
+ try {
1462
+ const wasmBuffer = await wasmFile.arrayBuffer();
1463
+ const module = await WebAssembly.compile(wasmBuffer);
1464
+ const jsonFile = await fetch(jsonPath);
1465
+ const json = await jsonFile.text();
1466
+ const meta = JSON.parse(json);
1467
+ const cOptions = meta.compile_options;
1468
+ const poly = cOptions.indexOf("wasm-e") !== -1;
1469
+ return { cfactory: 0, code: new Uint8Array(wasmBuffer), module, json, poly };
1470
+ } catch (e) {
1471
+ throw e;
1472
+ }
1473
+ }
1474
+ static async loadDSPMixer(mixerPath, fs) {
1475
+ try {
1476
+ let mixerBuffer = null;
1477
+ if (fs) {
1478
+ mixerBuffer = fs.readFile(mixerPath, { encoding: "binary" });
1479
+ } else {
1480
+ const mixerFile = await fetch(mixerPath);
1481
+ mixerBuffer = await mixerFile.arrayBuffer();
1482
+ }
1483
+ return WebAssembly.compile(mixerBuffer);
1484
+ } catch (e) {
1485
+ throw e;
1486
+ }
1487
+ }
1488
+ static async createAsyncMonoDSPInstance(factory) {
1489
+ const pattern = /"type":\s*"soundfile"/;
1490
+ const isDetected = pattern.test(factory.json);
1491
+ if (isDetected) {
1492
+ const memory = this.createMemoryMono(factory);
1493
+ const instance = await WebAssembly.instantiate(factory.module, this.createWasmImport(memory));
1494
+ return this.createMonoDSPInstanceAux(instance, factory.json, memory);
1495
+ } else {
1496
+ const instance = await WebAssembly.instantiate(factory.module, this.createWasmImport());
1497
+ return this.createMonoDSPInstanceAux(instance, factory.json);
1498
+ }
1499
+ }
1500
+ static createSyncMonoDSPInstance(factory) {
1501
+ const pattern = /"type":\s*"soundfile"/;
1502
+ const isDetected = pattern.test(factory.json);
1503
+ if (isDetected) {
1504
+ const memory = this.createMemoryMono(factory);
1505
+ const instance = new WebAssembly.Instance(factory.module, this.createWasmImport(memory));
1506
+ return this.createMonoDSPInstanceAux(instance, factory.json, memory);
1507
+ } else {
1508
+ const instance = new WebAssembly.Instance(factory.module, this.createWasmImport());
1509
+ return this.createMonoDSPInstanceAux(instance, factory.json);
1510
+ }
1511
+ }
1512
+ static async createAsyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory) {
1513
+ const memory = this.createMemoryPoly(voices, voiceFactory, effectFactory);
1514
+ const voiceInstance = await WebAssembly.instantiate(voiceFactory.module, this.createWasmImport(memory));
1515
+ const voiceFunctions = voiceInstance.exports;
1516
+ const voiceAPI = new FaustDspInstance(voiceFunctions);
1517
+ const mixerAPI = this.createMixerAux(mixerModule, memory);
1518
+ if (effectFactory) {
1519
+ const effectInstance = await WebAssembly.instantiate(effectFactory.module, this.createWasmImport(memory));
1520
+ const effectFunctions = effectInstance.exports;
1521
+ const effectAPI = new FaustDspInstance(effectFunctions);
1522
+ return {
1523
+ memory,
1524
+ voices,
1525
+ voiceAPI,
1526
+ effectAPI,
1527
+ mixerAPI,
1528
+ voiceJSON: voiceFactory.json,
1529
+ effectJSON: effectFactory.json
1530
+ };
1531
+ } else {
1532
+ return {
1533
+ memory,
1534
+ voices,
1535
+ voiceAPI,
1536
+ mixerAPI,
1537
+ voiceJSON: voiceFactory.json
1538
+ };
1539
+ }
1540
+ }
1541
+ static createSyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory) {
1542
+ const memory = this.createMemoryPoly(voices, voiceFactory, effectFactory);
1543
+ const voiceInstance = new WebAssembly.Instance(voiceFactory.module, this.createWasmImport(memory));
1544
+ const voiceFunctions = voiceInstance.exports;
1545
+ const voiceAPI = new FaustDspInstance(voiceFunctions);
1546
+ const mixerAPI = this.createMixerAux(mixerModule, memory);
1547
+ if (effectFactory) {
1548
+ const effectInstance = new WebAssembly.Instance(effectFactory.module, this.createWasmImport(memory));
1549
+ const effectFunctions = effectInstance.exports;
1550
+ const effectAPI = new FaustDspInstance(effectFunctions);
1551
+ return {
1552
+ memory,
1553
+ voices,
1554
+ voiceAPI,
1555
+ effectAPI,
1556
+ mixerAPI,
1557
+ voiceJSON: voiceFactory.json,
1558
+ effectJSON: effectFactory.json
1559
+ };
1560
+ } else {
1561
+ return {
1562
+ memory,
1563
+ voices,
1564
+ voiceAPI,
1565
+ mixerAPI,
1566
+ voiceJSON: voiceFactory.json
1567
+ };
1568
+ }
1569
+ }
1570
+ };
1571
+ var FaustWasmInstantiator_default = FaustWasmInstantiator;
1572
+
1573
+ // src/FaustSensors.ts
1574
+ var FaustSensors = class _FaustSensors {
1575
+ /**
1576
+ * Function to convert a number to an axis type
1577
+ *
1578
+ * @param value number
1579
+ * @returns axis type
1580
+ */
1581
+ static convertToAxis(value) {
1582
+ switch (value) {
1583
+ case 0:
1584
+ return 0 /* x */;
1585
+ case 1:
1586
+ return 1 /* y */;
1587
+ case 2:
1588
+ return 2 /* z */;
1589
+ default:
1590
+ console.error("Error: Axis not found value: " + value);
1591
+ return 0 /* x */;
1592
+ }
1593
+ }
1594
+ /**
1595
+ * Function to convert a number to a curve type
1596
+ *
1597
+ * @param value number
1598
+ * @returns curve type
1599
+ */
1600
+ static convertToCurve(value) {
1601
+ switch (value) {
1602
+ case 0:
1603
+ return 0 /* Up */;
1604
+ case 1:
1605
+ return 1 /* Down */;
1606
+ case 2:
1607
+ return 2 /* UpDown */;
1608
+ case 3:
1609
+ return 3 /* DownUp */;
1610
+ default:
1611
+ console.error("Error: Curve not found value: " + value);
1612
+ return 0 /* Up */;
1613
+ }
1614
+ }
1615
+ static get Range() {
1616
+ if (!this._Range) {
1617
+ this._Range = class {
1618
+ constructor(x, y) {
1619
+ this.fLo = Math.min(x, y);
1620
+ this.fHi = Math.max(x, y);
1621
+ }
1622
+ clip(x) {
1623
+ if (x < this.fLo)
1624
+ return this.fLo;
1625
+ if (x > this.fHi)
1626
+ return this.fHi;
1627
+ return x;
1628
+ }
1629
+ };
1630
+ }
1631
+ return this._Range;
1632
+ }
1633
+ /**
1634
+ * Interpolator class
1635
+ */
1636
+ static get Interpolator() {
1637
+ if (!this._Interpolator) {
1638
+ this._Interpolator = class {
1639
+ constructor(lo, hi, v1, v2) {
1640
+ this.fRange = new _FaustSensors.Range(lo, hi);
1641
+ if (hi !== lo) {
1642
+ this.fCoef = (v2 - v1) / (hi - lo);
1643
+ this.fOffset = v1 - lo * this.fCoef;
1644
+ } else {
1645
+ this.fCoef = 0;
1646
+ this.fOffset = (v1 + v2) / 2;
1647
+ }
1648
+ }
1649
+ returnMappedValue(v) {
1650
+ var x = this.fRange.clip(v);
1651
+ return this.fOffset + x * this.fCoef;
1652
+ }
1653
+ getLowHigh(amin, amax) {
1654
+ return { amin: this.fRange.fLo, amax: this.fRange.fHi };
1655
+ }
1656
+ };
1657
+ }
1658
+ return this._Interpolator;
1659
+ }
1660
+ /**
1661
+ * Interpolator3pt class, combine two interpolators
1662
+ */
1663
+ static get Interpolator3pt() {
1664
+ if (!this._Interpolator3pt) {
1665
+ this._Interpolator3pt = class {
1666
+ constructor(lo, mid, hi, v1, vMid, v2) {
1667
+ this.fSegment1 = new _FaustSensors.Interpolator(lo, mid, v1, vMid);
1668
+ this.fSegment2 = new _FaustSensors.Interpolator(mid, hi, vMid, v2);
1669
+ this.fMid = mid;
1670
+ }
1671
+ returnMappedValue(x) {
1672
+ return x < this.fMid ? this.fSegment1.returnMappedValue(x) : this.fSegment2.returnMappedValue(x);
1673
+ }
1674
+ getMappingValues(amin, amid, amax) {
1675
+ var lowHighSegment1 = this.fSegment1.getLowHigh(amin, amid);
1676
+ var lowHighSegment2 = this.fSegment2.getLowHigh(amid, amax);
1677
+ return { amin: lowHighSegment1.amin, amid: lowHighSegment2.amin, amax: lowHighSegment2.amax };
1678
+ }
1679
+ };
1680
+ }
1681
+ return this._Interpolator3pt;
1682
+ }
1683
+ /**
1684
+ * UpConverter class, convert accelerometer value to Faust value
1685
+ */
1686
+ static get UpConverter() {
1687
+ if (!this._UpConverter) {
1688
+ this._UpConverter = class {
1689
+ constructor(amin, amid, amax, fmin, fmid, fmax) {
1690
+ this.fActive = true;
1691
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
1692
+ this.fF2A = new _FaustSensors.Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
1693
+ }
1694
+ uiToFaust(x) {
1695
+ return this.fA2F.returnMappedValue(x);
1696
+ }
1697
+ faustToUi(x) {
1698
+ return this.fF2A.returnMappedValue(x);
1699
+ }
1700
+ setMappingValues(amin, amid, amax, min, init, max) {
1701
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, min, init, max);
1702
+ this.fF2A = new _FaustSensors.Interpolator3pt(min, init, max, amin, amid, amax);
1703
+ }
1704
+ getMappingValues(amin, amid, amax) {
1705
+ return this.fA2F.getMappingValues(amin, amid, amax);
1706
+ }
1707
+ setActive(onOff) {
1708
+ this.fActive = onOff;
1709
+ }
1710
+ getActive() {
1711
+ return this.fActive;
1712
+ }
1713
+ };
1714
+ }
1715
+ return this._UpConverter;
1716
+ }
1717
+ /**
1718
+ * DownConverter class, convert accelerometer value to Faust value
1719
+ */
1720
+ static get DownConverter() {
1721
+ if (!this._DownConverter) {
1722
+ this._DownConverter = class {
1723
+ constructor(amin, amid, amax, fmin, fmid, fmax) {
1724
+ this.fActive = true;
1725
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
1726
+ this.fF2A = new _FaustSensors.Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
1727
+ }
1728
+ uiToFaust(x) {
1729
+ return this.fA2F.returnMappedValue(x);
1730
+ }
1731
+ faustToUi(x) {
1732
+ return this.fF2A.returnMappedValue(x);
1733
+ }
1734
+ setMappingValues(amin, amid, amax, min, init, max) {
1735
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, max, init, min);
1736
+ this.fF2A = new _FaustSensors.Interpolator3pt(min, init, max, amax, amid, amin);
1737
+ }
1738
+ getMappingValues(amin, amid, amax) {
1739
+ return this.fA2F.getMappingValues(amin, amid, amax);
1740
+ }
1741
+ setActive(onOff) {
1742
+ this.fActive = onOff;
1743
+ }
1744
+ getActive() {
1745
+ return this.fActive;
1746
+ }
1747
+ };
1748
+ }
1749
+ return this._DownConverter;
1750
+ }
1751
+ /**
1752
+ * UpDownConverter class, convert accelerometer value to Faust value
1753
+ */
1754
+ static get UpDownConverter() {
1755
+ if (!this._UpDownConverter) {
1756
+ this._UpDownConverter = class {
1757
+ constructor(amin, amid, amax, fmin, fmid, fmax) {
1758
+ this.fActive = true;
1759
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
1760
+ this.fF2A = new _FaustSensors.Interpolator(fmin, fmax, amin, amax);
1761
+ }
1762
+ uiToFaust(x) {
1763
+ return this.fA2F.returnMappedValue(x);
1764
+ }
1765
+ faustToUi(x) {
1766
+ return this.fF2A.returnMappedValue(x);
1767
+ }
1768
+ setMappingValues(amin, amid, amax, min, init, max) {
1769
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, min, max, min);
1770
+ this.fF2A = new _FaustSensors.Interpolator(min, max, amin, amax);
1771
+ }
1772
+ getMappingValues(amin, amid, amax) {
1773
+ return this.fA2F.getMappingValues(amin, amid, amax);
1774
+ }
1775
+ setActive(onOff) {
1776
+ this.fActive = onOff;
1777
+ }
1778
+ getActive() {
1779
+ return this.fActive;
1780
+ }
1781
+ };
1782
+ }
1783
+ return this._UpDownConverter;
1784
+ }
1785
+ static get DownUpConverter() {
1786
+ if (!this._DownUpConverter) {
1787
+ this._DownUpConverter = class {
1788
+ constructor(amin, amid, amax, fmin, fmid, fmax) {
1789
+ this.fActive = true;
1790
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
1791
+ this.fF2A = new _FaustSensors.Interpolator(fmin, fmax, amin, amax);
1792
+ }
1793
+ uiToFaust(x) {
1794
+ return this.fA2F.returnMappedValue(x);
1795
+ }
1796
+ faustToUi(x) {
1797
+ return this.fF2A.returnMappedValue(x);
1798
+ }
1799
+ setMappingValues(amin, amid, amax, min, init, max) {
1800
+ this.fA2F = new _FaustSensors.Interpolator3pt(amin, amid, amax, max, min, max);
1801
+ this.fF2A = new _FaustSensors.Interpolator(min, max, amin, amax);
1802
+ }
1803
+ getMappingValues(amin, amid, amax) {
1804
+ return this.fA2F.getMappingValues(amin, amid, amax);
1805
+ }
1806
+ setActive(onOff) {
1807
+ this.fActive = onOff;
1808
+ }
1809
+ getActive() {
1810
+ return this.fActive;
1811
+ }
1812
+ };
1813
+ }
1814
+ return this._DownUpConverter;
1815
+ }
1816
+ /**
1817
+ * Public function to build the accelerometer handler
1818
+ *
1819
+ * @returns `UpdatableValueConverter` built for the given curve
1820
+ */
1821
+ static buildHandler(curve, amin, amid, amax, min, init, max) {
1822
+ switch (curve) {
1823
+ case 0 /* Up */:
1824
+ return new _FaustSensors.UpConverter(amin, amid, amax, min, init, max);
1825
+ case 1 /* Down */:
1826
+ return new _FaustSensors.DownConverter(amin, amid, amax, min, init, max);
1827
+ case 2 /* UpDown */:
1828
+ return new _FaustSensors.UpDownConverter(amin, amid, amax, min, init, max);
1829
+ case 3 /* DownUp */:
1830
+ return new _FaustSensors.DownUpConverter(amin, amid, amax, min, init, max);
1831
+ default:
1832
+ return new _FaustSensors.UpConverter(amin, amid, amax, min, init, max);
1833
+ }
1834
+ }
1835
+ };
1836
+
1837
+ // src/FaustWebAudioDsp.ts
1838
+ var WasmAllocator = class {
1839
+ constructor(memory, offset) {
1840
+ this.memory = memory;
1841
+ this.allocatedBytes = offset;
1842
+ }
1843
+ /**
1844
+ * Allocates a block of memory of the specified size, returning the pointer to the
1845
+ * beginning of the block. The block is allocated at the current offset and the
1846
+ * offset is incremented by the size of the block.
1847
+ *
1848
+ * @param sizeInBytes The size of the block to allocate in bytes.
1849
+ * @returns The offset (pointer) to the beginning of the allocated block.
1850
+ */
1851
+ alloc(sizeInBytes) {
1852
+ const currentOffset = this.allocatedBytes;
1853
+ const newOffset = currentOffset + sizeInBytes;
1854
+ const totalMemoryBytes = this.memory.buffer.byteLength;
1855
+ if (newOffset > totalMemoryBytes) {
1856
+ const neededPages = Math.ceil((newOffset - totalMemoryBytes) / 65536);
1857
+ console.log(`GROW: ${neededPages} pages`);
1858
+ this.memory.grow(neededPages);
1859
+ }
1860
+ this.allocatedBytes = newOffset;
1861
+ return currentOffset;
1862
+ }
1863
+ /**
1864
+ * Returns the underlying buffer object.
1865
+ *
1866
+ * @returns The buffer object.
1867
+ */
1868
+ getBuffer() {
1869
+ return this.memory.buffer;
1870
+ }
1871
+ /**
1872
+ * Returns the Int32 view of the underlying buffer object.
1873
+ *
1874
+ * @returns The view of the memory buffer as Int32Array.
1875
+ */
1876
+ getInt32Array() {
1877
+ return new Int32Array(this.memory.buffer);
1878
+ }
1879
+ /**
1880
+ * Returns the Int64 view of the underlying buffer object.
1881
+ *
1882
+ * @returns The view of the memory buffer as BigInt64Array.
1883
+ */
1884
+ getInt64Array() {
1885
+ return new BigInt64Array(this.memory.buffer);
1886
+ }
1887
+ /**
1888
+ * Returns the Float32 view of the underlying buffer object.
1889
+ *
1890
+ * @returns The view of the memory buffer as Float32Array.
1891
+ */
1892
+ getFloat32Array() {
1893
+ return new Float32Array(this.memory.buffer);
1894
+ }
1895
+ /**
1896
+ * Returns the Float64 view of the underlying buffer object..
1897
+ *
1898
+ * @returns The view of the memory buffer as Float64Array.
1899
+ */
1900
+ getFloat64Array() {
1901
+ return new Float64Array(this.memory.buffer);
1902
+ }
1903
+ };
1904
+ var Soundfile = class _Soundfile {
1905
+ /** Maximum number of soundfile parts. */
1906
+ static get MAX_SOUNDFILE_PARTS() {
1907
+ return 256;
1908
+ }
1909
+ /** Maximum number of channels. */
1910
+ static get MAX_CHAN() {
1911
+ return 64;
1912
+ }
1913
+ /** Maximum buffer size in frames. */
1914
+ static get BUFFER_SIZE() {
1915
+ return 1024;
1916
+ }
1917
+ /** Default sample rate. */
1918
+ static get SAMPLE_RATE() {
1919
+ return 44100;
1920
+ }
1921
+ constructor(allocator, sampleSize, curChan, length, maxChan, totalParts) {
1922
+ this.fSampleSize = sampleSize;
1923
+ this.fIntSize = this.fSampleSize;
1924
+ this.fPtrSize = 4;
1925
+ this.fAllocator = allocator;
1926
+ console.log(`Soundfile constructor: curChan: ${curChan}, length: ${length}, maxChan: ${maxChan}, totalParts: ${totalParts}`);
1927
+ this.fPtr = allocator.alloc(4 * this.fPtrSize);
1928
+ this.fLength = allocator.alloc(_Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
1929
+ this.fSR = allocator.alloc(_Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
1930
+ this.fOffset = allocator.alloc(_Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
1931
+ this.fBuffers = this.allocBuffers(curChan, length, maxChan);
1932
+ const HEAP32 = this.fAllocator.getInt32Array();
1933
+ HEAP32[this.fPtr >> 2] = this.fBuffers;
1934
+ HEAP32[this.fPtr + this.fPtrSize >> 2] = this.fLength;
1935
+ HEAP32[this.fPtr + 2 * this.fPtrSize >> 2] = this.fSR;
1936
+ HEAP32[this.fPtr + 3 * this.fPtrSize >> 2] = this.fOffset;
1937
+ for (let chan = 0; chan < curChan; chan++) {
1938
+ const buffer = HEAP32[(this.fBuffers >> 2) + chan];
1939
+ console.log(`allocBuffers AFTER: ${chan} - ${buffer}`);
1940
+ }
1941
+ }
1942
+ allocBuffers(curChan, length, maxChan) {
1943
+ const buffers = this.fAllocator.alloc(maxChan * this.fPtrSize);
1944
+ console.log(`allocBuffers buffers: ${buffers}`);
1945
+ for (let chan = 0; chan < curChan; chan++) {
1946
+ const buffer = this.fAllocator.alloc(length * this.fSampleSize);
1947
+ const HEAP32 = this.fAllocator.getInt32Array();
1948
+ HEAP32[(buffers >> 2) + chan] = buffer;
1949
+ }
1950
+ return buffers;
1951
+ }
1952
+ shareBuffers(curChan, maxChan) {
1953
+ const HEAP32 = this.fAllocator.getInt32Array();
1954
+ for (let chan = curChan; chan < maxChan; chan++) {
1955
+ HEAP32[(this.fBuffers >> 2) + chan] = HEAP32[(this.fBuffers >> 2) + chan % curChan];
1956
+ }
1957
+ }
1958
+ copyToOut(part, maxChannels, offset, audioData) {
1959
+ if (this.fIntSize === 4) {
1960
+ const HEAP32 = this.fAllocator.getInt32Array();
1961
+ HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] = audioData.audioBuffer[0].length;
1962
+ HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] = audioData.sampleRate;
1963
+ HEAP32[(this.fOffset >> Math.log2(this.fIntSize)) + part] = offset;
1964
+ } else {
1965
+ const HEAP64 = this.fAllocator.getInt64Array();
1966
+ HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(audioData.audioBuffer[0].length);
1967
+ HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(audioData.sampleRate);
1968
+ HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] = BigInt(offset);
1969
+ }
1970
+ console.log(`copyToOut: part: ${part}, maxChannels: ${maxChannels}, offset: ${offset}, buffer: ${audioData}`);
1971
+ if (this.fSampleSize === 8) {
1972
+ this.copyToOutReal64(maxChannels, offset, audioData);
1973
+ } else {
1974
+ this.copyToOutReal32(maxChannels, offset, audioData);
1975
+ }
1976
+ }
1977
+ copyToOutReal32(maxChannels, offset, audioData) {
1978
+ const HEAP32 = this.fAllocator.getInt32Array();
1979
+ const HEAPF = this.fAllocator.getFloat32Array();
1980
+ for (let chan = 0; chan < audioData.audioBuffer.length; chan++) {
1981
+ const input = audioData.audioBuffer[chan];
1982
+ const output = HEAP32[(this.fBuffers >> 2) + chan];
1983
+ const begin = output + offset * this.fSampleSize >> Math.log2(this.fSampleSize);
1984
+ const end = output + (offset + input.length) * this.fSampleSize >> Math.log2(this.fSampleSize);
1985
+ console.log(`copyToOutReal32 begin: ${begin}, end: ${end}, delta: ${end - begin}`);
1986
+ const outputReal = HEAPF.subarray(
1987
+ output + offset * this.fSampleSize >> Math.log2(this.fSampleSize),
1988
+ output + (offset + input.length) * this.fSampleSize >> Math.log2(this.fSampleSize)
1989
+ );
1990
+ for (let sample = 0; sample < input.length; sample++) {
1991
+ outputReal[sample] = input[sample];
1992
+ }
1993
+ }
1994
+ }
1995
+ copyToOutReal64(maxChannels, offset, audioData) {
1996
+ const HEAP32 = this.fAllocator.getInt32Array();
1997
+ const HEAPF = this.fAllocator.getFloat64Array();
1998
+ for (let chan = 0; chan < audioData.audioBuffer.length; chan++) {
1999
+ const input = audioData.audioBuffer[chan];
2000
+ const output = HEAP32[(this.fBuffers >> 2) + chan];
2001
+ const begin = output + offset * this.fSampleSize >> Math.log2(this.fSampleSize);
2002
+ const end = output + (offset + input.length) * this.fSampleSize >> Math.log2(this.fSampleSize);
2003
+ console.log(`copyToOutReal64 begin: ${begin}, end: ${end}, delta: ${end - begin}`);
2004
+ const outputReal = HEAPF.subarray(
2005
+ output + offset * this.fSampleSize >> Math.log2(this.fSampleSize),
2006
+ output + (offset + input.length) * this.fSampleSize >> Math.log2(this.fSampleSize)
2007
+ );
2008
+ for (let sample = 0; sample < input.length; sample++) {
2009
+ outputReal[sample] = input[sample];
2010
+ }
2011
+ }
2012
+ }
2013
+ emptyFile(part, offset) {
2014
+ if (this.fIntSize === 4) {
2015
+ const HEAP32 = this.fAllocator.getInt32Array();
2016
+ HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] = _Soundfile.BUFFER_SIZE;
2017
+ HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] = _Soundfile.SAMPLE_RATE;
2018
+ HEAP32[(this.fOffset >> Math.log2(this.fIntSize)) + part] = offset;
2019
+ } else {
2020
+ const HEAP64 = this.fAllocator.getInt64Array();
2021
+ HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(_Soundfile.BUFFER_SIZE);
2022
+ HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(_Soundfile.SAMPLE_RATE);
2023
+ HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] = BigInt(offset);
2024
+ }
2025
+ return offset + _Soundfile.BUFFER_SIZE;
2026
+ }
2027
+ displayMemory(where = "", mem = false) {
2028
+ console.log("Soundfile memory: " + where);
2029
+ console.log(`fPtr: ${this.fPtr}`);
2030
+ console.log(`fBuffers: ${this.fBuffers}`);
2031
+ console.log(`fLength: ${this.fLength}`);
2032
+ console.log(`fSR: ${this.fSR}`);
2033
+ console.log(`fOffset: ${this.fOffset}`);
2034
+ const HEAP32 = this.fAllocator.getInt32Array();
2035
+ if (mem)
2036
+ console.log(`HEAP32: ${HEAP32}`);
2037
+ console.log(`HEAP32[this.fPtr >> 2]: ${HEAP32[this.fPtr >> 2]}`);
2038
+ console.log(`HEAP32[(this.fPtr + ptrSize) >> 2]: ${HEAP32[this.fPtr + this.fPtrSize >> 2]}`);
2039
+ console.log(`HEAP32[(this.fPtr + 2 * ptrSize) >> 2]: ${HEAP32[this.fPtr + 2 * this.fPtrSize >> 2]}`);
2040
+ console.log(`HEAP32[(this.fPtr + 3 * ptrSize) >> 2]: ${HEAP32[this.fPtr + 3 * this.fPtrSize >> 2]}`);
2041
+ }
2042
+ // Return the pointer to the soundfile structure in wasm memory
2043
+ getPtr() {
2044
+ return this.fPtr;
2045
+ }
2046
+ getHEAP32() {
2047
+ return this.fAllocator.getInt32Array();
2048
+ }
2049
+ getHEAPFloat32() {
2050
+ return this.fAllocator.getFloat32Array();
2051
+ }
2052
+ getHEAPFloat64() {
2053
+ return this.fAllocator.getFloat64Array();
2054
+ }
2055
+ };
2056
+ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2057
+ constructor(sampleSize, bufferSize, soundfiles) {
2058
+ this.fOutputHandler = null;
2059
+ this.fComputeHandler = null;
2060
+ // To handle MIDI events plot
2061
+ this.fPlotHandler = null;
2062
+ this.fCachedEvents = [];
2063
+ this.fBufferNum = 0;
2064
+ this.fInChannels = [];
2065
+ this.fOutChannels = [];
2066
+ this.fOutputsTimer = 5;
2067
+ // UI items path
2068
+ this.fInputsItems = [];
2069
+ this.fOutputsItems = [];
2070
+ this.fDescriptor = [];
2071
+ // Soundfile handling
2072
+ this.fSoundfiles = [];
2073
+ this.fSoundfileBuffers = {};
2074
+ // MIDI handling
2075
+ this.fPitchwheelLabel = [];
2076
+ this.fCtrlLabel = new Array(128).fill(null).map(() => []);
2077
+ this.fPathTable = {};
2078
+ this.fUICallback = (item) => {
2079
+ if (item.type === "hbargraph" || item.type === "vbargraph") {
2080
+ this.fOutputsItems.push(item.address);
2081
+ this.fPathTable[item.address] = item.index;
2082
+ } else if (item.type === "vslider" || item.type === "hslider" || item.type === "button" || item.type === "checkbox" || item.type === "nentry") {
2083
+ this.fInputsItems.push(item.address);
2084
+ this.fPathTable[item.address] = item.index;
2085
+ this.fDescriptor.push(item);
2086
+ if (!item.meta)
2087
+ return;
2088
+ item.meta.forEach((meta) => {
2089
+ const { midi, acc, gyr } = meta;
2090
+ if (midi) {
2091
+ const strMidi = midi.trim();
2092
+ if (strMidi === "pitchwheel") {
2093
+ const matched = strMidi.match(/^pitchwheel\s(\d+)/);
2094
+ if (matched) {
2095
+ this.fPitchwheelLabel.push({ path: item.address, chan: parseInt(matched[1]), min: item.min, max: item.max });
2096
+ } else {
2097
+ this.fPitchwheelLabel.push({ path: item.address, chan: 0, min: item.min, max: item.max });
2098
+ }
2099
+ } else {
2100
+ const matched2 = strMidi.match(/^ctrl\s(\d+)\s(\d+)/);
2101
+ const matched1 = strMidi.match(/^ctrl\s(\d+)/);
2102
+ if (matched2) {
2103
+ this.fCtrlLabel[parseInt(matched2[1])].push({ path: item.address, chan: parseInt(matched2[2]), min: item.min, max: item.max });
2104
+ } else if (matched1) {
2105
+ this.fCtrlLabel[parseInt(matched1[1])].push({ path: item.address, chan: 0, min: item.min, max: item.max });
2106
+ }
2107
+ }
2108
+ }
2109
+ if (acc) {
2110
+ const numAcc = acc.trim().split(" ").map(Number);
2111
+ this.setupAccHandler(item.address, FaustSensors.convertToAxis(numAcc[0]), FaustSensors.convertToCurve(numAcc[1]), numAcc[2], numAcc[3], numAcc[4], item.min, item.init, item.max);
2112
+ }
2113
+ if (gyr) {
2114
+ const numAcc = gyr.trim().split(" ").map(Number);
2115
+ this.setupGyrHandler(item.address, FaustSensors.convertToAxis(numAcc[0]), FaustSensors.convertToCurve(numAcc[1]), numAcc[2], numAcc[3], numAcc[4], item.min, item.init, item.max);
2116
+ }
2117
+ });
2118
+ } else if (item.type === "soundfile") {
2119
+ this.fSoundfiles.push({ name: item.label, url: item.url, index: item.index, basePtr: -1 });
2120
+ }
2121
+ };
2122
+ // Audio callback
2123
+ this.fProcessing = false;
2124
+ this.fDestroyed = false;
2125
+ this.fFirstCall = true;
2126
+ this.fBufferSize = bufferSize;
2127
+ this.fPtrSize = sampleSize;
2128
+ this.fSampleSize = sampleSize;
2129
+ this.fSoundfileBuffers = soundfiles;
2130
+ this.fAcc = { x: [], y: [], z: [] };
2131
+ this.fGyr = { x: [], y: [], z: [] };
2132
+ }
2133
+ // Tools
2134
+ static remap(v, mn0, mx0, mn1, mx1) {
2135
+ return (v - mn0) / (mx0 - mn0) * (mx1 - mn1) + mn1;
2136
+ }
2137
+ // JSON parsing functions
2138
+ static parseUI(ui, callback) {
2139
+ ui.forEach((group) => this.parseGroup(group, callback));
2140
+ }
2141
+ static parseGroup(group, callback) {
2142
+ if (group.items) {
2143
+ this.parseItems(group.items, callback);
2144
+ }
2145
+ }
2146
+ static parseItems(items, callback) {
2147
+ items.forEach((item) => this.parseItem(item, callback));
2148
+ }
2149
+ static parseItem(item, callback) {
2150
+ if (item.type === "vgroup" || item.type === "hgroup" || item.type === "tgroup") {
2151
+ this.parseItems(item.items, callback);
2152
+ } else {
2153
+ callback(item);
2154
+ }
2155
+ }
2156
+ /** Split the soundfile names and return an array of names */
2157
+ static splitSoundfileNames(input) {
2158
+ let trimmed = input.replace(/^\{|\}$/g, "");
2159
+ return trimmed.split(";").map((str) => str.length <= 2 ? "" : str.substring(1, str.length - 1));
2160
+ }
2161
+ get hasAccInput() {
2162
+ return this.fAcc.x.length + this.fAcc.y.length + this.fAcc.z.length > 0;
2163
+ }
2164
+ propagateAcc(accelerationIncludingGravity, invert = false) {
2165
+ const { x, y, z } = accelerationIncludingGravity;
2166
+ if (invert) {
2167
+ if (x !== null)
2168
+ this.fAcc.x.forEach((handler) => handler(-x));
2169
+ if (y !== null)
2170
+ this.fAcc.y.forEach((handler) => handler(-y));
2171
+ if (z !== null)
2172
+ this.fAcc.z.forEach((handler) => handler(-z));
2173
+ } else {
2174
+ if (x !== null)
2175
+ this.fAcc.x.forEach((handler) => handler(x));
2176
+ if (y !== null)
2177
+ this.fAcc.y.forEach((handler) => handler(y));
2178
+ if (z !== null)
2179
+ this.fAcc.z.forEach((handler) => handler(z));
2180
+ }
2181
+ }
2182
+ get hasGyrInput() {
2183
+ return this.fGyr.x.length + this.fGyr.y.length + this.fGyr.z.length > 0;
2184
+ }
2185
+ propagateGyr(event) {
2186
+ const { alpha, beta, gamma } = event;
2187
+ if (alpha !== null)
2188
+ this.fGyr.x.forEach((handler) => handler(alpha));
2189
+ if (beta !== null)
2190
+ this.fGyr.y.forEach((handler) => handler(beta));
2191
+ if (gamma !== null)
2192
+ this.fGyr.z.forEach((handler) => handler(gamma));
2193
+ }
2194
+ /** Build the accelerometer handler */
2195
+ setupAccHandler(path, axis, curve, amin, amid, amax, min, init, max) {
2196
+ const handler = FaustSensors.buildHandler(curve, amin, amid, amax, min, init, max);
2197
+ switch (axis) {
2198
+ case 0 /* x */:
2199
+ this.fAcc.x.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2200
+ break;
2201
+ case 1 /* y */:
2202
+ this.fAcc.y.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2203
+ break;
2204
+ case 2 /* z */:
2205
+ this.fAcc.z.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2206
+ break;
2207
+ }
2208
+ }
2209
+ /** Build the gyroscope handler */
2210
+ setupGyrHandler(path, axis, curve, amin, amid, amax, min, init, max) {
2211
+ const handler = FaustSensors.buildHandler(curve, amin, amid, amax, min, init, max);
2212
+ switch (axis) {
2213
+ case 0 /* x */:
2214
+ this.fGyr.x.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2215
+ break;
2216
+ case 1 /* y */:
2217
+ this.fGyr.y.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2218
+ break;
2219
+ case 2 /* z */:
2220
+ this.fGyr.z.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
2221
+ break;
2222
+ }
2223
+ }
2224
+ static extractUrlsFromMeta(dspMeta) {
2225
+ const soundfilesEntry = dspMeta.meta.find((entry) => entry.soundfiles !== void 0);
2226
+ if (soundfilesEntry) {
2227
+ return soundfilesEntry.soundfiles.split(";").filter((url) => url !== "");
2228
+ } else {
2229
+ return [];
2230
+ }
2231
+ }
2232
+ /**
2233
+ * Load a soundfile possibly containing several parts in the DSP struct.
2234
+ * Soundfile pointers are located at 'index' offset, to be read in the JSON file.
2235
+ * The DSP struct is located at baseDSP in the wasm memory,
2236
+ * either a monophonic DSP, or a voice in a polyphonic context.
2237
+ *
2238
+ * @param allocator : the wasm memory allocator
2239
+ * @param baseDSP : the base DSP in the wasm memory
2240
+ * @param name : the name of the soundfile
2241
+ * @param url : the url of the soundfile
2242
+ */
2243
+ loadSoundfile(allocator, baseDSP, name, url) {
2244
+ console.log(`Soundfile ${name} paths: ${url}`);
2245
+ const soundfileIds = _FaustBaseWebAudioDsp.splitSoundfileNames(url);
2246
+ const item = this.fSoundfiles.find((item2) => item2.url === url);
2247
+ if (!item)
2248
+ throw new Error(`Soundfile with ${url} cannot be found !}`);
2249
+ if (item.basePtr !== -1) {
2250
+ const HEAP32 = allocator.getInt32Array();
2251
+ console.log(`Soundfile CACHE ${url}} : ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`);
2252
+ HEAP32[baseDSP + item.index >> 2] = item.basePtr;
2253
+ } else {
2254
+ const soundfile = this.createSoundfile(allocator, soundfileIds, this.fSoundfileBuffers);
2255
+ if (soundfile) {
2256
+ const HEAP32 = soundfile.getHEAP32();
2257
+ item.basePtr = soundfile.getPtr();
2258
+ console.log(`Soundfile ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`);
2259
+ HEAP32[baseDSP + item.index >> 2] = item.basePtr;
2260
+ } else {
2261
+ console.log(`Soundfile ${name} for ${url} cannot be created !}`);
2262
+ }
2263
+ }
2264
+ }
2265
+ createSoundfile(allocator, soundfileIdList, soundfiles, maxChan = Soundfile.MAX_CHAN) {
2266
+ let curChan = 1;
2267
+ let totalLength = 0;
2268
+ for (const soundfileId of soundfileIdList) {
2269
+ let chan = 0;
2270
+ let len = 0;
2271
+ const audioData = soundfiles[soundfileId];
2272
+ if (audioData) {
2273
+ chan = audioData.audioBuffer.length;
2274
+ len = audioData.audioBuffer[0].length;
2275
+ } else {
2276
+ len = Soundfile.BUFFER_SIZE;
2277
+ chan = 1;
2278
+ }
2279
+ curChan = Math.max(curChan, chan);
2280
+ totalLength += len;
2281
+ }
2282
+ totalLength += (Soundfile.MAX_SOUNDFILE_PARTS - soundfileIdList.length) * Soundfile.BUFFER_SIZE;
2283
+ const soundfile = new Soundfile(allocator, this.fSampleSize, curChan, totalLength, maxChan, soundfileIdList.length);
2284
+ let offset = 0;
2285
+ for (let part = 0; part < soundfileIdList.length; part++) {
2286
+ const soundfileId = soundfileIdList[part];
2287
+ const audioData = soundfiles[soundfileId];
2288
+ if (audioData) {
2289
+ soundfile.copyToOut(part, maxChan, offset, audioData);
2290
+ offset += audioData.audioBuffer[0].length;
2291
+ } else {
2292
+ offset = soundfile.emptyFile(part, offset);
2293
+ }
2294
+ }
2295
+ for (let part = soundfileIdList.length; part < Soundfile.MAX_SOUNDFILE_PARTS; part++) {
2296
+ offset = soundfile.emptyFile(part, offset);
2297
+ }
2298
+ soundfile.shareBuffers(curChan, maxChan);
2299
+ return soundfile;
2300
+ }
2301
+ /**
2302
+ * Init soundfiles memory.
2303
+ *
2304
+ * @param allocator : the wasm memory allocator
2305
+ * @param sfReader : the soundfile reader
2306
+ * @param baseDSP : the DSP struct (either a monophonic DSP of polyphonic voice) base DSP in the wasm memory
2307
+ */
2308
+ initSoundfileMemory(allocator, baseDSP) {
2309
+ for (const { name, url } of this.fSoundfiles) {
2310
+ this.loadSoundfile(allocator, baseDSP, name, url);
2311
+ }
2312
+ ;
2313
+ }
2314
+ updateOutputs() {
2315
+ if (this.fOutputsItems.length > 0 && this.fOutputHandler && this.fOutputsTimer-- === 0) {
2316
+ this.fOutputsTimer = 5;
2317
+ this.fOutputsItems.forEach((item) => {
2318
+ var _a;
2319
+ return (_a = this.fOutputHandler) == null ? void 0 : _a.call(this, item, this.getParamValue(item));
2320
+ });
2321
+ }
2322
+ }
2323
+ // Public API
2324
+ metadata(handler) {
2325
+ if (this.fJSONDsp.meta) {
2326
+ this.fJSONDsp.meta.forEach((meta) => handler(Object.keys(meta)[0], meta[Object.keys(meta)[0]]));
2327
+ }
2328
+ }
2329
+ compute(input, output) {
2330
+ return false;
2331
+ }
2332
+ setOutputParamHandler(handler) {
2333
+ this.fOutputHandler = handler;
2334
+ }
2335
+ getOutputParamHandler() {
2336
+ return this.fOutputHandler;
2337
+ }
2338
+ setComputeHandler(handler) {
2339
+ this.fComputeHandler = handler;
2340
+ }
2341
+ getComputeHandler() {
2342
+ return this.fComputeHandler;
2343
+ }
2344
+ setPlotHandler(handler) {
2345
+ this.fPlotHandler = handler;
2346
+ }
2347
+ getPlotHandler() {
2348
+ return this.fPlotHandler;
2349
+ }
2350
+ getNumInputs() {
2351
+ return -1;
2352
+ }
2353
+ getNumOutputs() {
2354
+ return -1;
2355
+ }
2356
+ midiMessage(data) {
2357
+ if (this.fPlotHandler)
2358
+ this.fCachedEvents.push({ data, type: "midi" });
2359
+ const cmd = data[0] >> 4;
2360
+ const channel = data[0] & 15;
2361
+ const data1 = data[1];
2362
+ const data2 = data[2];
2363
+ if (cmd === 11)
2364
+ return this.ctrlChange(channel, data1, data2);
2365
+ if (cmd === 14)
2366
+ return this.pitchWheel(channel, data2 * 128 + data1);
2367
+ }
2368
+ ctrlChange(channel, ctrl, value) {
2369
+ if (this.fPlotHandler)
2370
+ this.fCachedEvents.push({ type: "ctrlChange", data: [channel, ctrl, value] });
2371
+ if (this.fCtrlLabel[ctrl].length) {
2372
+ this.fCtrlLabel[ctrl].forEach((ctrl2) => {
2373
+ const { path, chan } = ctrl2;
2374
+ if (chan === 0 || channel === chan - 1) {
2375
+ this.setParamValue(path, _FaustBaseWebAudioDsp.remap(value, 0, 127, ctrl2.min, ctrl2.max));
2376
+ if (this.fOutputHandler)
2377
+ this.fOutputHandler(path, this.getParamValue(path));
2378
+ }
2379
+ });
2380
+ }
2381
+ }
2382
+ pitchWheel(channel, wheel) {
2383
+ if (this.fPlotHandler)
2384
+ this.fCachedEvents.push({ type: "pitchWheel", data: [channel, wheel] });
2385
+ this.fPitchwheelLabel.forEach((pw) => {
2386
+ const { path, chan } = pw;
2387
+ if (chan === 0 || channel === chan - 1) {
2388
+ this.setParamValue(path, _FaustBaseWebAudioDsp.remap(wheel, 0, 16383, pw.min, pw.max));
2389
+ if (this.fOutputHandler)
2390
+ this.fOutputHandler(path, this.getParamValue(path));
2391
+ }
2392
+ });
2393
+ }
2394
+ setParamValue(path, value) {
2395
+ }
2396
+ getParamValue(path) {
2397
+ return 0;
2398
+ }
2399
+ getParams() {
2400
+ return this.fInputsItems;
2401
+ }
2402
+ getMeta() {
2403
+ return this.fJSONDsp;
2404
+ }
2405
+ getJSON() {
2406
+ return JSON.stringify(this.getMeta());
2407
+ }
2408
+ getUI() {
2409
+ return this.fJSONDsp.ui;
2410
+ }
2411
+ getDescriptors() {
2412
+ return this.fDescriptor;
2413
+ }
2414
+ hasSoundfiles() {
2415
+ return this.fSoundfiles.length > 0;
2416
+ }
2417
+ start() {
2418
+ this.fProcessing = true;
2419
+ }
2420
+ stop() {
2421
+ this.fProcessing = false;
2422
+ }
2423
+ destroy() {
2424
+ this.fDestroyed = true;
2425
+ this.fOutputHandler = null;
2426
+ this.fComputeHandler = null;
2427
+ this.fPlotHandler = null;
2428
+ }
2429
+ };
2430
+ var FaustMonoWebAudioDsp = class extends FaustBaseWebAudioDsp {
2431
+ constructor(instance, sampleRate, sampleSize, bufferSize, soundfiles) {
2432
+ super(sampleSize, bufferSize, soundfiles);
2433
+ this.fInstance = instance;
2434
+ console.log(`sampleSize: ${sampleSize} bufferSize: ${bufferSize}`);
2435
+ this.fJSONDsp = JSON.parse(this.fInstance.json);
2436
+ FaustBaseWebAudioDsp.parseUI(this.fJSONDsp.ui, this.fUICallback);
2437
+ this.fEndMemory = this.initMemory();
2438
+ this.fInstance.api.init(this.fDSP, sampleRate);
2439
+ if (this.fSoundfiles.length > 0) {
2440
+ const allocator = new WasmAllocator(this.fInstance.memory, this.fEndMemory);
2441
+ this.initSoundfileMemory(allocator, this.fDSP);
2442
+ }
2443
+ }
2444
+ initMemory() {
2445
+ this.fDSP = 0;
2446
+ const $audio = this.fJSONDsp.size;
2447
+ this.fAudioInputs = $audio;
2448
+ this.fAudioOutputs = this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
2449
+ const $audioInputs = this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
2450
+ const $audioOutputs = $audioInputs + this.getNumInputs() * this.fBufferSize * this.fSampleSize;
2451
+ const endMemory = $audioOutputs + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
2452
+ const HEAP = this.fInstance.memory.buffer;
2453
+ const HEAP32 = new Int32Array(HEAP);
2454
+ const HEAPF = this.fSampleSize === 4 ? new Float32Array(HEAP) : new Float64Array(HEAP);
2455
+ if (this.getNumInputs() > 0) {
2456
+ for (let chan = 0; chan < this.getNumInputs(); chan++) {
2457
+ HEAP32[(this.fAudioInputs >> 2) + chan] = $audioInputs + this.fBufferSize * this.fSampleSize * chan;
2458
+ }
2459
+ const dspInChans = HEAP32.subarray(this.fAudioInputs >> 2, this.fAudioInputs + this.getNumInputs() * this.fPtrSize >> 2);
2460
+ for (let chan = 0; chan < this.getNumInputs(); chan++) {
2461
+ this.fInChannels[chan] = HEAPF.subarray(dspInChans[chan] >> Math.log2(this.fSampleSize), dspInChans[chan] + this.fBufferSize * this.fSampleSize >> Math.log2(this.fSampleSize));
2462
+ }
2463
+ }
2464
+ if (this.getNumOutputs() > 0) {
2465
+ for (let chan = 0; chan < this.getNumOutputs(); chan++) {
2466
+ HEAP32[(this.fAudioOutputs >> 2) + chan] = $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
2467
+ }
2468
+ const dspOutChans = HEAP32.subarray(this.fAudioOutputs >> 2, this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize >> 2);
2469
+ for (let chan = 0; chan < this.getNumOutputs(); chan++) {
2470
+ this.fOutChannels[chan] = HEAPF.subarray(dspOutChans[chan] >> Math.log2(this.fSampleSize), dspOutChans[chan] + this.fBufferSize * this.fSampleSize >> Math.log2(this.fSampleSize));
2471
+ }
2472
+ }
2473
+ return endMemory;
2474
+ }
2475
+ toString() {
2476
+ return `============== Mono Memory layout ==============
2477
+ this.fBufferSize: ${this.fBufferSize}
2478
+ this.fJSONDsp.size: ${this.fJSONDsp.size}
2479
+ this.fAudioInputs: ${this.fAudioInputs}
2480
+ this.fAudioOutputs: ${this.fAudioOutputs}
2481
+ this.fDSP: ${this.fDSP}`;
2482
+ }
2483
+ // Public API
2484
+ compute(input, output) {
2485
+ if (this.fDestroyed)
2486
+ return false;
2487
+ if (!this.fProcessing)
2488
+ return true;
2489
+ if (this.fFirstCall) {
2490
+ this.initMemory();
2491
+ this.fFirstCall = false;
2492
+ }
2493
+ if (typeof input === "function") {
2494
+ input(this.fInChannels);
2495
+ } else {
2496
+ if (this.getNumInputs() > 0 && (!input || !input[0] || input[0].length === 0)) {
2497
+ return true;
2498
+ }
2499
+ if (this.getNumOutputs() > 0 && typeof output !== "function" && (!output || !output[0] || output[0].length === 0)) {
2500
+ return true;
2501
+ }
2502
+ if (input !== void 0) {
2503
+ for (let chan = 0; chan < Math.min(this.getNumInputs(), input.length); chan++) {
2504
+ const dspInput = this.fInChannels[chan];
2505
+ dspInput.set(input[chan]);
2506
+ }
2507
+ }
2508
+ }
2509
+ if (this.fComputeHandler)
2510
+ this.fComputeHandler(this.fBufferSize);
2511
+ this.fInstance.api.compute(this.fDSP, this.fBufferSize, this.fAudioInputs, this.fAudioOutputs);
2512
+ this.updateOutputs();
2513
+ let forPlot = this.fOutChannels;
2514
+ if (typeof output === "function") {
2515
+ output(this.fOutChannels);
2516
+ } else {
2517
+ for (let chan = 0; chan < Math.min(this.getNumOutputs(), output.length); chan++) {
2518
+ const dspOutput = this.fOutChannels[chan];
2519
+ output[chan].set(dspOutput);
2520
+ }
2521
+ forPlot = output;
2522
+ }
2523
+ if (this.fPlotHandler) {
2524
+ this.fPlotHandler(forPlot, this.fBufferNum++, this.fCachedEvents.length ? this.fCachedEvents : void 0);
2525
+ this.fCachedEvents = [];
2526
+ }
2527
+ return true;
2528
+ }
2529
+ metadata(handler) {
2530
+ super.metadata(handler);
2531
+ }
2532
+ getNumInputs() {
2533
+ return this.fInstance.api.getNumInputs(this.fDSP);
2534
+ }
2535
+ getNumOutputs() {
2536
+ return this.fInstance.api.getNumOutputs(this.fDSP);
2537
+ }
2538
+ setParamValue(path, value) {
2539
+ if (this.fPlotHandler)
2540
+ this.fCachedEvents.push({ type: "param", data: { path, value } });
2541
+ this.fInstance.api.setParamValue(this.fDSP, this.fPathTable[path], value);
2542
+ }
2543
+ getParamValue(path) {
2544
+ return this.fInstance.api.getParamValue(this.fDSP, this.fPathTable[path]);
2545
+ }
2546
+ getMeta() {
2547
+ return this.fJSONDsp;
2548
+ }
2549
+ getJSON() {
2550
+ return this.fInstance.json;
2551
+ }
2552
+ getDescriptors() {
2553
+ return this.fDescriptor;
2554
+ }
2555
+ getUI() {
2556
+ return this.fJSONDsp.ui;
2557
+ }
2558
+ };
2559
+ var FaustWebAudioDspVoice = class _FaustWebAudioDspVoice {
2560
+ constructor($dsp, api, inputItems, pathTable, sampleRate) {
2561
+ this.fFreqLabel = [];
2562
+ this.fGateLabel = [];
2563
+ this.fGainLabel = [];
2564
+ this.fKeyLabel = [];
2565
+ this.fVelLabel = [];
2566
+ // Voice DSP code
2567
+ // Accessed by PolyDSPImp class
2568
+ this.fCurNote = _FaustWebAudioDspVoice.kFreeVoice;
2569
+ this.fNextNote = -1;
2570
+ this.fNextVel = -1;
2571
+ this.fDate = 0;
2572
+ this.fLevel = 0;
2573
+ this.fRelease = 0;
2574
+ this.fDSP = $dsp;
2575
+ this.fAPI = api;
2576
+ this.fAPI.init(this.fDSP, sampleRate);
2577
+ this.extractPaths(inputItems, pathTable);
2578
+ }
2579
+ // Voice state
2580
+ static get kActiveVoice() {
2581
+ return 0;
2582
+ }
2583
+ static get kFreeVoice() {
2584
+ return -1;
2585
+ }
2586
+ static get kReleaseVoice() {
2587
+ return -2;
2588
+ }
2589
+ static get kLegatoVoice() {
2590
+ return -3;
2591
+ }
2592
+ static get kNoVoice() {
2593
+ return -4;
2594
+ }
2595
+ static get VOICE_STOP_LEVEL() {
2596
+ return 5e-4;
2597
+ }
2598
+ static midiToFreq(note) {
2599
+ return 440 * 2 ** ((note - 69) / 12);
2600
+ }
2601
+ static normalizeVelocity(velocity) {
2602
+ return velocity / 127;
2603
+ }
2604
+ extractPaths(inputItems, pathTable) {
2605
+ inputItems.forEach((item) => {
2606
+ if (item.endsWith("/gate")) {
2607
+ this.fGateLabel.push(pathTable[item]);
2608
+ } else if (item.endsWith("/freq")) {
2609
+ this.fFreqLabel.push(pathTable[item]);
2610
+ } else if (item.endsWith("/key")) {
2611
+ this.fKeyLabel.push(pathTable[item]);
2612
+ } else if (item.endsWith("/gain")) {
2613
+ this.fGainLabel.push(pathTable[item]);
2614
+ } else if (item.endsWith("/vel") && item.endsWith("/velocity")) {
2615
+ this.fVelLabel.push(pathTable[item]);
2616
+ }
2617
+ });
2618
+ }
2619
+ // Public API
2620
+ keyOn(pitch, velocity, legato = false) {
2621
+ if (legato) {
2622
+ this.fNextNote = pitch;
2623
+ this.fNextVel = velocity;
2624
+ } else {
2625
+ this.fFreqLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, _FaustWebAudioDspVoice.midiToFreq(pitch)));
2626
+ this.fGateLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, 1));
2627
+ this.fGainLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, _FaustWebAudioDspVoice.normalizeVelocity(velocity)));
2628
+ this.fKeyLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, pitch));
2629
+ this.fVelLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, velocity));
2630
+ this.fCurNote = pitch;
2631
+ }
2632
+ }
2633
+ keyOff(hard = false) {
2634
+ this.fGateLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, 0));
2635
+ if (hard) {
2636
+ this.fCurNote = _FaustWebAudioDspVoice.kFreeVoice;
2637
+ } else {
2638
+ this.fRelease = this.fAPI.getSampleRate(this.fDSP) / 2;
2639
+ this.fCurNote = _FaustWebAudioDspVoice.kReleaseVoice;
2640
+ }
2641
+ }
2642
+ computeLegato(bufferSize, $inputs, $outputZero, $outputsHalf) {
2643
+ let size = bufferSize / 2;
2644
+ this.fGateLabel.forEach((index) => this.fAPI.setParamValue(this.fDSP, index, 0));
2645
+ this.fAPI.compute(this.fDSP, size, $inputs, $outputZero);
2646
+ this.keyOn(this.fNextNote, this.fNextVel);
2647
+ this.fAPI.compute(this.fDSP, size, $inputs, $outputsHalf);
2648
+ }
2649
+ compute(bufferSize, $inputs, $outputs) {
2650
+ this.fAPI.compute(this.fDSP, bufferSize, $inputs, $outputs);
2651
+ }
2652
+ setParamValue(index, value) {
2653
+ this.fAPI.setParamValue(this.fDSP, index, value);
2654
+ }
2655
+ getParamValue(index) {
2656
+ return this.fAPI.getParamValue(this.fDSP, index);
2657
+ }
2658
+ };
2659
+ var FaustPolyWebAudioDsp = class _FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp {
2660
+ constructor(instance, sampleRate, sampleSize, bufferSize, soundfiles) {
2661
+ super(sampleSize, bufferSize, soundfiles);
2662
+ this.fInstance = instance;
2663
+ console.log(`sampleSize: ${sampleSize} bufferSize: ${bufferSize}`);
2664
+ this.fJSONDsp = JSON.parse(this.fInstance.voiceJSON);
2665
+ this.fJSONEffect = this.fInstance.effectAPI && this.fInstance.effectJSON ? JSON.parse(this.fInstance.effectJSON) : null;
2666
+ FaustBaseWebAudioDsp.parseUI(this.fJSONDsp.ui, this.fUICallback);
2667
+ if (this.fJSONEffect)
2668
+ FaustBaseWebAudioDsp.parseUI(this.fJSONEffect.ui, this.fUICallback);
2669
+ this.fEndMemory = this.initMemory();
2670
+ this.fVoiceTable = [];
2671
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2672
+ this.fVoiceTable.push(new FaustWebAudioDspVoice(
2673
+ this.fJSONDsp.size * voice,
2674
+ this.fInstance.voiceAPI,
2675
+ this.fInputsItems,
2676
+ this.fPathTable,
2677
+ sampleRate
2678
+ ));
2679
+ }
2680
+ if (this.fInstance.effectAPI)
2681
+ this.fInstance.effectAPI.init(this.fEffect, sampleRate);
2682
+ if (this.fSoundfiles.length > 0) {
2683
+ const allocator = new WasmAllocator(this.fInstance.memory, this.fEndMemory);
2684
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2685
+ this.initSoundfileMemory(allocator, this.fJSONDsp.size * voice);
2686
+ }
2687
+ }
2688
+ }
2689
+ initMemory() {
2690
+ this.fEffect = this.fJSONDsp.size * this.fInstance.voices;
2691
+ const $audio = this.fEffect + (this.fJSONEffect ? this.fJSONEffect.size : 0);
2692
+ this.fAudioInputs = $audio;
2693
+ this.fAudioOutputs = this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
2694
+ this.fAudioMixing = this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
2695
+ this.fAudioMixingHalf = this.fAudioMixing + this.getNumOutputs() * this.fPtrSize;
2696
+ const $audioInputs = this.fAudioMixingHalf + this.getNumOutputs() * this.fPtrSize;
2697
+ const $audioOutputs = $audioInputs + this.getNumInputs() * this.fBufferSize * this.fSampleSize;
2698
+ const $audioMixing = $audioOutputs + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
2699
+ const endMemory = $audioMixing + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
2700
+ const HEAP = this.fInstance.memory.buffer;
2701
+ const HEAP32 = new Int32Array(HEAP);
2702
+ const HEAPF = this.fSampleSize === 4 ? new Float32Array(HEAP) : new Float64Array(HEAP);
2703
+ if (this.getNumInputs() > 0) {
2704
+ for (let chan = 0; chan < this.getNumInputs(); chan++) {
2705
+ HEAP32[(this.fAudioInputs >> 2) + chan] = $audioInputs + this.fBufferSize * this.fSampleSize * chan;
2706
+ }
2707
+ const dspInChans = HEAP32.subarray(this.fAudioInputs >> 2, this.fAudioInputs + this.getNumInputs() * this.fPtrSize >> 2);
2708
+ for (let chan = 0; chan < this.getNumInputs(); chan++) {
2709
+ this.fInChannels[chan] = HEAPF.subarray(dspInChans[chan] >> Math.log2(this.fSampleSize), dspInChans[chan] + this.fBufferSize * this.fSampleSize >> Math.log2(this.fSampleSize));
2710
+ }
2711
+ }
2712
+ if (this.getNumOutputs() > 0) {
2713
+ for (let chan = 0; chan < this.getNumOutputs(); chan++) {
2714
+ HEAP32[(this.fAudioOutputs >> 2) + chan] = $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
2715
+ HEAP32[(this.fAudioMixing >> 2) + chan] = $audioMixing + this.fBufferSize * this.fSampleSize * chan;
2716
+ HEAP32[(this.fAudioMixingHalf >> 2) + chan] = $audioMixing + this.fBufferSize * this.fSampleSize * chan + this.fBufferSize / 2 * this.fSampleSize;
2717
+ }
2718
+ const dspOutChans = HEAP32.subarray(this.fAudioOutputs >> 2, this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize >> 2);
2719
+ for (let chan = 0; chan < this.getNumOutputs(); chan++) {
2720
+ this.fOutChannels[chan] = HEAPF.subarray(dspOutChans[chan] >> Math.log2(this.fSampleSize), dspOutChans[chan] + this.fBufferSize * this.fSampleSize >> Math.log2(this.fSampleSize));
2721
+ }
2722
+ }
2723
+ return endMemory;
2724
+ }
2725
+ toString() {
2726
+ return `============== Poly Memory layout ==============
2727
+ this.fBufferSize: ${this.fBufferSize}
2728
+ this.fJSONDsp.size: ${this.fJSONDsp.size}
2729
+ this.fAudioInputs: ${this.fAudioInputs}
2730
+ this.fAudioOutputs: ${this.fAudioOutputs}
2731
+ this.fAudioMixing: ${this.fAudioMixing}
2732
+ this.fAudioMixingHalf: ${this.fAudioMixingHalf}`;
2733
+ }
2734
+ allocVoice(voice, type) {
2735
+ this.fVoiceTable[voice].fDate++;
2736
+ this.fVoiceTable[voice].fCurNote = type;
2737
+ return voice;
2738
+ }
2739
+ getPlayingVoice(pitch) {
2740
+ let voicePlaying = FaustWebAudioDspVoice.kNoVoice;
2741
+ let oldestDatePlaying = Number.MAX_VALUE;
2742
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2743
+ if (this.fVoiceTable[voice].fCurNote === pitch) {
2744
+ if (this.fVoiceTable[voice].fDate < oldestDatePlaying) {
2745
+ oldestDatePlaying = this.fVoiceTable[voice].fDate;
2746
+ voicePlaying = voice;
2747
+ }
2748
+ }
2749
+ }
2750
+ return voicePlaying;
2751
+ }
2752
+ getFreeVoice() {
2753
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2754
+ if (this.fVoiceTable[voice].fCurNote === FaustWebAudioDspVoice.kFreeVoice) {
2755
+ return this.allocVoice(voice, FaustWebAudioDspVoice.kActiveVoice);
2756
+ }
2757
+ }
2758
+ let voiceRelease = FaustWebAudioDspVoice.kNoVoice;
2759
+ let voicePlaying = FaustWebAudioDspVoice.kNoVoice;
2760
+ let oldestDateRelease = Number.MAX_VALUE;
2761
+ let oldestDatePlaying = Number.MAX_VALUE;
2762
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2763
+ if (this.fVoiceTable[voice].fCurNote === FaustWebAudioDspVoice.kReleaseVoice) {
2764
+ if (this.fVoiceTable[voice].fDate < oldestDateRelease) {
2765
+ oldestDateRelease = this.fVoiceTable[voice].fDate;
2766
+ voiceRelease = voice;
2767
+ }
2768
+ } else if (this.fVoiceTable[voice].fDate < oldestDatePlaying) {
2769
+ oldestDatePlaying = this.fVoiceTable[voice].fDate;
2770
+ voicePlaying = voice;
2771
+ }
2772
+ }
2773
+ if (oldestDateRelease !== Number.MAX_VALUE) {
2774
+ console.log(`Steal release voice : voice_date = ${this.fVoiceTable[voiceRelease].fDate} voice = ${voiceRelease}`);
2775
+ return this.allocVoice(voiceRelease, FaustWebAudioDspVoice.kLegatoVoice);
2776
+ }
2777
+ if (oldestDatePlaying !== Number.MAX_VALUE) {
2778
+ console.log(`Steal playing voice : voice_date = ${this.fVoiceTable[voicePlaying].fDate} voice = ${voicePlaying}`);
2779
+ return this.allocVoice(voicePlaying, FaustWebAudioDspVoice.kLegatoVoice);
2780
+ }
2781
+ return FaustWebAudioDspVoice.kNoVoice;
2782
+ }
2783
+ // Public API
2784
+ compute(input, output) {
2785
+ if (this.fDestroyed)
2786
+ return false;
2787
+ if (this.fFirstCall) {
2788
+ this.initMemory();
2789
+ this.fFirstCall = false;
2790
+ }
2791
+ if (!this.fProcessing)
2792
+ return true;
2793
+ if (this.getNumInputs() > 0 && (!input || !input[0] || input[0].length === 0)) {
2794
+ return true;
2795
+ }
2796
+ if (this.getNumOutputs() > 0 && (!output || !output[0] || output[0].length === 0)) {
2797
+ return true;
2798
+ }
2799
+ if (input !== void 0) {
2800
+ for (let chan = 0; chan < Math.min(this.getNumInputs(), input.length); ++chan) {
2801
+ const dspInput = this.fInChannels[chan];
2802
+ dspInput.set(input[chan]);
2803
+ }
2804
+ }
2805
+ if (this.fComputeHandler)
2806
+ this.fComputeHandler(this.fBufferSize);
2807
+ this.fInstance.mixerAPI.clearOutput(this.fBufferSize, this.getNumOutputs(), this.fAudioOutputs);
2808
+ this.fVoiceTable.forEach((voice) => {
2809
+ if (voice.fCurNote === FaustWebAudioDspVoice.kLegatoVoice) {
2810
+ voice.computeLegato(this.fBufferSize, this.fAudioInputs, this.fAudioMixing, this.fAudioMixingHalf);
2811
+ this.fInstance.mixerAPI.fadeOut(this.fBufferSize / 2, this.getNumOutputs(), this.fAudioMixing);
2812
+ voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(this.fBufferSize, this.getNumOutputs(), this.fAudioMixing, this.fAudioOutputs);
2813
+ } else if (voice.fCurNote !== FaustWebAudioDspVoice.kFreeVoice) {
2814
+ voice.compute(this.fBufferSize, this.fAudioInputs, this.fAudioMixing);
2815
+ voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(this.fBufferSize, this.getNumOutputs(), this.fAudioMixing, this.fAudioOutputs);
2816
+ voice.fRelease -= this.fBufferSize;
2817
+ if (voice.fCurNote == FaustWebAudioDspVoice.kReleaseVoice && (voice.fLevel < FaustWebAudioDspVoice.VOICE_STOP_LEVEL && voice.fRelease < 0)) {
2818
+ voice.fCurNote = FaustWebAudioDspVoice.kFreeVoice;
2819
+ }
2820
+ }
2821
+ });
2822
+ if (this.fInstance.effectAPI)
2823
+ this.fInstance.effectAPI.compute(this.fEffect, this.fBufferSize, this.fAudioOutputs, this.fAudioOutputs);
2824
+ this.updateOutputs();
2825
+ if (output !== void 0) {
2826
+ for (let chan = 0; chan < Math.min(this.getNumOutputs(), output.length); chan++) {
2827
+ const dspOutput = this.fOutChannels[chan];
2828
+ output[chan].set(dspOutput);
2829
+ }
2830
+ if (this.fPlotHandler) {
2831
+ this.fPlotHandler(output, this.fBufferNum++, this.fCachedEvents.length ? this.fCachedEvents : void 0);
2832
+ this.fCachedEvents = [];
2833
+ }
2834
+ }
2835
+ return true;
2836
+ }
2837
+ getNumInputs() {
2838
+ return this.fInstance.voiceAPI.getNumInputs(0);
2839
+ }
2840
+ getNumOutputs() {
2841
+ return this.fInstance.voiceAPI.getNumOutputs(0);
2842
+ }
2843
+ static findPath(o, p) {
2844
+ if (typeof o !== "object") {
2845
+ return false;
2846
+ } else if (o.address) {
2847
+ return o.address === p;
2848
+ } else {
2849
+ for (const k in o) {
2850
+ if (_FaustPolyWebAudioDsp.findPath(o[k], p))
2851
+ return true;
2852
+ }
2853
+ return false;
2854
+ }
2855
+ }
2856
+ setParamValue(path, value) {
2857
+ if (this.fPlotHandler)
2858
+ this.fCachedEvents.push({ type: "param", data: { path, value } });
2859
+ if (this.fJSONEffect && _FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) && this.fInstance.effectAPI) {
2860
+ this.fInstance.effectAPI.setParamValue(this.fEffect, this.fPathTable[path], value);
2861
+ } else {
2862
+ this.fVoiceTable.forEach((voice) => voice.setParamValue(this.fPathTable[path], value));
2863
+ }
2864
+ }
2865
+ getParamValue(path) {
2866
+ if (this.fJSONEffect && _FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) && this.fInstance.effectAPI) {
2867
+ return this.fInstance.effectAPI.getParamValue(this.fEffect, this.fPathTable[path]);
2868
+ } else {
2869
+ return this.fVoiceTable[0].getParamValue(this.fPathTable[path]);
2870
+ }
2871
+ }
2872
+ getMeta() {
2873
+ const o = this.fJSONDsp;
2874
+ const e = this.fJSONEffect;
2875
+ const r = { ...o };
2876
+ if (e) {
2877
+ r.ui = [{
2878
+ type: "tgroup",
2879
+ label: "Sequencer",
2880
+ items: [
2881
+ { type: "vgroup", label: "Instrument", items: o.ui },
2882
+ { type: "vgroup", label: "Effect", items: e.ui }
2883
+ ]
2884
+ }];
2885
+ } else {
2886
+ r.ui = [{
2887
+ type: "tgroup",
2888
+ label: "Polyphonic",
2889
+ items: [
2890
+ { type: "vgroup", label: "Voices", items: o.ui }
2891
+ ]
2892
+ }];
2893
+ }
2894
+ return r;
2895
+ }
2896
+ getJSON() {
2897
+ return JSON.stringify(this.getMeta());
2898
+ }
2899
+ getUI() {
2900
+ return this.getMeta().ui;
2901
+ }
2902
+ getDescriptors() {
2903
+ return this.fDescriptor;
2904
+ }
2905
+ midiMessage(data) {
2906
+ const cmd = data[0] >> 4;
2907
+ const channel = data[0] & 15;
2908
+ const data1 = data[1];
2909
+ const data2 = data[2];
2910
+ if (cmd === 8 || cmd === 9 && data2 === 0)
2911
+ return this.keyOff(channel, data1, data2);
2912
+ else if (cmd === 9)
2913
+ return this.keyOn(channel, data1, data2);
2914
+ else
2915
+ super.midiMessage(data);
2916
+ }
2917
+ ctrlChange(channel, ctrl, value) {
2918
+ if (ctrl === 123 || ctrl === 120) {
2919
+ this.allNotesOff(true);
2920
+ } else {
2921
+ super.ctrlChange(channel, ctrl, value);
2922
+ }
2923
+ }
2924
+ keyOn(channel, pitch, velocity) {
2925
+ if (this.fPlotHandler)
2926
+ this.fCachedEvents.push({ type: "keyOn", data: [channel, pitch, velocity] });
2927
+ const voice = this.getFreeVoice();
2928
+ this.fVoiceTable[voice].keyOn(pitch, velocity, this.fVoiceTable[voice].fCurNote == FaustWebAudioDspVoice.kLegatoVoice);
2929
+ }
2930
+ keyOff(channel, pitch, velocity) {
2931
+ if (this.fPlotHandler)
2932
+ this.fCachedEvents.push({ type: "keyOff", data: [channel, pitch, velocity] });
2933
+ const voice = this.getPlayingVoice(pitch);
2934
+ if (voice !== FaustWebAudioDspVoice.kNoVoice) {
2935
+ this.fVoiceTable[voice].keyOff();
2936
+ } else {
2937
+ console.log("Playing pitch = %d not found\n", pitch);
2938
+ }
2939
+ }
2940
+ allNotesOff(hard = true) {
2941
+ this.fCachedEvents.push({ type: "ctrlChange", data: [0, 123, 0] });
2942
+ this.fVoiceTable.forEach((voice) => voice.keyOff(hard));
2943
+ }
2944
+ };
2945
+
2946
+ // src/FaustOfflineProcessor.ts
2947
+ var FaustOfflineProcessor = class {
2948
+ constructor(instance, bufferSize) {
2949
+ this.fDSPCode = instance;
2950
+ this.fBufferSize = bufferSize;
2951
+ this.fInputs = new Array(this.fDSPCode.getNumInputs()).fill(null).map(() => new Float32Array(bufferSize));
2952
+ this.fOutputs = new Array(this.fDSPCode.getNumOutputs()).fill(null).map(() => new Float32Array(bufferSize));
2953
+ }
2954
+ // Public API
2955
+ getParameterDescriptors() {
2956
+ const params = [];
2957
+ const callback = (item) => {
2958
+ let param = null;
2959
+ const polyKeywords = ["/gate", "/freq", "/gain", "/key", "/vel", "/velocity"];
2960
+ const isPolyReserved = "address" in item && !!polyKeywords.find((k) => item.address.endsWith(k));
2961
+ if (this.fDSPCode instanceof FaustMonoWebAudioDsp || !isPolyReserved) {
2962
+ if (item.type === "vslider" || item.type === "hslider" || item.type === "nentry") {
2963
+ param = { name: item.address, defaultValue: item.init || 0, minValue: item.min || 0, maxValue: item.max || 0 };
2964
+ } else if (item.type === "button" || item.type === "checkbox") {
2965
+ param = { name: item.address, defaultValue: item.init || 0, minValue: 0, maxValue: 1 };
2966
+ }
2967
+ }
2968
+ if (param)
2969
+ params.push(param);
2970
+ };
2971
+ FaustBaseWebAudioDsp.parseUI(this.fDSPCode.getUI(), callback);
2972
+ return params;
2973
+ }
2974
+ compute(input, output) {
2975
+ return this.fDSPCode.compute(input, output);
2976
+ }
2977
+ setOutputParamHandler(handler) {
2978
+ this.fDSPCode.setOutputParamHandler(handler);
2979
+ }
2980
+ getOutputParamHandler() {
2981
+ return this.fDSPCode.getOutputParamHandler();
2982
+ }
2983
+ setComputeHandler(handler) {
2984
+ this.fDSPCode.setComputeHandler(handler);
2985
+ }
2986
+ getComputeHandler() {
2987
+ return this.fDSPCode.getComputeHandler();
2988
+ }
2989
+ setPlotHandler(handler) {
2990
+ this.fDSPCode.setPlotHandler(handler);
2991
+ }
2992
+ getPlotHandler() {
2993
+ return this.fDSPCode.getPlotHandler();
2994
+ }
2995
+ getNumInputs() {
2996
+ return this.fDSPCode.getNumInputs();
2997
+ }
2998
+ getNumOutputs() {
2999
+ return this.fDSPCode.getNumOutputs();
3000
+ }
3001
+ metadata(handler) {
3002
+ }
3003
+ midiMessage(data) {
3004
+ this.fDSPCode.midiMessage(data);
3005
+ }
3006
+ ctrlChange(chan, ctrl, value) {
3007
+ this.fDSPCode.ctrlChange(chan, ctrl, value);
3008
+ }
3009
+ pitchWheel(chan, value) {
3010
+ this.fDSPCode.pitchWheel(chan, value);
3011
+ }
3012
+ setParamValue(path, value) {
3013
+ this.fDSPCode.setParamValue(path, value);
3014
+ }
3015
+ getParamValue(path) {
3016
+ return this.fDSPCode.getParamValue(path);
3017
+ }
3018
+ getParams() {
3019
+ return this.fDSPCode.getParams();
3020
+ }
3021
+ getMeta() {
3022
+ return this.fDSPCode.getMeta();
3023
+ }
3024
+ getJSON() {
3025
+ return this.fDSPCode.getJSON();
3026
+ }
3027
+ getDescriptors() {
3028
+ return this.fDSPCode.getDescriptors();
3029
+ }
3030
+ getUI() {
3031
+ return this.fDSPCode.getUI();
3032
+ }
3033
+ start() {
3034
+ this.fDSPCode.start();
3035
+ }
3036
+ stop() {
3037
+ this.fDSPCode.stop();
3038
+ }
3039
+ destroy() {
3040
+ this.fDSPCode.destroy();
3041
+ }
3042
+ get hasAccInput() {
3043
+ return this.fDSPCode.hasAccInput;
3044
+ }
3045
+ propagateAcc(accelerationIncludingGravity, invert = false) {
3046
+ this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
3047
+ }
3048
+ get hasGyrInput() {
3049
+ return this.fDSPCode.hasGyrInput;
3050
+ }
3051
+ propagateGyr(event) {
3052
+ this.fDSPCode.propagateGyr(event);
3053
+ }
3054
+ /**
3055
+ * Render frames in an array.
3056
+ *
3057
+ * @param inputs - input signal
3058
+ * @param length - the number of frames to render (default: bufferSize)
3059
+ * @param onUpdate - a callback after each buffer calculated, with an argument "current sample"
3060
+ * @return an array of Float32Array with the rendered frames
3061
+ */
3062
+ render(inputs = [], length = this.fBufferSize, onUpdate) {
3063
+ let l = 0;
3064
+ const outputs = new Array(this.fDSPCode.getNumOutputs()).fill(null).map(() => new Float32Array(length));
3065
+ this.fDSPCode.start();
3066
+ while (l < length) {
3067
+ const sliceLength = Math.min(length - l, this.fBufferSize);
3068
+ for (let i = 0; i < this.fDSPCode.getNumInputs(); i++) {
3069
+ let input;
3070
+ if (inputs[i]) {
3071
+ if (inputs[i].length <= l) {
3072
+ input = new Float32Array(sliceLength);
3073
+ } else if (inputs[i].length > l + sliceLength) {
3074
+ input = inputs[i].subarray(l, l + sliceLength);
3075
+ } else {
3076
+ input = inputs[i].subarray(l, inputs[i].length);
3077
+ }
3078
+ } else {
3079
+ input = new Float32Array(sliceLength);
3080
+ }
3081
+ this.fInputs[i] = input;
3082
+ }
3083
+ this.fDSPCode.compute(this.fInputs, this.fOutputs);
3084
+ for (let i = 0; i < this.fDSPCode.getNumOutputs(); i++) {
3085
+ const output = this.fOutputs[i];
3086
+ if (sliceLength < this.fBufferSize) {
3087
+ outputs[i].set(output.subarray(0, sliceLength), l);
3088
+ } else {
3089
+ outputs[i].set(output, l);
3090
+ }
3091
+ }
3092
+ l += this.fBufferSize;
3093
+ onUpdate == null ? void 0 : onUpdate(l);
3094
+ }
3095
+ this.fDSPCode.stop();
3096
+ return outputs;
3097
+ }
3098
+ };
3099
+ var FaustMonoOfflineProcessor = class extends FaustOfflineProcessor {
3100
+ };
3101
+ var FaustPolyOfflineProcessor = class extends FaustOfflineProcessor {
3102
+ keyOn(channel, pitch, velocity) {
3103
+ this.fDSPCode.keyOn(channel, pitch, velocity);
3104
+ }
3105
+ keyOff(channel, pitch, velocity) {
3106
+ this.fDSPCode.keyOff(channel, pitch, velocity);
3107
+ }
3108
+ allNotesOff(hard) {
3109
+ this.fDSPCode.allNotesOff(hard);
3110
+ }
3111
+ };
3112
+ var FaustOfflineProcessor_default = FaustOfflineProcessor;
3113
+
3114
+ // src/FaustSvgDiagrams.ts
3115
+ var FaustSvgDiagrams = class {
3116
+ constructor(compiler) {
3117
+ this.compiler = compiler;
3118
+ }
3119
+ from(name, code, args) {
3120
+ const fs = this.compiler.fs();
3121
+ try {
3122
+ const files2 = fs.readdir(`/${name}-svg/`);
3123
+ files2.filter((file) => file !== "." && file !== "..").forEach((file) => fs.unlink(`/${name}-svg/${file}`));
3124
+ } catch {
3125
+ }
3126
+ const success = this.compiler.generateAuxFiles(name, code, `-lang wasm -o binary -svg ${args}`);
3127
+ if (!success)
3128
+ throw new Error(this.compiler.getErrorMessage());
3129
+ const svgs = {};
3130
+ const files = fs.readdir(`/${name}-svg/`);
3131
+ files.filter((file) => file !== "." && file !== "..").forEach((file) => svgs[file] = fs.readFile(`/${name}-svg/${file}`, { encoding: "utf8" }));
3132
+ return svgs;
3133
+ }
3134
+ };
3135
+ var FaustSvgDiagrams_default = FaustSvgDiagrams;
3136
+
3137
+ // src/FaustCmajor.ts
3138
+ var FaustCmajor = class {
3139
+ constructor(compiler) {
3140
+ this.fCompiler = compiler;
3141
+ }
3142
+ compile(name, code, args) {
3143
+ const fs = this.fCompiler.fs();
3144
+ const success = this.fCompiler.generateAuxFiles(name, code, `-lang cmajor-hybrid -cn ${name} -o ${name}.cmajor`);
3145
+ return success ? fs.readFile(`${name}.cmajor`, { encoding: "utf8" }) : "";
3146
+ }
3147
+ };
3148
+ var FaustCmajor_default = FaustCmajor;
3149
+
3150
+ // src/LibFaust.ts
3151
+ var LibFaust = class {
3152
+ constructor(module) {
3153
+ this.fModule = module;
3154
+ this.fCompiler = new module.libFaustWasm();
3155
+ this.fFileSystem = this.fModule.FS;
3156
+ }
3157
+ module() {
3158
+ return this.fModule;
3159
+ }
3160
+ fs() {
3161
+ return this.fFileSystem;
3162
+ }
3163
+ version() {
3164
+ return this.fCompiler.version();
3165
+ }
3166
+ createDSPFactory(name, code, args, useInternalMemory) {
3167
+ return this.fCompiler.createDSPFactory(name, code, args, useInternalMemory);
3168
+ }
3169
+ deleteDSPFactory(cFactory) {
3170
+ return this.fCompiler.deleteDSPFactory(cFactory);
3171
+ }
3172
+ expandDSP(name, code, args) {
3173
+ return this.fCompiler.expandDSP(name, code, args);
3174
+ }
3175
+ generateAuxFiles(name, code, args) {
3176
+ return this.fCompiler.generateAuxFiles(name, code, args);
3177
+ }
3178
+ deleteAllDSPFactories() {
3179
+ return this.fCompiler.deleteAllDSPFactories();
3180
+ }
3181
+ getErrorAfterException() {
3182
+ return this.fCompiler.getErrorAfterException();
3183
+ }
3184
+ cleanupAfterException() {
3185
+ return this.fCompiler.cleanupAfterException();
3186
+ }
3187
+ getInfos(what) {
3188
+ return this.fCompiler.getInfos(what);
3189
+ }
3190
+ toString() {
3191
+ return `LibFaust module: ${this.fModule}, compiler: ${this.fCompiler}`;
3192
+ }
3193
+ };
3194
+ var LibFaust_default = LibFaust;
3195
+
3196
+ // src/WavEncoder.ts
3197
+ var WavEncoder = class {
3198
+ static encode(audioBuffer, options) {
3199
+ const numberOfChannels = audioBuffer.length;
3200
+ const length = audioBuffer[0].length;
3201
+ const { shared, float } = options;
3202
+ const bitDepth = float ? 32 : options.bitDepth | 0 || 16;
3203
+ const byteDepth = bitDepth >> 3;
3204
+ const byteLength = length * numberOfChannels * byteDepth;
3205
+ const AB = shared ? globalThis.SharedArrayBuffer || globalThis.ArrayBuffer : globalThis.ArrayBuffer;
3206
+ const ab = new AB((44 + byteLength) * Uint8Array.BYTES_PER_ELEMENT);
3207
+ const dataView = new DataView(ab);
3208
+ const writer = new Writer(dataView);
3209
+ const format = {
3210
+ formatId: float ? 3 : 1,
3211
+ float: !!float,
3212
+ numberOfChannels,
3213
+ sampleRate: options.sampleRate,
3214
+ symmetric: !!options.symmetric,
3215
+ length,
3216
+ bitDepth,
3217
+ byteDepth
3218
+ };
3219
+ this.writeHeader(writer, format);
3220
+ this.writeData(writer, audioBuffer, format);
3221
+ return ab;
3222
+ }
3223
+ static writeHeader(writer, format) {
3224
+ const { formatId, sampleRate, bitDepth, numberOfChannels, length, byteDepth } = format;
3225
+ writer.string("RIFF");
3226
+ writer.uint32(writer.dataView.byteLength - 8);
3227
+ writer.string("WAVE");
3228
+ writer.string("fmt ");
3229
+ writer.uint32(16);
3230
+ writer.uint16(formatId);
3231
+ writer.uint16(numberOfChannels);
3232
+ writer.uint32(sampleRate);
3233
+ writer.uint32(sampleRate * numberOfChannels * byteDepth);
3234
+ writer.uint16(numberOfChannels * byteDepth);
3235
+ writer.uint16(bitDepth);
3236
+ writer.string("data");
3237
+ writer.uint32(length * numberOfChannels * byteDepth);
3238
+ return writer.pos;
3239
+ }
3240
+ static writeData(writer, audioBuffer, format) {
3241
+ const { bitDepth, float, length, numberOfChannels, symmetric } = format;
3242
+ if (bitDepth === 32 && float) {
3243
+ const { dataView, pos } = writer;
3244
+ const ab = dataView.buffer;
3245
+ const f32View = new Float32Array(ab, pos);
3246
+ if (numberOfChannels === 1) {
3247
+ f32View.set(audioBuffer[0]);
3248
+ return;
3249
+ }
3250
+ for (let ch = 0; ch < numberOfChannels; ch++) {
3251
+ const channel = audioBuffer[ch];
3252
+ for (let i = 0; i < length; i++) {
3253
+ f32View[i * numberOfChannels + ch] = channel[i];
3254
+ }
3255
+ }
3256
+ return;
3257
+ }
3258
+ const encoderOption = float ? "f" : symmetric ? "s" : "";
3259
+ const methodName = "pcm" + bitDepth + encoderOption;
3260
+ if (!writer[methodName]) {
3261
+ throw new TypeError("Not supported bit depth: " + bitDepth);
3262
+ }
3263
+ const write = writer[methodName].bind(writer);
3264
+ for (let i = 0; i < length; i++) {
3265
+ for (let j = 0; j < numberOfChannels; j++) {
3266
+ write(audioBuffer[j][i]);
3267
+ }
3268
+ }
3269
+ }
3270
+ };
3271
+ var Writer = class {
3272
+ constructor(dataView) {
3273
+ this.pos = 0;
3274
+ this.dataView = dataView;
3275
+ }
3276
+ int16(value) {
3277
+ this.dataView.setInt16(this.pos, value, true);
3278
+ this.pos += 2;
3279
+ }
3280
+ uint16(value) {
3281
+ this.dataView.setUint16(this.pos, value, true);
3282
+ this.pos += 2;
3283
+ }
3284
+ uint32(value) {
3285
+ this.dataView.setUint32(this.pos, value, true);
3286
+ this.pos += 4;
3287
+ }
3288
+ string(value) {
3289
+ for (let i = 0, imax = value.length; i < imax; i++) {
3290
+ this.dataView.setUint8(this.pos++, value.charCodeAt(i));
3291
+ }
3292
+ }
3293
+ pcm8(valueIn) {
3294
+ let value = valueIn;
3295
+ value = Math.max(-1, Math.min(value, 1));
3296
+ value = (value * 0.5 + 0.5) * 255;
3297
+ value = Math.round(value) | 0;
3298
+ this.dataView.setUint8(
3299
+ this.pos,
3300
+ value
3301
+ /* , true*/
3302
+ );
3303
+ this.pos += 1;
3304
+ }
3305
+ pcm8s(valueIn) {
3306
+ let value = valueIn;
3307
+ value = Math.round(value * 128) + 128;
3308
+ value = Math.max(0, Math.min(value, 255));
3309
+ this.dataView.setUint8(
3310
+ this.pos,
3311
+ value
3312
+ /* , true*/
3313
+ );
3314
+ this.pos += 1;
3315
+ }
3316
+ pcm16(valueIn) {
3317
+ let value = valueIn;
3318
+ value = Math.max(-1, Math.min(value, 1));
3319
+ value = value < 0 ? value * 32768 : value * 32767;
3320
+ value = Math.round(value) | 0;
3321
+ this.dataView.setInt16(this.pos, value, true);
3322
+ this.pos += 2;
3323
+ }
3324
+ pcm16s(valueIn) {
3325
+ let value = valueIn;
3326
+ value = Math.round(value * 32768);
3327
+ value = Math.max(-32768, Math.min(value, 32767));
3328
+ this.dataView.setInt16(this.pos, value, true);
3329
+ this.pos += 2;
3330
+ }
3331
+ pcm24(valueIn) {
3332
+ let value = valueIn;
3333
+ value = Math.max(-1, Math.min(value, 1));
3334
+ value = value < 0 ? 16777216 + value * 8388608 : value * 8388607;
3335
+ value = Math.round(value) | 0;
3336
+ const x0 = value >> 0 & 255;
3337
+ const x1 = value >> 8 & 255;
3338
+ const x2 = value >> 16 & 255;
3339
+ this.dataView.setUint8(this.pos + 0, x0);
3340
+ this.dataView.setUint8(this.pos + 1, x1);
3341
+ this.dataView.setUint8(this.pos + 2, x2);
3342
+ this.pos += 3;
3343
+ }
3344
+ pcm24s(valueIn) {
3345
+ let value = valueIn;
3346
+ value = Math.round(value * 8388608);
3347
+ value = Math.max(-8388608, Math.min(value, 8388607));
3348
+ const x0 = value >> 0 & 255;
3349
+ const x1 = value >> 8 & 255;
3350
+ const x2 = value >> 16 & 255;
3351
+ this.dataView.setUint8(this.pos + 0, x0);
3352
+ this.dataView.setUint8(this.pos + 1, x1);
3353
+ this.dataView.setUint8(this.pos + 2, x2);
3354
+ this.pos += 3;
3355
+ }
3356
+ pcm32(valueIn) {
3357
+ let value = valueIn;
3358
+ value = Math.max(-1, Math.min(value, 1));
3359
+ value = value < 0 ? value * 2147483648 : value * 2147483647;
3360
+ value = Math.round(value) | 0;
3361
+ this.dataView.setInt32(this.pos, value, true);
3362
+ this.pos += 4;
3363
+ }
3364
+ pcm32s(valueIn) {
3365
+ let value = valueIn;
3366
+ value = Math.round(value * 2147483648);
3367
+ value = Math.max(-2147483648, Math.min(value, 2147483647));
3368
+ this.dataView.setInt32(this.pos, value, true);
3369
+ this.pos += 4;
3370
+ }
3371
+ pcm32f(value) {
3372
+ this.dataView.setFloat32(this.pos, value, true);
3373
+ this.pos += 4;
3374
+ }
3375
+ };
3376
+ var WavEncoder_default = WavEncoder;
3377
+
3378
+ // src/WavDecoder.ts
3379
+ var WavDecoder = class {
3380
+ static decode(buffer, options) {
3381
+ const dataView = new DataView(buffer);
3382
+ const reader = new Reader(dataView);
3383
+ if (reader.string(4) !== "RIFF") {
3384
+ throw new TypeError("Invalid WAV file");
3385
+ }
3386
+ reader.uint32();
3387
+ if (reader.string(4) !== "WAVE") {
3388
+ throw new TypeError("Invalid WAV file");
3389
+ }
3390
+ let format = null;
3391
+ let audioData = null;
3392
+ do {
3393
+ const chunkType = reader.string(4);
3394
+ const chunkSize = reader.uint32();
3395
+ if (chunkType === "fmt ") {
3396
+ format = this.decodeFormat(reader, chunkSize);
3397
+ } else if (chunkType === "data") {
3398
+ audioData = this.decodeData(reader, chunkSize, format, options || {});
3399
+ } else {
3400
+ reader.skip(chunkSize);
3401
+ }
3402
+ } while (audioData === null);
3403
+ return audioData;
3404
+ }
3405
+ static decodeFormat(reader, chunkSize) {
3406
+ const formats = {
3407
+ 1: "lpcm",
3408
+ 3: "lpcm"
3409
+ };
3410
+ const formatId = reader.uint16();
3411
+ if (!formats.hasOwnProperty(formatId)) {
3412
+ throw new TypeError("Unsupported format in WAV file: 0x" + formatId.toString(16));
3413
+ }
3414
+ const format = {
3415
+ formatId,
3416
+ float: formatId === 3,
3417
+ numberOfChannels: reader.uint16(),
3418
+ sampleRate: reader.uint32(),
3419
+ byteRate: reader.uint32(),
3420
+ blockSize: reader.uint16(),
3421
+ bitDepth: reader.uint16()
3422
+ };
3423
+ reader.skip(chunkSize - 16);
3424
+ return format;
3425
+ }
3426
+ static decodeData(reader, chunkSizeIn, format, options) {
3427
+ const chunkSize = Math.min(chunkSizeIn, reader.remain());
3428
+ const length = Math.floor(chunkSize / format.blockSize);
3429
+ const numberOfChannels = format.numberOfChannels;
3430
+ const sampleRate = format.sampleRate;
3431
+ const channelData = new Array(numberOfChannels);
3432
+ for (let ch = 0; ch < numberOfChannels; ch++) {
3433
+ const AB = options.shared ? globalThis.SharedArrayBuffer || globalThis.ArrayBuffer : globalThis.ArrayBuffer;
3434
+ const ab = new AB(length * Float32Array.BYTES_PER_ELEMENT);
3435
+ channelData[ch] = new Float32Array(ab);
3436
+ }
3437
+ this.readPCM(reader, channelData, length, format, options);
3438
+ return {
3439
+ numberOfChannels,
3440
+ length,
3441
+ sampleRate,
3442
+ channelData
3443
+ };
3444
+ }
3445
+ static readPCM(reader, channelData, length, format, options) {
3446
+ const bitDepth = format.bitDepth;
3447
+ const decoderOption = format.float ? "f" : options.symmetric ? "s" : "";
3448
+ const methodName = "pcm" + bitDepth + decoderOption;
3449
+ if (!reader[methodName]) {
3450
+ throw new TypeError("Not supported bit depth: " + format.bitDepth);
3451
+ }
3452
+ const read = reader[methodName].bind(reader);
3453
+ const numberOfChannels = format.numberOfChannels;
3454
+ for (let i = 0; i < length; i++) {
3455
+ for (let ch = 0; ch < numberOfChannels; ch++) {
3456
+ channelData[ch][i] = read();
3457
+ }
3458
+ }
3459
+ }
3460
+ };
3461
+ var Reader = class {
3462
+ constructor(dataView) {
3463
+ this.pos = 0;
3464
+ this.dataView = dataView;
3465
+ }
3466
+ remain() {
3467
+ return this.dataView.byteLength - this.pos;
3468
+ }
3469
+ skip(n) {
3470
+ this.pos += n;
3471
+ }
3472
+ uint8() {
3473
+ const data = this.dataView.getUint8(this.pos);
3474
+ this.pos += 1;
3475
+ return data;
3476
+ }
3477
+ int16() {
3478
+ const data = this.dataView.getInt16(this.pos, true);
3479
+ this.pos += 2;
3480
+ return data;
3481
+ }
3482
+ uint16() {
3483
+ const data = this.dataView.getUint16(this.pos, true);
3484
+ this.pos += 2;
3485
+ return data;
3486
+ }
3487
+ uint32() {
3488
+ const data = this.dataView.getUint32(this.pos, true);
3489
+ this.pos += 4;
3490
+ return data;
3491
+ }
3492
+ string(n) {
3493
+ let data = "";
3494
+ for (let i = 0; i < n; i++) {
3495
+ data += String.fromCharCode(this.uint8());
3496
+ }
3497
+ return data;
3498
+ }
3499
+ pcm8() {
3500
+ const data = this.dataView.getUint8(this.pos) - 128;
3501
+ this.pos += 1;
3502
+ return data < 0 ? data / 128 : data / 127;
3503
+ }
3504
+ pcm8s() {
3505
+ const data = this.dataView.getUint8(this.pos) - 127.5;
3506
+ this.pos += 1;
3507
+ return data / 127.5;
3508
+ }
3509
+ pcm16() {
3510
+ const data = this.dataView.getInt16(this.pos, true);
3511
+ this.pos += 2;
3512
+ return data < 0 ? data / 32768 : data / 32767;
3513
+ }
3514
+ pcm16s() {
3515
+ const data = this.dataView.getInt16(this.pos, true);
3516
+ this.pos += 2;
3517
+ return data / 32768;
3518
+ }
3519
+ pcm24() {
3520
+ const x0 = this.dataView.getUint8(this.pos + 0);
3521
+ const x1 = this.dataView.getUint8(this.pos + 1);
3522
+ const x2 = this.dataView.getUint8(this.pos + 2);
3523
+ const xx = x0 + (x1 << 8) + (x2 << 16);
3524
+ const data = xx > 8388608 ? xx - 16777216 : xx;
3525
+ this.pos += 3;
3526
+ return data < 0 ? data / 8388608 : data / 8388607;
3527
+ }
3528
+ pcm24s() {
3529
+ const x0 = this.dataView.getUint8(this.pos + 0);
3530
+ const x1 = this.dataView.getUint8(this.pos + 1);
3531
+ const x2 = this.dataView.getUint8(this.pos + 2);
3532
+ const xx = x0 + (x1 << 8) + (x2 << 16);
3533
+ const data = xx > 8388608 ? xx - 16777216 : xx;
3534
+ this.pos += 3;
3535
+ return data / 8388608;
3536
+ }
3537
+ pcm32() {
3538
+ const data = this.dataView.getInt32(this.pos, true);
3539
+ this.pos += 4;
3540
+ return data < 0 ? data / 2147483648 : data / 2147483647;
3541
+ }
3542
+ pcm32s() {
3543
+ const data = this.dataView.getInt32(this.pos, true);
3544
+ this.pos += 4;
3545
+ return data / 2147483648;
3546
+ }
3547
+ pcm32f() {
3548
+ const data = this.dataView.getFloat32(this.pos, true);
3549
+ this.pos += 4;
3550
+ return data;
3551
+ }
3552
+ pcm64f() {
3553
+ const data = this.dataView.getFloat64(this.pos, true);
3554
+ this.pos += 8;
3555
+ return data;
3556
+ }
3557
+ };
3558
+ var WavDecoder_default = WavDecoder;
3559
+
3560
+ // src/SoundfileReader.ts
3561
+ var SoundfileReader = class {
3562
+ // Set the fallback paths
3563
+ static get fallbackPaths() {
3564
+ return [location.href, this.getParentUrl(location.href), location.origin];
3565
+ }
3566
+ /**
3567
+ * Extract the parent URL from an URL.
3568
+ * @param url : the URL
3569
+ * @returns : the parent URL
3570
+ */
3571
+ static getParentUrl(url) {
3572
+ return url.substring(0, url.lastIndexOf("/") + 1);
3573
+ }
3574
+ /**
3575
+ * Convert an audio buffer to audio data.
3576
+ *
3577
+ * @param audioBuffer : the audio buffer to convert
3578
+ * @returns : the audio data
3579
+ */
3580
+ static toAudioData(audioBuffer) {
3581
+ const { sampleRate, numberOfChannels } = audioBuffer;
3582
+ return {
3583
+ sampleRate,
3584
+ audioBuffer: new Array(numberOfChannels).fill(null).map((v, i) => audioBuffer.getChannelData(i))
3585
+ };
3586
+ }
3587
+ /**
3588
+ * Extract the URLs from the metadata.
3589
+ *
3590
+ * @param dspMeta : the metadata
3591
+ * @returns : the URLs
3592
+ */
3593
+ static findSoundfilesFromMeta(dspMeta) {
3594
+ const soundfiles = {};
3595
+ const callback = (item) => {
3596
+ if (item.type === "soundfile") {
3597
+ const urls = FaustBaseWebAudioDsp.splitSoundfileNames(item.url);
3598
+ urls.forEach((url) => soundfiles[url] = null);
3599
+ }
3600
+ };
3601
+ FaustBaseWebAudioDsp.parseUI(dspMeta.ui, callback);
3602
+ return soundfiles;
3603
+ }
3604
+ /**
3605
+ * Check if the file exists.
3606
+ *
3607
+ * @param url : the url of the file to check
3608
+ * @returns : true if the file exists, otherwise false
3609
+ */
3610
+ static async checkFileExists(url) {
3611
+ try {
3612
+ console.log(`"checkFileExists" url: ${url}`);
3613
+ const response = await fetch(url);
3614
+ console.log(`"checkFileExists" response.ok: ${response.ok}`);
3615
+ return response.ok;
3616
+ } catch (error) {
3617
+ console.error("Fetch error:", error);
3618
+ return false;
3619
+ }
3620
+ }
3621
+ /**
3622
+ * Fetch the soundfile.
3623
+ *
3624
+ * @param url : the url of the soundfile
3625
+ * @param audioCtx : the audio context
3626
+ * @returns : the audio data
3627
+ */
3628
+ static async fetchSoundfile(url, audioCtx) {
3629
+ console.log(`Loading sound file from ${url}`);
3630
+ const response = await fetch(url);
3631
+ if (!response.ok)
3632
+ throw new Error(`Failed to load sound file from ${url}: ${response.statusText}`);
3633
+ const arrayBuffer = await response.arrayBuffer();
3634
+ const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
3635
+ return this.toAudioData(audioBuffer);
3636
+ }
3637
+ /**
3638
+ * Load the soundfile.
3639
+ *
3640
+ * @param filename : the filename
3641
+ * @param metaUrls : the metadata URLs
3642
+ * @param soundfiles : the soundfiles
3643
+ * @param audioCtx : the audio context
3644
+ */
3645
+ static async loadSoundfile(filename, metaUrls, soundfiles, audioCtx) {
3646
+ if (soundfiles[filename])
3647
+ return;
3648
+ const urlsToCheck = [filename, ...[...metaUrls, ...this.fallbackPaths].map((path) => new URL(filename, path.endsWith("/") ? path : `${path}/`).href)];
3649
+ const checkResults = await Promise.all(urlsToCheck.map((url) => this.checkFileExists(url)));
3650
+ const successIndex = checkResults.findIndex((r) => !!r);
3651
+ if (successIndex === -1)
3652
+ throw new Error(`Failed to load sound file ${filename}, all check failed.`);
3653
+ soundfiles[filename] = await this.fetchSoundfile(urlsToCheck[successIndex], audioCtx);
3654
+ }
3655
+ /**
3656
+ * Load the soundfiles, public API.
3657
+ *
3658
+ * @param dspMeta : the metadata
3659
+ * @param soundfilesIn : the soundfiles
3660
+ * @param audioCtx : the audio context
3661
+ * @returns : the soundfiles
3662
+ */
3663
+ static async loadSoundfiles(dspMeta, soundfilesIn, audioCtx) {
3664
+ const metaUrls = FaustBaseWebAudioDsp.extractUrlsFromMeta(dspMeta);
3665
+ const soundfiles = this.findSoundfilesFromMeta(dspMeta);
3666
+ for (const id in soundfiles) {
3667
+ if (soundfilesIn[id]) {
3668
+ soundfiles[id] = soundfilesIn[id];
3669
+ continue;
3670
+ }
3671
+ try {
3672
+ await this.loadSoundfile(id, metaUrls, soundfiles, audioCtx);
3673
+ } catch (error) {
3674
+ console.error(error);
3675
+ }
3676
+ }
3677
+ return soundfiles;
3678
+ }
3679
+ };
3680
+ var SoundfileReader_default = SoundfileReader;
3681
+
3682
+ // src/FaustAudioWorkletNode.ts
3683
+ var _hasAccInput, _hasGyrInput;
3684
+ var FaustAudioWorkletNode = class extends (globalThis.AudioWorkletNode || null) {
3685
+ constructor(context, name, factory, options = {}) {
3686
+ const JSONObj = JSON.parse(factory.json);
3687
+ super(context, name, {
3688
+ numberOfInputs: JSONObj.inputs > 0 ? 1 : 0,
3689
+ numberOfOutputs: JSONObj.outputs > 0 ? 1 : 0,
3690
+ channelCount: Math.max(1, JSONObj.inputs),
3691
+ outputChannelCount: [JSONObj.outputs],
3692
+ channelCountMode: "explicit",
3693
+ channelInterpretation: "speakers",
3694
+ processorOptions: options.processorOptions,
3695
+ ...options
3696
+ });
3697
+ __privateAdd(this, _hasAccInput, false);
3698
+ __privateAdd(this, _hasGyrInput, false);
3699
+ // Public API
3700
+ // Accelerometer and gyroscope handlers
3701
+ this.handleDeviceMotion = ({ accelerationIncludingGravity }) => {
3702
+ const isAndroid = /Android/i.test(navigator.userAgent);
3703
+ if (!accelerationIncludingGravity)
3704
+ return;
3705
+ const { x, y, z } = accelerationIncludingGravity;
3706
+ this.propagateAcc({ x, y, z }, isAndroid);
3707
+ };
3708
+ this.handleDeviceOrientation = ({ alpha, beta, gamma }) => {
3709
+ this.propagateGyr({ alpha, beta, gamma });
3710
+ };
3711
+ this.fJSONDsp = JSONObj;
3712
+ this.fJSON = factory.json;
3713
+ this.fOutputHandler = null;
3714
+ this.fComputeHandler = null;
3715
+ this.fPlotHandler = null;
3716
+ this.fDescriptor = [];
3717
+ this.fInputsItems = [];
3718
+ this.fUICallback = (item) => {
3719
+ if (item.type === "vslider" || item.type === "hslider" || item.type === "button" || item.type === "checkbox" || item.type === "nentry") {
3720
+ this.fInputsItems.push(item.address);
3721
+ this.fDescriptor.push(item);
3722
+ if (!item.meta)
3723
+ return;
3724
+ item.meta.forEach((meta) => {
3725
+ const { midi, acc, gyr } = meta;
3726
+ if (acc)
3727
+ __privateSet(this, _hasAccInput, true);
3728
+ if (gyr)
3729
+ __privateSet(this, _hasGyrInput, true);
3730
+ });
3731
+ }
3732
+ };
3733
+ FaustBaseWebAudioDsp.parseUI(this.fJSONDsp.ui, this.fUICallback);
3734
+ this.port.onmessage = (e) => {
3735
+ if (e.data.type === "param" && this.fOutputHandler) {
3736
+ this.fOutputHandler(e.data.path, e.data.value);
3737
+ } else if (e.data.type === "plot" && this.fPlotHandler) {
3738
+ this.fPlotHandler(e.data.value, e.data.index, e.data.events);
3739
+ }
3740
+ };
3741
+ }
3742
+ /** Setup accelerometer and gyroscope handlers */
3743
+ async startSensors() {
3744
+ if (this.hasAccInput) {
3745
+ if (window.DeviceMotionEvent) {
3746
+ if (typeof window.DeviceMotionEvent.requestPermission === "function") {
3747
+ try {
3748
+ const response = await window.DeviceMotionEvent.requestPermission();
3749
+ if (response === "granted") {
3750
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
3751
+ } else if (response === "denied") {
3752
+ alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
3753
+ throw new Error("Unable to access the accelerometer.");
3754
+ }
3755
+ } catch (error) {
3756
+ console.error(error);
3757
+ }
3758
+ } else {
3759
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
3760
+ }
3761
+ } else {
3762
+ console.log("Cannot set the accelerometer handler.");
3763
+ }
3764
+ }
3765
+ if (this.hasGyrInput) {
3766
+ if (window.DeviceMotionEvent) {
3767
+ if (typeof window.DeviceOrientationEvent.requestPermission === "function") {
3768
+ try {
3769
+ const response = await window.DeviceOrientationEvent.requestPermission();
3770
+ if (response === "granted") {
3771
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
3772
+ } else if (response === "denied") {
3773
+ alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
3774
+ throw new Error("Unable to access the gyroscope.");
3775
+ }
3776
+ } catch (error) {
3777
+ console.error(error);
3778
+ }
3779
+ } else {
3780
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
3781
+ }
3782
+ } else {
3783
+ console.log("Cannot set the gyroscope handler.");
3784
+ }
3785
+ }
3786
+ }
3787
+ stopSensors() {
3788
+ if (this.hasAccInput) {
3789
+ window.removeEventListener("devicemotion", this.handleDeviceMotion, true);
3790
+ }
3791
+ if (this.hasGyrInput) {
3792
+ window.removeEventListener("deviceorientation", this.handleDeviceOrientation, true);
3793
+ }
3794
+ }
3795
+ setOutputParamHandler(handler) {
3796
+ this.fOutputHandler = handler;
3797
+ }
3798
+ getOutputParamHandler() {
3799
+ return this.fOutputHandler;
3800
+ }
3801
+ setComputeHandler(handler) {
3802
+ this.fComputeHandler = handler;
3803
+ }
3804
+ getComputeHandler() {
3805
+ return this.fComputeHandler;
3806
+ }
3807
+ setPlotHandler(handler) {
3808
+ this.fPlotHandler = handler;
3809
+ if (this.fPlotHandler) {
3810
+ this.port.postMessage({ type: "setPlotHandler", data: true });
3811
+ } else {
3812
+ this.port.postMessage({ type: "setPlotHandler", data: false });
3813
+ }
3814
+ }
3815
+ getPlotHandler() {
3816
+ return this.fPlotHandler;
3817
+ }
3818
+ setupWamEventHandler() {
3819
+ this.port.postMessage({ type: "setupWamEventHandler" });
3820
+ }
3821
+ getNumInputs() {
3822
+ return this.fJSONDsp.inputs;
3823
+ }
3824
+ getNumOutputs() {
3825
+ return this.fJSONDsp.outputs;
3826
+ }
3827
+ // Implemented in subclasses
3828
+ compute(inputs, outputs) {
3829
+ return false;
3830
+ }
3831
+ metadata(handler) {
3832
+ if (this.fJSONDsp.meta) {
3833
+ this.fJSONDsp.meta.forEach((meta) => handler(Object.keys(meta)[0], meta[Object.keys(meta)[0]]));
3834
+ }
3835
+ }
3836
+ midiMessage(data) {
3837
+ const cmd = data[0] >> 4;
3838
+ const channel = data[0] & 15;
3839
+ const data1 = data[1];
3840
+ const data2 = data[2];
3841
+ if (cmd === 11)
3842
+ this.ctrlChange(channel, data1, data2);
3843
+ else if (cmd === 14)
3844
+ this.pitchWheel(channel, data2 * 128 + data1);
3845
+ else
3846
+ this.port.postMessage({ type: "midi", data });
3847
+ }
3848
+ ctrlChange(channel, ctrl, value) {
3849
+ const e = { type: "ctrlChange", data: [channel, ctrl, value] };
3850
+ this.port.postMessage(e);
3851
+ }
3852
+ pitchWheel(channel, wheel) {
3853
+ const e = { type: "pitchWheel", data: [channel, wheel] };
3854
+ this.port.postMessage(e);
3855
+ }
3856
+ get hasAccInput() {
3857
+ return __privateGet(this, _hasAccInput);
3858
+ }
3859
+ propagateAcc(accelerationIncludingGravity, invert = false) {
3860
+ if (!accelerationIncludingGravity)
3861
+ return;
3862
+ const e = { type: "acc", data: accelerationIncludingGravity, invert };
3863
+ this.port.postMessage(e);
3864
+ }
3865
+ get hasGyrInput() {
3866
+ return __privateGet(this, _hasGyrInput);
3867
+ }
3868
+ propagateGyr(event) {
3869
+ if (!event)
3870
+ return;
3871
+ const e = { type: "gyr", data: event };
3872
+ this.port.postMessage(e);
3873
+ }
3874
+ setParamValue(path, value) {
3875
+ const e = { type: "param", data: { path, value } };
3876
+ this.port.postMessage(e);
3877
+ const param = this.parameters.get(path);
3878
+ if (param)
3879
+ param.setValueAtTime(value, this.context.currentTime);
3880
+ }
3881
+ getParamValue(path) {
3882
+ const param = this.parameters.get(path);
3883
+ return param ? param.value : 0;
3884
+ }
3885
+ getParams() {
3886
+ return this.fInputsItems;
3887
+ }
3888
+ getMeta() {
3889
+ return this.fJSONDsp;
3890
+ }
3891
+ getJSON() {
3892
+ return JSON.stringify(this.getMeta());
3893
+ }
3894
+ getUI() {
3895
+ return this.fJSONDsp.ui;
3896
+ }
3897
+ getDescriptors() {
3898
+ return this.fDescriptor;
3899
+ }
3900
+ start() {
3901
+ this.port.postMessage({ type: "start" });
3902
+ }
3903
+ stop() {
3904
+ this.port.postMessage({ type: "stop" });
3905
+ }
3906
+ destroy() {
3907
+ this.port.postMessage({ type: "destroy" });
3908
+ this.port.close();
3909
+ }
3910
+ };
3911
+ _hasAccInput = new WeakMap();
3912
+ _hasGyrInput = new WeakMap();
3913
+ var FaustMonoAudioWorkletNode = class extends FaustAudioWorkletNode {
3914
+ constructor(context, options) {
3915
+ super(context, options.processorOptions.name, options.processorOptions.factory, options);
3916
+ this.onprocessorerror = (e) => {
3917
+ throw e;
3918
+ };
3919
+ }
3920
+ };
3921
+ var FaustPolyAudioWorkletNode = class extends FaustAudioWorkletNode {
3922
+ constructor(context, options) {
3923
+ super(
3924
+ context,
3925
+ options.processorOptions.name,
3926
+ options.processorOptions.voiceFactory,
3927
+ options
3928
+ );
3929
+ this.onprocessorerror = (e) => {
3930
+ throw e;
3931
+ };
3932
+ this.fJSONEffect = options.processorOptions.effectFactory ? JSON.parse(options.processorOptions.effectFactory.json) : null;
3933
+ if (this.fJSONEffect) {
3934
+ FaustBaseWebAudioDsp.parseUI(this.fJSONEffect.ui, this.fUICallback);
3935
+ }
3936
+ }
3937
+ // Public API
3938
+ keyOn(channel, pitch, velocity) {
3939
+ const e = { type: "keyOn", data: [channel, pitch, velocity] };
3940
+ this.port.postMessage(e);
3941
+ }
3942
+ keyOff(channel, pitch, velocity) {
3943
+ const e = { type: "keyOff", data: [channel, pitch, velocity] };
3944
+ this.port.postMessage(e);
3945
+ }
3946
+ allNotesOff(hard) {
3947
+ const e = { type: "ctrlChange", data: [0, 123, 0] };
3948
+ this.port.postMessage(e);
3949
+ }
3950
+ getMeta() {
3951
+ const o = this.fJSONDsp;
3952
+ const e = this.fJSONEffect;
3953
+ const r = { ...o };
3954
+ if (e) {
3955
+ r.ui = [{
3956
+ type: "tgroup",
3957
+ label: "Sequencer",
3958
+ items: [
3959
+ { type: "vgroup", label: "Instrument", items: o.ui },
3960
+ { type: "vgroup", label: "Effect", items: e.ui }
3961
+ ]
3962
+ }];
3963
+ } else {
3964
+ r.ui = [{
3965
+ type: "tgroup",
3966
+ label: "Polyphonic",
3967
+ items: [
3968
+ { type: "vgroup", label: "Voices", items: o.ui }
3969
+ ]
3970
+ }];
3971
+ }
3972
+ return r;
3973
+ }
3974
+ getJSON() {
3975
+ return JSON.stringify(this.getMeta());
3976
+ }
3977
+ getUI() {
3978
+ return this.getMeta().ui;
3979
+ }
3980
+ };
3981
+
3982
+ // src/FaustScriptProcessorNode.ts
3983
+ var FaustScriptProcessorNode = class extends (globalThis.ScriptProcessorNode || null) {
3984
+ constructor() {
3985
+ super(...arguments);
3986
+ this.handleDeviceMotion = void 0;
3987
+ this.handleDeviceOrientation = void 0;
3988
+ }
3989
+ init(instance) {
3990
+ this.fDSPCode = instance;
3991
+ this.fInputs = new Array(this.fDSPCode.getNumInputs());
3992
+ this.fOutputs = new Array(this.fDSPCode.getNumOutputs());
3993
+ this.handleDeviceMotion = ({ accelerationIncludingGravity }) => {
3994
+ const isAndroid = /Android/i.test(navigator.userAgent);
3995
+ if (!accelerationIncludingGravity)
3996
+ return;
3997
+ const { x, y, z } = accelerationIncludingGravity;
3998
+ this.propagateAcc({ x, y, z }, isAndroid);
3999
+ };
4000
+ this.handleDeviceOrientation = ({ alpha, beta, gamma }) => {
4001
+ this.propagateGyr({ alpha, beta, gamma });
4002
+ };
4003
+ this.onaudioprocess = (e) => {
4004
+ for (let chan = 0; chan < this.fDSPCode.getNumInputs(); chan++) {
4005
+ this.fInputs[chan] = e.inputBuffer.getChannelData(chan);
4006
+ }
4007
+ for (let chan = 0; chan < this.fDSPCode.getNumOutputs(); chan++) {
4008
+ this.fOutputs[chan] = e.outputBuffer.getChannelData(chan);
4009
+ }
4010
+ return this.fDSPCode.compute(this.fInputs, this.fOutputs);
4011
+ };
4012
+ this.start();
4013
+ }
4014
+ // Public API
4015
+ /** Setup accelerometer and gyroscope handlers */
4016
+ async startSensors() {
4017
+ if (this.hasAccInput) {
4018
+ if (window.DeviceMotionEvent) {
4019
+ if (typeof window.DeviceMotionEvent.requestPermission === "function") {
4020
+ try {
4021
+ const response = await window.DeviceMotionEvent.requestPermission();
4022
+ if (response === "granted") {
4023
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
4024
+ } else if (response === "denied") {
4025
+ alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
4026
+ throw new Error("Unable to access the accelerometer.");
4027
+ }
4028
+ } catch (error) {
4029
+ console.error(error);
4030
+ }
4031
+ } else {
4032
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
4033
+ }
4034
+ } else {
4035
+ console.log("Cannot set the accelerometer handler.");
4036
+ }
4037
+ }
4038
+ if (this.hasGyrInput) {
4039
+ if (window.DeviceMotionEvent) {
4040
+ if (typeof window.DeviceOrientationEvent.requestPermission === "function") {
4041
+ try {
4042
+ const response = await window.DeviceOrientationEvent.requestPermission();
4043
+ if (response === "granted") {
4044
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
4045
+ } else if (response === "denied") {
4046
+ alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
4047
+ throw new Error("Unable to access the gyroscope.");
4048
+ }
4049
+ } catch (error) {
4050
+ console.error(error);
4051
+ }
4052
+ } else {
4053
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
4054
+ }
4055
+ } else {
4056
+ console.log("Cannot set the gyroscope handler.");
4057
+ }
4058
+ }
4059
+ }
4060
+ stopSensors() {
4061
+ if (this.hasAccInput) {
4062
+ window.removeEventListener("devicemotion", this.handleDeviceMotion, true);
4063
+ }
4064
+ if (this.hasGyrInput) {
4065
+ window.removeEventListener("deviceorientation", this.handleDeviceOrientation, true);
4066
+ }
4067
+ }
4068
+ compute(input, output) {
4069
+ return this.fDSPCode.compute(input, output);
4070
+ }
4071
+ setOutputParamHandler(handler) {
4072
+ this.fDSPCode.setOutputParamHandler(handler);
4073
+ }
4074
+ getOutputParamHandler() {
4075
+ return this.fDSPCode.getOutputParamHandler();
4076
+ }
4077
+ setComputeHandler(handler) {
4078
+ this.fDSPCode.setComputeHandler(handler);
4079
+ }
4080
+ getComputeHandler() {
4081
+ return this.fDSPCode.getComputeHandler();
4082
+ }
4083
+ setPlotHandler(handler) {
4084
+ this.fDSPCode.setPlotHandler(handler);
4085
+ }
4086
+ getPlotHandler() {
4087
+ return this.fDSPCode.getPlotHandler();
4088
+ }
4089
+ getNumInputs() {
4090
+ return this.fDSPCode.getNumInputs();
4091
+ }
4092
+ getNumOutputs() {
4093
+ return this.fDSPCode.getNumOutputs();
4094
+ }
4095
+ metadata(handler) {
4096
+ }
4097
+ midiMessage(data) {
4098
+ this.fDSPCode.midiMessage(data);
4099
+ }
4100
+ ctrlChange(chan, ctrl, value) {
4101
+ this.fDSPCode.ctrlChange(chan, ctrl, value);
4102
+ }
4103
+ pitchWheel(chan, value) {
4104
+ this.fDSPCode.pitchWheel(chan, value);
4105
+ }
4106
+ setParamValue(path, value) {
4107
+ this.fDSPCode.setParamValue(path, value);
4108
+ }
4109
+ getParamValue(path) {
4110
+ return this.fDSPCode.getParamValue(path);
4111
+ }
4112
+ getParams() {
4113
+ return this.fDSPCode.getParams();
4114
+ }
4115
+ getMeta() {
4116
+ return this.fDSPCode.getMeta();
4117
+ }
4118
+ getJSON() {
4119
+ return this.fDSPCode.getJSON();
4120
+ }
4121
+ getDescriptors() {
4122
+ return this.fDSPCode.getDescriptors();
4123
+ }
4124
+ getUI() {
4125
+ return this.fDSPCode.getUI();
4126
+ }
4127
+ start() {
4128
+ this.fDSPCode.start();
4129
+ }
4130
+ stop() {
4131
+ this.fDSPCode.stop();
4132
+ }
4133
+ destroy() {
4134
+ this.fDSPCode.destroy();
4135
+ }
4136
+ get hasAccInput() {
4137
+ return this.fDSPCode.hasAccInput;
4138
+ }
4139
+ propagateAcc(accelerationIncludingGravity, invert = false) {
4140
+ this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
4141
+ }
4142
+ get hasGyrInput() {
4143
+ return this.fDSPCode.hasGyrInput;
4144
+ }
4145
+ propagateGyr(event) {
4146
+ this.fDSPCode.propagateGyr(event);
4147
+ }
4148
+ };
4149
+ var FaustMonoScriptProcessorNode = class extends FaustScriptProcessorNode {
4150
+ };
4151
+ var FaustPolyScriptProcessorNode = class extends FaustScriptProcessorNode {
4152
+ keyOn(channel, pitch, velocity) {
4153
+ this.fDSPCode.keyOn(channel, pitch, velocity);
4154
+ }
4155
+ keyOff(channel, pitch, velocity) {
4156
+ this.fDSPCode.keyOff(channel, pitch, velocity);
4157
+ }
4158
+ allNotesOff(hard) {
4159
+ this.fDSPCode.allNotesOff(hard);
4160
+ }
4161
+ };
4162
+
4163
+ // src/FaustDspGenerator.ts
4164
+ var _FaustMonoDspGenerator = class _FaustMonoDspGenerator {
4165
+ constructor() {
4166
+ this.factory = null;
4167
+ }
4168
+ async compile(compiler, name, code, args) {
4169
+ this.factory = await compiler.createMonoDSPFactory(name, code, args);
4170
+ if (this.factory) {
4171
+ this.name = name;
4172
+ return this;
4173
+ } else {
4174
+ return null;
4175
+ }
4176
+ }
4177
+ addSoundfiles(soundfileMap) {
4178
+ if (!this.factory)
4179
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4180
+ for (const id in soundfileMap) {
4181
+ this.factory.soundfiles[id] = soundfileMap[id];
4182
+ }
4183
+ }
4184
+ getSoundfileList() {
4185
+ if (!this.factory)
4186
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4187
+ const meta = JSON.parse(this.factory.json);
4188
+ const map = SoundfileReader_default.findSoundfilesFromMeta(meta);
4189
+ return Object.keys(map);
4190
+ }
4191
+ async createNode(context, name = this.name, factory = this.factory, sp = false, bufferSize = 1024, processorName = (factory == null ? void 0 : factory.shaKey) || name, processorOptions = {}) {
4192
+ var _a, _b;
4193
+ if (!factory)
4194
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4195
+ const meta = JSON.parse(factory.json);
4196
+ const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
4197
+ factory.soundfiles = await SoundfileReader_default.loadSoundfiles(meta, factory.soundfiles || {}, context);
4198
+ if (sp) {
4199
+ const instance = await FaustWasmInstantiator_default.createAsyncMonoDSPInstance(factory);
4200
+ const monoDsp = new FaustMonoWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize, factory.soundfiles);
4201
+ const sp2 = context.createScriptProcessor(bufferSize, monoDsp.getNumInputs(), monoDsp.getNumOutputs());
4202
+ Object.setPrototypeOf(sp2, FaustMonoScriptProcessorNode.prototype);
4203
+ sp2.init(monoDsp);
4204
+ return sp2;
4205
+ } else {
4206
+ if (!_FaustMonoDspGenerator.gWorkletProcessors.has(context))
4207
+ _FaustMonoDspGenerator.gWorkletProcessors.set(context, /* @__PURE__ */ new Set());
4208
+ if (!((_a = _FaustMonoDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _a.has(processorName))) {
4209
+ try {
4210
+ const processorCode = `
4211
+ // DSP name and JSON string for DSP are generated
4212
+ const faustData = ${JSON.stringify({
4213
+ processorName,
4214
+ dspName: name,
4215
+ dspMeta: meta,
4216
+ poly: false
4217
+ })};
4218
+ // Implementation needed classes of functions
4219
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
4220
+ var FaustDspInstance = ${FaustDspInstance.name};
4221
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
4222
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
4223
+ var ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
4224
+ var FaustMonoWebAudioDsp = ${FaustMonoWebAudioDsp.name};
4225
+ var ${FaustWasmInstantiator_default.name} = ${FaustWasmInstantiator_default.toString()}
4226
+ var FaustWasmInstantiator = ${FaustWasmInstantiator_default.name};
4227
+ var ${Soundfile.name} = ${Soundfile.toString()}
4228
+ var Soundfile = ${Soundfile.name};
4229
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
4230
+ var WasmAllocator = ${WasmAllocator.name};
4231
+ var ${FaustSensors.name} = ${FaustSensors.toString()}
4232
+ var FaustSensors = ${FaustSensors.name};
4233
+ // Put them in dependencies
4234
+ const dependencies = {
4235
+ FaustBaseWebAudioDsp,
4236
+ FaustMonoWebAudioDsp,
4237
+ FaustWasmInstantiator
4238
+ };
4239
+ // Generate the actual AudioWorkletProcessor code
4240
+ (${FaustAudioWorkletProcessor_default.toString()})(dependencies, faustData);
4241
+ `;
4242
+ const url = URL.createObjectURL(new Blob([processorCode], { type: "text/javascript" }));
4243
+ await context.audioWorklet.addModule(url);
4244
+ (_b = _FaustMonoDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _b.add(processorName);
4245
+ } catch (e) {
4246
+ throw e;
4247
+ }
4248
+ }
4249
+ const node = new FaustMonoAudioWorkletNode(context, { processorOptions: { name: processorName, factory, sampleSize, ...processorOptions } });
4250
+ return node;
4251
+ }
4252
+ }
4253
+ async createFFTNode(context, fftUtils, name = this.name, factory = this.factory, fftOptions = {}, processorName = (factory == null ? void 0 : factory.shaKey) ? `${factory.shaKey}_fft` : name, processorOptions = {}) {
4254
+ var _a, _b;
4255
+ if (!factory)
4256
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4257
+ const meta = JSON.parse(factory.json);
4258
+ const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
4259
+ factory.soundfiles = await SoundfileReader_default.loadSoundfiles(meta, factory.soundfiles || {}, context);
4260
+ if (!_FaustMonoDspGenerator.gWorkletProcessors.has(context))
4261
+ _FaustMonoDspGenerator.gWorkletProcessors.set(context, /* @__PURE__ */ new Set());
4262
+ if (!((_a = _FaustMonoDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _a.has(processorName))) {
4263
+ try {
4264
+ const processorCode = `
4265
+ // DSP name and JSON string for DSP are generated
4266
+ const faustData = ${JSON.stringify({
4267
+ processorName,
4268
+ dspName: name,
4269
+ dspMeta: meta,
4270
+ fftOptions
4271
+ })};
4272
+ // Implementation needed classes of functions
4273
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
4274
+ var FaustDspInstance = ${FaustDspInstance.name};
4275
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
4276
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
4277
+ var ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
4278
+ var FaustMonoWebAudioDsp = ${FaustMonoWebAudioDsp.name};
4279
+ var ${FaustWasmInstantiator_default.name} = ${FaustWasmInstantiator_default.toString()}
4280
+ var FaustWasmInstantiator = ${FaustWasmInstantiator_default.name};
4281
+ var ${Soundfile.name} = ${Soundfile.toString()}
4282
+ var Soundfile = ${Soundfile.name};
4283
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
4284
+ var WasmAllocator = ${WasmAllocator.name};
4285
+ var ${FaustSensors.name} = ${FaustSensors.toString()}
4286
+ var FaustSensors = ${FaustSensors.name};
4287
+ var FFTUtils = ${fftUtils.toString()}
4288
+ // Put them in dependencies
4289
+ const dependencies = {
4290
+ FaustBaseWebAudioDsp,
4291
+ FaustMonoWebAudioDsp,
4292
+ FaustWasmInstantiator,
4293
+ FFTUtils
4294
+ };
4295
+ // Generate the actual AudioWorkletProcessor code
4296
+ (${FaustFFTAudioWorkletProcessor_default.toString()})(dependencies, faustData);
4297
+ `;
4298
+ const url = URL.createObjectURL(new Blob([processorCode], { type: "text/javascript" }));
4299
+ await context.audioWorklet.addModule(url);
4300
+ (_b = _FaustMonoDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _b.add(processorName);
4301
+ } catch (e) {
4302
+ throw e;
4303
+ }
4304
+ }
4305
+ const node = new FaustMonoAudioWorkletNode(context, { channelCount: Math.max(1, Math.ceil(meta.inputs / 3)), outputChannelCount: [Math.ceil(meta.outputs / 2)], processorOptions: { name: processorName, factory, sampleSize, ...processorOptions } });
4306
+ if (fftOptions.fftSize) {
4307
+ const param = node.parameters.get("fftSize");
4308
+ if (param)
4309
+ param.value = fftOptions.fftSize;
4310
+ }
4311
+ if (fftOptions.fftOverlap) {
4312
+ const param = node.parameters.get("fftOverlap");
4313
+ if (param)
4314
+ param.value = fftOptions.fftOverlap;
4315
+ }
4316
+ if (typeof fftOptions.defaultWindowFunction === "number") {
4317
+ const param = node.parameters.get("windowFunction");
4318
+ if (param)
4319
+ param.value = fftOptions.defaultWindowFunction + 1;
4320
+ }
4321
+ if (typeof fftOptions.noIFFT === "boolean") {
4322
+ const param = node.parameters.get("noIFFT");
4323
+ if (param)
4324
+ param.value = +fftOptions.noIFFT;
4325
+ }
4326
+ return node;
4327
+ }
4328
+ async createAudioWorkletProcessor(name = this.name, factory = this.factory, processorName = (factory == null ? void 0 : factory.shaKey) || name) {
4329
+ if (!factory)
4330
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4331
+ const meta = JSON.parse(factory.json);
4332
+ const dependencies = {
4333
+ FaustBaseWebAudioDsp,
4334
+ FaustMonoWebAudioDsp,
4335
+ FaustWasmInstantiator: FaustWasmInstantiator_default,
4336
+ FaustPolyWebAudioDsp: void 0,
4337
+ FaustWebAudioDspVoice: void 0
4338
+ };
4339
+ try {
4340
+ const faustData = {
4341
+ processorName,
4342
+ dspName: name,
4343
+ dspMeta: meta,
4344
+ poly: false
4345
+ };
4346
+ const Processor = FaustAudioWorkletProcessor_default(dependencies, faustData);
4347
+ return Processor;
4348
+ } catch (e) {
4349
+ throw e;
4350
+ }
4351
+ }
4352
+ async createOfflineProcessor(sampleRate, bufferSize, factory = this.factory, context) {
4353
+ if (!factory)
4354
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4355
+ const meta = JSON.parse(factory.json);
4356
+ const instance = await FaustWasmInstantiator_default.createAsyncMonoDSPInstance(factory);
4357
+ const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
4358
+ if (context)
4359
+ factory.soundfiles = await SoundfileReader_default.loadSoundfiles(meta, factory.soundfiles || {}, context);
4360
+ const monoDsp = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, bufferSize, factory.soundfiles);
4361
+ return new FaustMonoOfflineProcessor(monoDsp, bufferSize);
4362
+ }
4363
+ getMeta() {
4364
+ return JSON.parse(this.factory.json);
4365
+ }
4366
+ getJSON() {
4367
+ return JSON.stringify(this.getMeta());
4368
+ }
4369
+ getUI() {
4370
+ return this.getMeta().ui;
4371
+ }
4372
+ };
4373
+ // Set of all created WorkletProcessors, each of them has to be unique
4374
+ _FaustMonoDspGenerator.gWorkletProcessors = /* @__PURE__ */ new Map();
4375
+ var FaustMonoDspGenerator = _FaustMonoDspGenerator;
4376
+ var _FaustPolyDspGenerator = class _FaustPolyDspGenerator {
4377
+ constructor() {
4378
+ this.voiceFactory = null;
4379
+ this.effectFactory = null;
4380
+ }
4381
+ async compile(compiler, name, dspCodeAux, args, effectCodeAux = `dsp_code = environment{
4382
+ ${dspCodeAux}
4383
+ };
4384
+ process = dsp_code.effect;`) {
4385
+ try {
4386
+ this.effectFactory = await compiler.createPolyDSPFactory(name, effectCodeAux, args);
4387
+ if (this.effectFactory) {
4388
+ const effectJSON = JSON.parse(this.effectFactory.json);
4389
+ const dspCode = `// Voice output is forced to 2, when DSP is stereo or effect has 2 ins or 2 outs,
4390
+ // so that the effect can process the 2 channels of the voice
4391
+ adaptOut(1,1,1) = _;
4392
+ adaptOut(1,1,2) = _ <: _,0; // The left channel only is kept
4393
+ adaptOut(1,2,1) = _ <: _,_;
4394
+ adaptOut(1,2,2) = _ <: _,_;
4395
+ adaptOut(2,1,1) = _,_;
4396
+ adaptOut(2,1,2) = _,_;
4397
+ adaptOut(2,2,1) = _,_;
4398
+ adaptOut(2,2,2) = _,_;
4399
+ adaptor(F) = adaptOut(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
4400
+ dsp_code = environment{
4401
+ ${dspCodeAux}
4402
+ };
4403
+ process = dsp_code.process : adaptor(dsp_code.process);
4404
+ `;
4405
+ const effectCode = `// Inputs
4406
+ adaptIn(1,1,1) = _;
4407
+ adaptIn(1,1,2) = _,_ :> _;
4408
+ adaptIn(1,2,1) = _,_;
4409
+ adaptIn(1,2,2) = _,_;
4410
+ adaptIn(2,1,1) = _,_ :> _;
4411
+ adaptIn(2,1,2) = _,_ :> _;
4412
+ adaptIn(2,2,1) = _,_;
4413
+ adaptIn(2,2,2) = _,_;
4414
+ // Outputs
4415
+ adaptOut(1,1) = _ <: _,0; // The left channel only is kept
4416
+ adaptOut(1,2) = _,_;
4417
+ adaptOut(2,1) = _ <: _,0; // The left channel only is kept
4418
+ adaptOut(2,2) = _,_;
4419
+ adaptorIns(F) = adaptIn(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
4420
+ adaptorOuts = adaptOut(${effectJSON.inputs},${effectJSON.outputs});
4421
+ dsp_code = environment{
4422
+ ${dspCodeAux}
4423
+ };
4424
+ process = adaptorIns(dsp_code.process) : dsp_code.effect : adaptorOuts;
4425
+ `;
4426
+ this.voiceFactory = await compiler.createPolyDSPFactory(name, dspCode, args);
4427
+ try {
4428
+ this.effectFactory = await compiler.createPolyDSPFactory(name, effectCode, args + " -inpl");
4429
+ } catch (e) {
4430
+ console.warn(e);
4431
+ }
4432
+ }
4433
+ } catch (e) {
4434
+ console.warn(e);
4435
+ this.voiceFactory = await compiler.createPolyDSPFactory(name, dspCodeAux, args);
4436
+ }
4437
+ if (this.voiceFactory) {
4438
+ this.name = name;
4439
+ const voiceMeta = JSON.parse(this.voiceFactory.json);
4440
+ const isDouble = voiceMeta.compile_options.match("-double");
4441
+ const { mixerBuffer, mixerModule } = await compiler.getAsyncInternalMixerModule(!!isDouble);
4442
+ this.mixerBuffer = mixerBuffer;
4443
+ this.mixerModule = mixerModule;
4444
+ return this;
4445
+ } else {
4446
+ return null;
4447
+ }
4448
+ }
4449
+ addSoundfiles(soundfileMap) {
4450
+ if (!this.voiceFactory)
4451
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4452
+ for (const id in soundfileMap) {
4453
+ this.voiceFactory.soundfiles[id] = soundfileMap[id];
4454
+ }
4455
+ }
4456
+ getSoundfileList() {
4457
+ if (!this.voiceFactory)
4458
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4459
+ const meta = JSON.parse(this.voiceFactory.json);
4460
+ const map = SoundfileReader_default.findSoundfilesFromMeta(meta);
4461
+ if (!this.effectFactory)
4462
+ return Object.keys(map);
4463
+ const effectMeta = JSON.parse(this.effectFactory.json);
4464
+ const effectMap = SoundfileReader_default.findSoundfilesFromMeta(effectMeta);
4465
+ return Object.keys({ ...effectMap, ...map });
4466
+ }
4467
+ async createNode(context, voices, name = this.name, voiceFactory = this.voiceFactory, mixerModule = this.mixerModule, effectFactory = this.effectFactory, sp = false, bufferSize = 1024, processorName = ((voiceFactory == null ? void 0 : voiceFactory.shaKey) || "") + ((effectFactory == null ? void 0 : effectFactory.shaKey) || "") || `${name}_poly`, processorOptions = {}) {
4468
+ var _a, _b;
4469
+ if (!voiceFactory)
4470
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4471
+ const voiceMeta = JSON.parse(voiceFactory.json);
4472
+ const effectMeta = effectFactory ? JSON.parse(effectFactory.json) : void 0;
4473
+ const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
4474
+ voiceFactory.soundfiles = await SoundfileReader_default.loadSoundfiles(voiceMeta, voiceFactory.soundfiles || {}, context);
4475
+ if (effectFactory)
4476
+ effectFactory.soundfiles = await SoundfileReader_default.loadSoundfiles(effectMeta, effectFactory.soundfiles || {}, context);
4477
+ if (sp) {
4478
+ const instance = await FaustWasmInstantiator_default.createAsyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory || void 0);
4479
+ const soundfiles = { ...effectFactory == null ? void 0 : effectFactory.soundfiles, ...voiceFactory.soundfiles };
4480
+ const polyDsp = new FaustPolyWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize, soundfiles);
4481
+ const sp2 = context.createScriptProcessor(bufferSize, polyDsp.getNumInputs(), polyDsp.getNumOutputs());
4482
+ Object.setPrototypeOf(sp2, FaustPolyScriptProcessorNode.prototype);
4483
+ sp2.init(polyDsp);
4484
+ return sp2;
4485
+ } else {
4486
+ if (!_FaustPolyDspGenerator.gWorkletProcessors.has(context))
4487
+ _FaustPolyDspGenerator.gWorkletProcessors.set(context, /* @__PURE__ */ new Set());
4488
+ if (!((_a = _FaustPolyDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _a.has(processorName))) {
4489
+ try {
4490
+ const processorCode = `
4491
+ // DSP name and JSON string for DSP are generated
4492
+ const faustData = ${JSON.stringify({
4493
+ processorName,
4494
+ dspName: name,
4495
+ dspMeta: voiceMeta,
4496
+ poly: true,
4497
+ effectMeta
4498
+ })};
4499
+ // Implementation needed classes of functions
4500
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
4501
+ var FaustDspInstance = ${FaustDspInstance.name};
4502
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
4503
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
4504
+ var ${FaustPolyWebAudioDsp.name} = ${FaustPolyWebAudioDsp.toString()}
4505
+ var FaustPolyWebAudioDsp = ${FaustPolyWebAudioDsp.name};
4506
+ var ${FaustWebAudioDspVoice.name} = ${FaustWebAudioDspVoice.toString()}
4507
+ var FaustWebAudioDspVoice = ${FaustWebAudioDspVoice.name};
4508
+ var ${FaustWasmInstantiator_default.name} = ${FaustWasmInstantiator_default.toString()}
4509
+ var FaustWasmInstantiator = ${FaustWasmInstantiator_default.name};
4510
+ var ${Soundfile.name} = ${Soundfile.toString()}
4511
+ var Soundfile = ${Soundfile.name};
4512
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
4513
+ var WasmAllocator = ${WasmAllocator.name};
4514
+ var ${FaustSensors.name} = ${FaustSensors.toString()}
4515
+ var FaustSensors = ${FaustSensors.name};
4516
+ // Put them in dependencies
4517
+ const dependencies = {
4518
+ FaustBaseWebAudioDsp,
4519
+ FaustPolyWebAudioDsp,
4520
+ FaustWasmInstantiator
4521
+ };
4522
+ // Generate the actual AudioWorkletProcessor code
4523
+ (${FaustAudioWorkletProcessor_default.toString()})(dependencies, faustData);
4524
+ `;
4525
+ const url = URL.createObjectURL(new Blob([processorCode], { type: "text/javascript" }));
4526
+ await context.audioWorklet.addModule(url);
4527
+ (_b = _FaustPolyDspGenerator.gWorkletProcessors.get(context)) == null ? void 0 : _b.add(processorName);
4528
+ } catch (e) {
4529
+ throw e;
4530
+ }
4531
+ }
4532
+ const node = new FaustPolyAudioWorkletNode(context, { processorOptions: { name: processorName, voiceFactory, mixerModule, voices, sampleSize, effectFactory: effectFactory || void 0, ...processorOptions } });
4533
+ return node;
4534
+ }
4535
+ }
4536
+ async createAudioWorkletProcessor(name = this.name, voiceFactory = this.voiceFactory, effectFactory = this.effectFactory, processorName = ((voiceFactory == null ? void 0 : voiceFactory.shaKey) || "") + ((effectFactory == null ? void 0 : effectFactory.shaKey) || "") || `${name}_poly`) {
4537
+ if (!voiceFactory)
4538
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4539
+ const voiceMeta = JSON.parse(voiceFactory.json);
4540
+ const effectMeta = effectFactory ? JSON.parse(effectFactory.json) : void 0;
4541
+ const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
4542
+ try {
4543
+ const dependencies = {
4544
+ FaustBaseWebAudioDsp,
4545
+ FaustMonoWebAudioDsp: void 0,
4546
+ FaustWasmInstantiator: FaustWasmInstantiator_default,
4547
+ FaustPolyWebAudioDsp,
4548
+ FaustWebAudioDspVoice
4549
+ };
4550
+ const faustData = {
4551
+ processorName,
4552
+ dspName: name,
4553
+ dspMeta: voiceMeta,
4554
+ poly: true,
4555
+ effectMeta
4556
+ };
4557
+ const Processor = FaustAudioWorkletProcessor_default(dependencies, faustData);
4558
+ return Processor;
4559
+ } catch (e) {
4560
+ throw e;
4561
+ }
4562
+ }
4563
+ async createOfflineProcessor(sampleRate, bufferSize, voices, voiceFactory = this.voiceFactory, mixerModule = this.mixerModule, effectFactory = this.effectFactory, context) {
4564
+ if (!voiceFactory)
4565
+ throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
4566
+ const voiceMeta = JSON.parse(voiceFactory.json);
4567
+ const effectMeta = effectFactory ? JSON.parse(effectFactory.json) : void 0;
4568
+ const instance = await FaustWasmInstantiator_default.createAsyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory || void 0);
4569
+ const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
4570
+ if (context) {
4571
+ voiceFactory.soundfiles = await SoundfileReader_default.loadSoundfiles(voiceMeta, voiceFactory.soundfiles || {}, context);
4572
+ if (effectFactory)
4573
+ effectFactory.soundfiles = await SoundfileReader_default.loadSoundfiles(effectMeta, effectFactory.soundfiles || {}, context);
4574
+ }
4575
+ const soundfiles = { ...effectFactory == null ? void 0 : effectFactory.soundfiles, ...voiceFactory.soundfiles };
4576
+ const polyDsp = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, bufferSize, soundfiles);
4577
+ return new FaustPolyOfflineProcessor(polyDsp, bufferSize);
4578
+ }
4579
+ getMeta() {
4580
+ const o = this.voiceFactory ? JSON.parse(this.voiceFactory.json) : null;
4581
+ const e = this.effectFactory ? JSON.parse(this.effectFactory.json) : null;
4582
+ const r = { ...o };
4583
+ if (e) {
4584
+ r.ui = [{
4585
+ type: "tgroup",
4586
+ label: "Sequencer",
4587
+ items: [
4588
+ { type: "vgroup", label: "Instrument", items: o.ui },
4589
+ { type: "vgroup", label: "Effect", items: e.ui }
4590
+ ]
4591
+ }];
4592
+ } else {
4593
+ r.ui = [{
4594
+ type: "tgroup",
4595
+ label: "Polyphonic",
4596
+ items: [
4597
+ { type: "vgroup", label: "Voices", items: o.ui }
4598
+ ]
4599
+ }];
4600
+ }
4601
+ return r;
4602
+ }
4603
+ getJSON() {
4604
+ return JSON.stringify(this.getMeta());
4605
+ }
4606
+ getUI() {
4607
+ return this.getMeta().ui;
4608
+ }
4609
+ };
4610
+ // Set of all created WorkletProcessors, each of them has to be unique
4611
+ _FaustPolyDspGenerator.gWorkletProcessors = /* @__PURE__ */ new Map();
4612
+ var FaustPolyDspGenerator = _FaustPolyDspGenerator;
4613
+ export {
4614
+ FaustAudioWorkletNode,
4615
+ FaustBaseWebAudioDsp,
4616
+ FaustCmajor_default as FaustCmajor,
4617
+ FaustCompiler_default as FaustCompiler,
4618
+ FaustDspInstance,
4619
+ FaustMonoAudioWorkletNode,
4620
+ FaustMonoDspGenerator,
4621
+ FaustMonoOfflineProcessor,
4622
+ FaustMonoScriptProcessorNode,
4623
+ FaustMonoWebAudioDsp,
4624
+ FaustOfflineProcessor_default as FaustOfflineProcessor,
4625
+ FaustPolyAudioWorkletNode,
4626
+ FaustPolyDspGenerator,
4627
+ FaustPolyOfflineProcessor,
4628
+ FaustPolyScriptProcessorNode,
4629
+ FaustPolyWebAudioDsp,
4630
+ FaustScriptProcessorNode,
4631
+ FaustSvgDiagrams_default as FaustSvgDiagrams,
4632
+ FaustWasmInstantiator_default as FaustWasmInstantiator,
4633
+ FaustWebAudioDspVoice,
4634
+ LibFaust_default as LibFaust,
4635
+ Soundfile,
4636
+ SoundfileReader_default as SoundfileReader,
4637
+ WasmAllocator,
4638
+ WavDecoder_default as WavDecoder,
4639
+ WavEncoder_default as WavEncoder,
4640
+ ab2str,
4641
+ FaustAudioWorkletProcessor_default as getFaustAudioWorkletProcessor,
4642
+ FaustFFTAudioWorkletProcessor_default as getFaustFFTAudioWorkletProcessor,
4643
+ instantiateFaustModuleFromFile_default as instantiateFaustModuleFromFile,
4644
+ str2ab
4645
+ };
4646
+ //# sourceMappingURL=index.js.map