@grame/faustwasm 0.3.1 → 0.4.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.
- package/README.md +10 -4
- package/assets/standalone/faustwasm/index.d.ts +11 -5
- package/assets/standalone/faustwasm/index.js +71 -30
- package/assets/standalone/faustwasm/index.js.map +2 -2
- package/assets/standalone/icon.png +0 -0
- package/assets/standalone/index-poly.js +11 -0
- package/assets/standalone/index.html +4 -2
- package/assets/standalone/index.js +11 -0
- package/assets/standalone/manifest.json +18 -0
- package/assets/standalone/service-worker.js +48 -0
- package/dist/cjs/index.d.ts +11 -5
- package/dist/cjs/index.js +71 -30
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs-bundle/index.d.ts +11 -5
- package/dist/cjs-bundle/index.js +71 -30
- package/dist/cjs-bundle/index.js.map +2 -2
- package/dist/esm/index.d.ts +11 -5
- package/dist/esm/index.js +71 -30
- package/dist/esm/index.js.map +2 -2
- package/dist/esm-bundle/index.d.ts +11 -5
- package/dist/esm-bundle/index.js +71 -30
- package/dist/esm-bundle/index.js.map +2 -2
- package/package.json +1 -1
- package/src/FaustAudioWorkletNode.ts +17 -8
- package/src/FaustAudioWorkletProcessor.ts +3 -3
- package/src/FaustOfflineProcessor.ts +4 -4
- package/src/FaustScriptProcessorNode.ts +17 -7
- package/src/FaustWebAudioDsp.ts +13 -6
- package/src/SoundfileReader.ts +16 -2
- package/src/copyWebStandaloneAssets.js +11 -1
- package/test/faustlive-wasm/faustwasm/index.d.ts +11 -5
- package/test/faustlive-wasm/faustwasm/index.js +71 -30
- package/test/faustlive-wasm/faustwasm/index.js.map +2 -2
- package/test/osc2.dsp +1 -1
- package/build +0 -18
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ The FaustWasm library presents a convenient, high-level API that wraps around [F
|
|
|
4
4
|
|
|
5
5
|
The library offers functionality for compiling Faust DSP code into WebAssembly, enabling its utilization as WebAudio nodes within a standard WebAudio node graph. Moreover, it supports offline rendering scenarios. Furthermore, supplementary tools can be employed for generating SVGs from Faust DSP programs.
|
|
6
6
|
|
|
7
|
+
Synthesizer and effect mono nodes, as well as [polyphonic](https://faustdoc.grame.fr/manual/midi/#midi-polyphony-support) poly nodes can be created. MIDI support is activated as soon as [MIDI metadata](https://faustdoc.grame.fr/manual/midi/#configuring-midi-in-faust) are used in the DSP code for mono nodes, and always in polyphonic mode.
|
|
8
|
+
|
|
9
|
+
[Sensors](https://faustdoc.grame.fr/manual/syntax/#sensors-control-metadatas) (accelerometer and gyroscope) are supported, as well as the [Progressive Web Application](https://en.wikipedia.org/wiki/Progressive_web_app) model.
|
|
10
|
+
|
|
7
11
|
## Usage
|
|
8
12
|
|
|
9
13
|
Please use a stable version of [Node.js](https://nodejs.org) 16+ to work with this project.
|
|
@@ -55,21 +59,23 @@ node scripts/faust2wasm.js test/poly.dsp test/out -poly
|
|
|
55
59
|
```
|
|
56
60
|
will create a set of files: `poly.js`, `poly.wasm`, `poly.json`, `poly.html` (and possibly `poly_effect.wasm`, `poly_effect.json`) in the `out` folder.
|
|
57
61
|
|
|
58
|
-
You can create a standalone
|
|
62
|
+
You can create a standalone Progressive Web Application using the same command line:
|
|
59
63
|
|
|
60
64
|
```bash
|
|
61
65
|
rm -rf test/out # make sure you are under the faustwasm directory.
|
|
62
66
|
node scripts/faust2wasm.js test/rev.dsp test/out -standalone
|
|
63
67
|
```
|
|
64
|
-
will create a set of files: `rev.js`, `rev.wasm`, `rev.json`, `
|
|
68
|
+
will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `rev.js`, `rev.wasm`, `rev.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `out` folder.
|
|
69
|
+
|
|
70
|
+
The folder contains the necessary ressources to deploy the Faust application as a PWA on a server, to be installed and used offline. Note that audio files used by the `soundfile` primitives in the DSP code will have to be mannually added in the folder.
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
A standalone polyphonic and MIDI standalone Progressive Web Application can be created with:
|
|
67
73
|
|
|
68
74
|
```bash
|
|
69
75
|
rm -rf test/out # make sure you are under the faustwasm directory.
|
|
70
76
|
node scripts/faust2wasm.js test/organ1.dsp test/out -standalone
|
|
71
77
|
```
|
|
72
|
-
will create a set of files: `organ1.js`, `organ1.wasm`, `organ1.json`, `organ1_effect.wasm`, `organ1_effect.json`, `
|
|
78
|
+
will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `organ1.js`, `organ1.wasm`, `organ1.json`, `organ1_effect.wasm`, `organ1_effect.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `out` folder.
|
|
73
79
|
|
|
74
80
|
#### Generate SVG Diagrams of a Faust DSP
|
|
75
81
|
|
|
@@ -635,7 +635,7 @@ export interface IFaustBaseWebAudioDsp {
|
|
|
635
635
|
/** Indicating if the DSP handles the accelerometer */
|
|
636
636
|
readonly hasAccInput: boolean;
|
|
637
637
|
/** Accelerometer handling */
|
|
638
|
-
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]
|
|
638
|
+
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean): void;
|
|
639
639
|
/** Indicating if the DSP handles the gyroscope */
|
|
640
640
|
readonly hasGyrInput: boolean;
|
|
641
641
|
/** Gyroscope handling */
|
|
@@ -724,7 +724,7 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
|
|
|
724
724
|
/** Split the soundfile names and return an array of names */
|
|
725
725
|
static splitSoundfileNames(input: string): string[];
|
|
726
726
|
get hasAccInput(): boolean;
|
|
727
|
-
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]
|
|
727
|
+
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
|
|
728
728
|
get hasGyrInput(): boolean;
|
|
729
729
|
propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
|
|
730
730
|
/** Build the accelerometer handler */
|
|
@@ -1123,7 +1123,7 @@ export declare class FaustOfflineProcessor<Poly extends boolean = false> {
|
|
|
1123
1123
|
stop(): void;
|
|
1124
1124
|
destroy(): void;
|
|
1125
1125
|
get hasAccInput(): boolean;
|
|
1126
|
-
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]
|
|
1126
|
+
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
|
|
1127
1127
|
get hasGyrInput(): boolean;
|
|
1128
1128
|
propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
|
|
1129
1129
|
/**
|
|
@@ -1211,6 +1211,12 @@ export declare class WavDecoder {
|
|
|
1211
1211
|
/** Read metadata and fetch soundfiles */
|
|
1212
1212
|
export declare class SoundfileReader {
|
|
1213
1213
|
static get fallbackPaths(): string[];
|
|
1214
|
+
/**
|
|
1215
|
+
* Extract the parent URL from an URL.
|
|
1216
|
+
* @param url : the URL
|
|
1217
|
+
* @returns : the parent URL
|
|
1218
|
+
*/
|
|
1219
|
+
private static getParentUrl;
|
|
1214
1220
|
/**
|
|
1215
1221
|
* Convert an audio buffer to audio data.
|
|
1216
1222
|
*
|
|
@@ -1293,7 +1299,7 @@ export declare class FaustAudioWorkletNode<Poly extends boolean = false> extends
|
|
|
1293
1299
|
ctrlChange(channel: number, ctrl: number, value: number): void;
|
|
1294
1300
|
pitchWheel(channel: number, wheel: number): void;
|
|
1295
1301
|
get hasAccInput(): boolean;
|
|
1296
|
-
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]
|
|
1302
|
+
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
|
|
1297
1303
|
get hasGyrInput(): boolean;
|
|
1298
1304
|
propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
|
|
1299
1305
|
setParamValue(path: string, value: number): void;
|
|
@@ -1366,7 +1372,7 @@ export declare class FaustScriptProcessorNode<Poly extends boolean = false> exte
|
|
|
1366
1372
|
stop(): void;
|
|
1367
1373
|
destroy(): void;
|
|
1368
1374
|
get hasAccInput(): boolean;
|
|
1369
|
-
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]
|
|
1375
|
+
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
|
|
1370
1376
|
get hasGyrInput(): boolean;
|
|
1371
1377
|
propagateGyr(event: Pick<DeviceOrientationEvent, "alpha" | "beta" | "gamma">): void;
|
|
1372
1378
|
}
|
|
@@ -138,7 +138,7 @@ var getFaustAudioWorkletProcessor = (dependencies, faustData, register = true) =
|
|
|
138
138
|
const msg = e.data;
|
|
139
139
|
switch (msg.type) {
|
|
140
140
|
case "acc": {
|
|
141
|
-
this.propagateAcc(msg.data);
|
|
141
|
+
this.propagateAcc(msg.data, msg.invert);
|
|
142
142
|
break;
|
|
143
143
|
}
|
|
144
144
|
case "gyr": {
|
|
@@ -199,8 +199,8 @@ var getFaustAudioWorkletProcessor = (dependencies, faustData, register = true) =
|
|
|
199
199
|
pitchWheel(channel, wheel) {
|
|
200
200
|
this.fDSPCode.pitchWheel(channel, wheel);
|
|
201
201
|
}
|
|
202
|
-
propagateAcc(accelerationIncludingGravity) {
|
|
203
|
-
this.fDSPCode.propagateAcc(accelerationIncludingGravity);
|
|
202
|
+
propagateAcc(accelerationIncludingGravity, invert = false) {
|
|
203
|
+
this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
|
|
204
204
|
}
|
|
205
205
|
propagateGyr(event) {
|
|
206
206
|
this.fDSPCode.propagateGyr(event);
|
|
@@ -2103,14 +2103,23 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
|
|
|
2103
2103
|
get hasAccInput() {
|
|
2104
2104
|
return this.fAcc.x.length + this.fAcc.y.length + this.fAcc.z.length > 0;
|
|
2105
2105
|
}
|
|
2106
|
-
propagateAcc(accelerationIncludingGravity) {
|
|
2106
|
+
propagateAcc(accelerationIncludingGravity, invert = false) {
|
|
2107
2107
|
const { x, y, z } = accelerationIncludingGravity;
|
|
2108
|
-
if (
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2108
|
+
if (invert) {
|
|
2109
|
+
if (x !== null)
|
|
2110
|
+
this.fAcc.x.forEach((handler) => handler(-x));
|
|
2111
|
+
if (y !== null)
|
|
2112
|
+
this.fAcc.y.forEach((handler) => handler(-y));
|
|
2113
|
+
if (z !== null)
|
|
2114
|
+
this.fAcc.z.forEach((handler) => handler(-z));
|
|
2115
|
+
} else {
|
|
2116
|
+
if (x !== null)
|
|
2117
|
+
this.fAcc.x.forEach((handler) => handler(x));
|
|
2118
|
+
if (y !== null)
|
|
2119
|
+
this.fAcc.y.forEach((handler) => handler(y));
|
|
2120
|
+
if (z !== null)
|
|
2121
|
+
this.fAcc.z.forEach((handler) => handler(z));
|
|
2122
|
+
}
|
|
2114
2123
|
}
|
|
2115
2124
|
get hasGyrInput() {
|
|
2116
2125
|
return this.fGyr.x.length + this.fGyr.y.length + this.fGyr.z.length > 0;
|
|
@@ -2970,8 +2979,8 @@ var FaustOfflineProcessor = class {
|
|
|
2970
2979
|
get hasAccInput() {
|
|
2971
2980
|
return this.fDSPCode.hasAccInput;
|
|
2972
2981
|
}
|
|
2973
|
-
propagateAcc(accelerationIncludingGravity) {
|
|
2974
|
-
this.fDSPCode.propagateAcc(accelerationIncludingGravity);
|
|
2982
|
+
propagateAcc(accelerationIncludingGravity, invert = false) {
|
|
2983
|
+
this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
|
|
2975
2984
|
}
|
|
2976
2985
|
get hasGyrInput() {
|
|
2977
2986
|
return this.fDSPCode.hasGyrInput;
|
|
@@ -3487,8 +3496,17 @@ var WavDecoder_default = WavDecoder;
|
|
|
3487
3496
|
|
|
3488
3497
|
// src/SoundfileReader.ts
|
|
3489
3498
|
var SoundfileReader = class {
|
|
3499
|
+
// Set the fallback paths
|
|
3490
3500
|
static get fallbackPaths() {
|
|
3491
|
-
return [location.href, location.origin];
|
|
3501
|
+
return [location.href, this.getParentUrl(location.href), location.origin];
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Extract the parent URL from an URL.
|
|
3505
|
+
* @param url : the URL
|
|
3506
|
+
* @returns : the parent URL
|
|
3507
|
+
*/
|
|
3508
|
+
static getParentUrl(url) {
|
|
3509
|
+
return url.substring(0, url.lastIndexOf("/") + 1);
|
|
3492
3510
|
}
|
|
3493
3511
|
/**
|
|
3494
3512
|
* Convert an audio buffer to audio data.
|
|
@@ -3529,7 +3547,8 @@ var SoundfileReader = class {
|
|
|
3529
3547
|
static async checkFileExists(url) {
|
|
3530
3548
|
try {
|
|
3531
3549
|
console.log(`"checkFileExists" url: ${url}`);
|
|
3532
|
-
const response = await fetch(url
|
|
3550
|
+
const response = await fetch(url);
|
|
3551
|
+
console.log(`"checkFileExists" response.ok: ${response.ok}`);
|
|
3533
3552
|
return response.ok;
|
|
3534
3553
|
} catch (error) {
|
|
3535
3554
|
console.error("Fetch error:", error);
|
|
@@ -3649,12 +3668,23 @@ var FaustAudioWorkletNode = class extends (globalThis.AudioWorkletNode || null)
|
|
|
3649
3668
|
/** Setup accelerometer and gyroscope handlers */
|
|
3650
3669
|
async listenSensors() {
|
|
3651
3670
|
if (this.hasAccInput) {
|
|
3652
|
-
const
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3671
|
+
const isAndroid = /Android/i.test(navigator.userAgent);
|
|
3672
|
+
let handleDeviceMotion = null;
|
|
3673
|
+
if (isAndroid) {
|
|
3674
|
+
handleDeviceMotion = ({ accelerationIncludingGravity }) => {
|
|
3675
|
+
if (!accelerationIncludingGravity)
|
|
3676
|
+
return;
|
|
3677
|
+
const { x, y, z } = accelerationIncludingGravity;
|
|
3678
|
+
this.propagateAcc({ x, y, z }, true);
|
|
3679
|
+
};
|
|
3680
|
+
} else {
|
|
3681
|
+
handleDeviceMotion = ({ accelerationIncludingGravity }) => {
|
|
3682
|
+
if (!accelerationIncludingGravity)
|
|
3683
|
+
return;
|
|
3684
|
+
const { x, y, z } = accelerationIncludingGravity;
|
|
3685
|
+
this.propagateAcc({ x, y, z });
|
|
3686
|
+
};
|
|
3687
|
+
}
|
|
3658
3688
|
if (window.DeviceMotionEvent) {
|
|
3659
3689
|
if (typeof window.DeviceMotionEvent.requestPermission === "function") {
|
|
3660
3690
|
try {
|
|
@@ -3755,10 +3785,10 @@ var FaustAudioWorkletNode = class extends (globalThis.AudioWorkletNode || null)
|
|
|
3755
3785
|
get hasAccInput() {
|
|
3756
3786
|
return __privateGet(this, _hasAccInput);
|
|
3757
3787
|
}
|
|
3758
|
-
propagateAcc(accelerationIncludingGravity) {
|
|
3788
|
+
propagateAcc(accelerationIncludingGravity, invert = false) {
|
|
3759
3789
|
if (!accelerationIncludingGravity)
|
|
3760
3790
|
return;
|
|
3761
|
-
const e = { type: "acc", data: accelerationIncludingGravity };
|
|
3791
|
+
const e = { type: "acc", data: accelerationIncludingGravity, invert };
|
|
3762
3792
|
this.port.postMessage(e);
|
|
3763
3793
|
}
|
|
3764
3794
|
get hasGyrInput() {
|
|
@@ -3907,12 +3937,23 @@ var FaustScriptProcessorNode = class extends (globalThis.ScriptProcessorNode ||
|
|
|
3907
3937
|
/** Setup accelerometer and gyroscope handlers */
|
|
3908
3938
|
async listenSensors() {
|
|
3909
3939
|
if (this.hasAccInput) {
|
|
3910
|
-
const
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3940
|
+
const isAndroid = /Android/i.test(navigator.userAgent);
|
|
3941
|
+
let handleDeviceMotion = null;
|
|
3942
|
+
if (isAndroid) {
|
|
3943
|
+
handleDeviceMotion = ({ accelerationIncludingGravity }) => {
|
|
3944
|
+
if (!accelerationIncludingGravity)
|
|
3945
|
+
return;
|
|
3946
|
+
const { x, y, z } = accelerationIncludingGravity;
|
|
3947
|
+
this.propagateAcc({ x, y, z }, true);
|
|
3948
|
+
};
|
|
3949
|
+
} else {
|
|
3950
|
+
handleDeviceMotion = ({ accelerationIncludingGravity }) => {
|
|
3951
|
+
if (!accelerationIncludingGravity)
|
|
3952
|
+
return;
|
|
3953
|
+
const { x, y, z } = accelerationIncludingGravity;
|
|
3954
|
+
this.propagateAcc({ x, y, z });
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3916
3957
|
if (window.DeviceMotionEvent) {
|
|
3917
3958
|
if (typeof window.DeviceMotionEvent.requestPermission === "function") {
|
|
3918
3959
|
try {
|
|
@@ -4023,8 +4064,8 @@ var FaustScriptProcessorNode = class extends (globalThis.ScriptProcessorNode ||
|
|
|
4023
4064
|
get hasAccInput() {
|
|
4024
4065
|
return this.fDSPCode.hasAccInput;
|
|
4025
4066
|
}
|
|
4026
|
-
propagateAcc(accelerationIncludingGravity) {
|
|
4027
|
-
this.fDSPCode.propagateAcc(accelerationIncludingGravity);
|
|
4067
|
+
propagateAcc(accelerationIncludingGravity, invert = false) {
|
|
4068
|
+
this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
|
|
4028
4069
|
}
|
|
4029
4070
|
get hasGyrInput() {
|
|
4030
4071
|
return this.fDSPCode.hasGyrInput;
|