@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.
- package/README.md +2 -2
- package/assets/standalone/create-node.js +31 -1
- package/assets/standalone/faust-ui/index.js +2 -2
- package/assets/standalone/faust-ui/index.js.map +1 -1
- package/assets/standalone/faustwasm/index.d.ts +76 -9
- package/assets/standalone/faustwasm/index.js +272 -107
- package/assets/standalone/faustwasm/index.js.map +4 -4
- package/assets/standalone/index-pwa.js +132 -98
- package/assets/standalone/index-template.js +44 -23
- package/assets/standalone/index.js +95 -80
- package/assets/standalone/service-worker.js +47 -8
- package/dist/cjs/index.d.ts +76 -9
- package/dist/cjs/index.js +272 -107
- package/dist/cjs/index.js.map +4 -4
- package/dist/cjs-bundle/index.d.ts +76 -9
- package/dist/cjs-bundle/index.js +272 -107
- package/dist/cjs-bundle/index.js.map +4 -4
- package/dist/esm/index.d.ts +76 -9
- package/dist/esm/index.js +272 -107
- package/dist/esm/index.js.map +4 -4
- package/dist/esm-bundle/index.d.ts +76 -9
- package/dist/esm-bundle/index.js +272 -107
- package/dist/esm-bundle/index.js.map +4 -4
- package/package.json +2 -2
- package/src/FaustAudioWorkletCommunicator.ts +143 -0
- package/src/FaustAudioWorkletNode.ts +27 -42
- package/src/FaustAudioWorkletProcessor.ts +34 -15
- package/src/FaustDspGenerator.ts +20 -2
- package/src/FaustFFTAudioWorkletProcessor.ts +31 -2
- package/src/FaustOfflineProcessor.ts +6 -0
- package/src/FaustScriptProcessorNode.ts +8 -31
- package/src/FaustWebAudioDsp.ts +38 -10
- package/test/faustlive-wasm/faust-ui/index.js +2 -2
- package/test/faustlive-wasm/faust-ui/index.js.map +1 -1
- package/test/faustlive-wasm/faustwasm/index.d.ts +76 -9
- package/test/faustlive-wasm/faustwasm/index.js +272 -107
- package/test/faustlive-wasm/faustwasm/index.js.map +4 -4
- 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.
|
|
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.
|
|
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.
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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
|
|
214
|
-
this.
|
|
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
|
|
221
|
-
this.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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" }));
|
package/src/FaustDspGenerator.ts
CHANGED
|
@@ -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.
|
|
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
|
*
|