@grame/faustwasm 0.7.9 → 0.8.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 (34) hide show
  1. package/README.md +2 -2
  2. package/assets/standalone/faustwasm/index.d.ts +76 -9
  3. package/assets/standalone/faustwasm/index.js +270 -77
  4. package/assets/standalone/faustwasm/index.js.map +4 -4
  5. package/assets/standalone/index-pwa.js +7 -8
  6. package/assets/standalone/index-template.js +2 -2
  7. package/assets/standalone/index.js +59 -61
  8. package/assets/standalone/service-worker.js +47 -8
  9. package/dist/cjs/index.d.ts +76 -9
  10. package/dist/cjs/index.js +270 -77
  11. package/dist/cjs/index.js.map +4 -4
  12. package/dist/cjs-bundle/index.d.ts +76 -9
  13. package/dist/cjs-bundle/index.js +271 -78
  14. package/dist/cjs-bundle/index.js.map +4 -4
  15. package/dist/esm/index.d.ts +76 -9
  16. package/dist/esm/index.js +270 -77
  17. package/dist/esm/index.js.map +4 -4
  18. package/dist/esm-bundle/index.d.ts +76 -9
  19. package/dist/esm-bundle/index.js +271 -78
  20. package/dist/esm-bundle/index.js.map +4 -4
  21. package/libfaust-wasm/libfaust-wasm.wasm +0 -0
  22. package/package.json +1 -1
  23. package/src/FaustAudioWorkletCommunicator.ts +143 -0
  24. package/src/FaustAudioWorkletNode.ts +23 -12
  25. package/src/FaustAudioWorkletProcessor.ts +34 -15
  26. package/src/FaustDspGenerator.ts +20 -2
  27. package/src/FaustFFTAudioWorkletProcessor.ts +31 -2
  28. package/src/FaustOfflineProcessor.ts +6 -0
  29. package/src/FaustScriptProcessorNode.ts +4 -1
  30. package/src/FaustWebAudioDsp.ts +38 -10
  31. package/test/faustlive-wasm/faustwasm/index.d.ts +76 -9
  32. package/test/faustlive-wasm/faustwasm/index.js +270 -77
  33. package/test/faustlive-wasm/faustwasm/index.js.map +4 -4
  34. package/assets/standalone/coi-serviceworker.js +0 -146
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.7.9",
3
+ "version": "0.8.0",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -0,0 +1,143 @@
1
+
2
+ /**
3
+ * Layout:
4
+ *
5
+ *
6
+ * invert-isAndroid (uint8)
7
+ * new-acc-data-available (uint8)
8
+ * new-gyr-data-available (uint8)
9
+ * empty (uint8)
10
+ *
11
+ * acc.x, acc.y, acc.z (f32)
12
+ *
13
+ * gyr.alpha, gyr.beta, gyr.gamma (f32)
14
+ */
15
+ export class FaustAudioWorkletCommunicator {
16
+ protected readonly port: MessagePort;
17
+ protected readonly supportSharedArrayBuffer: boolean;
18
+ protected readonly byteLength: number;
19
+ protected uin8Invert: Uint8ClampedArray;
20
+ protected uin8NewAccData: Uint8ClampedArray;
21
+ protected uin8NewGyrData: Uint8ClampedArray;
22
+ protected f32Acc: Float32Array;
23
+ protected f32Gyr: Float32Array;
24
+ constructor(port: MessagePort) {
25
+ this.port = port;
26
+ this.supportSharedArrayBuffer = !!globalThis.SharedArrayBuffer;
27
+ this.byteLength
28
+ = 4 * Uint8Array.BYTES_PER_ELEMENT
29
+ + 3 * Float32Array.BYTES_PER_ELEMENT
30
+ + 3 * Float32Array.BYTES_PER_ELEMENT;
31
+ }
32
+ initializeBuffer(ab: SharedArrayBuffer | ArrayBuffer) {
33
+ let ptr = 0;
34
+ this.uin8Invert = new Uint8ClampedArray(ab, ptr, 1);
35
+ ptr += Uint8ClampedArray.BYTES_PER_ELEMENT;
36
+ this.uin8NewAccData = new Uint8ClampedArray(ab, ptr, 1);
37
+ ptr += Uint8ClampedArray.BYTES_PER_ELEMENT;
38
+ this.uin8NewGyrData = new Uint8ClampedArray(ab, ptr, 1);
39
+ ptr += Uint8ClampedArray.BYTES_PER_ELEMENT;
40
+ ptr += Uint8ClampedArray.BYTES_PER_ELEMENT;; // empty
41
+ this.f32Acc = new Float32Array(ab, ptr, 3);
42
+ ptr += 3 * Float32Array.BYTES_PER_ELEMENT;
43
+ this.f32Gyr = new Float32Array(ab, ptr, 3);
44
+ ptr += 3 * Float32Array.BYTES_PER_ELEMENT;
45
+ }
46
+ setNewAccDataAvailable(value: boolean) {
47
+ if (!this.uin8NewAccData) return;
48
+ this.uin8NewAccData[0] = +value;
49
+ }
50
+ getNewAccDataAvailable() {
51
+ return !!this.uin8NewAccData?.[0];
52
+ }
53
+ setNewGyrDataAvailable(value: boolean) {
54
+ if (!this.uin8NewGyrData) return;
55
+ this.uin8NewGyrData[0] = +value;
56
+ }
57
+ getNewGyrDataAvailable() {
58
+ return !!this.uin8NewGyrData?.[0];
59
+ }
60
+ setAcc({ x, y, z }: { x: number, y: number, z: number }, invert = false) {
61
+ if (!this.supportSharedArrayBuffer) {
62
+ const e = { type: "acc", data: { x, y, z }, invert };
63
+ this.port.postMessage(e);
64
+ }
65
+ if (!this.uin8NewAccData) return;
66
+ this.uin8Invert[0] = +invert;
67
+ this.f32Acc[0] = x;
68
+ this.f32Acc[1] = y;
69
+ this.f32Acc[2] = z;
70
+ this.uin8NewAccData[0] = 1;
71
+ }
72
+ getAcc() {
73
+ if (!this.uin8NewAccData) return;
74
+ const invert = !!this.uin8Invert[0];
75
+ const [x, y, z] = this.f32Acc;
76
+ return { x, y, z, invert };
77
+ }
78
+ setGyr({ alpha, beta, gamma }: { alpha: number, beta: number, gamma: number }) {
79
+ if (!this.supportSharedArrayBuffer) {
80
+ const e = { type: "gyr", data: { alpha, beta, gamma } };
81
+ this.port.postMessage(e);
82
+ }
83
+ if (!this.uin8NewGyrData) return;
84
+ this.f32Gyr[0] = alpha;
85
+ this.f32Gyr[1] = beta;
86
+ this.f32Gyr[2] = gamma;
87
+ this.uin8NewGyrData[0] = 1;
88
+ }
89
+ getGyr() {
90
+ if (!this.uin8NewGyrData) return;
91
+ const [alpha, beta, gamma] = this.f32Gyr;
92
+ return { alpha, beta, gamma };
93
+ }
94
+ }
95
+
96
+ export class FaustAudioWorkletNodeCommunicator extends FaustAudioWorkletCommunicator {
97
+ constructor(port: MessagePort) {
98
+ super(port);
99
+ if (this.supportSharedArrayBuffer) {
100
+ const sab = new SharedArrayBuffer(this.byteLength);
101
+ this.initializeBuffer(sab);
102
+ this.port.postMessage({ type: "initSab", sab });
103
+ } else {
104
+ const ab = new ArrayBuffer(this.byteLength);
105
+ this.initializeBuffer(ab);
106
+ }
107
+ }
108
+ }
109
+
110
+ export class FaustAudioWorkletProcessorCommunicator extends FaustAudioWorkletCommunicator {
111
+ constructor(port: MessagePort) {
112
+ super(port);
113
+
114
+ if (this.supportSharedArrayBuffer) {
115
+ this.port.addEventListener("message", (event) => {
116
+ const { data } = event;
117
+ if (data.type === "initSab") {
118
+ this.initializeBuffer(data.sab);
119
+ }
120
+ });
121
+ } else {
122
+ const ab = new ArrayBuffer(this.byteLength);
123
+ this.initializeBuffer(ab);
124
+ this.port.addEventListener("message", (event) => {
125
+ const msg = event.data;
126
+
127
+ switch (msg.type) {
128
+ // Sensors messages
129
+ case "acc": {
130
+ this.setAcc(msg.data, msg.invert);
131
+ break;
132
+ }
133
+ case "gyr": {
134
+ this.setGyr(msg.data);
135
+ break;
136
+ }
137
+ default:
138
+ break;
139
+ }
140
+ });
141
+ }
142
+ }
143
+ }
@@ -1,6 +1,7 @@
1
1
  import { OutputParamHandler, ComputeHandler, PlotHandler, UIHandler, MetadataHandler, FaustBaseWebAudioDsp, IFaustMonoWebAudioDsp, IFaustPolyWebAudioDsp } from "./FaustWebAudioDsp";
2
2
  import type { FaustAudioWorkletNodeOptions } from "./FaustAudioWorkletProcessor";
3
3
  import type { LooseFaustDspFactory, FaustDspMeta, FaustUIInputItem, FaustUIItem } from "./types";
4
+ import { FaustAudioWorkletNodeCommunicator } from "./FaustAudioWorkletCommunicator";
4
5
 
5
6
  /**
6
7
  * Base class for Monophonic and Polyphonic AudioWorkletNode
@@ -15,6 +16,7 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
15
16
  protected fPlotHandler: PlotHandler | null;
16
17
  protected fUICallback: UIHandler;
17
18
  protected fDescriptor: FaustUIInputItem[];
19
+ protected fCommunicator: FaustAudioWorkletNodeCommunicator;
18
20
  #hasAccInput = false;
19
21
  #hasGyrInput = false;
20
22
 
@@ -60,17 +62,20 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
60
62
 
61
63
  FaustBaseWebAudioDsp.parseUI(this.fJSONDsp.ui, this.fUICallback);
62
64
 
65
+ this.fCommunicator = new FaustAudioWorkletNodeCommunicator(this.port);
66
+
63
67
  // Patch it with additional functions
64
- this.port.onmessage = (e: MessageEvent) => {
65
- if (e.data.type === "param" && this.fOutputHandler) {
66
- this.fOutputHandler(e.data.path, e.data.value);
67
- } else if (e.data.type === "plot" && this.fPlotHandler) {
68
- this.fPlotHandler(e.data.value, e.data.index, e.data.events);
69
- }
70
- };
68
+ this.port.addEventListener("message", this.handleMessageAux);
69
+ this.port.start();
71
70
  }
72
71
 
73
- // Public API
72
+ protected handleMessageAux = (e: MessageEvent) => {
73
+ if (e.data.type === "param" && this.fOutputHandler) {
74
+ this.fOutputHandler(e.data.path, e.data.value);
75
+ } else if (e.data.type === "plot" && this.fPlotHandler) {
76
+ this.fPlotHandler(e.data.value, e.data.index, e.data.events);
77
+ }
78
+ };
74
79
 
75
80
  // Accelerometer and gyroscope handlers
76
81
  private handleDeviceMotion = ({ accelerationIncludingGravity }: DeviceMotionEvent) => {
@@ -84,6 +89,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
84
89
  this.propagateGyr({ alpha, beta, gamma });
85
90
  };
86
91
 
92
+ // Public API
93
+
87
94
  /** Setup accelerometer and gyroscope handlers */
88
95
  async startSensors() {
89
96
  if (this.hasAccInput) {
@@ -140,6 +147,7 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
140
147
  window.removeEventListener("deviceorientation", this.handleDeviceOrientation, true);
141
148
  }
142
149
  }
150
+
143
151
  setOutputParamHandler(handler: OutputParamHandler | null) {
144
152
  this.fOutputHandler = handler;
145
153
  }
@@ -166,6 +174,7 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
166
174
  getPlotHandler(): PlotHandler | null {
167
175
  return this.fPlotHandler;
168
176
  }
177
+
169
178
  setupWamEventHandler() {
170
179
  this.port.postMessage({ type: "setupWamEventHandler" });
171
180
  }
@@ -208,17 +217,19 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
208
217
  }
209
218
 
210
219
  get hasAccInput() { return this.#hasAccInput; }
220
+
211
221
  propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
212
222
  if (!accelerationIncludingGravity) return;
213
- const e = { type: "acc", data: accelerationIncludingGravity, invert: invert };
214
- this.port.postMessage(e);
223
+ const { x, y, z } = accelerationIncludingGravity;
224
+ this.fCommunicator.setAcc({ x: x!, y: y!, z: z! }, invert);
215
225
  }
216
226
 
217
227
  get hasGyrInput() { return this.#hasGyrInput; }
228
+
218
229
  propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
219
230
  if (!event) return;
220
- const e = { type: "gyr", data: event };
221
- this.port.postMessage(e);
231
+ const { alpha, beta, gamma } = event;
232
+ this.fCommunicator.setGyr({ alpha: alpha!, beta: beta!, gamma: gamma! });
222
233
  }
223
234
 
224
235
  setParamValue(path: string, value: number) {
@@ -1,3 +1,4 @@
1
+ import type { FaustAudioWorkletProcessorCommunicator } from "./FaustAudioWorkletCommunicator";
1
2
  import type FaustWasmInstantiator from "./FaustWasmInstantiator";
2
3
  import type { FaustBaseWebAudioDsp, FaustWebAudioDspVoice, FaustMonoWebAudioDsp, FaustPolyWebAudioDsp } from "./FaustWebAudioDsp";
3
4
  import type { AudioParamDescriptor, AudioWorkletGlobalScope, LooseFaustDspFactory, FaustDspMeta, FaustUIItem } from "./types";
@@ -19,6 +20,7 @@ export interface FaustAudioWorkletProcessorDependencies<Poly extends boolean = f
19
20
  FaustPolyWebAudioDsp: Poly extends true ? typeof FaustPolyWebAudioDsp : undefined;
20
21
  FaustWebAudioDspVoice: Poly extends true ? typeof FaustWebAudioDspVoice : undefined;
21
22
  FaustWasmInstantiator: typeof FaustWasmInstantiator;
23
+ FaustAudioWorkletProcessorCommunicator: typeof FaustAudioWorkletProcessorCommunicator;
22
24
  }
23
25
  export interface FaustAudioWorkletNodeOptions<Poly extends boolean = false> extends AudioWorkletNodeOptions {
24
26
  processorOptions: Poly extends true ? FaustPolyAudioWorkletProcessorOptions : FaustMonoAudioWorkletProcessorOptions;
@@ -52,7 +54,8 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
52
54
 
53
55
  const {
54
56
  FaustBaseWebAudioDsp,
55
- FaustWasmInstantiator
57
+ FaustWasmInstantiator,
58
+ FaustAudioWorkletProcessorCommunicator
56
59
  } = dependencies;
57
60
 
58
61
  const {
@@ -79,7 +82,7 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
79
82
  /**
80
83
  * Base class for Monophonic and Polyphonic AudioWorkletProcessor
81
84
  */
82
- class FaustAudioWorkletProcessor<Poly extends boolean = false> extends AudioWorkletProcessor {
85
+ abstract class FaustAudioWorkletProcessor<Poly extends boolean = false> extends AudioWorkletProcessor {
83
86
 
84
87
  // Use ! syntax when the field is not defined in the constructor
85
88
  protected fDSPCode!: Poly extends true ? FaustPolyWebAudioDsp : FaustMonoWebAudioDsp;
@@ -87,18 +90,19 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
87
90
  protected paramValuesCache: Record<string, number> = {};
88
91
 
89
92
  protected wamInfo?: { moduleId: string; instanceId: string };
93
+ protected fCommunicator: FaustAudioWorkletProcessorCommunicator;
90
94
 
91
95
  constructor(options: FaustAudioWorkletNodeOptions<Poly>) {
92
96
  super(options);
93
97
 
94
98
  // Setup port message handling
95
- this.port.onmessage = (e: MessageEvent) => this.handleMessageAux(e);
99
+ this.fCommunicator = new FaustAudioWorkletProcessorCommunicator(this.port);
96
100
 
97
101
  const { parameterDescriptors } = (this.constructor as typeof AudioWorkletProcessor);
98
102
  parameterDescriptors.forEach((pd) => {
99
103
  this.paramValuesCache[pd.name] = pd.defaultValue || 0;
100
104
  })
101
-
105
+
102
106
  const { moduleId, instanceId } = options.processorOptions;
103
107
  if (!moduleId || !instanceId) return;
104
108
  this.wamInfo = { moduleId, instanceId };
@@ -120,7 +124,7 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
120
124
  setupWamEventHandler() {
121
125
  if (!this.wamInfo) return;
122
126
  const { moduleId, instanceId } = this.wamInfo;
123
- const { webAudioModules } = (globalThis as unknown as WamAudioWorkletGlobalScope);
127
+ const { webAudioModules } = (globalThis as unknown as WamAudioWorkletGlobalScope);
124
128
  const ModuleScope = webAudioModules.getModuleScope(moduleId) as WamParamMgrSDKBaseModuleScope;
125
129
  const paramMgrProcessor = ModuleScope?.paramMgrProcessors?.[instanceId];
126
130
  if (!paramMgrProcessor) return;
@@ -140,6 +144,21 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
140
144
  this.paramValuesCache[path] = paramValue;
141
145
  }
142
146
  }
147
+ if (this.fCommunicator.getNewAccDataAvailable()) {
148
+ const acc = this.fCommunicator.getAcc();
149
+ if (acc) {
150
+ this.fCommunicator.setNewAccDataAvailable(false);
151
+ const { invert, ...data } = acc;
152
+ this.propagateAcc(data, invert);
153
+ }
154
+ }
155
+ if (this.fCommunicator.getNewGyrDataAvailable()) {
156
+ const gyr = this.fCommunicator.getGyr();
157
+ if (gyr) {
158
+ this.fCommunicator.setNewGyrDataAvailable(false);
159
+ this.propagateGyr(gyr);
160
+ }
161
+ }
143
162
 
144
163
  return this.fDSPCode.compute(inputs[0], outputs[0]);
145
164
  }
@@ -148,15 +167,6 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
148
167
  const msg = e.data;
149
168
 
150
169
  switch (msg.type) {
151
- // Sensors messages
152
- case "acc": {
153
- this.propagateAcc(msg.data, msg.invert);
154
- break;
155
- }
156
- case "gyr": {
157
- this.propagateGyr(msg.data);
158
- break;
159
- }
160
170
  // Generic MIDI message
161
171
  case "midi": {
162
172
  this.midiMessage(msg.data);
@@ -248,11 +258,19 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
248
258
  // Create Monophonic DSP
249
259
  this.fDSPCode = new FaustMonoWebAudioDsp(instance, sampleRate, sampleSize, 128, factory.soundfiles);
250
260
 
261
+ // Setup port message handling
262
+ this.port.addEventListener("message", this.handleMessageAux);
263
+ this.port.start();
264
+
251
265
  // Setup output handler
252
266
  this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
253
267
 
254
268
  this.fDSPCode.start();
255
269
  }
270
+
271
+ protected handleMessageAux = (e: MessageEvent) => { // use arrow function for binding
272
+ super.handleMessageAux(e);
273
+ }
256
274
  }
257
275
 
258
276
  /**
@@ -273,7 +291,8 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
273
291
  this.fDSPCode = new FaustPolyWebAudioDsp(instance, sampleRate, sampleSize, 128, soundfiles);
274
292
 
275
293
  // Setup port message handling
276
- this.port.onmessage = (e: MessageEvent) => this.handleMessageAux(e);
294
+ this.port.addEventListener("message", this.handleMessageAux);
295
+ this.port.start();
277
296
 
278
297
  // Setup output handler
279
298
  this.fDSPCode.setOutputParamHandler((path, value) => this.port.postMessage({ path, value, type: "param" }));
@@ -10,6 +10,7 @@ import SoundfileReader from "./SoundfileReader";
10
10
  import FaustSensors from "./FaustSensors";
11
11
  import type { IFaustCompiler } from "./FaustCompiler";
12
12
  import type { FaustDspFactory, FaustUIDescriptor, FaustDspMeta, FFTUtils, LooseFaustDspFactory, AudioData } from "./types";
13
+ import { FaustAudioWorkletCommunicator, FaustAudioWorkletProcessorCommunicator } from "./FaustAudioWorkletCommunicator";
13
14
 
14
15
 
15
16
  export interface GeneratorSupportingSoundfiles {
@@ -294,11 +295,16 @@ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
294
295
  var WasmAllocator = ${WasmAllocator.name};
295
296
  var ${FaustSensors.name} = ${FaustSensors.toString()}
296
297
  var FaustSensors = ${FaustSensors.name};
298
+ var ${FaustAudioWorkletCommunicator.name} = ${FaustAudioWorkletCommunicator.toString()}
299
+ var FaustAudioWorkletCommunicator = ${FaustAudioWorkletCommunicator.name};
300
+ var ${FaustAudioWorkletProcessorCommunicator.name} = ${FaustAudioWorkletProcessorCommunicator.toString()}
301
+ var FaustAudioWorkletProcessorCommunicator = ${FaustAudioWorkletProcessorCommunicator.name};
297
302
  // Put them in dependencies
298
303
  const dependencies = {
299
304
  FaustBaseWebAudioDsp,
300
305
  FaustMonoWebAudioDsp,
301
- FaustWasmInstantiator
306
+ FaustWasmInstantiator,
307
+ FaustAudioWorkletProcessorCommunicator
302
308
  };
303
309
  // Generate the actual AudioWorkletProcessor code
304
310
  (${getFaustAudioWorkletProcessor.toString()})(dependencies, faustData);
@@ -361,12 +367,17 @@ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
361
367
  var WasmAllocator = ${WasmAllocator.name};
362
368
  var ${FaustSensors.name} = ${FaustSensors.toString()}
363
369
  var FaustSensors = ${FaustSensors.name};
370
+ var ${FaustAudioWorkletCommunicator.name} = ${FaustAudioWorkletCommunicator.toString()}
371
+ var FaustAudioWorkletCommunicator = ${FaustAudioWorkletCommunicator.name};
372
+ var ${FaustAudioWorkletProcessorCommunicator.name} = ${FaustAudioWorkletProcessorCommunicator.toString()}
373
+ var FaustAudioWorkletProcessorCommunicator = ${FaustAudioWorkletProcessorCommunicator.name};
364
374
  var FFTUtils = ${fftUtils.toString()}
365
375
  // Put them in dependencies
366
376
  const dependencies = {
367
377
  FaustBaseWebAudioDsp,
368
378
  FaustMonoWebAudioDsp,
369
379
  FaustWasmInstantiator,
380
+ FaustAudioWorkletProcessorCommunicator,
370
381
  FFTUtils
371
382
  };
372
383
  // Generate the actual AudioWorkletProcessor code
@@ -415,6 +426,7 @@ const dependencies = {
415
426
  FaustBaseWebAudioDsp,
416
427
  FaustMonoWebAudioDsp,
417
428
  FaustWasmInstantiator,
429
+ FaustAudioWorkletProcessorCommunicator,
418
430
  FaustPolyWebAudioDsp: undefined,
419
431
  FaustWebAudioDspVoice: undefined,
420
432
  }
@@ -631,11 +643,16 @@ var ${WasmAllocator.name} = ${WasmAllocator.toString()}
631
643
  var WasmAllocator = ${WasmAllocator.name};
632
644
  var ${FaustSensors.name} = ${FaustSensors.toString()}
633
645
  var FaustSensors = ${FaustSensors.name};
646
+ var ${FaustAudioWorkletCommunicator.name} = ${FaustAudioWorkletCommunicator.toString()}
647
+ var FaustAudioWorkletCommunicator = ${FaustAudioWorkletCommunicator.name};
648
+ var ${FaustAudioWorkletProcessorCommunicator.name} = ${FaustAudioWorkletProcessorCommunicator.toString()}
649
+ var FaustAudioWorkletProcessorCommunicator = ${FaustAudioWorkletProcessorCommunicator.name};
634
650
  // Put them in dependencies
635
651
  const dependencies = {
636
652
  FaustBaseWebAudioDsp,
637
653
  FaustPolyWebAudioDsp,
638
- FaustWasmInstantiator
654
+ FaustWasmInstantiator,
655
+ FaustAudioWorkletProcessorCommunicator
639
656
  };
640
657
  // Generate the actual AudioWorkletProcessor code
641
658
  (${getFaustAudioWorkletProcessor.toString()})(dependencies, faustData);
@@ -676,6 +693,7 @@ const dependencies = {
676
693
  FaustWasmInstantiator,
677
694
  FaustPolyWebAudioDsp,
678
695
  FaustWebAudioDspVoice,
696
+ FaustAudioWorkletProcessorCommunicator
679
697
  };
680
698
  // DSP name and JSON string for DSP are generated
681
699
  const faustData = {
@@ -1,3 +1,4 @@
1
+ import type { FaustAudioWorkletProcessorCommunicator } from "./FaustAudioWorkletCommunicator";
1
2
  import type { FaustMonoDspInstance } from "./FaustDspInstance";
2
3
  import type FaustWasmInstantiator from "./FaustWasmInstantiator";
3
4
  import type { FaustBaseWebAudioDsp, FaustMonoWebAudioDsp, PlotHandler } from "./FaustWebAudioDsp";
@@ -25,6 +26,7 @@ export interface FaustFFTAudioWorkletProcessorDependencies {
25
26
  FaustBaseWebAudioDsp: typeof FaustBaseWebAudioDsp;
26
27
  FaustMonoWebAudioDsp: typeof FaustMonoWebAudioDsp;
27
28
  FaustWasmInstantiator: typeof FaustWasmInstantiator;
29
+ FaustAudioWorkletProcessorCommunicator: typeof FaustAudioWorkletProcessorCommunicator;
28
30
  FFTUtils: typeof FFTUtils;
29
31
  }
30
32
  export interface FaustFFTAudioWorkletNodeOptions extends AudioWorkletNodeOptions {
@@ -48,6 +50,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
48
50
  FaustBaseWebAudioDsp,
49
51
  FaustWasmInstantiator,
50
52
  FaustMonoWebAudioDsp,
53
+ FaustAudioWorkletProcessorCommunicator,
51
54
  FFTUtils
52
55
  } = dependencies;
53
56
 
@@ -127,6 +130,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
127
130
  protected paramValuesCache: Record<string, number> = {};
128
131
 
129
132
  protected wamInfo?: { moduleId: string; instanceId: string };
133
+ protected communicator: FaustAudioWorkletProcessorCommunicator;
130
134
 
131
135
  private dspInstance!: FaustMonoDspInstance;
132
136
  private sampleSize!: number;
@@ -178,7 +182,9 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
178
182
  super(options);
179
183
 
180
184
  // Setup port message handling
181
- this.port.onmessage = (e: MessageEvent) => this.handleMessageAux(e);
185
+ this.port.addEventListener("message", this.handleMessageAux);
186
+ this.port.start();
187
+ this.communicator = new FaustAudioWorkletProcessorCommunicator(this.port);
182
188
 
183
189
  const { parameterDescriptors } = (this.constructor as typeof AudioWorkletProcessor);
184
190
  parameterDescriptors.forEach((pd) => {
@@ -360,6 +366,21 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
360
366
  this.paramValuesCache[path] = paramValue;
361
367
  }
362
368
  }
369
+ if (this.communicator.getNewAccDataAvailable()) {
370
+ const acc = this.communicator.getAcc();
371
+ if (acc) {
372
+ this.communicator.setNewAccDataAvailable(false);
373
+ const { invert, ...data } = acc;
374
+ this.propagateAcc(data, invert);
375
+ }
376
+ }
377
+ if (this.communicator.getNewGyrDataAvailable()) {
378
+ const gyr = this.communicator.getGyr();
379
+ if (gyr) {
380
+ this.communicator.setNewGyrDataAvailable(false);
381
+ this.propagateGyr(gyr);
382
+ }
383
+ }
363
384
 
364
385
  // Write audio input into fftInput buffer, advance pointers
365
386
  if (input?.length) {
@@ -400,7 +421,7 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
400
421
  return true;
401
422
  }
402
423
 
403
- protected handleMessageAux(e: MessageEvent) { // use arrow function for binding
424
+ protected handleMessageAux = (e: MessageEvent) => { // use arrow function for binding
404
425
  const msg = e.data;
405
426
 
406
427
  switch (msg.type) {
@@ -462,6 +483,14 @@ const getFaustFFTAudioWorkletProcessor = (dependencies: FaustFFTAudioWorkletProc
462
483
  this.fDSPCode?.pitchWheel(channel, wheel);
463
484
  }
464
485
 
486
+ protected propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
487
+ this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
488
+ }
489
+
490
+ protected propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
491
+ this.fDSPCode.propagateGyr(event);
492
+ }
493
+
465
494
  resetFFT(sizeIn: number, overlapIn: number, windowFunctionIn: number, inputChannels: number, outputChannels: number, bufferSize: number) {
466
495
  const fftSize = ~~ceil(Math.max(2, sizeIn || 1024), 2);
467
496
  const fftOverlap = ~~Math.min(fftSize, Math.max(1, overlapIn));
@@ -82,15 +82,21 @@ export class FaustOfflineProcessor<Poly extends boolean = false> {
82
82
  destroy() { this.fDSPCode.destroy(); }
83
83
 
84
84
  get hasAccInput() { return this.fDSPCode.hasAccInput; }
85
+
85
86
  propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
86
87
  this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
87
88
  }
88
89
 
89
90
  get hasGyrInput() { return this.fDSPCode.hasGyrInput; }
91
+
90
92
  propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
91
93
  this.fDSPCode.propagateGyr(event);
92
94
  }
93
95
 
96
+ startSensors(): void { }
97
+
98
+ stopSensors(): void { }
99
+
94
100
  /**
95
101
  * Render frames in an array.
96
102
  *
@@ -50,7 +50,7 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
50
50
 
51
51
  // Public API
52
52
 
53
- /** Setup accelerometer and gyroscope handlers */
53
+ /** Start accelerometer and gyroscope handlers */
54
54
  async startSensors() {
55
55
  if (this.hasAccInput) {
56
56
  if (window.DeviceMotionEvent) {
@@ -98,6 +98,7 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
98
98
  }
99
99
  }
100
100
 
101
+ /** Stop accelerometer and gyroscope handlers */
101
102
  stopSensors() {
102
103
  if (this.hasAccInput) {
103
104
  window.removeEventListener("devicemotion", this.handleDeviceMotion, true);
@@ -143,11 +144,13 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
143
144
  destroy() { this.fDSPCode.destroy(); }
144
145
 
145
146
  get hasAccInput() { return this.fDSPCode.hasAccInput; }
147
+
146
148
  propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
147
149
  this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
148
150
  }
149
151
 
150
152
  get hasGyrInput() { return this.fDSPCode.hasGyrInput; }
153
+
151
154
  propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
152
155
  this.fDSPCode.propagateGyr(event);
153
156
  }
@@ -496,6 +496,35 @@ export interface IFaustBaseWebAudioDsp {
496
496
  */
497
497
  getJSON(): string;
498
498
 
499
+ /**
500
+ * Start accelerometer and gyroscope handlers.
501
+ */
502
+ startSensors(): void;
503
+
504
+ /**
505
+ * Stop accelerometer and gyroscope handlers.
506
+ */
507
+ stopSensors(): void;
508
+
509
+ /** Indicating if the DSP handles the accelerometer */
510
+ readonly hasAccInput: boolean;
511
+
512
+ /**
513
+ * Accelerometer handling.
514
+ * accelerationIncludingGravity: DeviceMotionEvent["accelerationIncludingGravity"]
515
+ * invert: boolean
516
+ */
517
+ propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean): void;
518
+
519
+ /** Indicating if the DSP handles the gyroscope */
520
+ readonly hasGyrInput: boolean;
521
+
522
+ /**
523
+ * Gyroscope handling.
524
+ * event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">
525
+ */
526
+ propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
527
+
499
528
  /**
500
529
  * Start the DSP audio processing.
501
530
  */
@@ -510,16 +539,6 @@ export interface IFaustBaseWebAudioDsp {
510
539
  * Destroy the DSP.
511
540
  */
512
541
  destroy(): void;
513
-
514
- /** Indicating if the DSP handles the accelerometer */
515
- readonly hasAccInput: boolean;
516
- /** Accelerometer handling */
517
- propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean): void;
518
-
519
- /** Indicating if the DSP handles the gyroscope */
520
- readonly hasGyrInput: boolean;
521
- /** Gyroscope handling */
522
- propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
523
542
  }
524
543
 
525
544
  export interface IFaustMonoWebAudioDsp extends IFaustBaseWebAudioDsp { }
@@ -984,6 +1003,14 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
984
1003
 
985
1004
  hasSoundfiles() { return this.fSoundfiles.length > 0; }
986
1005
 
1006
+ startSensors(): void {
1007
+ this.startSensors();
1008
+ }
1009
+
1010
+ stopSensors(): void {
1011
+ this.stopSensors();
1012
+ }
1013
+
987
1014
  start() {
988
1015
  this.fProcessing = true;
989
1016
  }
@@ -998,6 +1025,7 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
998
1025
  this.fComputeHandler = null;
999
1026
  this.fPlotHandler = null;
1000
1027
  }
1028
+
1001
1029
  }
1002
1030
 
1003
1031
  export class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaustMonoWebAudioDsp {