@grame/faustwasm 0.12.2 → 0.13.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 (81) hide show
  1. package/.prettierrc +5 -0
  2. package/README.md +21 -3
  3. package/assets/standalone/faustwasm/index.d.ts +38 -16
  4. package/assets/standalone/faustwasm/index.js +1574 -404
  5. package/assets/standalone/faustwasm/index.js.map +2 -2
  6. package/dist/cjs/index.d.ts +38 -16
  7. package/dist/cjs/index.js +1573 -404
  8. package/dist/cjs/index.js.map +2 -2
  9. package/dist/cjs-bundle/index.d.ts +38 -16
  10. package/dist/cjs-bundle/index.js +1576 -406
  11. package/dist/cjs-bundle/index.js.map +2 -2
  12. package/dist/esm/index.d.ts +38 -16
  13. package/dist/esm/index.js +1574 -404
  14. package/dist/esm/index.js.map +2 -2
  15. package/dist/esm-bundle/index.d.ts +38 -16
  16. package/dist/esm-bundle/index.js +1576 -406
  17. package/dist/esm-bundle/index.js.map +2 -2
  18. package/eslint.config.js +11 -0
  19. package/package.json +57 -51
  20. package/sound.cpp +163 -0
  21. package/sound.dsp +4 -0
  22. package/sound.json +1 -0
  23. package/sound.wasm +0 -0
  24. package/src/FaustAudioWorkletCommunicator.ts +150 -143
  25. package/src/FaustAudioWorkletNode.ts +173 -75
  26. package/src/FaustAudioWorkletProcessor.ts +218 -90
  27. package/src/FaustCmajor.ts +9 -3
  28. package/src/FaustCompiler.ts +112 -35
  29. package/src/FaustDspGenerator.ts +561 -117
  30. package/src/FaustDspInstance.ts +58 -24
  31. package/src/FaustFFTAudioWorkletProcessor.ts +822 -612
  32. package/src/FaustOfflineProcessor.ts +187 -56
  33. package/src/FaustScriptProcessorNode.ts +156 -49
  34. package/src/FaustSensors.ts +426 -96
  35. package/src/FaustSvgDiagrams.ts +18 -5
  36. package/src/FaustWasmInstantiator.ts +224 -70
  37. package/src/FaustWebAudioDsp.ts +1060 -349
  38. package/src/LibFaust.ts +13 -4
  39. package/src/SoundfileReader.ts +175 -131
  40. package/src/WavDecoder.ts +42 -20
  41. package/src/WavEncoder.ts +35 -21
  42. package/src/copyWebStandaloneAssets.d.ts +20 -5
  43. package/src/copyWebStandaloneAssets.js +203 -75
  44. package/src/exports-bundle.ts +5 -5
  45. package/src/exports.ts +24 -24
  46. package/src/faust2CmajorFiles.d.ts +7 -3
  47. package/src/faust2cmajorFiles.js +10 -8
  48. package/src/faust2svgFiles.d.ts +7 -3
  49. package/src/faust2svgFiles.js +9 -7
  50. package/src/faust2wasmFiles.d.ts +10 -5
  51. package/src/faust2wasmFiles.js +34 -17
  52. package/src/faust2wavFiles.d.ts +12 -3
  53. package/src/faust2wavFiles.js +25 -12
  54. package/src/index-bundle-iife.ts +2 -2
  55. package/src/index-bundle.ts +1 -1
  56. package/src/index.ts +1 -1
  57. package/src/instantiateFaustModule.ts +43 -36
  58. package/src/instantiateFaustModuleFromFile.ts +30 -14
  59. package/src/types.ts +101 -25
  60. package/test/faustlive-wasm/faustwasm/index.d.ts +38 -16
  61. package/test/faustlive-wasm/faustwasm/index.js +1574 -404
  62. package/test/faustlive-wasm/faustwasm/index.js.map +2 -2
  63. package/test/web/create-faust-node.html +53 -0
  64. package/test/web/create-faust-node.js +186 -0
  65. package/test/organ/create-node.js +0 -252
  66. package/test/organ/dsp-meta.json +0 -131
  67. package/test/organ/dsp-module.wasm +0 -0
  68. package/test/organ/faust-pwa.js +0 -344
  69. package/test/organ/faust-ui/index.css +0 -442
  70. package/test/organ/faust-ui/index.css.map +0 -1
  71. package/test/organ/faust-ui/index.d.ts +0 -1
  72. package/test/organ/faust-ui/index.js +0 -3756
  73. package/test/organ/faust-ui/index.js.map +0 -1
  74. package/test/organ/faustwasm/index.d.ts +0 -1705
  75. package/test/organ/faustwasm/index.js +0 -4773
  76. package/test/organ/faustwasm/index.js.map +0 -7
  77. package/test/organ/icon.png +0 -0
  78. package/test/organ/index.html +0 -76
  79. package/test/organ/index.js +0 -69
  80. package/test/organ/manifest.json +0 -17
  81. package/test/organ/service-worker.js +0 -165
@@ -1,11 +1,31 @@
1
- import type { FaustMonoDspInstance, FaustPolyDspInstance, IFaustDspInstance } from "./FaustDspInstance";
2
- import type { AudioData, FaustDspMeta, FaustUIDescriptor, FaustUIGroup, FaustUIInputItem, FaustUIItem, LooseFaustDspFactory } from "./types";
3
- import FaustSensors, { Axis, Curve, UpdatableValueConverter } from "./FaustSensors";
1
+ import type {
2
+ FaustMonoDspInstance,
3
+ FaustPolyDspInstance,
4
+ IFaustDspInstance
5
+ } from './FaustDspInstance';
6
+ import type {
7
+ AudioData,
8
+ FaustDspMeta,
9
+ FaustUIDescriptor,
10
+ FaustUIGroup,
11
+ FaustUIInputItem,
12
+ FaustUIItem,
13
+ LooseFaustDspFactory
14
+ } from './types';
15
+ import FaustSensors, {
16
+ Axis,
17
+ Curve,
18
+ UpdatableValueConverter
19
+ } from './FaustSensors';
4
20
 
5
21
  // Public API
6
22
  export type OutputParamHandler = (path: string, value: number) => void;
7
23
  export type ComputeHandler = (buffer_size: number) => void;
8
- export type PlotHandler = (plotted: Float32Array[] | Float64Array[], index: number, events?: { type: string; data: any }[]) => void;
24
+ export type PlotHandler = (
25
+ plotted: Float32Array[] | Float64Array[],
26
+ index: number,
27
+ events?: { type: string; data: any }[]
28
+ ) => void;
9
29
  export type MetadataHandler = (key: string, value: string) => void;
10
30
 
11
31
  // Implementation API
@@ -25,7 +45,7 @@ export type SensorEventHandlers = {
25
45
  export interface AudioBufferItem {
26
46
  pathName: string;
27
47
  audioBuffer: AudioBuffer;
28
- };
48
+ }
29
49
 
30
50
  /** Definition of the SoundfileItem type */
31
51
  export interface SoundfileItem {
@@ -37,13 +57,13 @@ export interface SoundfileItem {
37
57
  index: number;
38
58
  /** Base pointer in wasm memory */
39
59
  basePtr: number;
40
- };
60
+ }
41
61
 
42
62
  /**
43
63
  * WasmAllocator is a basic memory management class designed to allocate
44
64
  * blocks of memory within a WebAssembly.Memory object. It provides a simple
45
65
  * alloc method to allocate a contiguous block of memory of a specified size.
46
- *
66
+ *
47
67
  * The allocator operates by keeping a linear progression through the memory,
48
68
  * always allocating the next block at the end of the last. This approach does not
49
69
  * handle freeing of memory or reuse of memory spaces.
@@ -65,7 +85,7 @@ export class WasmAllocator {
65
85
  * Allocates a block of memory of the specified size, returning the pointer to the
66
86
  * beginning of the block. The block is allocated at the current offset and the
67
87
  * offset is incremented by the size of the block.
68
- *
88
+ *
69
89
  * @param sizeInBytes The size of the block to allocate in bytes.
70
90
  * @returns The offset (pointer) to the beginning of the allocated block.
71
91
  */
@@ -81,7 +101,9 @@ export class WasmAllocator {
81
101
  if (newOffset > totalMemoryBytes) {
82
102
  // Calculate the number of WebAssembly pages needed to fit the new allocation.
83
103
  // WebAssembly memory pages are 64KiB each.
84
- const neededPages = Math.ceil((newOffset - totalMemoryBytes) / 65536);
104
+ const neededPages = Math.ceil(
105
+ (newOffset - totalMemoryBytes) / 65536
106
+ );
85
107
  // Grow the memory by the required number of pages.
86
108
  console.log(`GROW: ${neededPages} pages`);
87
109
  this.memory.grow(neededPages);
@@ -95,7 +117,7 @@ export class WasmAllocator {
95
117
 
96
118
  /**
97
119
  * Returns the underlying buffer object.
98
- *
120
+ *
99
121
  * @returns The buffer object.
100
122
  */
101
123
  getBuffer(): ArrayBuffer {
@@ -104,7 +126,7 @@ export class WasmAllocator {
104
126
 
105
127
  /**
106
128
  * Returns the Int32 view of the underlying buffer object.
107
- *
129
+ *
108
130
  * @returns The view of the memory buffer as Int32Array.
109
131
  */
110
132
  getInt32Array(): Int32Array {
@@ -113,7 +135,7 @@ export class WasmAllocator {
113
135
 
114
136
  /**
115
137
  * Returns the Int64 view of the underlying buffer object.
116
- *
138
+ *
117
139
  * @returns The view of the memory buffer as BigInt64Array.
118
140
  */
119
141
  getInt64Array(): BigInt64Array {
@@ -122,7 +144,7 @@ export class WasmAllocator {
122
144
 
123
145
  /**
124
146
  * Returns the Float32 view of the underlying buffer object.
125
- *
147
+ *
126
148
  * @returns The view of the memory buffer as Float32Array.
127
149
  */
128
150
  getFloat32Array(): Float32Array {
@@ -131,7 +153,7 @@ export class WasmAllocator {
131
153
 
132
154
  /**
133
155
  * Returns the Float64 view of the underlying buffer object..
134
- *
156
+ *
135
157
  * @returns The view of the memory buffer as Float64Array.
136
158
  */
137
159
  getFloat64Array(): Float64Array {
@@ -144,16 +166,24 @@ export class WasmAllocator {
144
166
  */
145
167
  export class Soundfile {
146
168
  /** Maximum number of soundfile parts. */
147
- static get MAX_SOUNDFILE_PARTS() { return 256; }
169
+ static get MAX_SOUNDFILE_PARTS() {
170
+ return 256;
171
+ }
148
172
 
149
173
  /** Maximum number of channels. */
150
- static get MAX_CHAN() { return 64; }
174
+ static get MAX_CHAN() {
175
+ return 64;
176
+ }
151
177
 
152
178
  /** Maximum buffer size in frames. */
153
- static get BUFFER_SIZE() { return 1024; }
179
+ static get BUFFER_SIZE() {
180
+ return 1024;
181
+ }
154
182
 
155
183
  /** Default sample rate. */
156
- static get SAMPLE_RATE() { return 44100; }
184
+ static get SAMPLE_RATE() {
185
+ return 44100;
186
+ }
157
187
 
158
188
  /** Pointer to the soundfile structure in wasm memory */
159
189
  private readonly fPtr: number;
@@ -166,8 +196,14 @@ export class Soundfile {
166
196
  private readonly fIntSize: number;
167
197
  private readonly fAllocator: WasmAllocator;
168
198
 
169
- constructor(allocator: WasmAllocator, sampleSize: number, curChan: number, length: number, maxChan: number, totalParts: number) {
170
-
199
+ constructor(
200
+ allocator: WasmAllocator,
201
+ sampleSize: number,
202
+ curChan: number,
203
+ length: number,
204
+ maxChan: number,
205
+ totalParts: number
206
+ ) {
171
207
  this.fSampleSize = sampleSize;
172
208
 
173
209
  // To be coherent with the code generated by the wast/wasm backends:
@@ -175,19 +211,27 @@ export class Soundfile {
175
211
  // - that uses 8 bytes for int when double is used (to simplify the code generation)
176
212
  this.fIntSize = this.fSampleSize;
177
213
 
178
- this.fPtrSize = 4; // Not related to float/double choice, so always 4
214
+ this.fPtrSize = 4; // Not related to float/double choice, so always 4
179
215
 
180
216
  this.fAllocator = allocator;
181
217
 
182
- console.log(`Soundfile constructor: curChan: ${curChan}, length: ${length}, maxChan: ${maxChan}, totalParts: ${totalParts}`);
218
+ console.log(
219
+ `Soundfile constructor: curChan: ${curChan}, length: ${length}, maxChan: ${maxChan}, totalParts: ${totalParts}`
220
+ );
183
221
 
184
222
  // Allocate wasm memory for the soundfile structure
185
223
  this.fPtr = allocator.alloc(4 * this.fPtrSize); // 4 fPtrSize: fBuffers, fLength, fSR, fOffset
186
224
 
187
225
  // Use the 4 or 8 bytes size for int. The access are then adapted in copyToOut and emptyFile methods
188
- this.fLength = allocator.alloc(Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
189
- this.fSR = allocator.alloc(Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
190
- this.fOffset = allocator.alloc(Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize);
226
+ this.fLength = allocator.alloc(
227
+ Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize
228
+ );
229
+ this.fSR = allocator.alloc(
230
+ Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize
231
+ );
232
+ this.fOffset = allocator.alloc(
233
+ Soundfile.MAX_SOUNDFILE_PARTS * this.fIntSize
234
+ );
191
235
 
192
236
  this.fBuffers = this.allocBuffers(curChan, length, maxChan);
193
237
 
@@ -197,8 +241,8 @@ export class Soundfile {
197
241
  const HEAP32 = this.fAllocator.getInt32Array();
198
242
  HEAP32[this.fPtr >> 2] = this.fBuffers;
199
243
  HEAP32[(this.fPtr + this.fPtrSize) >> 2] = this.fLength;
200
- HEAP32[(this.fPtr + (2 * this.fPtrSize)) >> 2] = this.fSR;
201
- HEAP32[(this.fPtr + (3 * this.fPtrSize)) >> 2] = this.fOffset;
244
+ HEAP32[(this.fPtr + 2 * this.fPtrSize) >> 2] = this.fSR;
245
+ HEAP32[(this.fPtr + 3 * this.fPtrSize) >> 2] = this.fOffset;
202
246
 
203
247
  for (let chan = 0; chan < curChan; chan++) {
204
248
  const buffer: number = HEAP32[(this.fBuffers >> 2) + chan];
@@ -208,13 +252,19 @@ export class Soundfile {
208
252
  //this.displayMemory("Allocated soundfile structure 2");
209
253
  }
210
254
 
211
- private allocBuffers(curChan: number, length: number, maxChan: number): number {
255
+ private allocBuffers(
256
+ curChan: number,
257
+ length: number,
258
+ maxChan: number
259
+ ): number {
212
260
  const buffers = this.fAllocator.alloc(maxChan * this.fPtrSize);
213
261
 
214
262
  console.log(`allocBuffers buffers: ${buffers}`);
215
263
 
216
264
  for (let chan = 0; chan < curChan; chan++) {
217
- const buffer: number = this.fAllocator.alloc(length * this.fSampleSize);
265
+ const buffer: number = this.fAllocator.alloc(
266
+ length * this.fSampleSize
267
+ );
218
268
  // HEAP32 is the Int32Array view of the memory buffer which can change after grow in `alloc` method
219
269
  // so we need to recompute the buffer address
220
270
  const HEAP32 = this.fAllocator.getInt32Array();
@@ -228,25 +278,40 @@ export class Soundfile {
228
278
  // Share the same buffers for all other channels so that we have maxChan channels available
229
279
  const HEAP32 = this.fAllocator.getInt32Array();
230
280
  for (let chan = curChan; chan < maxChan; chan++) {
231
- HEAP32[(this.fBuffers >> 2) + chan] = HEAP32[(this.fBuffers >> 2) + chan % curChan];
281
+ HEAP32[(this.fBuffers >> 2) + chan] =
282
+ HEAP32[(this.fBuffers >> 2) + (chan % curChan)];
232
283
  }
233
284
  }
234
285
 
235
- copyToOut(part: number, maxChannels: number, offset: number, audioData: AudioData) {
286
+ copyToOut(
287
+ part: number,
288
+ maxChannels: number,
289
+ offset: number,
290
+ audioData: AudioData
291
+ ) {
236
292
  // Set the soundfile fields in wasm memory
237
293
  if (this.fIntSize === 4) {
238
294
  const HEAP32 = this.fAllocator.getInt32Array();
239
- HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] = audioData.audioBuffer[0].length;
240
- HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] = audioData.sampleRate;
295
+ HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] =
296
+ audioData.audioBuffer[0].length;
297
+ HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] =
298
+ audioData.sampleRate;
241
299
  HEAP32[(this.fOffset >> Math.log2(this.fIntSize)) + part] = offset;
242
300
  } else {
243
301
  const HEAP64 = this.fAllocator.getInt64Array();
244
- HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(audioData.audioBuffer[0].length);
245
- HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(audioData.sampleRate);
246
- HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] = BigInt(offset);
302
+ HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(
303
+ audioData.audioBuffer[0].length
304
+ );
305
+ HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(
306
+ audioData.sampleRate
307
+ );
308
+ HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] =
309
+ BigInt(offset);
247
310
  }
248
311
 
249
- console.log(`copyToOut: part: ${part}, maxChannels: ${maxChannels}, offset: ${offset}, buffer: ${audioData}`);
312
+ console.log(
313
+ `copyToOut: part: ${part}, maxChannels: ${maxChannels}, offset: ${offset}, buffer: ${audioData}`
314
+ );
250
315
 
251
316
  //this.displayMemory("IN copyToOut, BEFORE copyToOutReal", true);
252
317
  // Copy the soundfile data to the buffer
@@ -264,11 +329,21 @@ export class Soundfile {
264
329
  for (let chan = 0; chan < audioData.audioBuffer.length; chan++) {
265
330
  const input: Float32Array = audioData.audioBuffer[chan];
266
331
  const output: number = HEAP32[(this.fBuffers >> 2) + chan];
267
- const begin: number = (output + (offset * this.fSampleSize)) >> Math.log2(this.fSampleSize);
268
- const end: number = (output + (offset + input.length) * this.fSampleSize) >> Math.log2(this.fSampleSize);
269
- console.log(`copyToOutReal32 begin: ${begin}, end: ${end}, delta: ${end - begin}`);
270
- const outputReal: Float32Array = HEAPF.subarray((output + (offset * this.fSampleSize)) >> Math.log2(this.fSampleSize),
271
- (output + (offset + input.length) * this.fSampleSize) >> Math.log2(this.fSampleSize));
332
+ const begin: number =
333
+ (output + offset * this.fSampleSize) >>
334
+ Math.log2(this.fSampleSize);
335
+ const end: number =
336
+ (output + (offset + input.length) * this.fSampleSize) >>
337
+ Math.log2(this.fSampleSize);
338
+ console.log(
339
+ `copyToOutReal32 begin: ${begin}, end: ${end}, delta: ${end - begin}`
340
+ );
341
+ const outputReal: Float32Array = HEAPF.subarray(
342
+ (output + offset * this.fSampleSize) >>
343
+ Math.log2(this.fSampleSize),
344
+ (output + (offset + input.length) * this.fSampleSize) >>
345
+ Math.log2(this.fSampleSize)
346
+ );
272
347
  for (let sample = 0; sample < input.length; sample++) {
273
348
  outputReal[sample] = input[sample];
274
349
  }
@@ -281,11 +356,21 @@ export class Soundfile {
281
356
  for (let chan = 0; chan < audioData.audioBuffer.length; chan++) {
282
357
  const input: Float32Array = audioData.audioBuffer[chan];
283
358
  const output: number = HEAP32[(this.fBuffers >> 2) + chan];
284
- const begin: number = (output + (offset * this.fSampleSize)) >> Math.log2(this.fSampleSize);
285
- const end: number = (output + (offset + input.length) * this.fSampleSize) >> Math.log2(this.fSampleSize);
286
- console.log(`copyToOutReal64 begin: ${begin}, end: ${end}, delta: ${end - begin}`);
287
- const outputReal: Float64Array = HEAPF.subarray((output + (offset * this.fSampleSize)) >> Math.log2(this.fSampleSize),
288
- (output + (offset + input.length) * this.fSampleSize) >> Math.log2(this.fSampleSize));
359
+ const begin: number =
360
+ (output + offset * this.fSampleSize) >>
361
+ Math.log2(this.fSampleSize);
362
+ const end: number =
363
+ (output + (offset + input.length) * this.fSampleSize) >>
364
+ Math.log2(this.fSampleSize);
365
+ console.log(
366
+ `copyToOutReal64 begin: ${begin}, end: ${end}, delta: ${end - begin}`
367
+ );
368
+ const outputReal: Float64Array = HEAPF.subarray(
369
+ (output + offset * this.fSampleSize) >>
370
+ Math.log2(this.fSampleSize),
371
+ (output + (offset + input.length) * this.fSampleSize) >>
372
+ Math.log2(this.fSampleSize)
373
+ );
289
374
  for (let sample = 0; sample < input.length; sample++) {
290
375
  outputReal[sample] = input[sample];
291
376
  }
@@ -296,22 +381,29 @@ export class Soundfile {
296
381
  // Set the soundfile fields in wasm memory
297
382
  if (this.fIntSize === 4) {
298
383
  const HEAP32 = this.fAllocator.getInt32Array();
299
- HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] = Soundfile.BUFFER_SIZE;
300
- HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] = Soundfile.SAMPLE_RATE;
384
+ HEAP32[(this.fLength >> Math.log2(this.fIntSize)) + part] =
385
+ Soundfile.BUFFER_SIZE;
386
+ HEAP32[(this.fSR >> Math.log2(this.fIntSize)) + part] =
387
+ Soundfile.SAMPLE_RATE;
301
388
  HEAP32[(this.fOffset >> Math.log2(this.fIntSize)) + part] = offset;
302
389
  } else {
303
390
  const HEAP64 = this.fAllocator.getInt64Array();
304
- HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(Soundfile.BUFFER_SIZE);
305
- HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(Soundfile.SAMPLE_RATE);
306
- HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] = BigInt(offset);
391
+ HEAP64[(this.fLength >> Math.log2(this.fIntSize)) + part] = BigInt(
392
+ Soundfile.BUFFER_SIZE
393
+ );
394
+ HEAP64[(this.fSR >> Math.log2(this.fIntSize)) + part] = BigInt(
395
+ Soundfile.SAMPLE_RATE
396
+ );
397
+ HEAP64[(this.fOffset >> Math.log2(this.fIntSize)) + part] =
398
+ BigInt(offset);
307
399
  }
308
400
 
309
401
  // Update and return the new offset
310
402
  return offset + Soundfile.BUFFER_SIZE;
311
403
  }
312
404
 
313
- displayMemory(where: string = "", mem: boolean = false) {
314
- console.log("Soundfile memory: " + where);
405
+ displayMemory(where: string = '', mem: boolean = false) {
406
+ console.log('Soundfile memory: ' + where);
315
407
  console.log(`fPtr: ${this.fPtr}`);
316
408
  console.log(`fBuffers: ${this.fBuffers}`);
317
409
  console.log(`fLength: ${this.fLength}`);
@@ -320,9 +412,15 @@ export class Soundfile {
320
412
  const HEAP32 = this.fAllocator.getInt32Array();
321
413
  if (mem) console.log(`HEAP32: ${HEAP32}`);
322
414
  console.log(`HEAP32[this.fPtr >> 2]: ${HEAP32[this.fPtr >> 2]}`);
323
- console.log(`HEAP32[(this.fPtr + ptrSize) >> 2]: ${HEAP32[(this.fPtr + this.fPtrSize) >> 2]}`);
324
- console.log(`HEAP32[(this.fPtr + 2 * ptrSize) >> 2]: ${HEAP32[(this.fPtr + 2 * this.fPtrSize) >> 2]}`);
325
- console.log(`HEAP32[(this.fPtr + 3 * ptrSize) >> 2]: ${HEAP32[(this.fPtr + 3 * this.fPtrSize) >> 2]}`);
415
+ console.log(
416
+ `HEAP32[(this.fPtr + ptrSize) >> 2]: ${HEAP32[(this.fPtr + this.fPtrSize) >> 2]}`
417
+ );
418
+ console.log(
419
+ `HEAP32[(this.fPtr + 2 * ptrSize) >> 2]: ${HEAP32[(this.fPtr + 2 * this.fPtrSize) >> 2]}`
420
+ );
421
+ console.log(
422
+ `HEAP32[(this.fPtr + 3 * ptrSize) >> 2]: ${HEAP32[(this.fPtr + 3 * this.fPtrSize) >> 2]}`
423
+ );
326
424
  }
327
425
 
328
426
  // Return the pointer to the soundfile structure in wasm memory
@@ -345,7 +443,7 @@ export class Soundfile {
345
443
  /**
346
444
  * DSP implementation that mimic the C++ 'dsp' class:
347
445
  * - adding MIDI control: metadata are decoded and incoming MIDI messages will control the associated controllers
348
- * - an output handler can be set to treat produced output controllers (like 'bargraph')
446
+ * - an output handler can be set to treat produced output controllers (like 'bargraph')
349
447
  * - regular controllers are handled using setParamValue/getParamValue and getParams methods
350
448
  */
351
449
  export interface IFaustBaseWebAudioDsp {
@@ -365,7 +463,7 @@ export interface IFaustBaseWebAudioDsp {
365
463
 
366
464
  /**
367
465
  * Call the output parameter handler with a path and value.
368
- *
466
+ *
369
467
  * @param path - the path to the wanted parameter (retrieved using 'getParams' method)
370
468
  * @param value - the float value for the wanted control
371
469
  */
@@ -455,17 +553,17 @@ export interface IFaustBaseWebAudioDsp {
455
553
 
456
554
  /**
457
555
  * Handle MIDI keyOn messages.
458
- * @param channel
459
- * @param pitch
460
- * @param velocity
556
+ * @param channel
557
+ * @param pitch
558
+ * @param velocity
461
559
  */
462
560
  keyOn(channel: number, pitch: number, velocity: number): void;
463
561
 
464
562
  /**
465
563
  * Handle MIDI keyOn messages.
466
- * @param channel
467
- * @param pitch
468
- * @param velocity
564
+ * @param channel
565
+ * @param pitch
566
+ * @param velocity
469
567
  */
470
568
  keyOff(channel: number, pitch: number, velocity: number): void;
471
569
 
@@ -508,10 +606,10 @@ export interface IFaustBaseWebAudioDsp {
508
606
  getUI(): FaustUIDescriptor;
509
607
 
510
608
  /**
511
- * Get DSP UI items description.
512
- *
513
- * @return the DSP UI items description
514
- */
609
+ * Get DSP UI items description.
610
+ *
611
+ * @return the DSP UI items description
612
+ */
515
613
  getDescriptors(): FaustUIInputItem[];
516
614
 
517
615
  /**
@@ -522,8 +620,8 @@ export interface IFaustBaseWebAudioDsp {
522
620
  getJSON(): string;
523
621
 
524
622
  /**
525
- * Start accelerometer and gyroscope handlers.
526
- */
623
+ * Start accelerometer and gyroscope handlers.
624
+ */
527
625
  startSensors(): void;
528
626
 
529
627
  /**
@@ -534,24 +632,31 @@ export interface IFaustBaseWebAudioDsp {
534
632
  /** Indicating if the DSP handles the accelerometer */
535
633
  readonly hasAccInput: boolean;
536
634
 
537
- /**
635
+ /**
538
636
  * Accelerometer handling.
539
637
  * accelerationIncludingGravity: DeviceMotionEvent["accelerationIncludingGravity"]
540
638
  * invert: boolean
541
639
  */
542
- propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean): void;
640
+ propagateAcc(
641
+ accelerationIncludingGravity: NonNullable<
642
+ DeviceMotionEvent['accelerationIncludingGravity']
643
+ >,
644
+ invert: boolean
645
+ ): void;
543
646
 
544
647
  /** Indicating if the DSP handles the gyroscope */
545
648
  readonly hasGyrInput: boolean;
546
649
 
547
- /**
650
+ /**
548
651
  * Gyroscope handling.
549
652
  * event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">
550
653
  */
551
- propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
654
+ propagateGyr(
655
+ event: Pick<DeviceOrientationEvent, 'alpha' | 'beta' | 'gamma'>
656
+ ): void;
552
657
 
553
658
  /**
554
- * Start the DSP audio processing.
659
+ * Start the DSP audio processing.
555
660
  */
556
661
  start(): void;
557
662
 
@@ -566,8 +671,10 @@ export interface IFaustBaseWebAudioDsp {
566
671
  destroy(): void;
567
672
  }
568
673
 
569
- export interface IFaustMonoWebAudioDsp extends IFaustBaseWebAudioDsp { }
570
- export interface IFaustMonoWebAudioNode extends IFaustMonoWebAudioDsp, AudioNode { }
674
+ export type IFaustMonoWebAudioDsp = IFaustBaseWebAudioDsp;
675
+ export interface IFaustMonoWebAudioNode
676
+ extends IFaustMonoWebAudioDsp,
677
+ AudioNode {}
571
678
 
572
679
  export interface IFaustPolyWebAudioDsp extends IFaustBaseWebAudioDsp {
573
680
  /**
@@ -595,7 +702,9 @@ export interface IFaustPolyWebAudioDsp extends IFaustBaseWebAudioDsp {
595
702
  */
596
703
  allNotesOff(hard: boolean): void;
597
704
  }
598
- export interface IFaustPolyWebAudioNode extends IFaustPolyWebAudioDsp, AudioNode { }
705
+ export interface IFaustPolyWebAudioNode
706
+ extends IFaustPolyWebAudioDsp,
707
+ AudioNode {}
599
708
 
600
709
  export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
601
710
  protected fOutputHandler: OutputParamHandler | null = null;
@@ -618,7 +727,7 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
618
727
 
619
728
  // Soundfile handling
620
729
  protected fSoundfiles: SoundfileItem[] = [];
621
- protected fSoundfileBuffers: LooseFaustDspFactory["soundfiles"] = {};
730
+ protected fSoundfileBuffers: LooseFaustDspFactory['soundfiles'] = {};
622
731
  /** Keep the end of memory offset before soundfiles */
623
732
  protected fEndMemory: number;
624
733
 
@@ -635,20 +744,51 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
635
744
  protected fSampleSize: number;
636
745
 
637
746
  // MIDI handling
638
- protected fPitchwheelLabel: { path: string; chan: number; min: number; max: number }[] = [];
639
- protected fCtrlLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
747
+ protected fPitchwheelLabel: {
748
+ path: string;
749
+ chan: number;
750
+ min: number;
751
+ max: number;
752
+ }[] = [];
753
+ protected fCtrlLabel: {
754
+ path: string;
755
+ chan: number;
756
+ min: number;
757
+ max: number;
758
+ }[][] = new Array(128).fill(null).map(() => []);
640
759
  // array of MIDI key handlers; array index is the MIDI note number
641
- protected fMidiKeyLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
642
- protected fMidiKeyOnLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
643
- protected fMidiKeyOffLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
760
+ protected fMidiKeyLabel: {
761
+ path: string;
762
+ chan: number;
763
+ min: number;
764
+ max: number;
765
+ }[][] = new Array(128).fill(null).map(() => []);
766
+ protected fMidiKeyOnLabel: {
767
+ path: string;
768
+ chan: number;
769
+ min: number;
770
+ max: number;
771
+ }[][] = new Array(128).fill(null).map(() => []);
772
+ protected fMidiKeyOffLabel: {
773
+ path: string;
774
+ chan: number;
775
+ min: number;
776
+ max: number;
777
+ }[][] = new Array(128).fill(null).map(() => []);
644
778
 
645
779
  protected fPathTable: { [address: string]: number } = {};
646
780
  protected fUICallback: UIHandler = (item: FaustUIItem) => {
647
- if (item.type === "hbargraph" || item.type === "vbargraph") {
781
+ if (item.type === 'hbargraph' || item.type === 'vbargraph') {
648
782
  // Keep bargraph adresses
649
783
  this.fOutputsItems.push(item.address);
650
784
  this.fPathTable[item.address] = item.index;
651
- } else if (item.type === "vslider" || item.type === "hslider" || item.type === "button" || item.type === "checkbox" || item.type === "nentry") {
785
+ } else if (
786
+ item.type === 'vslider' ||
787
+ item.type === 'hslider' ||
788
+ item.type === 'button' ||
789
+ item.type === 'checkbox' ||
790
+ item.type === 'nentry'
791
+ ) {
652
792
  // Keep inputs adresses
653
793
  this.fInputsItems.push(item.address);
654
794
  this.fPathTable[item.address] = item.index;
@@ -659,14 +799,24 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
659
799
  // Parse 'midi' metadata
660
800
  if (midi) {
661
801
  const strMidi = midi.trim();
662
- if (strMidi === "pitchwheel") {
802
+ if (strMidi === 'pitchwheel') {
663
803
  const matched = strMidi.match(/^pitchwheel\s(\d+)/);
664
804
  // "pitchwheel chan"
665
805
  if (matched) {
666
- this.fPitchwheelLabel.push({ path: item.address, chan: parseInt(matched[1]), min: item.min as number, max: item.max as number });
806
+ this.fPitchwheelLabel.push({
807
+ path: item.address,
808
+ chan: parseInt(matched[1]),
809
+ min: item.min as number,
810
+ max: item.max as number
811
+ });
667
812
  // "pitchwheel"
668
813
  } else {
669
- this.fPitchwheelLabel.push({ path: item.address, chan: 0, min: item.min as number, max: item.max as number });
814
+ this.fPitchwheelLabel.push({
815
+ path: item.address,
816
+ chan: 0,
817
+ min: item.min as number,
818
+ max: item.max as number
819
+ });
670
820
  }
671
821
  } else {
672
822
  // "ctrl num chan"
@@ -674,44 +824,106 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
674
824
  // "ctrl num"
675
825
  const matched1 = strMidi.match(/^ctrl\s(\d+)/);
676
826
  // match `key <note>[ <channel>]`
677
- const matchedKey = strMidi.match(/^key\s+(\d+)(?:\s+(\d+))?$/);
827
+ const matchedKey = strMidi.match(
828
+ /^key\s+(\d+)(?:\s+(\d+))?$/
829
+ );
678
830
  //match `keyon <note>[ <channel>]`
679
- const matchedKeyOn = strMidi.match(/^keyon\s+(\d+)(?:\s+(\d+))?$/);
831
+ const matchedKeyOn = strMidi.match(
832
+ /^keyon\s+(\d+)(?:\s+(\d+))?$/
833
+ );
680
834
  //match `keyoff <note>[ <channel>]`
681
- const matchedKeyOff = strMidi.match(/^keyoff\s+(\d+)(?:\s+(\d+))?$/);
835
+ const matchedKeyOff = strMidi.match(
836
+ /^keyoff\s+(\d+)(?:\s+(\d+))?$/
837
+ );
682
838
  if (matched2) {
683
- this.fCtrlLabel[parseInt(matched2[1])].push({ path: item.address, chan: parseInt(matched2[2]), min: item.min as number, max: item.max as number });
839
+ this.fCtrlLabel[parseInt(matched2[1])].push({
840
+ path: item.address,
841
+ chan: parseInt(matched2[2]),
842
+ min: item.min as number,
843
+ max: item.max as number
844
+ });
684
845
  } else if (matched1) {
685
- this.fCtrlLabel[parseInt(matched1[1])].push({ path: item.address, chan: 0, min: item.min as number, max: item.max as number });
846
+ this.fCtrlLabel[parseInt(matched1[1])].push({
847
+ path: item.address,
848
+ chan: 0,
849
+ min: item.min as number,
850
+ max: item.max as number
851
+ });
686
852
  } else if (matchedKey) {
687
853
  const note = parseInt(matchedKey[1]);
688
- const channel = matchedKey[2] ? parseInt(matchedKey[2]) : 0;
689
- this.fMidiKeyLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
854
+ const channel = matchedKey[2]
855
+ ? parseInt(matchedKey[2])
856
+ : 0;
857
+ this.fMidiKeyLabel[note].push({
858
+ path: item.address,
859
+ chan: channel,
860
+ min: (item.min as number) ?? 0,
861
+ max: (item.max as number) ?? 1
862
+ });
690
863
  } else if (matchedKeyOn) {
691
864
  const note = parseInt(matchedKeyOn[1]);
692
- const channel = matchedKeyOn[2] ? parseInt(matchedKeyOn[2]) : 0;
693
- this.fMidiKeyOnLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
865
+ const channel = matchedKeyOn[2]
866
+ ? parseInt(matchedKeyOn[2])
867
+ : 0;
868
+ this.fMidiKeyOnLabel[note].push({
869
+ path: item.address,
870
+ chan: channel,
871
+ min: (item.min as number) ?? 0,
872
+ max: (item.max as number) ?? 1
873
+ });
694
874
  } else if (matchedKeyOff) {
695
875
  const note = parseInt(matchedKeyOff[1]);
696
- const channel = matchedKeyOff[2] ? parseInt(matchedKeyOff[2]) : 0;
697
- this.fMidiKeyOffLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
876
+ const channel = matchedKeyOff[2]
877
+ ? parseInt(matchedKeyOff[2])
878
+ : 0;
879
+ this.fMidiKeyOffLabel[note].push({
880
+ path: item.address,
881
+ chan: channel,
882
+ min: (item.min as number) ?? 0,
883
+ max: (item.max as number) ?? 1
884
+ });
698
885
  }
699
886
  }
700
887
  }
701
888
 
702
889
  // Parse 'acc' metadata
703
890
  if (acc) {
704
- const numAcc: number[] = acc.trim().split(" ").map(Number);
705
- this.setupAccHandler(item.address, FaustSensors.convertToAxis(numAcc[0]), FaustSensors.convertToCurve(numAcc[1]), numAcc[2], numAcc[3], numAcc[4], item.min as number, item.init as number, item.max as number);
891
+ const numAcc: number[] = acc.trim().split(' ').map(Number);
892
+ this.setupAccHandler(
893
+ item.address,
894
+ FaustSensors.convertToAxis(numAcc[0]),
895
+ FaustSensors.convertToCurve(numAcc[1]),
896
+ numAcc[2],
897
+ numAcc[3],
898
+ numAcc[4],
899
+ item.min as number,
900
+ item.init as number,
901
+ item.max as number
902
+ );
706
903
  }
707
904
  // Parse 'gyr' metadata
708
905
  if (gyr) {
709
- const numAcc: number[] = gyr.trim().split(" ").map(Number);
710
- this.setupGyrHandler(item.address, FaustSensors.convertToAxis(numAcc[0]), FaustSensors.convertToCurve(numAcc[1]), numAcc[2], numAcc[3], numAcc[4], item.min as number, item.init as number, item.max as number);
906
+ const numAcc: number[] = gyr.trim().split(' ').map(Number);
907
+ this.setupGyrHandler(
908
+ item.address,
909
+ FaustSensors.convertToAxis(numAcc[0]),
910
+ FaustSensors.convertToCurve(numAcc[1]),
911
+ numAcc[2],
912
+ numAcc[3],
913
+ numAcc[4],
914
+ item.min as number,
915
+ item.init as number,
916
+ item.max as number
917
+ );
711
918
  }
712
919
  });
713
- } else if (item.type === "soundfile") {
714
- this.fSoundfiles.push({ name: item.label, url: item.url, index: item.index, basePtr: -1 });
920
+ } else if (item.type === 'soundfile') {
921
+ this.fSoundfiles.push({
922
+ name: item.label,
923
+ url: item.url,
924
+ index: item.index,
925
+ basePtr: -1
926
+ });
715
927
  }
716
928
  };
717
929
 
@@ -722,7 +934,11 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
722
934
 
723
935
  protected fJSONDsp!: FaustDspMeta;
724
936
 
725
- constructor(sampleSize: number, bufferSize: number, soundfiles: LooseFaustDspFactory["soundfiles"]) {
937
+ constructor(
938
+ sampleSize: number,
939
+ bufferSize: number,
940
+ soundfiles: LooseFaustDspFactory['soundfiles']
941
+ ) {
726
942
  this.fBufferSize = bufferSize;
727
943
  this.fPtrSize = sampleSize; // Done on wast/wasm backend side
728
944
  this.fSampleSize = sampleSize;
@@ -732,26 +948,45 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
732
948
  }
733
949
 
734
950
  // Tools
735
- static remap(v: number, mn0: number, mx0: number, mn1: number, mx1: number) {
736
- return (v - mn0) / (mx0 - mn0) * (mx1 - mn1) + mn1;
951
+ static remap(
952
+ v: number,
953
+ mn0: number,
954
+ mx0: number,
955
+ mn1: number,
956
+ mx1: number
957
+ ) {
958
+ return ((v - mn0) / (mx0 - mn0)) * (mx1 - mn1) + mn1;
737
959
  }
738
960
 
739
961
  // JSON parsing functions
740
- static parseUI(ui: FaustUIDescriptor, callback: (item: FaustUIItem) => any) {
741
- ui.forEach(group => this.parseGroup(group, callback));
962
+ static parseUI(
963
+ ui: FaustUIDescriptor,
964
+ callback: (item: FaustUIItem) => any
965
+ ) {
966
+ ui.forEach((group) => this.parseGroup(group, callback));
742
967
  }
743
968
 
744
- static parseGroup(group: FaustUIGroup, callback: (item: FaustUIItem) => any) {
969
+ static parseGroup(
970
+ group: FaustUIGroup,
971
+ callback: (item: FaustUIItem) => any
972
+ ) {
745
973
  if (group.items) {
746
974
  this.parseItems(group.items, callback);
747
975
  }
748
976
  }
749
- static parseItems(items: FaustUIItem[], callback: (item: FaustUIItem) => any) {
750
- items.forEach(item => this.parseItem(item, callback));
977
+ static parseItems(
978
+ items: FaustUIItem[],
979
+ callback: (item: FaustUIItem) => any
980
+ ) {
981
+ items.forEach((item) => this.parseItem(item, callback));
751
982
  }
752
983
 
753
984
  static parseItem(item: FaustUIItem, callback: (item: FaustUIItem) => any) {
754
- if (item.type === "vgroup" || item.type === "hgroup" || item.type === "tgroup") {
985
+ if (
986
+ item.type === 'vgroup' ||
987
+ item.type === 'hgroup' ||
988
+ item.type === 'tgroup'
989
+ ) {
755
990
  this.parseItems(item.items, callback);
756
991
  } else {
757
992
  callback(item);
@@ -761,82 +996,145 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
761
996
  /** Split the soundfile names and return an array of names */
762
997
  static splitSoundfileNames(input: string): string[] {
763
998
  // Trim off the curly braces at the start and end, if present
764
- let trimmed = input.replace(/^\{|\}$/g, '');
999
+ const trimmed = input.replace(/^\{|\}$/g, '');
765
1000
  // Split the string into an array of strings and remove first and last characters
766
- return trimmed.split(";").map(str => str.length <= 2 ? '' : str.substring(1, str.length - 1));
767
- }
768
-
769
- get hasAccInput() { return this.fAcc.x.length + this.fAcc.y.length + this.fAcc.z.length > 0; }
770
- propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
771
-
1001
+ return trimmed
1002
+ .split(';')
1003
+ .map((str) =>
1004
+ str.length <= 2 ? '' : str.substring(1, str.length - 1)
1005
+ );
1006
+ }
1007
+
1008
+ get hasAccInput() {
1009
+ return this.fAcc.x.length + this.fAcc.y.length + this.fAcc.z.length > 0;
1010
+ }
1011
+ propagateAcc(
1012
+ accelerationIncludingGravity: NonNullable<
1013
+ DeviceMotionEvent['accelerationIncludingGravity']
1014
+ >,
1015
+ invert: boolean = false
1016
+ ) {
772
1017
  // Get accelerometervalues
773
1018
  const { x, y, z } = accelerationIncludingGravity;
774
1019
 
775
1020
  if (invert) {
776
1021
  // Call the accelerometer handlers
777
- if (x !== null) this.fAcc.x.forEach(handler => handler(-x));
778
- if (y !== null) this.fAcc.y.forEach(handler => handler(-y));
779
- if (z !== null) this.fAcc.z.forEach(handler => handler(-z));
1022
+ if (x !== null) this.fAcc.x.forEach((handler) => handler(-x));
1023
+ if (y !== null) this.fAcc.y.forEach((handler) => handler(-y));
1024
+ if (z !== null) this.fAcc.z.forEach((handler) => handler(-z));
780
1025
  } else {
781
1026
  // Call the accelerometer handlers
782
- if (x !== null) this.fAcc.x.forEach(handler => handler(x));
783
- if (y !== null) this.fAcc.y.forEach(handler => handler(y));
784
- if (z !== null) this.fAcc.z.forEach(handler => handler(z));
1027
+ if (x !== null) this.fAcc.x.forEach((handler) => handler(x));
1028
+ if (y !== null) this.fAcc.y.forEach((handler) => handler(y));
1029
+ if (z !== null) this.fAcc.z.forEach((handler) => handler(z));
785
1030
  }
786
1031
  }
787
1032
 
788
- get hasGyrInput() { return this.fGyr.x.length + this.fGyr.y.length + this.fGyr.z.length > 0; }
789
- propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
790
-
1033
+ get hasGyrInput() {
1034
+ return this.fGyr.x.length + this.fGyr.y.length + this.fGyr.z.length > 0;
1035
+ }
1036
+ propagateGyr(
1037
+ event: Pick<DeviceOrientationEvent, 'alpha' | 'beta' | 'gamma'>
1038
+ ) {
791
1039
  // Get gyroscope values
792
1040
  const { alpha, beta, gamma } = event;
793
1041
 
794
1042
  // Call the gyroscope handlers
795
- if (alpha !== null) this.fGyr.x.forEach(handler => handler(alpha));
796
- if (beta !== null) this.fGyr.y.forEach(handler => handler(beta));
797
- if (gamma !== null) this.fGyr.z.forEach(handler => handler(gamma));
1043
+ if (alpha !== null) this.fGyr.x.forEach((handler) => handler(alpha));
1044
+ if (beta !== null) this.fGyr.y.forEach((handler) => handler(beta));
1045
+ if (gamma !== null) this.fGyr.z.forEach((handler) => handler(gamma));
798
1046
  }
799
1047
 
800
1048
  /** Build the accelerometer handler */
801
- private setupAccHandler(path: string, axis: Axis, curve: Curve, amin: number, amid: number, amax: number, min: number, init: number, max: number) {
802
-
803
- const handler: UpdatableValueConverter = FaustSensors.buildHandler(curve, amin, amid, amax, min, init, max);
1049
+ private setupAccHandler(
1050
+ path: string,
1051
+ axis: Axis,
1052
+ curve: Curve,
1053
+ amin: number,
1054
+ amid: number,
1055
+ amax: number,
1056
+ min: number,
1057
+ init: number,
1058
+ max: number
1059
+ ) {
1060
+ const handler: UpdatableValueConverter = FaustSensors.buildHandler(
1061
+ curve,
1062
+ amin,
1063
+ amid,
1064
+ amax,
1065
+ min,
1066
+ init,
1067
+ max
1068
+ );
804
1069
  switch (axis) {
805
1070
  case Axis.x:
806
- this.fAcc.x.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1071
+ this.fAcc.x.push((val) =>
1072
+ this.setParamValue(path, handler.uiToFaust(val))
1073
+ );
807
1074
  break;
808
1075
  case Axis.y:
809
- this.fAcc.y.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1076
+ this.fAcc.y.push((val) =>
1077
+ this.setParamValue(path, handler.uiToFaust(val))
1078
+ );
810
1079
  break;
811
1080
  case Axis.z:
812
- this.fAcc.z.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1081
+ this.fAcc.z.push((val) =>
1082
+ this.setParamValue(path, handler.uiToFaust(val))
1083
+ );
813
1084
  break;
814
1085
  }
815
1086
  }
816
1087
 
817
1088
  /** Build the gyroscope handler */
818
- private setupGyrHandler(path: string, axis: Axis, curve: Curve, amin: number, amid: number, amax: number, min: number, init: number, max: number) {
819
-
820
- const handler: UpdatableValueConverter = FaustSensors.buildHandler(curve, amin, amid, amax, min, init, max);
1089
+ private setupGyrHandler(
1090
+ path: string,
1091
+ axis: Axis,
1092
+ curve: Curve,
1093
+ amin: number,
1094
+ amid: number,
1095
+ amax: number,
1096
+ min: number,
1097
+ init: number,
1098
+ max: number
1099
+ ) {
1100
+ const handler: UpdatableValueConverter = FaustSensors.buildHandler(
1101
+ curve,
1102
+ amin,
1103
+ amid,
1104
+ amax,
1105
+ min,
1106
+ init,
1107
+ max
1108
+ );
821
1109
  switch (axis) {
822
1110
  case Axis.x:
823
- this.fGyr.x.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1111
+ this.fGyr.x.push((val) =>
1112
+ this.setParamValue(path, handler.uiToFaust(val))
1113
+ );
824
1114
  break;
825
1115
  case Axis.y:
826
- this.fGyr.y.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1116
+ this.fGyr.y.push((val) =>
1117
+ this.setParamValue(path, handler.uiToFaust(val))
1118
+ );
827
1119
  break;
828
1120
  case Axis.z:
829
- this.fGyr.z.push((val) => this.setParamValue(path, handler.uiToFaust(val)));
1121
+ this.fGyr.z.push((val) =>
1122
+ this.setParamValue(path, handler.uiToFaust(val))
1123
+ );
830
1124
  break;
831
1125
  }
832
1126
  }
833
1127
 
834
1128
  static extractUrlsFromMeta(dspMeta: FaustDspMeta): string[] {
835
1129
  // Find the entry with the "soundfiles" key
836
- const soundfilesEntry = dspMeta.meta.find(entry => entry.soundfiles !== undefined);
1130
+ const soundfilesEntry = dspMeta.meta.find(
1131
+ (entry) => entry.soundfiles !== undefined
1132
+ );
837
1133
  // If the entry is found, split the string by semicolon to get the URLs
838
1134
  if (soundfilesEntry) {
839
- return soundfilesEntry.soundfiles.split(";").filter(url => url !== "");
1135
+ return soundfilesEntry.soundfiles
1136
+ .split(';')
1137
+ .filter((url) => url !== '');
840
1138
  } else {
841
1139
  return [];
842
1140
  }
@@ -845,45 +1143,65 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
845
1143
  /**
846
1144
  * Load a soundfile possibly containing several parts in the DSP struct.
847
1145
  * Soundfile pointers are located at 'index' offset, to be read in the JSON file.
848
- * The DSP struct is located at baseDSP in the wasm memory,
1146
+ * The DSP struct is located at baseDSP in the wasm memory,
849
1147
  * either a monophonic DSP, or a voice in a polyphonic context.
850
- *
1148
+ *
851
1149
  * @param allocator : the wasm memory allocator
852
1150
  * @param baseDSP : the base DSP in the wasm memory
853
1151
  * @param name : the name of the soundfile
854
1152
  * @param url : the url of the soundfile
855
1153
  */
856
- private loadSoundfile(allocator: WasmAllocator, baseDSP: number, name: string, url: string) {
1154
+ private loadSoundfile(
1155
+ allocator: WasmAllocator,
1156
+ baseDSP: number,
1157
+ name: string,
1158
+ url: string
1159
+ ) {
857
1160
  console.log(`Soundfile ${name} paths: ${url}`);
858
1161
  const soundfileIds = FaustBaseWebAudioDsp.splitSoundfileNames(url);
859
- const item = this.fSoundfiles.find(item => item.url === url);
1162
+ const item = this.fSoundfiles.find((item) => item.url === url);
860
1163
  if (!item) throw new Error(`Soundfile with ${url} cannot be found !}`);
861
1164
  // Use the cached Soundfile
862
1165
  if (item.basePtr !== -1) {
863
1166
  // Update HEAP32 after soundfile creation
864
1167
  const HEAP32 = allocator.getInt32Array();
865
1168
  // Fill the soundfile structure in wasm memory, soundfiles are at the beginning of the DSP memory
866
- console.log(`Soundfile CACHE ${url}} : ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`);
1169
+ console.log(
1170
+ `Soundfile CACHE ${url}} : ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`
1171
+ );
867
1172
  // Soundfile is located at 'index' in the DSP struct, to be added with baseDSP in the wasm memory
868
1173
  HEAP32[(baseDSP + item.index) >> 2] = item.basePtr;
869
1174
  } else {
870
1175
  // Create the soundfiles
871
- const soundfile = this.createSoundfile(allocator, soundfileIds, this.fSoundfileBuffers);
1176
+ const soundfile = this.createSoundfile(
1177
+ allocator,
1178
+ soundfileIds,
1179
+ this.fSoundfileBuffers
1180
+ );
872
1181
  if (soundfile) {
873
1182
  // Update HEAP32 after soundfile creation
874
1183
  const HEAP32 = soundfile.getHEAP32();
875
1184
  // Get the soundfile pointer in wasm memory
876
1185
  item.basePtr = soundfile.getPtr();
877
- console.log(`Soundfile ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`);
1186
+ console.log(
1187
+ `Soundfile ${name} loaded at ${item.basePtr} in wasm memory with index ${item.index}`
1188
+ );
878
1189
  // Soundfile is located at 'index' in the DSP struct, to be added with baseDSP in the wasm memory
879
1190
  HEAP32[(baseDSP + item.index) >> 2] = item.basePtr;
880
1191
  } else {
881
- console.log(`Soundfile ${name} for ${url} cannot be created !}`);
1192
+ console.log(
1193
+ `Soundfile ${name} for ${url} cannot be created !}`
1194
+ );
882
1195
  }
883
1196
  }
884
1197
  }
885
1198
 
886
- createSoundfile(allocator: WasmAllocator, soundfileIdList: string[], soundfiles: LooseFaustDspFactory["soundfiles"], maxChan = Soundfile.MAX_CHAN) {
1199
+ createSoundfile(
1200
+ allocator: WasmAllocator,
1201
+ soundfileIdList: string[],
1202
+ soundfiles: LooseFaustDspFactory['soundfiles'],
1203
+ maxChan = Soundfile.MAX_CHAN
1204
+ ) {
887
1205
  let curChan = 1; // At least one channel
888
1206
  let totalLength = 0;
889
1207
 
@@ -904,10 +1222,19 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
904
1222
  }
905
1223
 
906
1224
  // Complete with empty parts
907
- totalLength += (Soundfile.MAX_SOUNDFILE_PARTS - soundfileIdList.length) * Soundfile.BUFFER_SIZE;
1225
+ totalLength +=
1226
+ (Soundfile.MAX_SOUNDFILE_PARTS - soundfileIdList.length) *
1227
+ Soundfile.BUFFER_SIZE;
908
1228
 
909
1229
  // Create the soundfile
910
- const soundfile = new Soundfile(allocator, this.fSampleSize, curChan, totalLength, maxChan, soundfileIdList.length);
1230
+ const soundfile = new Soundfile(
1231
+ allocator,
1232
+ this.fSampleSize,
1233
+ curChan,
1234
+ totalLength,
1235
+ maxChan,
1236
+ soundfileIdList.length
1237
+ );
911
1238
 
912
1239
  //soundfile.displayMemory("After soundfile creation");
913
1240
  // Init offset
@@ -931,7 +1258,11 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
931
1258
  //soundfile.displayMemory("After reading soundfiles");
932
1259
 
933
1260
  // Complete with empty parts
934
- for (let part = soundfileIdList.length; part < Soundfile.MAX_SOUNDFILE_PARTS; part++) {
1261
+ for (
1262
+ let part = soundfileIdList.length;
1263
+ part < Soundfile.MAX_SOUNDFILE_PARTS;
1264
+ part++
1265
+ ) {
935
1266
  offset = soundfile.emptyFile(part, offset);
936
1267
  }
937
1268
 
@@ -944,30 +1275,38 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
944
1275
 
945
1276
  return soundfile;
946
1277
  }
947
- /**
1278
+ /**
948
1279
  * Init soundfiles memory.
949
- *
1280
+ *
950
1281
  * @param allocator : the wasm memory allocator
951
1282
  * @param baseDSP : the DSP struct (either a monophonic DSP of polyphonic voice) base DSP in the wasm memory
952
- */
1283
+ */
953
1284
  protected initSoundfileMemory(allocator: WasmAllocator, baseDSP: number) {
954
1285
  // Create and fill the soundfile structure
955
1286
  for (const { name, url } of this.fSoundfiles) {
956
1287
  this.loadSoundfile(allocator, baseDSP, name, url);
957
- };
1288
+ }
958
1289
  }
959
1290
 
960
1291
  protected updateOutputs() {
961
- if (this.fOutputsItems.length > 0 && this.fOutputHandler && this.fOutputsTimer-- === 0) {
1292
+ if (
1293
+ this.fOutputsItems.length > 0 &&
1294
+ this.fOutputHandler &&
1295
+ this.fOutputsTimer-- === 0
1296
+ ) {
962
1297
  this.fOutputsTimer = 5;
963
- this.fOutputsItems.forEach(item => this.fOutputHandler?.(item, this.getParamValue(item)));
1298
+ this.fOutputsItems.forEach((item) =>
1299
+ this.fOutputHandler?.(item, this.getParamValue(item))
1300
+ );
964
1301
  }
965
1302
  }
966
1303
 
967
1304
  // Public API
968
1305
  metadata(handler: MetadataHandler) {
969
1306
  if (this.fJSONDsp.meta) {
970
- this.fJSONDsp.meta.forEach(meta => handler(Object.keys(meta)[0], meta[Object.keys(meta)[0]]));
1307
+ this.fJSONDsp.meta.forEach((meta) =>
1308
+ handler(Object.keys(meta)[0], meta[Object.keys(meta)[0]])
1309
+ );
971
1310
  }
972
1311
  }
973
1312
 
@@ -985,7 +1324,7 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
985
1324
  if (this.fOutputHandler) {
986
1325
  this.fOutputHandler(path, value);
987
1326
  } else {
988
- console.warn("No OutputParamHandler set for this Faust node.");
1327
+ console.warn('No OutputParamHandler set for this Faust node.');
989
1328
  }
990
1329
  }
991
1330
 
@@ -1011,18 +1350,16 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
1011
1350
  }
1012
1351
 
1013
1352
  midiMessage(data: number[] | Uint8Array) {
1014
- if (this.fPlotHandler) this.fCachedEvents.push({ data, type: "midi" });
1353
+ if (this.fPlotHandler) this.fCachedEvents.push({ data, type: 'midi' });
1015
1354
  const cmd = data[0] >> 4;
1016
1355
  const channel = data[0] & 0xf;
1017
1356
  const data1 = data[1];
1018
1357
  const data2 = data[2];
1019
1358
  if (cmd === 11) return this.ctrlChange(channel, data1, data2);
1020
- if (cmd === 14) return this.pitchWheel(channel, (data2 * 128.0 + data1));
1359
+ if (cmd === 14) return this.pitchWheel(channel, data2 * 128.0 + data1);
1021
1360
  if (cmd === 9) {
1022
- if (data2 > 0)
1023
- return this.keyOn(channel, data1, data2);
1024
- else
1025
- return this.keyOff(channel, data1, data2);
1361
+ if (data2 > 0) return this.keyOn(channel, data1, data2);
1362
+ else return this.keyOff(channel, data1, data2);
1026
1363
  }
1027
1364
  if (cmd === 8) {
1028
1365
  return this.keyOff(channel, data1, data2);
@@ -1030,47 +1367,99 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
1030
1367
  }
1031
1368
 
1032
1369
  ctrlChange(channel: number, ctrl: number, value: number) {
1033
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "ctrlChange", data: [channel, ctrl, value] });
1370
+ if (this.fPlotHandler)
1371
+ this.fCachedEvents.push({
1372
+ type: 'ctrlChange',
1373
+ data: [channel, ctrl, value]
1374
+ });
1034
1375
  if (this.fCtrlLabel[ctrl].length) {
1035
1376
  this.fCtrlLabel[ctrl].forEach((ctrl) => {
1036
1377
  const { path, chan } = ctrl;
1037
1378
  if (chan === 0 || channel === chan - 1) {
1038
- this.setParamValue(path, FaustBaseWebAudioDsp.remap(value, 0, 127, ctrl.min, ctrl.max));
1379
+ this.setParamValue(
1380
+ path,
1381
+ FaustBaseWebAudioDsp.remap(
1382
+ value,
1383
+ 0,
1384
+ 127,
1385
+ ctrl.min,
1386
+ ctrl.max
1387
+ )
1388
+ );
1039
1389
  // Typically used to reflect parameter change on GUI
1040
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1390
+ if (this.fOutputHandler)
1391
+ this.fOutputHandler(path, this.getParamValue(path));
1041
1392
  }
1042
1393
  });
1043
1394
  }
1044
1395
  }
1045
1396
 
1046
1397
  keyOn(channel: number, pitch: number, velocity: number) {
1047
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOn", data: [channel, pitch, velocity] });
1398
+ if (this.fPlotHandler)
1399
+ this.fCachedEvents.push({
1400
+ type: 'keyOn',
1401
+ data: [channel, pitch, velocity]
1402
+ });
1048
1403
  this.fMidiKeyOnLabel[pitch].forEach((key) => {
1049
1404
  const { path, chan } = key;
1050
1405
  if (chan === 0 || channel === chan - 1) {
1051
- this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1406
+ this.setParamValue(
1407
+ path,
1408
+ FaustBaseWebAudioDsp.remap(
1409
+ velocity,
1410
+ 0,
1411
+ 127,
1412
+ key.min,
1413
+ key.max
1414
+ )
1415
+ );
1052
1416
  // Typically used to reflect parameter change on GUI
1053
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1417
+ if (this.fOutputHandler)
1418
+ this.fOutputHandler(path, this.getParamValue(path));
1054
1419
  }
1055
1420
  });
1056
1421
  this.fMidiKeyLabel[pitch].forEach((key) => {
1057
1422
  const { path, chan } = key;
1058
1423
  if (chan === 0 || channel === chan - 1) {
1059
- this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1424
+ this.setParamValue(
1425
+ path,
1426
+ FaustBaseWebAudioDsp.remap(
1427
+ velocity,
1428
+ 0,
1429
+ 127,
1430
+ key.min,
1431
+ key.max
1432
+ )
1433
+ );
1060
1434
  // Typically used to reflect parameter change on GUI
1061
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1435
+ if (this.fOutputHandler)
1436
+ this.fOutputHandler(path, this.getParamValue(path));
1062
1437
  }
1063
1438
  });
1064
1439
  }
1065
1440
 
1066
1441
  keyOff(channel: number, pitch: number, velocity: number) {
1067
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOff", data: [channel, pitch, velocity] });
1442
+ if (this.fPlotHandler)
1443
+ this.fCachedEvents.push({
1444
+ type: 'keyOff',
1445
+ data: [channel, pitch, velocity]
1446
+ });
1068
1447
  this.fMidiKeyOffLabel[pitch].forEach((key) => {
1069
1448
  const { path, chan } = key;
1070
1449
  if (chan === 0 || channel === chan - 1) {
1071
- this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1450
+ this.setParamValue(
1451
+ path,
1452
+ FaustBaseWebAudioDsp.remap(
1453
+ velocity,
1454
+ 0,
1455
+ 127,
1456
+ key.min,
1457
+ key.max
1458
+ )
1459
+ );
1072
1460
  // Typically used to reflect parameter change on GUI
1073
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1461
+ if (this.fOutputHandler)
1462
+ this.fOutputHandler(path, this.getParamValue(path));
1074
1463
  }
1075
1464
  });
1076
1465
  this.fMidiKeyLabel[pitch].forEach((key) => {
@@ -1078,33 +1467,56 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
1078
1467
  if (chan === 0 || channel === chan - 1) {
1079
1468
  this.setParamValue(path, 0);
1080
1469
  // Typically used to reflect parameter change on GUI
1081
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1470
+ if (this.fOutputHandler)
1471
+ this.fOutputHandler(path, this.getParamValue(path));
1082
1472
  }
1083
1473
  });
1084
1474
  }
1085
1475
 
1086
1476
  pitchWheel(channel: number, wheel: number) {
1087
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "pitchWheel", data: [channel, wheel] });
1477
+ if (this.fPlotHandler)
1478
+ this.fCachedEvents.push({
1479
+ type: 'pitchWheel',
1480
+ data: [channel, wheel]
1481
+ });
1088
1482
  this.fPitchwheelLabel.forEach((pw) => {
1089
1483
  const { path, chan } = pw;
1090
1484
  if (chan === 0 || channel === chan - 1) {
1091
- this.setParamValue(path, FaustBaseWebAudioDsp.remap(wheel, 0, 16383, pw.min, pw.max));
1485
+ this.setParamValue(
1486
+ path,
1487
+ FaustBaseWebAudioDsp.remap(wheel, 0, 16383, pw.min, pw.max)
1488
+ );
1092
1489
  // Typically used to reflect parameter change on GUI
1093
- if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1490
+ if (this.fOutputHandler)
1491
+ this.fOutputHandler(path, this.getParamValue(path));
1094
1492
  }
1095
1493
  });
1096
1494
  }
1097
1495
 
1098
- setParamValue(path: string, value: number) { }
1099
- getParamValue(path: string) { return 0; }
1496
+ setParamValue(path: string, value: number) {}
1497
+ getParamValue(path: string) {
1498
+ return 0;
1499
+ }
1100
1500
 
1101
- getParams() { return this.fInputsItems; }
1102
- getMeta() { return this.fJSONDsp; }
1103
- getJSON() { return JSON.stringify(this.getMeta()); }
1104
- getUI() { return this.fJSONDsp.ui; }
1105
- getDescriptors() { return this.fDescriptor; }
1501
+ getParams() {
1502
+ return this.fInputsItems;
1503
+ }
1504
+ getMeta() {
1505
+ return this.fJSONDsp;
1506
+ }
1507
+ getJSON() {
1508
+ return JSON.stringify(this.getMeta());
1509
+ }
1510
+ getUI() {
1511
+ return this.fJSONDsp.ui;
1512
+ }
1513
+ getDescriptors() {
1514
+ return this.fDescriptor;
1515
+ }
1106
1516
 
1107
- hasSoundfiles() { return this.fSoundfiles.length > 0; }
1517
+ hasSoundfiles() {
1518
+ return this.fSoundfiles.length > 0;
1519
+ }
1108
1520
 
1109
1521
  startSensors(): void {
1110
1522
  this.startSensors();
@@ -1128,16 +1540,22 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
1128
1540
  this.fComputeHandler = null;
1129
1541
  this.fPlotHandler = null;
1130
1542
  }
1131
-
1132
1543
  }
1133
1544
 
1134
- export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaustMonoWebAudioDsp {
1135
-
1545
+ export class FaustMonoWebAudioDsp
1546
+ extends FaustBaseWebAudioDsp
1547
+ implements IFaustMonoWebAudioDsp
1548
+ {
1136
1549
  private fInstance: FaustMonoDspInstance;
1137
1550
  private fDSP!: number;
1138
1551
 
1139
- constructor(instance: FaustMonoDspInstance, sampleRate: number, sampleSize: number, bufferSize: number, soundfiles: LooseFaustDspFactory["soundfiles"]) {
1140
-
1552
+ constructor(
1553
+ instance: FaustMonoDspInstance,
1554
+ sampleRate: number,
1555
+ sampleSize: number,
1556
+ bufferSize: number,
1557
+ soundfiles: LooseFaustDspFactory['soundfiles']
1558
+ ) {
1141
1559
  super(sampleSize, bufferSize, soundfiles);
1142
1560
  this.fInstance = instance;
1143
1561
 
@@ -1157,9 +1575,11 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1157
1575
 
1158
1576
  // Init soundfiles memory is needed
1159
1577
  if (this.fSoundfiles.length > 0) {
1160
-
1161
1578
  // Create memory allocator for soundfiles in wasm memory, starting at the end of DSP memory
1162
- const allocator = new WasmAllocator(this.fInstance.memory, this.fEndMemory);
1579
+ const allocator = new WasmAllocator(
1580
+ this.fInstance.memory,
1581
+ this.fEndMemory
1582
+ );
1163
1583
 
1164
1584
  // Init soundfiles memory
1165
1585
  this.initSoundfileMemory(allocator, this.fDSP);
@@ -1167,7 +1587,6 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1167
1587
  }
1168
1588
 
1169
1589
  private initMemory(): number {
1170
-
1171
1590
  // Start of DSP memory: Mono DSP is placed first with index 0
1172
1591
  this.fDSP = 0;
1173
1592
 
@@ -1176,37 +1595,62 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1176
1595
 
1177
1596
  // Setup audio pointers offset
1178
1597
  this.fAudioInputs = $audio;
1179
- this.fAudioOutputs = this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
1598
+ this.fAudioOutputs =
1599
+ this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
1180
1600
 
1181
1601
  // Prepare wasm memory layout
1182
- const $audioInputs = this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
1183
- const $audioOutputs = $audioInputs + this.getNumInputs() * this.fBufferSize * this.fSampleSize;
1602
+ const $audioInputs =
1603
+ this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
1604
+ const $audioOutputs =
1605
+ $audioInputs +
1606
+ this.getNumInputs() * this.fBufferSize * this.fSampleSize;
1184
1607
  // Compute memory end in bytes
1185
- const endMemory = $audioOutputs + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
1608
+ const endMemory =
1609
+ $audioOutputs +
1610
+ this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
1186
1611
 
1187
1612
  // Setup Int32 and Real views of the memory
1188
1613
  const HEAP = this.fInstance.memory.buffer;
1189
1614
  const HEAP32 = new Int32Array(HEAP);
1190
- const HEAPF = (this.fSampleSize === 4) ? new Float32Array(HEAP) : new Float64Array(HEAP);
1615
+ const HEAPF =
1616
+ this.fSampleSize === 4
1617
+ ? new Float32Array(HEAP)
1618
+ : new Float64Array(HEAP);
1191
1619
 
1192
1620
  if (this.getNumInputs() > 0) {
1193
1621
  for (let chan = 0; chan < this.getNumInputs(); chan++) {
1194
- HEAP32[(this.fAudioInputs >> 2) + chan] = $audioInputs + this.fBufferSize * this.fSampleSize * chan;
1622
+ HEAP32[(this.fAudioInputs >> 2) + chan] =
1623
+ $audioInputs + this.fBufferSize * this.fSampleSize * chan;
1195
1624
  }
1196
1625
  // Prepare Ins buffer tables
1197
- const dspInChans = HEAP32.subarray(this.fAudioInputs >> 2, (this.fAudioInputs + this.getNumInputs() * this.fPtrSize) >> 2);
1626
+ const dspInChans = HEAP32.subarray(
1627
+ this.fAudioInputs >> 2,
1628
+ (this.fAudioInputs + this.getNumInputs() * this.fPtrSize) >> 2
1629
+ );
1198
1630
  for (let chan = 0; chan < this.getNumInputs(); chan++) {
1199
- this.fInChannels[chan] = HEAPF.subarray(dspInChans[chan] >> Math.log2(this.fSampleSize), (dspInChans[chan] + this.fBufferSize * this.fSampleSize) >> Math.log2(this.fSampleSize));
1631
+ this.fInChannels[chan] = HEAPF.subarray(
1632
+ dspInChans[chan] >> Math.log2(this.fSampleSize),
1633
+ (dspInChans[chan] + this.fBufferSize * this.fSampleSize) >>
1634
+ Math.log2(this.fSampleSize)
1635
+ );
1200
1636
  }
1201
1637
  }
1202
1638
  if (this.getNumOutputs() > 0) {
1203
1639
  for (let chan = 0; chan < this.getNumOutputs(); chan++) {
1204
- HEAP32[(this.fAudioOutputs >> 2) + chan] = $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
1640
+ HEAP32[(this.fAudioOutputs >> 2) + chan] =
1641
+ $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
1205
1642
  }
1206
1643
  // Prepare Out buffer tables
1207
- const dspOutChans = HEAP32.subarray(this.fAudioOutputs >> 2, (this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize) >> 2);
1644
+ const dspOutChans = HEAP32.subarray(
1645
+ this.fAudioOutputs >> 2,
1646
+ (this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize) >> 2
1647
+ );
1208
1648
  for (let chan = 0; chan < this.getNumOutputs(); chan++) {
1209
- this.fOutChannels[chan] = HEAPF.subarray(dspOutChans[chan] >> Math.log2(this.fSampleSize), (dspOutChans[chan] + this.fBufferSize * this.fSampleSize) >> Math.log2(this.fSampleSize));
1649
+ this.fOutChannels[chan] = HEAPF.subarray(
1650
+ dspOutChans[chan] >> Math.log2(this.fSampleSize),
1651
+ (dspOutChans[chan] + this.fBufferSize * this.fSampleSize) >>
1652
+ Math.log2(this.fSampleSize)
1653
+ );
1210
1654
  }
1211
1655
  }
1212
1656
 
@@ -1223,8 +1667,14 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1223
1667
  }
1224
1668
 
1225
1669
  // Public API
1226
- compute(input: Float32Array[] | ((input: Float32Array[] | Float64Array[]) => any), output: Float32Array[] | ((output: Float32Array[] | Float64Array[]) => any)) {
1227
-
1670
+ compute(
1671
+ input:
1672
+ | Float32Array[]
1673
+ | ((input: Float32Array[] | Float64Array[]) => any),
1674
+ output:
1675
+ | Float32Array[]
1676
+ | ((output: Float32Array[] | Float64Array[]) => any)
1677
+ ) {
1228
1678
  // Check DSP state
1229
1679
  if (this.fDestroyed) return false;
1230
1680
 
@@ -1237,25 +1687,36 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1237
1687
  this.fFirstCall = false;
1238
1688
  }
1239
1689
 
1240
- if (typeof input === "function") {
1690
+ if (typeof input === 'function') {
1241
1691
  // Call input callback to avoid array copy
1242
1692
  input(this.fInChannels);
1243
1693
  } else {
1244
1694
  // Check inputs
1245
- if (this.getNumInputs() > 0 && (!input || !input[0] || input[0].length === 0)) {
1695
+ if (
1696
+ this.getNumInputs() > 0 &&
1697
+ (!input || !input[0] || input[0].length === 0)
1698
+ ) {
1246
1699
  // console.log("Process input error");
1247
1700
  return true;
1248
1701
  }
1249
1702
 
1250
1703
  // Check outputs
1251
- if (this.getNumOutputs() > 0 && typeof output !== "function" && (!output || !output[0] || output[0].length === 0)) {
1704
+ if (
1705
+ this.getNumOutputs() > 0 &&
1706
+ typeof output !== 'function' &&
1707
+ (!output || !output[0] || output[0].length === 0)
1708
+ ) {
1252
1709
  // console.log("Process output error");
1253
1710
  return true;
1254
1711
  }
1255
1712
 
1256
1713
  // Copy inputs
1257
1714
  if (input !== undefined) {
1258
- for (let chan = 0; chan < Math.min(this.getNumInputs(), input.length); chan++) {
1715
+ for (
1716
+ let chan = 0;
1717
+ chan < Math.min(this.getNumInputs(), input.length);
1718
+ chan++
1719
+ ) {
1259
1720
  const dspInput = this.fInChannels[chan];
1260
1721
  dspInput.set(input[chan]);
1261
1722
  }
@@ -1265,18 +1726,27 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1265
1726
  if (this.fComputeHandler) this.fComputeHandler(this.fBufferSize);
1266
1727
 
1267
1728
  // Compute
1268
- this.fInstance.api.compute(this.fDSP, this.fBufferSize, this.fAudioInputs, this.fAudioOutputs);
1729
+ this.fInstance.api.compute(
1730
+ this.fDSP,
1731
+ this.fBufferSize,
1732
+ this.fAudioInputs,
1733
+ this.fAudioOutputs
1734
+ );
1269
1735
 
1270
1736
  // Update bargraph
1271
1737
  this.updateOutputs();
1272
1738
 
1273
1739
  let forPlot = this.fOutChannels;
1274
- if (typeof output === "function") {
1740
+ if (typeof output === 'function') {
1275
1741
  // Call output callback to avoid array copy
1276
1742
  output(this.fOutChannels);
1277
1743
  } else {
1278
1744
  // Copy outputs
1279
- for (let chan = 0; chan < Math.min(this.getNumOutputs(), output.length); chan++) {
1745
+ for (
1746
+ let chan = 0;
1747
+ chan < Math.min(this.getNumOutputs(), output.length);
1748
+ chan++
1749
+ ) {
1280
1750
  const dspOutput = this.fOutChannels[chan];
1281
1751
  output[chan].set(dspOutput);
1282
1752
  // console.log("chan: " + chan + " output: " + dspOutput[0]);
@@ -1284,16 +1754,22 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1284
1754
  forPlot = output;
1285
1755
  }
1286
1756
 
1287
- // PlotHandler handling
1757
+ // PlotHandler handling
1288
1758
  if (this.fPlotHandler) {
1289
- this.fPlotHandler(forPlot, this.fBufferNum++, (this.fCachedEvents.length ? this.fCachedEvents : undefined));
1759
+ this.fPlotHandler(
1760
+ forPlot,
1761
+ this.fBufferNum++,
1762
+ this.fCachedEvents.length ? this.fCachedEvents : undefined
1763
+ );
1290
1764
  this.fCachedEvents = [];
1291
1765
  }
1292
1766
 
1293
1767
  return true;
1294
1768
  }
1295
1769
 
1296
- metadata(handler: MetadataHandler) { super.metadata(handler); }
1770
+ metadata(handler: MetadataHandler) {
1771
+ super.metadata(handler);
1772
+ }
1297
1773
 
1298
1774
  getNumInputs() {
1299
1775
  return this.fInstance.api.getNumInputs(this.fDSP);
@@ -1303,34 +1779,62 @@ export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1303
1779
  }
1304
1780
 
1305
1781
  setParamValue(path: string, value: number) {
1306
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "param", data: { path, value } });
1307
- this.fInstance.api.setParamValue(this.fDSP, this.fPathTable[path], value);
1782
+ if (this.fPlotHandler)
1783
+ this.fCachedEvents.push({ type: 'param', data: { path, value } });
1784
+ this.fInstance.api.setParamValue(
1785
+ this.fDSP,
1786
+ this.fPathTable[path],
1787
+ value
1788
+ );
1308
1789
  }
1309
1790
  getParamValue(path: string) {
1310
- return this.fInstance.api.getParamValue(this.fDSP, this.fPathTable[path]);
1791
+ return this.fInstance.api.getParamValue(
1792
+ this.fDSP,
1793
+ this.fPathTable[path]
1794
+ );
1311
1795
  }
1312
1796
 
1313
- getMeta() { return this.fJSONDsp; }
1314
- getJSON() { return this.fInstance.json; }
1315
- getDescriptors() { return this.fDescriptor; }
1316
- getUI() { return this.fJSONDsp.ui; }
1797
+ getMeta() {
1798
+ return this.fJSONDsp;
1799
+ }
1800
+ getJSON() {
1801
+ return this.fInstance.json;
1802
+ }
1803
+ getDescriptors() {
1804
+ return this.fDescriptor;
1805
+ }
1806
+ getUI() {
1807
+ return this.fJSONDsp.ui;
1808
+ }
1317
1809
  }
1318
1810
 
1319
1811
  export class FaustWebAudioDspVoice {
1320
1812
  // Voice state
1321
- static get kActiveVoice() { return 0; }
1322
- static get kFreeVoice() { return -1; }
1323
- static get kReleaseVoice() { return -2; }
1324
- static get kLegatoVoice() { return -3; }
1325
- static get kNoVoice() { return -4; }
1326
- static get VOICE_STOP_LEVEL() { return 0.00003162; } // -90 db
1813
+ static get kActiveVoice() {
1814
+ return 0;
1815
+ }
1816
+ static get kFreeVoice() {
1817
+ return -1;
1818
+ }
1819
+ static get kReleaseVoice() {
1820
+ return -2;
1821
+ }
1822
+ static get kLegatoVoice() {
1823
+ return -3;
1824
+ }
1825
+ static get kNoVoice() {
1826
+ return -4;
1827
+ }
1828
+ static get VOICE_STOP_LEVEL() {
1829
+ return 0.00003162;
1830
+ } // -90 db
1327
1831
 
1328
1832
  private fFreqLabel: number[] = [];
1329
1833
  private fGateLabel: number[] = [];
1330
1834
  private fGainLabel: number[] = [];
1331
1835
  private fKeyLabel: number[] = [];
1332
1836
  private fVelLabel: number[] = [];
1333
- private fDSP: number; // Voice DSP location in wasm memory
1837
+ private fDSP: number; // Voice DSP location in wasm memory
1334
1838
  private fAPI: IFaustDspInstance; // Voice DSP code
1335
1839
  // Accessed by PolyDSPImp class
1336
1840
  fCurNote = FaustWebAudioDspVoice.kFreeVoice;
@@ -1339,28 +1843,41 @@ export class FaustWebAudioDspVoice {
1339
1843
  fDate = 0;
1340
1844
  fLevel = 0;
1341
1845
 
1342
- constructor($dsp: number, api: IFaustDspInstance, inputItems: string[], pathTable: { [address: string]: number }, sampleRate: number) {
1846
+ constructor(
1847
+ $dsp: number,
1848
+ api: IFaustDspInstance,
1849
+ inputItems: string[],
1850
+ pathTable: { [address: string]: number },
1851
+ sampleRate: number
1852
+ ) {
1343
1853
  this.fDSP = $dsp;
1344
1854
  this.fAPI = api;
1345
1855
  this.fAPI.init(this.fDSP, sampleRate);
1346
1856
  this.extractPaths(inputItems, pathTable);
1347
1857
  }
1348
1858
 
1349
- static midiToFreq(note: number) { return 440.0 * 2 ** ((note - 69) / 12); }
1859
+ static midiToFreq(note: number) {
1860
+ return 440.0 * 2 ** ((note - 69) / 12);
1861
+ }
1350
1862
 
1351
- static normalizeVelocity(velocity: number) { return velocity / 127.0; }
1863
+ static normalizeVelocity(velocity: number) {
1864
+ return velocity / 127.0;
1865
+ }
1352
1866
 
1353
- private extractPaths(inputItems: string[], pathTable: { [address: string]: number }) {
1867
+ private extractPaths(
1868
+ inputItems: string[],
1869
+ pathTable: { [address: string]: number }
1870
+ ) {
1354
1871
  inputItems.forEach((item) => {
1355
- if (item.endsWith("/gate")) {
1872
+ if (item.endsWith('/gate')) {
1356
1873
  this.fGateLabel.push(pathTable[item]);
1357
- } else if (item.endsWith("/freq")) {
1874
+ } else if (item.endsWith('/freq')) {
1358
1875
  this.fFreqLabel.push(pathTable[item]);
1359
- } else if (item.endsWith("/key")) {
1876
+ } else if (item.endsWith('/key')) {
1360
1877
  this.fKeyLabel.push(pathTable[item]);
1361
- } else if (item.endsWith("/gain")) {
1878
+ } else if (item.endsWith('/gain')) {
1362
1879
  this.fGainLabel.push(pathTable[item]);
1363
- } else if (item.endsWith("/vel") && item.endsWith("/velocity")) {
1880
+ } else if (item.endsWith('/vel') && item.endsWith('/velocity')) {
1364
1881
  this.fVelLabel.push(pathTable[item]);
1365
1882
  }
1366
1883
  });
@@ -1372,18 +1889,38 @@ export class FaustWebAudioDspVoice {
1372
1889
  this.fNextNote = pitch;
1373
1890
  this.fNextVel = velocity;
1374
1891
  } else {
1375
- this.fFreqLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, FaustWebAudioDspVoice.midiToFreq(pitch)));
1376
- this.fGateLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, 1));
1377
- this.fGainLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, FaustWebAudioDspVoice.normalizeVelocity(velocity)));
1378
- this.fKeyLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, pitch));
1379
- this.fVelLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, velocity));
1892
+ this.fFreqLabel.forEach((index) =>
1893
+ this.fAPI.setParamValue(
1894
+ this.fDSP,
1895
+ index,
1896
+ FaustWebAudioDspVoice.midiToFreq(pitch)
1897
+ )
1898
+ );
1899
+ this.fGateLabel.forEach((index) =>
1900
+ this.fAPI.setParamValue(this.fDSP, index, 1)
1901
+ );
1902
+ this.fGainLabel.forEach((index) =>
1903
+ this.fAPI.setParamValue(
1904
+ this.fDSP,
1905
+ index,
1906
+ FaustWebAudioDspVoice.normalizeVelocity(velocity)
1907
+ )
1908
+ );
1909
+ this.fKeyLabel.forEach((index) =>
1910
+ this.fAPI.setParamValue(this.fDSP, index, pitch)
1911
+ );
1912
+ this.fVelLabel.forEach((index) =>
1913
+ this.fAPI.setParamValue(this.fDSP, index, velocity)
1914
+ );
1380
1915
  // Keep pitch
1381
1916
  this.fCurNote = pitch;
1382
1917
  }
1383
1918
  }
1384
1919
 
1385
1920
  keyOff(hard: boolean = false) {
1386
- this.fGateLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, 0));
1921
+ this.fGateLabel.forEach((index) =>
1922
+ this.fAPI.setParamValue(this.fDSP, index, 0)
1923
+ );
1387
1924
  if (hard) {
1388
1925
  this.fCurNote = FaustWebAudioDspVoice.kFreeVoice;
1389
1926
  } else {
@@ -1391,12 +1928,18 @@ export class FaustWebAudioDspVoice {
1391
1928
  }
1392
1929
  }
1393
1930
 
1394
- computeLegato(bufferSize: number, $inputs: number, $outputZero: number, $outputsHalf: number) {
1395
-
1396
- let size = bufferSize / 2;
1931
+ computeLegato(
1932
+ bufferSize: number,
1933
+ $inputs: number,
1934
+ $outputZero: number,
1935
+ $outputsHalf: number
1936
+ ) {
1937
+ const size = bufferSize / 2;
1397
1938
 
1398
1939
  // Reset envelops
1399
- this.fGateLabel.forEach(index => this.fAPI.setParamValue(this.fDSP, index, 0));
1940
+ this.fGateLabel.forEach((index) =>
1941
+ this.fAPI.setParamValue(this.fDSP, index, 0)
1942
+ );
1400
1943
 
1401
1944
  // Compute current voice on half buffer
1402
1945
  this.fAPI.compute(this.fDSP, size, $inputs, $outputZero);
@@ -1420,8 +1963,10 @@ export class FaustWebAudioDspVoice {
1420
1963
  }
1421
1964
  }
1422
1965
 
1423
- export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaustPolyWebAudioDsp {
1424
-
1966
+ export class FaustPolyWebAudioDsp
1967
+ extends FaustBaseWebAudioDsp
1968
+ implements IFaustPolyWebAudioDsp
1969
+ {
1425
1970
  private fInstance: FaustPolyDspInstance;
1426
1971
  private fEffect!: number;
1427
1972
  private fJSONEffect: FaustDspMeta | null;
@@ -1429,7 +1974,13 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1429
1974
  private fAudioMixingHalf!: number;
1430
1975
  private fVoiceTable: FaustWebAudioDspVoice[];
1431
1976
 
1432
- constructor(instance: FaustPolyDspInstance, sampleRate: number, sampleSize: number, bufferSize: number, soundfiles: LooseFaustDspFactory["soundfiles"]) {
1977
+ constructor(
1978
+ instance: FaustPolyDspInstance,
1979
+ sampleRate: number,
1980
+ sampleSize: number,
1981
+ bufferSize: number,
1982
+ soundfiles: LooseFaustDspFactory['soundfiles']
1983
+ ) {
1433
1984
  super(sampleSize, bufferSize, soundfiles);
1434
1985
  this.fInstance = instance;
1435
1986
 
@@ -1439,11 +1990,15 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1439
1990
  this.fJSONDsp = JSON.parse(this.fInstance.voiceJSON);
1440
1991
 
1441
1992
  // Create JSON for effect
1442
- this.fJSONEffect = (this.fInstance.effectAPI && this.fInstance.effectJSON) ? JSON.parse(this.fInstance.effectJSON) : null;
1993
+ this.fJSONEffect =
1994
+ this.fInstance.effectAPI && this.fInstance.effectJSON
1995
+ ? JSON.parse(this.fInstance.effectJSON)
1996
+ : null;
1443
1997
 
1444
1998
  // Setup GUI
1445
1999
  FaustBaseWebAudioDsp.parseUI(this.fJSONDsp.ui, this.fUICallback);
1446
- if (this.fJSONEffect) FaustBaseWebAudioDsp.parseUI(this.fJSONEffect.ui, this.fUICallback);
2000
+ if (this.fJSONEffect)
2001
+ FaustBaseWebAudioDsp.parseUI(this.fJSONEffect.ui, this.fUICallback);
1447
2002
 
1448
2003
  // Setup wasm memory
1449
2004
  this.fEndMemory = this.initMemory();
@@ -1451,22 +2006,28 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1451
2006
  // Init DSP voices
1452
2007
  this.fVoiceTable = [];
1453
2008
  for (let voice = 0; voice < this.fInstance.voices; voice++) {
1454
- this.fVoiceTable.push(new FaustWebAudioDspVoice(
1455
- this.fJSONDsp.size * voice,
1456
- this.fInstance.voiceAPI,
1457
- this.fInputsItems,
1458
- this.fPathTable,
1459
- sampleRate
1460
- ));
2009
+ this.fVoiceTable.push(
2010
+ new FaustWebAudioDspVoice(
2011
+ this.fJSONDsp.size * voice,
2012
+ this.fInstance.voiceAPI,
2013
+ this.fInputsItems,
2014
+ this.fPathTable,
2015
+ sampleRate
2016
+ )
2017
+ );
1461
2018
  }
1462
2019
 
1463
2020
  // Init effect
1464
- if (this.fInstance.effectAPI) this.fInstance.effectAPI.init(this.fEffect, sampleRate);
2021
+ if (this.fInstance.effectAPI)
2022
+ this.fInstance.effectAPI.init(this.fEffect, sampleRate);
1465
2023
 
1466
2024
  // Init soundfiles memory is needed
1467
2025
  if (this.fSoundfiles.length > 0) {
1468
2026
  // Create memory allocator for soundfiles in wasm memory, starting at the end of DSP memory
1469
- const allocator = new WasmAllocator(this.fInstance.memory, this.fEndMemory);
2027
+ const allocator = new WasmAllocator(
2028
+ this.fInstance.memory,
2029
+ this.fEndMemory
2030
+ );
1470
2031
  // Init soundfiles memory for all voices
1471
2032
  for (let voice = 0; voice < this.fInstance.voices; voice++) {
1472
2033
  this.initSoundfileMemory(allocator, this.fJSONDsp.size * voice);
@@ -1475,52 +2036,85 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1475
2036
  }
1476
2037
 
1477
2038
  private initMemory() {
1478
-
1479
2039
  // Effet start at the end of all DSP voices
1480
2040
  this.fEffect = this.fJSONDsp.size * this.fInstance.voices;
1481
2041
 
1482
2042
  // Audio buffer start at the end of effect
1483
- const $audio = this.fEffect + (this.fJSONEffect ? this.fJSONEffect.size : 0);
2043
+ const $audio =
2044
+ this.fEffect + (this.fJSONEffect ? this.fJSONEffect.size : 0);
1484
2045
 
1485
2046
  // Setup audio pointers offset
1486
2047
  this.fAudioInputs = $audio;
1487
- this.fAudioOutputs = this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
1488
- this.fAudioMixing = this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
1489
- this.fAudioMixingHalf = this.fAudioMixing + this.getNumOutputs() * this.fPtrSize;
2048
+ this.fAudioOutputs =
2049
+ this.fAudioInputs + this.getNumInputs() * this.fPtrSize;
2050
+ this.fAudioMixing =
2051
+ this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize;
2052
+ this.fAudioMixingHalf =
2053
+ this.fAudioMixing + this.getNumOutputs() * this.fPtrSize;
1490
2054
 
1491
2055
  // Prepare wasm memory layout
1492
- const $audioInputs = this.fAudioMixingHalf + this.getNumOutputs() * this.fPtrSize;
1493
- const $audioOutputs = $audioInputs + this.getNumInputs() * this.fBufferSize * this.fSampleSize;
1494
- const $audioMixing = $audioOutputs + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
2056
+ const $audioInputs =
2057
+ this.fAudioMixingHalf + this.getNumOutputs() * this.fPtrSize;
2058
+ const $audioOutputs =
2059
+ $audioInputs +
2060
+ this.getNumInputs() * this.fBufferSize * this.fSampleSize;
2061
+ const $audioMixing =
2062
+ $audioOutputs +
2063
+ this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
1495
2064
 
1496
2065
  // Compute memory end in bytes
1497
- const endMemory = $audioMixing + this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
2066
+ const endMemory =
2067
+ $audioMixing +
2068
+ this.getNumOutputs() * this.fBufferSize * this.fSampleSize;
1498
2069
 
1499
2070
  // Setup Int32 and Real views of the memory
1500
2071
  const HEAP = this.fInstance.memory.buffer;
1501
2072
  const HEAP32 = new Int32Array(HEAP);
1502
- const HEAPF = (this.fSampleSize === 4) ? new Float32Array(HEAP) : new Float64Array(HEAP);
2073
+ const HEAPF =
2074
+ this.fSampleSize === 4
2075
+ ? new Float32Array(HEAP)
2076
+ : new Float64Array(HEAP);
1503
2077
 
1504
2078
  if (this.getNumInputs() > 0) {
1505
2079
  for (let chan = 0; chan < this.getNumInputs(); chan++) {
1506
- HEAP32[(this.fAudioInputs >> 2) + chan] = $audioInputs + this.fBufferSize * this.fSampleSize * chan;
2080
+ HEAP32[(this.fAudioInputs >> 2) + chan] =
2081
+ $audioInputs + this.fBufferSize * this.fSampleSize * chan;
1507
2082
  }
1508
2083
  // Prepare Ins buffer tables
1509
- const dspInChans = HEAP32.subarray(this.fAudioInputs >> 2, (this.fAudioInputs + this.getNumInputs() * this.fPtrSize) >> 2);
2084
+ const dspInChans = HEAP32.subarray(
2085
+ this.fAudioInputs >> 2,
2086
+ (this.fAudioInputs + this.getNumInputs() * this.fPtrSize) >> 2
2087
+ );
1510
2088
  for (let chan = 0; chan < this.getNumInputs(); chan++) {
1511
- this.fInChannels[chan] = HEAPF.subarray(dspInChans[chan] >> Math.log2(this.fSampleSize), (dspInChans[chan] + this.fBufferSize * this.fSampleSize) >> Math.log2(this.fSampleSize));
2089
+ this.fInChannels[chan] = HEAPF.subarray(
2090
+ dspInChans[chan] >> Math.log2(this.fSampleSize),
2091
+ (dspInChans[chan] + this.fBufferSize * this.fSampleSize) >>
2092
+ Math.log2(this.fSampleSize)
2093
+ );
1512
2094
  }
1513
2095
  }
1514
2096
  if (this.getNumOutputs() > 0) {
1515
2097
  for (let chan = 0; chan < this.getNumOutputs(); chan++) {
1516
- HEAP32[(this.fAudioOutputs >> 2) + chan] = $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
1517
- HEAP32[(this.fAudioMixing >> 2) + chan] = $audioMixing + this.fBufferSize * this.fSampleSize * chan;
1518
- HEAP32[(this.fAudioMixingHalf >> 2) + chan] = $audioMixing + this.fBufferSize * this.fSampleSize * chan + this.fBufferSize / 2 * this.fSampleSize;
2098
+ HEAP32[(this.fAudioOutputs >> 2) + chan] =
2099
+ $audioOutputs + this.fBufferSize * this.fSampleSize * chan;
2100
+ HEAP32[(this.fAudioMixing >> 2) + chan] =
2101
+ $audioMixing + this.fBufferSize * this.fSampleSize * chan;
2102
+ HEAP32[(this.fAudioMixingHalf >> 2) + chan] =
2103
+ $audioMixing +
2104
+ this.fBufferSize * this.fSampleSize * chan +
2105
+ (this.fBufferSize / 2) * this.fSampleSize;
1519
2106
  }
1520
2107
  // Prepare Out buffer tables
1521
- const dspOutChans = HEAP32.subarray(this.fAudioOutputs >> 2, (this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize) >> 2);
2108
+ const dspOutChans = HEAP32.subarray(
2109
+ this.fAudioOutputs >> 2,
2110
+ (this.fAudioOutputs + this.getNumOutputs() * this.fPtrSize) >> 2
2111
+ );
1522
2112
  for (let chan = 0; chan < this.getNumOutputs(); chan++) {
1523
- this.fOutChannels[chan] = HEAPF.subarray(dspOutChans[chan] >> Math.log2(this.fSampleSize), (dspOutChans[chan] + this.fBufferSize * this.fSampleSize) >> Math.log2(this.fSampleSize));
2113
+ this.fOutChannels[chan] = HEAPF.subarray(
2114
+ dspOutChans[chan] >> Math.log2(this.fSampleSize),
2115
+ (dspOutChans[chan] + this.fBufferSize * this.fSampleSize) >>
2116
+ Math.log2(this.fSampleSize)
2117
+ );
1524
2118
  }
1525
2119
  }
1526
2120
 
@@ -1548,10 +2142,14 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1548
2142
  let oldestDatePlaying = Number.MAX_VALUE;
1549
2143
 
1550
2144
  for (let i = 0; i < this.fInstance.voices; i++) {
1551
- let curNote = this.fVoiceTable[i].fCurNote;
1552
- let nextNote = this.fVoiceTable[i].fNextNote;
1553
-
1554
- if ((curNote === pitch) || ((curNote === FaustWebAudioDspVoice.kLegatoVoice) && (nextNote === pitch))) {
2145
+ const curNote = this.fVoiceTable[i].fCurNote;
2146
+ const nextNote = this.fVoiceTable[i].fNextNote;
2147
+
2148
+ if (
2149
+ curNote === pitch ||
2150
+ (curNote === FaustWebAudioDspVoice.kLegatoVoice &&
2151
+ nextNote === pitch)
2152
+ ) {
1555
2153
  // Keeps oldest playing voice
1556
2154
  if (this.fVoiceTable[i].fDate < oldestDatePlaying) {
1557
2155
  oldestDatePlaying = this.fVoiceTable[i].fDate;
@@ -1564,8 +2162,14 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1564
2162
 
1565
2163
  private getFreeVoice() {
1566
2164
  for (let voice = 0; voice < this.fInstance.voices; voice++) {
1567
- if (this.fVoiceTable[voice].fCurNote === FaustWebAudioDspVoice.kFreeVoice) {
1568
- return this.allocVoice(voice, FaustWebAudioDspVoice.kActiveVoice);
2165
+ if (
2166
+ this.fVoiceTable[voice].fCurNote ===
2167
+ FaustWebAudioDspVoice.kFreeVoice
2168
+ ) {
2169
+ return this.allocVoice(
2170
+ voice,
2171
+ FaustWebAudioDspVoice.kActiveVoice
2172
+ );
1569
2173
  }
1570
2174
  }
1571
2175
 
@@ -1574,9 +2178,13 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1574
2178
  let oldestDateRelease = Number.MAX_VALUE;
1575
2179
  let oldestDatePlaying = Number.MAX_VALUE;
1576
2180
 
1577
- for (let voice = 0; voice < this.fInstance.voices; voice++) { // Scan all voices
2181
+ for (let voice = 0; voice < this.fInstance.voices; voice++) {
2182
+ // Scan all voices
1578
2183
  // Try to steal a voice in DspVoice.kReleaseVoice mode...
1579
- if (this.fVoiceTable[voice].fCurNote === FaustWebAudioDspVoice.kReleaseVoice) {
2184
+ if (
2185
+ this.fVoiceTable[voice].fCurNote ===
2186
+ FaustWebAudioDspVoice.kReleaseVoice
2187
+ ) {
1580
2188
  // Keeps oldest release voice
1581
2189
  if (this.fVoiceTable[voice].fDate < oldestDateRelease) {
1582
2190
  oldestDateRelease = this.fVoiceTable[voice].fDate;
@@ -1589,19 +2197,28 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1589
2197
  }
1590
2198
  // Then decide which one to steal
1591
2199
  if (oldestDateRelease !== Number.MAX_VALUE) {
1592
- console.log(`Steal release voice : voice_date = ${this.fVoiceTable[voiceRelease].fDate} voice = ${voiceRelease}`);
1593
- return this.allocVoice(voiceRelease, FaustWebAudioDspVoice.kLegatoVoice);
2200
+ console.log(
2201
+ `Steal release voice : voice_date = ${this.fVoiceTable[voiceRelease].fDate} voice = ${voiceRelease}`
2202
+ );
2203
+ return this.allocVoice(
2204
+ voiceRelease,
2205
+ FaustWebAudioDspVoice.kLegatoVoice
2206
+ );
1594
2207
  }
1595
2208
  if (oldestDatePlaying !== Number.MAX_VALUE) {
1596
- console.log(`Steal playing voice : voice_date = ${this.fVoiceTable[voicePlaying].fDate} voice = ${voicePlaying}`);
1597
- return this.allocVoice(voicePlaying, FaustWebAudioDspVoice.kLegatoVoice);
2209
+ console.log(
2210
+ `Steal playing voice : voice_date = ${this.fVoiceTable[voicePlaying].fDate} voice = ${voicePlaying}`
2211
+ );
2212
+ return this.allocVoice(
2213
+ voicePlaying,
2214
+ FaustWebAudioDspVoice.kLegatoVoice
2215
+ );
1598
2216
  }
1599
2217
  return FaustWebAudioDspVoice.kNoVoice;
1600
2218
  }
1601
2219
 
1602
2220
  // Public API
1603
2221
  compute(input: Float32Array[], output: Float32Array[]) {
1604
-
1605
2222
  // Check DSP state
1606
2223
  if (this.fDestroyed) return false;
1607
2224
 
@@ -1615,20 +2232,30 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1615
2232
  if (!this.fProcessing) return true;
1616
2233
 
1617
2234
  // Check inputs
1618
- if (this.getNumInputs() > 0 && (!input || !input[0] || input[0].length === 0)) {
2235
+ if (
2236
+ this.getNumInputs() > 0 &&
2237
+ (!input || !input[0] || input[0].length === 0)
2238
+ ) {
1619
2239
  // console.log("Process input error");
1620
2240
  return true;
1621
2241
  }
1622
2242
 
1623
2243
  // Check outputs
1624
- if (this.getNumOutputs() > 0 && (!output || !output[0] || output[0].length === 0)) {
2244
+ if (
2245
+ this.getNumOutputs() > 0 &&
2246
+ (!output || !output[0] || output[0].length === 0)
2247
+ ) {
1625
2248
  // console.log("Process output error");
1626
2249
  return true;
1627
2250
  }
1628
2251
 
1629
2252
  // Copy inputs
1630
2253
  if (input !== undefined) {
1631
- for (let chan = 0; chan < Math.min(this.getNumInputs(), input.length); ++chan) {
2254
+ for (
2255
+ let chan = 0;
2256
+ chan < Math.min(this.getNumInputs(), input.length);
2257
+ ++chan
2258
+ ) {
1632
2259
  const dspInput = this.fInChannels[chan];
1633
2260
  dspInput.set(input[chan]);
1634
2261
  }
@@ -1638,41 +2265,85 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1638
2265
  if (this.fComputeHandler) this.fComputeHandler(this.fBufferSize);
1639
2266
 
1640
2267
  // Compute
1641
- this.fInstance.mixerAPI.clearOutput(this.fBufferSize, this.getNumOutputs(), this.fAudioOutputs);
2268
+ this.fInstance.mixerAPI.clearOutput(
2269
+ this.fBufferSize,
2270
+ this.getNumOutputs(),
2271
+ this.fAudioOutputs
2272
+ );
1642
2273
  this.fVoiceTable.forEach((voice) => {
1643
2274
  if (voice.fCurNote === FaustWebAudioDspVoice.kLegatoVoice) {
1644
2275
  // Play from current note and next note
1645
- voice.computeLegato(this.fBufferSize, this.fAudioInputs, this.fAudioMixing, this.fAudioMixingHalf);
2276
+ voice.computeLegato(
2277
+ this.fBufferSize,
2278
+ this.fAudioInputs,
2279
+ this.fAudioMixing,
2280
+ this.fAudioMixingHalf
2281
+ );
1646
2282
  // FadeOut on first half buffer
1647
- this.fInstance.mixerAPI.fadeOut(this.fBufferSize / 2, this.getNumOutputs(), this.fAudioMixing);
2283
+ this.fInstance.mixerAPI.fadeOut(
2284
+ this.fBufferSize / 2,
2285
+ this.getNumOutputs(),
2286
+ this.fAudioMixing
2287
+ );
1648
2288
  // Mix it in result
1649
- voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(this.fBufferSize, this.getNumOutputs(), this.fAudioMixing, this.fAudioOutputs);
2289
+ voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(
2290
+ this.fBufferSize,
2291
+ this.getNumOutputs(),
2292
+ this.fAudioMixing,
2293
+ this.fAudioOutputs
2294
+ );
1650
2295
  } else if (voice.fCurNote !== FaustWebAudioDspVoice.kFreeVoice) {
1651
2296
  // Compute current note
1652
- voice.compute(this.fBufferSize, this.fAudioInputs, this.fAudioMixing);
2297
+ voice.compute(
2298
+ this.fBufferSize,
2299
+ this.fAudioInputs,
2300
+ this.fAudioMixing
2301
+ );
1653
2302
  // Mix it in result
1654
- voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(this.fBufferSize, this.getNumOutputs(), this.fAudioMixing, this.fAudioOutputs);
2303
+ voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(
2304
+ this.fBufferSize,
2305
+ this.getNumOutputs(),
2306
+ this.fAudioMixing,
2307
+ this.fAudioOutputs
2308
+ );
1655
2309
  // Check the level to possibly set the voice in kFreeVoice again
1656
- if ((voice.fCurNote == FaustWebAudioDspVoice.kReleaseVoice) && ((voice.fLevel < FaustWebAudioDspVoice.VOICE_STOP_LEVEL))) {
2310
+ if (
2311
+ voice.fCurNote == FaustWebAudioDspVoice.kReleaseVoice &&
2312
+ voice.fLevel < FaustWebAudioDspVoice.VOICE_STOP_LEVEL
2313
+ ) {
1657
2314
  voice.fCurNote = FaustWebAudioDspVoice.kFreeVoice;
1658
2315
  }
1659
2316
  }
1660
2317
  });
1661
- if (this.fInstance.effectAPI) this.fInstance.effectAPI.compute(this.fEffect, this.fBufferSize, this.fAudioOutputs, this.fAudioOutputs);
2318
+ if (this.fInstance.effectAPI)
2319
+ this.fInstance.effectAPI.compute(
2320
+ this.fEffect,
2321
+ this.fBufferSize,
2322
+ this.fAudioOutputs,
2323
+ this.fAudioOutputs
2324
+ );
1662
2325
 
1663
2326
  // Update bargraph
1664
2327
  this.updateOutputs();
1665
2328
 
1666
2329
  if (output !== undefined) {
1667
2330
  // Copy outputs
1668
- for (let chan = 0; chan < Math.min(this.getNumOutputs(), output.length); chan++) {
2331
+ for (
2332
+ let chan = 0;
2333
+ chan < Math.min(this.getNumOutputs(), output.length);
2334
+ chan++
2335
+ ) {
1669
2336
  const dspOutput = this.fOutChannels[chan];
1670
2337
  output[chan].set(dspOutput);
1671
2338
  }
1672
2339
 
1673
- // PlotHandler handling
2340
+ // PlotHandler handling
1674
2341
  if (this.fPlotHandler) {
1675
- this.fPlotHandler(output, this.fBufferNum++, (this.fCachedEvents.length ? this.fCachedEvents : undefined));
2342
+ this.fPlotHandler(
2343
+ output,
2344
+ this.fBufferNum++,
2345
+ this.fCachedEvents.length ? this.fCachedEvents : undefined
2346
+ );
1676
2347
  this.fCachedEvents = [];
1677
2348
  }
1678
2349
  }
@@ -1688,10 +2359,10 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1688
2359
  }
1689
2360
 
1690
2361
  private static findPath(o: any, p: string) {
1691
- if (typeof o !== "object") {
2362
+ if (typeof o !== 'object') {
1692
2363
  return false;
1693
2364
  } else if (o.address) {
1694
- return (o.address === p);
2365
+ return o.address === p;
1695
2366
  } else {
1696
2367
  for (const k in o) {
1697
2368
  if (FaustPolyWebAudioDsp.findPath(o[k], p)) return true;
@@ -1701,16 +2372,34 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1701
2372
  }
1702
2373
 
1703
2374
  setParamValue(path: string, value: number) {
1704
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "param", data: { path, value } });
1705
- if (this.fJSONEffect && FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) && this.fInstance.effectAPI) {
1706
- this.fInstance.effectAPI.setParamValue(this.fEffect, this.fPathTable[path], value);
2375
+ if (this.fPlotHandler)
2376
+ this.fCachedEvents.push({ type: 'param', data: { path, value } });
2377
+ if (
2378
+ this.fJSONEffect &&
2379
+ FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) &&
2380
+ this.fInstance.effectAPI
2381
+ ) {
2382
+ this.fInstance.effectAPI.setParamValue(
2383
+ this.fEffect,
2384
+ this.fPathTable[path],
2385
+ value
2386
+ );
1707
2387
  } else {
1708
- this.fVoiceTable.forEach(voice => voice.setParamValue(this.fPathTable[path], value));
2388
+ this.fVoiceTable.forEach((voice) =>
2389
+ voice.setParamValue(this.fPathTable[path], value)
2390
+ );
1709
2391
  }
1710
2392
  }
1711
2393
  getParamValue(path: string) {
1712
- if (this.fJSONEffect && FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) && this.fInstance.effectAPI) {
1713
- return this.fInstance.effectAPI.getParamValue(this.fEffect, this.fPathTable[path]);
2394
+ if (
2395
+ this.fJSONEffect &&
2396
+ FaustPolyWebAudioDsp.findPath(this.fJSONEffect.ui, path) &&
2397
+ this.fInstance.effectAPI
2398
+ ) {
2399
+ return this.fInstance.effectAPI.getParamValue(
2400
+ this.fEffect,
2401
+ this.fPathTable[path]
2402
+ );
1714
2403
  } else {
1715
2404
  return this.fVoiceTable[0].getParamValue(this.fPathTable[path]);
1716
2405
  }
@@ -1721,18 +2410,24 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1721
2410
  const e = this.fJSONEffect;
1722
2411
  const r = { ...o };
1723
2412
  if (e) {
1724
- r.ui = [{
1725
- type: "tgroup", label: "Sequencer", items: [
1726
- { type: "vgroup", label: "Instrument", items: o.ui },
1727
- { type: "vgroup", label: "Effect", items: e.ui }
1728
- ]
1729
- }];
2413
+ r.ui = [
2414
+ {
2415
+ type: 'tgroup',
2416
+ label: 'Sequencer',
2417
+ items: [
2418
+ { type: 'vgroup', label: 'Instrument', items: o.ui },
2419
+ { type: 'vgroup', label: 'Effect', items: e.ui }
2420
+ ]
2421
+ }
2422
+ ];
1730
2423
  } else {
1731
- r.ui = [{
1732
- type: "tgroup", label: "Polyphonic", items: [
1733
- { type: "vgroup", label: "Voices", items: o.ui }
1734
- ]
1735
- }];
2424
+ r.ui = [
2425
+ {
2426
+ type: 'tgroup',
2427
+ label: 'Polyphonic',
2428
+ items: [{ type: 'vgroup', label: 'Voices', items: o.ui }]
2429
+ }
2430
+ ];
1736
2431
  }
1737
2432
  return r as FaustDspMeta;
1738
2433
  }
@@ -1745,17 +2440,20 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1745
2440
  return this.getMeta().ui;
1746
2441
  }
1747
2442
 
1748
- getDescriptors() { return this.fDescriptor; }
2443
+ getDescriptors() {
2444
+ return this.fDescriptor;
2445
+ }
1749
2446
 
1750
2447
  midiMessage(data: number[] | Uint8Array) {
1751
2448
  const cmd = data[0] >> 4;
1752
2449
  const channel = data[0] & 0xf;
1753
2450
  const data1 = data[1];
1754
2451
  const data2 = data[2];
1755
- if (cmd === 8 || (cmd === 9 && data2 === 0)) return this.keyOff(channel, data1, data2);
2452
+ if (cmd === 8 || (cmd === 9 && data2 === 0))
2453
+ return this.keyOff(channel, data1, data2);
1756
2454
  else if (cmd === 9) return this.keyOn(channel, data1, data2);
1757
2455
  else super.midiMessage(data);
1758
- };
2456
+ }
1759
2457
 
1760
2458
  ctrlChange(channel: number, ctrl: number, value: number) {
1761
2459
  if (ctrl === 123 || ctrl === 120) {
@@ -1766,23 +2464,36 @@ export class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implements IFaust
1766
2464
  }
1767
2465
 
1768
2466
  keyOn(channel: number, pitch: number, velocity: number) {
1769
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOn", data: [channel, pitch, velocity] });
2467
+ if (this.fPlotHandler)
2468
+ this.fCachedEvents.push({
2469
+ type: 'keyOn',
2470
+ data: [channel, pitch, velocity]
2471
+ });
1770
2472
  const voice = this.getFreeVoice();
1771
- this.fVoiceTable[voice].keyOn(pitch, velocity, this.fVoiceTable[voice].fCurNote == FaustWebAudioDspVoice.kLegatoVoice);
2473
+ this.fVoiceTable[voice].keyOn(
2474
+ pitch,
2475
+ velocity,
2476
+ this.fVoiceTable[voice].fCurNote ==
2477
+ FaustWebAudioDspVoice.kLegatoVoice
2478
+ );
1772
2479
  }
1773
2480
 
1774
2481
  keyOff(channel: number, pitch: number, velocity: number) {
1775
- if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOff", data: [channel, pitch, velocity] });
2482
+ if (this.fPlotHandler)
2483
+ this.fCachedEvents.push({
2484
+ type: 'keyOff',
2485
+ data: [channel, pitch, velocity]
2486
+ });
1776
2487
  const voice = this.getPlayingVoice(pitch);
1777
2488
  if (voice !== FaustWebAudioDspVoice.kNoVoice) {
1778
2489
  this.fVoiceTable[voice].keyOff();
1779
2490
  } else {
1780
- console.log("Playing pitch = %d not found\n", pitch);
2491
+ console.log('Playing pitch = %d not found\n', pitch);
1781
2492
  }
1782
2493
  }
1783
2494
 
1784
2495
  allNotesOff(hard: boolean = true) {
1785
- this.fCachedEvents.push({ type: "ctrlChange", data: [0, 123, 0] });
1786
- this.fVoiceTable.forEach(voice => voice.keyOff(hard));
2496
+ this.fCachedEvents.push({ type: 'ctrlChange', data: [0, 123, 0] });
2497
+ this.fVoiceTable.forEach((voice) => voice.keyOff(hard));
1787
2498
  }
1788
2499
  }