@grame/faustwasm 0.1.6 → 0.2.0

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.
Files changed (42) hide show
  1. package/assets/standalone/faustwasm/index.d.ts +132 -99
  2. package/assets/standalone/faustwasm/index.js +907 -1230
  3. package/assets/standalone/faustwasm/index.js.map +4 -4
  4. package/dist/cjs/index.d.ts +132 -99
  5. package/dist/cjs/index.js +909 -1212
  6. package/dist/cjs/index.js.map +4 -4
  7. package/dist/cjs-bundle/index.d.ts +132 -99
  8. package/dist/cjs-bundle/index.js +1013 -1317
  9. package/dist/cjs-bundle/index.js.map +4 -4
  10. package/dist/esm/index.d.ts +132 -99
  11. package/dist/esm/index.js +907 -1230
  12. package/dist/esm/index.js.map +4 -4
  13. package/dist/esm-bundle/index.d.ts +132 -99
  14. package/dist/esm-bundle/index.js +1013 -1321
  15. package/dist/esm-bundle/index.js.map +4 -4
  16. package/libfaust-wasm/libfaust-wasm.js +1 -1
  17. package/libfaust-wasm/libfaust-wasm.wasm +0 -0
  18. package/package.json +15 -13
  19. package/src/FaustAudioWorkletProcessor.ts +3 -14
  20. package/src/FaustCmajor.ts +6 -6
  21. package/src/FaustCompiler.ts +2 -2
  22. package/src/FaustDspGenerator.ts +109 -75
  23. package/src/FaustDspInstance.ts +2 -2
  24. package/src/FaustFFTAudioWorkletProcessor.ts +3 -1
  25. package/src/FaustWebAudioDsp.ts +224 -449
  26. package/src/SoundfileReader.ts +117 -0
  27. package/src/exports.ts +1 -0
  28. package/src/faust2wasmFiles.js +1 -1
  29. package/src/types.ts +15 -7
  30. package/test/faustlive-wasm/faustwasm/index.d.ts +132 -99
  31. package/test/faustlive-wasm/faustwasm/index.js +907 -1230
  32. package/test/faustlive-wasm/faustwasm/index.js.map +4 -4
  33. package/test/soundfile.dsp +15 -0
  34. package/test/soundfile1.dsp +23 -0
  35. package/test/web/soundfile.html +69 -0
  36. package/out/clarinetMIDI.html +0 -50
  37. package/out/clarinetMIDI.js +0 -63
  38. package/out/clarinetMIDI.json +0 -431
  39. package/out/clarinetMIDI.wasm +0 -0
  40. package/out/faustwasm/index.d.ts +0 -1495
  41. package/out/faustwasm/index.js +0 -4470
  42. package/out/faustwasm/index.js.map +0 -7
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -9,9 +9,9 @@
9
9
  "scripts": {
10
10
  "build": "npm run build-cjs && npm run build-cjs-bundle && npm run build-esm && npm run build-esm-bundle && node postbuild-bundled.js & npm run build-types & npm run build-types-bundle",
11
11
  "build-cjs": "esbuild src/index.ts --target=es2019 --bundle --sourcemap --outdir=dist/cjs --format=iife --external:fs --external:url",
12
- "build-cjs-bundle": "node prebuild-bundled.js && esbuild src/index-bundle-iife.ts --target=es2019 --bundle --sourcemap --loader:.wasm=binary --loader:.data=binary --outfile=dist/cjs-bundle/index.js --format=iife --external:fs --external:url --external:path && node postbuild-bundled.js",
12
+ "build-cjs-bundle": "node prebuild-bundled.js && esbuild src/index-bundle-iife.ts --target=es2019 --bundle --sourcemap --loader:.wasm=binary --loader:.data=binary --outfile=dist/cjs-bundle/index.js --format=iife --external:fs --external:url --external:path --external:ws && node postbuild-bundled.js",
13
13
  "build-esm": "esbuild src/index.ts --target=es2019 --bundle --sourcemap --outdir=dist/esm --format=esm --external:fs --external:url",
14
- "build-esm-bundle": "node prebuild-bundled.js && esbuild src/index-bundle.ts --target=es2019 --bundle --sourcemap --loader:.wasm=binary --loader:.data=binary --outfile=dist/esm-bundle/index.js --format=esm --external:fs --external:url --external:path && node postbuild-bundled.js",
14
+ "build-esm-bundle": "node prebuild-bundled.js && esbuild src/index-bundle.ts --target=es2019 --bundle --sourcemap --loader:.wasm=binary --loader:.data=binary --outfile=dist/esm-bundle/index.js --format=esm --external:fs --external:url --external:path --external:ws && node postbuild-bundled.js",
15
15
  "build-types": "dts-bundle-generator -o dist/cjs/index.d.ts src/index.ts --external-imports",
16
16
  "build-types-bundle": "dts-bundle-generator -o dist/cjs-bundle/index.d.ts src/index-bundle.ts --external-imports",
17
17
  "postbuild": "node postbuild.js"
@@ -27,9 +27,9 @@
27
27
  "signal processing"
28
28
  ],
29
29
  "bin": {
30
- "faust2sndfile-ts": "scripts/faust2sndfile.js",
31
- "faust2svg-ts": "scripts/faust2svg.js",
32
- "faust2wasm-ts": "scripts/faust2wasm.js"
30
+ "faust2sndfile-ts": "scripts/faust2sndfile.js",
31
+ "faust2svg-ts": "scripts/faust2svg.js",
32
+ "faust2wasm-ts": "scripts/faust2wasm.js"
33
33
  },
34
34
  "author": "Grame-CNCM",
35
35
  "license": "LGPL-3.0",
@@ -38,13 +38,15 @@
38
38
  },
39
39
  "homepage": "https://github.com/grame-cncm/faustwasm#readme",
40
40
  "devDependencies": {
41
- "@aws-crypto/sha256-js": "^2.0.1",
41
+ "@aws-crypto/sha256-js": "^5.2.0",
42
42
  "@shren/faust-ui": "^1.1.9",
43
- "@types/emscripten": "^1.39.5",
44
- "@types/node": "^16.11.7",
45
- "@types/webmidi": "^2.0.6",
46
- "dts-bundle-generator": "^6.13.0",
47
- "esbuild": "^0.14.27",
48
- "typescript": "^4.4.4"
43
+ "@types/node": "^20.12.7",
44
+ "@types/webmidi": "^2.0.10",
45
+ "dts-bundle-generator": "^9.5.1",
46
+ "esbuild": "^0.20.2",
47
+ "typescript": "^5.4.5"
48
+ },
49
+ "dependencies": {
50
+ "@types/emscripten": "^1.39.10"
49
51
  }
50
52
  }
@@ -190,13 +190,7 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
190
190
  const instance = FaustWasmInstantiator.createSyncMonoDSPInstance(factory);
191
191
 
192
192
  // Create Monophonic DSP
193
- this.fDSPCode = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, 128);
194
-
195
- // Check for soundfile support
196
- if (this.fDSPCode.hasSoundfiles()) {
197
- console.error("FaustAudioWorkletProcessor: Soundfile support is not implemented yet, switch to ScriptProcessorNode for now");
198
- return;
199
- }
193
+ this.fDSPCode = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, 128, factory.soundfiles);
200
194
 
201
195
  // Setup output handler
202
196
  this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
@@ -218,14 +212,9 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
218
212
 
219
213
  const instance = FaustWasmInstantiator.createSyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory);
220
214
 
215
+ const soundfiles = { ...effectFactory?.soundfiles, ...voiceFactory.soundfiles };
221
216
  // Create Polyphonic DSP
222
- this.fDSPCode = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, 128);
223
-
224
- // Check for soundfile support
225
- if (this.fDSPCode.hasSoundfiles()) {
226
- console.error("FaustAudioWorkletProcessor: Soundfile support is not implemented yet, switch to ScriptProcessorNode for now");
227
- return;
228
- }
217
+ this.fDSPCode = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, 128, soundfiles);
229
218
 
230
219
  // Setup port message handling
231
220
  this.port.onmessage = (e: MessageEvent) => this.handleMessageAux(e);
@@ -1,4 +1,4 @@
1
- import type LibFaust from "./LibFaust";
1
+ import type FaustCompiler from "./FaustCompiler";
2
2
 
3
3
  interface IFaustCmajor {
4
4
  /**
@@ -13,15 +13,15 @@ interface IFaustCmajor {
13
13
  }
14
14
 
15
15
  class FaustCmajor implements IFaustCmajor {
16
- private fLibFaust: LibFaust;
16
+ private fCompiler: FaustCompiler;
17
17
 
18
- constructor(libfaust: LibFaust) {
19
- this.fLibFaust = libfaust;
18
+ constructor(compiler: FaustCompiler) {
19
+ this.fCompiler = compiler;
20
20
  }
21
21
 
22
22
  compile(name: string, code: string, args: string) {
23
- const fs = this.fLibFaust.fs();
24
- const success = this.fLibFaust.generateAuxFiles(name, code, `-lang cmajor-hybrid -cn ${name} -o ${name}.cmajor`);
23
+ const fs = this.fCompiler.fs();
24
+ const success = this.fCompiler.generateAuxFiles(name, code, `-lang cmajor-hybrid -cn ${name} -o ${name}.cmajor`);
25
25
  return (success) ? fs.readFile(`${name}.cmajor`, { encoding: "utf8" }) as string : "";
26
26
  }
27
27
  }
@@ -127,7 +127,7 @@ class FaustCompiler implements IFaustCompiler {
127
127
  const factory = table[shaKey];
128
128
  const { code, json, poly } = factory;
129
129
  const ab = str2ab(atob(code))
130
- awaited.push(WebAssembly.compile(ab).then(module => this.gFactories.set(shaKey, { shaKey, cfactory: 0, code: ab, module, json: JSON.stringify(json), poly })));
130
+ awaited.push(WebAssembly.compile(ab).then(module => this.gFactories.set(shaKey, { shaKey, cfactory: 0, code: ab, module, json: JSON.stringify(json), poly, soundfiles: {} })));
131
131
  }
132
132
  return Promise.all(awaited);
133
133
  }
@@ -167,7 +167,7 @@ class FaustCompiler implements IFaustCompiler {
167
167
  const ui8Code = this.intVec2intArray(faustDspWasm.data);
168
168
  faustDspWasm.data.delete();
169
169
  const module = await WebAssembly.compile(ui8Code);
170
- const factory: FaustDspFactory = { shaKey, cfactory: faustDspWasm.cfactory, code: ui8Code, module, json: faustDspWasm.json, poly };
170
+ const factory: FaustDspFactory = { shaKey, cfactory: faustDspWasm.cfactory, code: ui8Code, module, json: faustDspWasm.json, poly, soundfiles: {} };
171
171
  // Factory C++ side can be deallocated immediately
172
172
  this.deleteDSPFactory(factory);
173
173
  // Keep the compiled factory in the cache
@@ -5,9 +5,10 @@ import { FaustDspInstance } from "./FaustDspInstance";
5
5
  import FaustWasmInstantiator from "./FaustWasmInstantiator";
6
6
  import { FaustMonoOfflineProcessor, FaustPolyOfflineProcessor, IFaustMonoOfflineProcessor, IFaustPolyOfflineProcessor } from "./FaustOfflineProcessor";
7
7
  import { FaustMonoScriptProcessorNode, FaustPolyScriptProcessorNode } from "./FaustScriptProcessorNode";
8
- import { FaustBaseWebAudioDsp, FaustMonoWebAudioDsp, FaustPolyWebAudioDsp, FaustWebAudioDspVoice, IFaustMonoWebAudioNode, IFaustPolyWebAudioNode } from "./FaustWebAudioDsp";
8
+ import { FaustBaseWebAudioDsp, FaustMonoWebAudioDsp, FaustPolyWebAudioDsp, FaustWebAudioDspVoice, IFaustMonoWebAudioNode, IFaustPolyWebAudioNode, Soundfile, WasmAllocator } from "./FaustWebAudioDsp";
9
9
  import type { IFaustCompiler } from "./FaustCompiler";
10
10
  import type { FaustDspFactory, FaustUIDescriptor, FaustDspMeta, FFTUtils, LooseFaustDspFactory } from "./types";
11
+ import SoundfileReader from "./SoundfileReader";
11
12
 
12
13
  export interface IFaustMonoDspGenerator {
13
14
  /**
@@ -73,7 +74,11 @@ export interface IFaustMonoDspGenerator {
73
74
  * @param factory - default is the compiled factory
74
75
  * @returns the compiled processor or 'null' if failure
75
76
  */
76
- createOfflineProcessor(sampleRate: number, bufferSize: number, factory?: LooseFaustDspFactory, meta?: FaustDspMeta): Promise<IFaustMonoOfflineProcessor | null>;
77
+ createOfflineProcessor(
78
+ sampleRate: number,
79
+ bufferSize: number,
80
+ factory?: LooseFaustDspFactory
81
+ ): Promise<IFaustMonoOfflineProcessor | null>;
77
82
 
78
83
  /**
79
84
  * Get DSP JSON description with its UI and metadata as object.
@@ -134,7 +139,8 @@ export interface IFaustPolyDspGenerator {
134
139
  mixerModule?: WebAssembly.Module,
135
140
  effectFactory?: LooseFaustDspFactory | null,
136
141
  sp?: boolean,
137
- bufferSize?: number
142
+ bufferSize?: number,
143
+ processorName?: string
138
144
  ): Promise<IFaustPolyWebAudioNode | null>;
139
145
 
140
146
  /**
@@ -153,7 +159,8 @@ export interface IFaustPolyDspGenerator {
153
159
  voices: number,
154
160
  voiceFactory?: LooseFaustDspFactory,
155
161
  mixerModule?: WebAssembly.Module,
156
- effectFactory?: LooseFaustDspFactory | null
162
+ effectFactory?: LooseFaustDspFactory | null,
163
+ processorName?: string
157
164
  ): Promise<IFaustPolyOfflineProcessor | null>;
158
165
 
159
166
  /**
@@ -210,11 +217,10 @@ export class FaustMonoDspGenerator implements IFaustMonoDspGenerator {
210
217
 
211
218
  const meta = JSON.parse(factory.json);
212
219
  const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
220
+ factory.soundfiles = await SoundfileReader.loadSoundfiles(meta, factory.soundfiles || {}, context);
213
221
  if (sp) {
214
222
  const instance = await FaustWasmInstantiator.createAsyncMonoDSPInstance(factory);
215
- const monoDsp = new FaustMonoWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize);
216
- // Initialize the DSP instance, possibly loading soundfiles
217
- await monoDsp.init(context);
223
+ const monoDsp = new FaustMonoWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize, factory.soundfiles);
218
224
  const sp = context.createScriptProcessor(bufferSize, monoDsp.getNumInputs(), monoDsp.getNumOutputs()) as FaustMonoScriptProcessorNode;
219
225
  Object.setPrototypeOf(sp, FaustMonoScriptProcessorNode.prototype);
220
226
  sp.init(monoDsp);
@@ -233,15 +239,23 @@ const faustData = ${JSON.stringify({
233
239
  poly: false
234
240
  } as FaustData)};
235
241
  // Implementation needed classes of functions
236
- const ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
237
- const ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
238
- const ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
239
- const ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
242
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
243
+ var FaustDspInstance = ${FaustDspInstance.name};
244
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
245
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
246
+ var ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
247
+ var FaustMonoWebAudioDsp = ${FaustMonoWebAudioDsp.name};
248
+ var ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
249
+ var FaustWasmInstantiator = ${FaustWasmInstantiator.name};
250
+ var ${Soundfile.name} = ${Soundfile.toString()}
251
+ var Soundfile = ${Soundfile.name};
252
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
253
+ var WasmAllocator = ${WasmAllocator.name};
240
254
  // Put them in dependencies
241
255
  const dependencies = {
242
- FaustBaseWebAudioDsp: ${FaustBaseWebAudioDsp.name},
243
- FaustMonoWebAudioDsp: ${FaustMonoWebAudioDsp.name},
244
- FaustWasmInstantiator: ${FaustWasmInstantiator.name}
256
+ FaustBaseWebAudioDsp,
257
+ FaustMonoWebAudioDsp,
258
+ FaustWasmInstantiator
245
259
  };
246
260
  // Generate the actual AudioWorkletProcessor code
247
261
  (${getFaustAudioWorkletProcessor.toString()})(dependencies, faustData);
@@ -274,6 +288,7 @@ const dependencies = {
274
288
 
275
289
  const meta: FaustDspMeta = JSON.parse(factory.json);
276
290
  const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
291
+ factory.soundfiles = await SoundfileReader.loadSoundfiles(meta, factory.soundfiles || {}, context);
277
292
  // Dynamically create AudioWorkletProcessor if code not yet created
278
293
  if (!FaustMonoDspGenerator.gWorkletProcessors.has(context)) FaustMonoDspGenerator.gWorkletProcessors.set(context, new Set());
279
294
  if (!FaustMonoDspGenerator.gWorkletProcessors.get(context)?.has(processorName)) {
@@ -287,16 +302,24 @@ const faustData = ${JSON.stringify({
287
302
  fftOptions
288
303
  } as FaustFFTData)};
289
304
  // Implementation needed classes of functions
290
- const ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
291
- const ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
292
- const ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
293
- const ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
294
- const FFTUtils = ${fftUtils.toString()}
305
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
306
+ var FaustDspInstance = ${FaustDspInstance.name};
307
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
308
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
309
+ var ${FaustMonoWebAudioDsp.name} = ${FaustMonoWebAudioDsp.toString()}
310
+ var FaustMonoWebAudioDsp = ${FaustMonoWebAudioDsp.name};
311
+ var ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
312
+ var FaustWasmInstantiator = ${FaustWasmInstantiator.name};
313
+ var ${Soundfile.name} = ${Soundfile.toString()}
314
+ var Soundfile = ${Soundfile.name};
315
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
316
+ var WasmAllocator = ${WasmAllocator.name};
317
+ var FFTUtils = ${fftUtils.toString()}
295
318
  // Put them in dependencies
296
319
  const dependencies = {
297
- FaustBaseWebAudioDsp: ${FaustBaseWebAudioDsp.name},
298
- FaustMonoWebAudioDsp: ${FaustMonoWebAudioDsp.name},
299
- FaustWasmInstantiator: ${FaustWasmInstantiator.name},
320
+ FaustBaseWebAudioDsp,
321
+ FaustMonoWebAudioDsp,
322
+ FaustWasmInstantiator,
300
323
  FFTUtils
301
324
  };
302
325
  // Generate the actual AudioWorkletProcessor code
@@ -371,16 +394,14 @@ const dependencies = {
371
394
  async createOfflineProcessor(
372
395
  sampleRate: number,
373
396
  bufferSize: number,
374
- factory = this.factory as LooseFaustDspFactory,
397
+ factory = this.factory as LooseFaustDspFactory
375
398
  ) {
376
399
  if (!factory) throw new Error("Code is not compiled, please define the factory or call `await this.compile()` first.");
377
400
 
378
401
  const meta = JSON.parse(factory.json);
379
402
  const instance = await FaustWasmInstantiator.createAsyncMonoDSPInstance(factory);
380
403
  const sampleSize = meta.compile_options.match("-double") ? 8 : 4;
381
- const monoDsp = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, bufferSize);
382
- // Initialize the DSP instance, no soundfiles loading for now (TODO ?)
383
- await monoDsp.init(null);
404
+ const monoDsp = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, bufferSize, factory.soundfiles);
384
405
  return new FaustMonoOfflineProcessor(monoDsp, bufferSize);
385
406
  }
386
407
 
@@ -421,43 +442,45 @@ export class FaustPolyDspGenerator implements IFaustPolyDspGenerator {
421
442
  // the voice and effect are adapted, possibly clearing buffers
422
443
  if (this.effectFactory) {
423
444
  const effectJSON = JSON.parse(this.effectFactory.json);
424
- const dspCode = `
425
- // Voice output is forced to 2, when DSP is stereo or effect has 2 ins or 2 outs,
426
- // so that the effect can process the 2 channels of the voice
427
- adaptOut(1,1,1) = _;
428
- adaptOut(1,1,2) = _ <: _,0; // The left channel only is kept
429
- adaptOut(1,2,1) = _ <: _,_;
430
- adaptOut(1,2,2) = _ <: _,_;
431
- adaptOut(2,1,1) = _,_;
432
- adaptOut(2,1,2) = _,_;
433
- adaptOut(2,2,1) = _,_;
434
- adaptOut(2,2,2) = _,_;
435
- adaptor(F) = adaptOut(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
436
- dsp_code = environment{
437
- ${dspCodeAux}
438
- };
439
- process = dsp_code.process : adaptor(dsp_code.process);`
440
- const effectCode = `
441
- // Inputs
442
- adaptIn(1,1,1) = _;
443
- adaptIn(1,1,2) = _,_ :> _;
444
- adaptIn(1,2,1) = _,_;
445
- adaptIn(1,2,2) = _,_;
446
- adaptIn(2,1,1) = _,_ :> _;
447
- adaptIn(2,1,2) = _,_ :> _;
448
- adaptIn(2,2,1) = _,_;
449
- adaptIn(2,2,2) = _,_;
450
- // Outputs
451
- adaptOut(1,1) = _ <: _,0; // The left channel only is kept
452
- adaptOut(1,2) = _,_;
453
- adaptOut(2,1) = _ <: _,0; // The left channel only is kept
454
- adaptOut(2,2) = _,_;
455
- adaptorIns(F) = adaptIn(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
456
- adaptorOuts = adaptOut(${effectJSON.inputs},${effectJSON.outputs});
457
- dsp_code = environment{
458
- ${dspCodeAux}
459
- };
460
- process = adaptorIns(dsp_code.process) : dsp_code.effect : adaptorOuts;`
445
+ const dspCode = `\
446
+ // Voice output is forced to 2, when DSP is stereo or effect has 2 ins or 2 outs,
447
+ // so that the effect can process the 2 channels of the voice
448
+ adaptOut(1,1,1) = _;
449
+ adaptOut(1,1,2) = _ <: _,0; // The left channel only is kept
450
+ adaptOut(1,2,1) = _ <: _,_;
451
+ adaptOut(1,2,2) = _ <: _,_;
452
+ adaptOut(2,1,1) = _,_;
453
+ adaptOut(2,1,2) = _,_;
454
+ adaptOut(2,2,1) = _,_;
455
+ adaptOut(2,2,2) = _,_;
456
+ adaptor(F) = adaptOut(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
457
+ dsp_code = environment{
458
+ ${dspCodeAux}
459
+ };
460
+ process = dsp_code.process : adaptor(dsp_code.process);
461
+ `;
462
+ const effectCode = `\
463
+ // Inputs
464
+ adaptIn(1,1,1) = _;
465
+ adaptIn(1,1,2) = _,_ :> _;
466
+ adaptIn(1,2,1) = _,_;
467
+ adaptIn(1,2,2) = _,_;
468
+ adaptIn(2,1,1) = _,_ :> _;
469
+ adaptIn(2,1,2) = _,_ :> _;
470
+ adaptIn(2,2,1) = _,_;
471
+ adaptIn(2,2,2) = _,_;
472
+ // Outputs
473
+ adaptOut(1,1) = _ <: _,0; // The left channel only is kept
474
+ adaptOut(1,2) = _,_;
475
+ adaptOut(2,1) = _ <: _,0; // The left channel only is kept
476
+ adaptOut(2,2) = _,_;
477
+ adaptorIns(F) = adaptIn(outputs(F),${effectJSON.inputs},${effectJSON.outputs});
478
+ adaptorOuts = adaptOut(${effectJSON.inputs},${effectJSON.outputs});
479
+ dsp_code = environment{
480
+ ${dspCodeAux}
481
+ };
482
+ process = adaptorIns(dsp_code.process) : dsp_code.effect : adaptorOuts;
483
+ `;
461
484
  this.voiceFactory = await compiler.createPolyDSPFactory(name, dspCode, args);
462
485
  try {
463
486
  // Effect is processing same buffers for inputs and outputs, so has to use -inpl option
@@ -500,11 +523,12 @@ export class FaustPolyDspGenerator implements IFaustPolyDspGenerator {
500
523
  const voiceMeta = JSON.parse(voiceFactory.json);
501
524
  const effectMeta = effectFactory ? JSON.parse(effectFactory.json) : undefined;
502
525
  const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
526
+ voiceFactory.soundfiles = await SoundfileReader.loadSoundfiles(voiceMeta, voiceFactory.soundfiles || {}, context);
527
+ if (effectFactory) effectFactory.soundfiles = await SoundfileReader.loadSoundfiles(effectMeta, effectFactory.soundfiles || {}, context);
503
528
  if (sp) {
504
529
  const instance = await FaustWasmInstantiator.createAsyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory || undefined);
505
- const polyDsp = new FaustPolyWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize);
506
- // Initialize the DSP instance, possibly loading soundfiles
507
- await polyDsp.init(context);
530
+ const soundfiles = { ...effectFactory?.soundfiles, ...voiceFactory.soundfiles };
531
+ const polyDsp = new FaustPolyWebAudioDsp(instance, context.sampleRate, sampleSize, bufferSize, soundfiles);
508
532
  const sp = context.createScriptProcessor(bufferSize, polyDsp.getNumInputs(), polyDsp.getNumOutputs()) as FaustPolyScriptProcessorNode;
509
533
  Object.setPrototypeOf(sp, FaustPolyScriptProcessorNode.prototype);
510
534
  sp.init(polyDsp);
@@ -524,16 +548,25 @@ const faustData = ${JSON.stringify({
524
548
  effectMeta
525
549
  } as FaustData)};
526
550
  // Implementation needed classes of functions
527
- const ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
528
- const ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
529
- const ${FaustPolyWebAudioDsp.name} = ${FaustPolyWebAudioDsp.toString()}
530
- const ${FaustWebAudioDspVoice.name} = ${FaustWebAudioDspVoice.toString()}
531
- const ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
551
+ var ${FaustDspInstance.name} = ${FaustDspInstance.toString()}
552
+ var FaustDspInstance = ${FaustDspInstance.name};
553
+ var ${FaustBaseWebAudioDsp.name} = ${FaustBaseWebAudioDsp.toString()}
554
+ var FaustBaseWebAudioDsp = ${FaustBaseWebAudioDsp.name};
555
+ var ${FaustPolyWebAudioDsp.name} = ${FaustPolyWebAudioDsp.toString()}
556
+ var FaustPolyWebAudioDsp = ${FaustPolyWebAudioDsp.name};
557
+ var ${FaustWebAudioDspVoice.name} = ${FaustWebAudioDspVoice.toString()}
558
+ var FaustWebAudioDspVoice = ${FaustWebAudioDspVoice.name};
559
+ var ${FaustWasmInstantiator.name} = ${FaustWasmInstantiator.toString()}
560
+ var FaustWasmInstantiator = ${FaustWasmInstantiator.name};
561
+ var ${Soundfile.name} = ${Soundfile.toString()}
562
+ var Soundfile = ${Soundfile.name};
563
+ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
564
+ var WasmAllocator = ${WasmAllocator.name};
532
565
  // Put them in dependencies
533
566
  const dependencies = {
534
- FaustBaseWebAudioDsp: ${FaustBaseWebAudioDsp.name},
535
- FaustPolyWebAudioDsp: ${FaustPolyWebAudioDsp.name},
536
- FaustWasmInstantiator: ${FaustWasmInstantiator.name}
567
+ FaustBaseWebAudioDsp,
568
+ FaustPolyWebAudioDsp,
569
+ FaustWasmInstantiator
537
570
  };
538
571
  // Generate the actual AudioWorkletProcessor code
539
572
  (${getFaustAudioWorkletProcessor.toString()})(dependencies, faustData);
@@ -606,7 +639,8 @@ const dependencies = {
606
639
  const effectMeta = effectFactory ? JSON.parse(effectFactory.json) : undefined;
607
640
  const instance = await FaustWasmInstantiator.createAsyncPolyDSPInstance(voiceFactory, mixerModule, voices, effectFactory || undefined);
608
641
  const sampleSize = voiceMeta.compile_options.match("-double") ? 8 : 4;
609
- const polyDsp = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, bufferSize);
642
+ const soundfiles = { ...effectFactory?.soundfiles, ...voiceFactory.soundfiles };
643
+ const polyDsp = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, bufferSize, soundfiles);
610
644
  return new FaustPolyOfflineProcessor(polyDsp, bufferSize);
611
645
  }
612
646
 
@@ -31,7 +31,7 @@ export interface IFaustDspInstance {
31
31
  *
32
32
  * @param $dsp - the DSP pointer
33
33
  * @param index - the parameter index
34
- * @preturn the parameter value
34
+ * @return the parameter value
35
35
  */
36
36
  getParamValue($dsp: number, index: number): number;
37
37
 
@@ -39,7 +39,7 @@ export interface IFaustDspInstance {
39
39
  * Give the Faust wasm instance sample rate.
40
40
  *
41
41
  * @param $dsp - the DSP pointer
42
- * @preturn the sample rate
42
+ * @return the sample rate
43
43
  */
44
44
  getSampleRate($dsp: number): number;
45
45
 
@@ -162,6 +162,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
162
162
  private fPlotHandler: PlotHandler | null = null;
163
163
  private fCachedEvents: { type: string; data: any }[] = [];
164
164
  private fBufferNum = 0;
165
+ private soundfiles: LooseFaustDspFactory["soundfiles"] = {};
165
166
  get fftProcessorBufferSize() {
166
167
  return this.fftSize / 2 + 1;
167
168
  }
@@ -182,6 +183,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
182
183
 
183
184
  this.dspInstance = FaustWasmInstantiator.createSyncMonoDSPInstance(factory);
184
185
  this.sampleSize = sampleSize;
186
+ this.soundfiles = factory.soundfiles;
185
187
 
186
188
  // Init the FFT constructor and the Faust FFT Processor
187
189
  this.initFFT();
@@ -509,7 +511,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
509
511
  this.fDSPCode?.destroy();
510
512
 
511
513
  // Create Monophonic DSP
512
- this.fDSPCode = new FaustMonoWebAudioDsp(this.dspInstance, sampleRate, this.sampleSize, this.fftProcessorBufferSize);
514
+ this.fDSPCode = new FaustMonoWebAudioDsp(this.dspInstance, sampleRate, this.sampleSize, this.fftProcessorBufferSize, this.soundfiles);
513
515
 
514
516
  // Setup output handler
515
517
  this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));