@grame/faustwasm 0.7.10 → 0.8.2

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 (38) hide show
  1. package/README.md +2 -2
  2. package/assets/standalone/create-node.js +31 -1
  3. package/assets/standalone/faust-ui/index.js +2 -2
  4. package/assets/standalone/faust-ui/index.js.map +1 -1
  5. package/assets/standalone/faustwasm/index.d.ts +76 -9
  6. package/assets/standalone/faustwasm/index.js +272 -107
  7. package/assets/standalone/faustwasm/index.js.map +4 -4
  8. package/assets/standalone/index-pwa.js +132 -98
  9. package/assets/standalone/index-template.js +44 -23
  10. package/assets/standalone/index.js +95 -80
  11. package/assets/standalone/service-worker.js +47 -8
  12. package/dist/cjs/index.d.ts +76 -9
  13. package/dist/cjs/index.js +272 -107
  14. package/dist/cjs/index.js.map +4 -4
  15. package/dist/cjs-bundle/index.d.ts +76 -9
  16. package/dist/cjs-bundle/index.js +272 -107
  17. package/dist/cjs-bundle/index.js.map +4 -4
  18. package/dist/esm/index.d.ts +76 -9
  19. package/dist/esm/index.js +272 -107
  20. package/dist/esm/index.js.map +4 -4
  21. package/dist/esm-bundle/index.d.ts +76 -9
  22. package/dist/esm-bundle/index.js +272 -107
  23. package/dist/esm-bundle/index.js.map +4 -4
  24. package/package.json +2 -2
  25. package/src/FaustAudioWorkletCommunicator.ts +143 -0
  26. package/src/FaustAudioWorkletNode.ts +27 -42
  27. package/src/FaustAudioWorkletProcessor.ts +34 -15
  28. package/src/FaustDspGenerator.ts +20 -2
  29. package/src/FaustFFTAudioWorkletProcessor.ts +31 -2
  30. package/src/FaustOfflineProcessor.ts +6 -0
  31. package/src/FaustScriptProcessorNode.ts +8 -31
  32. package/src/FaustWebAudioDsp.ts +38 -10
  33. package/test/faustlive-wasm/faust-ui/index.js +2 -2
  34. package/test/faustlive-wasm/faust-ui/index.js.map +1 -1
  35. package/test/faustlive-wasm/faustwasm/index.d.ts +76 -9
  36. package/test/faustlive-wasm/faustwasm/index.js +272 -107
  37. package/test/faustlive-wasm/faustwasm/index.js.map +4 -4
  38. package/assets/standalone/coi-serviceworker.js +0 -146
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.7.10",
3
+ "version": "0.8.2",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -39,7 +39,7 @@
39
39
  "homepage": "https://github.com/grame-cncm/faustwasm#readme",
40
40
  "devDependencies": {
41
41
  "@aws-crypto/sha256-js": "^5.2.0",
42
- "@shren/faust-ui": "^1.1.13",
42
+ "@shren/faust-ui": "^1.1.16",
43
43
  "@types/node": "^20.12.7",
44
44
  "@types/webmidi": "^2.0.10",
45
45
  "@webaudiomodules/api": "^2.0.0-alpha.6",
@@ -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,25 +89,14 @@ 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) {
90
97
  if (window.DeviceMotionEvent) {
91
- if (typeof (window.DeviceMotionEvent as any).requestPermission === "function") { // for iOS 13+
92
- try {
93
- const response = await (window.DeviceMotionEvent as any).requestPermission();
94
- if (response === "granted") {
95
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
96
- } else if (response === "denied") {
97
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
98
- throw new Error("Unable to access the accelerometer.");
99
- }
100
- } catch (error) {
101
- console.error(error);
102
- }
103
- } else {
104
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
105
- }
98
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
99
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
106
100
  } else {
107
101
  // Browser doesn't support DeviceMotionEvent
108
102
  console.log("Cannot set the accelerometer handler.");
@@ -110,21 +104,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
110
104
  }
111
105
  if (this.hasGyrInput) {
112
106
  if (window.DeviceMotionEvent) {
113
- if (typeof (window.DeviceOrientationEvent as any).requestPermission === "function") { // for iOS 13+
114
- try {
115
- const response = await (window.DeviceOrientationEvent as any).requestPermission();
116
- if (response === "granted") {
117
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
118
- } else if (response === "denied") {
119
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
120
- throw new Error("Unable to access the gyroscope.");
121
- }
122
- } catch (error) {
123
- console.error(error);
124
- }
125
- } else {
126
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
127
- }
107
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
108
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
128
109
  } else {
129
110
  // Browser doesn't support DeviceMotionEvent
130
111
  console.log("Cannot set the gyroscope handler.");
@@ -140,6 +121,7 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
140
121
  window.removeEventListener("deviceorientation", this.handleDeviceOrientation, true);
141
122
  }
142
123
  }
124
+
143
125
  setOutputParamHandler(handler: OutputParamHandler | null) {
144
126
  this.fOutputHandler = handler;
145
127
  }
@@ -166,6 +148,7 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
166
148
  getPlotHandler(): PlotHandler | null {
167
149
  return this.fPlotHandler;
168
150
  }
151
+
169
152
  setupWamEventHandler() {
170
153
  this.port.postMessage({ type: "setupWamEventHandler" });
171
154
  }
@@ -208,17 +191,19 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
208
191
  }
209
192
 
210
193
  get hasAccInput() { return this.#hasAccInput; }
194
+
211
195
  propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
212
196
  if (!accelerationIncludingGravity) return;
213
- const e = { type: "acc", data: accelerationIncludingGravity, invert: invert };
214
- this.port.postMessage(e);
197
+ const { x, y, z } = accelerationIncludingGravity;
198
+ this.fCommunicator.setAcc({ x: x!, y: y!, z: z! }, invert);
215
199
  }
216
200
 
217
201
  get hasGyrInput() { return this.#hasGyrInput; }
202
+
218
203
  propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">) {
219
204
  if (!event) return;
220
- const e = { type: "gyr", data: event };
221
- this.port.postMessage(e);
205
+ const { alpha, beta, gamma } = event;
206
+ this.fCommunicator.setGyr({ alpha: alpha!, beta: beta!, gamma: gamma! });
222
207
  }
223
208
 
224
209
  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
  *