@grame/faustwasm 0.4.10 → 0.5.1

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 CHANGED
@@ -59,17 +59,34 @@ node scripts/faust2wasm.js test/poly.dsp test/out -poly
59
59
  ```
60
60
  will create a set of files: `index.js`, `dsp-module.wasm`, `dsp-meta.json`, `index.html` (and possibly `effect-module.wasm`, `effect-meta.json`) in the `out` folder.
61
61
 
62
-
63
- #### Creating a Progressive Web Application of a Faust DSP
62
+ #### Creating a Progressive Web Application (PWA) of a Faust DSP
64
63
 
65
64
  You can create a standalone Progressive Web Application using the same command line:
66
65
 
66
+ ```bash
67
+ node scripts/faust2wasm.js test/rev.dsp test/rev -pwa
68
+ ```
69
+ will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `index.js`, `dsp-module.wasm`, `dsp-meta.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `rev` folder.
70
+
71
+ 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.
72
+
73
+ A standalone polyphonic and MIDI standalone Progressive Web Application can be created with:
74
+
75
+ ```bash
76
+ node scripts/faust2wasm.js test/organ1.dsp test/organ1 -poly -pwa
77
+ ```
78
+ will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `index.js`, `dsp-module.wasm`, `dsp-meta.json`, `effect-module.wasm`, `effect-meta.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `organ1` folder.
79
+
80
+ #### Creating a standalone version of a Faust DSP, with audio and MIDI devices selector
81
+
82
+ You can create a standalone using the same command line:
83
+
67
84
  ```bash
68
85
  node scripts/faust2wasm.js test/rev.dsp test/rev -standalone
69
86
  ```
70
87
  will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `index.js`, `dsp-module.wasm`, `dsp-meta.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `rev` folder.
71
88
 
72
- 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. To test, be sure to launch a local web server at the `test` folder level, then go inside `test\rev` folder.
89
+ 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.
73
90
 
74
91
  A standalone polyphonic and MIDI standalone Progressive Web Application can be created with:
75
92
 
@@ -78,8 +95,6 @@ node scripts/faust2wasm.js test/organ1.dsp test/organ1 -poly -standalone
78
95
  ```
79
96
  will create a set of files: `icon.png`, `service-worker.js`, `manifest.json`, `index.js`, `dsp-module.wasm`, `dsp-meta.json`, `effect-module.wasm`, `effect-meta.json`, `index.html`, and the `faustwasm`, `faust-ui` folders in the `organ1` folder.
80
97
 
81
- To test, be sure to launch a local web server at the `test` folder level, then go inside `test\organ1` folder.
82
-
83
98
  #### Generate SVG Diagrams of a Faust DSP
84
99
 
85
100
  For example:
@@ -75,4 +75,31 @@ const createFaustNode = async (audioContext, dspName = "template", voices = 0, s
75
75
  return { faustNode, dspMeta };
76
76
  }
77
77
 
78
- export default createFaustNode;
78
+ /**
79
+ * Connects an audio input stream to a Faust audio node.
80
+ *
81
+ * @param {AudioContext} audioContext - The Web Audio API AudioContext to which the Faust audio node is connected.
82
+ * @param {string} id - The ID of the audio input device to connect.
83
+ * @param {FaustNode} faustNode - The Faust audio node to which the audio input stream will be connected.
84
+ * @param {MediaStreamAudioSourceNode} inputStreamNode - The audio input stream node to be connected to the Faust audio node.
85
+ * @returns {Promise<MediaStreamAudioSourceNode>} - The audio input stream node connected to the Faust audio node.
86
+ */
87
+ async function connectToAudioInput(audioContext, id, faustNode, inputStreamNode) {
88
+ const constraints = {
89
+ audio: {
90
+ echoCancellation: false,
91
+ noiseSuppression: false,
92
+ autoGainControl: false,
93
+ deviceId: id ? { exact: id } : undefined,
94
+ },
95
+ };
96
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
97
+ if (stream) {
98
+ if (inputStreamNode) inputStreamNode.disconnect();
99
+ inputStreamNode = audioContext.createMediaStreamSource(stream);
100
+ inputStreamNode.connect(faustNode);
101
+ }
102
+ return inputStreamNode;
103
+ };
104
+
105
+ export { createFaustNode, connectToAudioInput };
@@ -0,0 +1,76 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <link rel="manifest" href="./manifest.json">
5
+
6
+ <head>
7
+ <meta charset="UTF-8">
8
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
10
+ <title>Faust DSP</title>
11
+ <style>
12
+ body {
13
+ color: #b0b0b0;
14
+ background-color: #1f1f1f;
15
+ display: flex;
16
+ top: 0;
17
+ left: 0;
18
+ width: 100%;
19
+ height: 100%;
20
+ margin: 0;
21
+ position: absolute;
22
+ }
23
+
24
+ main {
25
+ margin: 20px;
26
+ display: flex;
27
+ flex-direction: column;
28
+ flex: 1 1 100%;
29
+ }
30
+
31
+ main span {
32
+ position: relative;
33
+ display: flex;
34
+ }
35
+
36
+ main span[hidden] {
37
+ display: none;
38
+ }
39
+
40
+ main span span {
41
+ margin: 0px 10px;
42
+ flex: 1;
43
+ }
44
+
45
+ main span select {
46
+ flex: 2;
47
+ }
48
+
49
+ #dsp-switch {
50
+ margin: 20px auto;
51
+ }
52
+
53
+ #button-dsp {
54
+ padding: 10px;
55
+ }
56
+
57
+ #div-faust-ui {
58
+ flex: 1 1 auto;
59
+ display: flex;
60
+ position: relative;
61
+ flex-direction: column;
62
+ color: black;
63
+ }
64
+ </style>
65
+ <link rel="stylesheet" href="./faust-ui/index.css">
66
+ </head>
67
+
68
+ <body>
69
+ <main>
70
+ <div id="div-faust-ui">
71
+ </div>
72
+ </main>
73
+ <script src="./index.js"></script>
74
+ </body>
75
+
76
+ </html>
@@ -0,0 +1,139 @@
1
+ // Set to > 0 if the DSP is polyphonic
2
+ const FAUST_DSP_VOICES = 0;
3
+
4
+ /**
5
+ * @typedef {import("./faustwasm").FaustAudioWorkletNode} FaustAudioWorkletNode
6
+ * @typedef {import("./faustwasm").FaustDspMeta} FaustDspMeta
7
+ * @typedef {import("./faustwasm").FaustUIDescriptor} FaustUIDescriptor
8
+ * @typedef {import("./faustwasm").FaustUIGroup} FaustUIGroup
9
+ * @typedef {import("./faustwasm").FaustUIItem} FaustUIItem
10
+ */
11
+
12
+ /**
13
+ * Registers the service worker.
14
+ */
15
+ if ("serviceWorker" in navigator) {
16
+ window.addEventListener("load", () => {
17
+ navigator.serviceWorker.register("./service-worker.js")
18
+ .then(reg => console.log("Service Worker registered", reg))
19
+ .catch(err => console.log("Service Worker registration failed", err));
20
+ });
21
+ }
22
+
23
+ /** @type {HTMLDivElement} */
24
+ const $divFaustUI = document.getElementById("div-faust-ui");
25
+
26
+ /** @type {typeof AudioContext} */
27
+ const AudioCtx = window.AudioContext || window.webkitAudioContext;
28
+ const audioContext = new AudioCtx({ latencyHint: 0.00001 });
29
+ audioContext.destination.channelInterpretation = "discrete";
30
+ audioContext.suspend();
31
+
32
+ /**
33
+ * @param {FaustAudioWorkletNode} faustNode
34
+ */
35
+ const createFaustUI = async (faustNode) => {
36
+ const { FaustUI } = await import("./faust-ui/index.js");
37
+ const $container = document.createElement("div");
38
+ $container.style.margin = "0";
39
+ $container.style.position = "absolute";
40
+ $container.style.overflow = "auto";
41
+ $container.style.display = "flex";
42
+ $container.style.flexDirection = "column";
43
+ $container.style.width = "100%";
44
+ $container.style.height = "100%";
45
+ $divFaustUI.appendChild($container);
46
+ const faustUI = new FaustUI({
47
+ ui: faustNode.getUI(),
48
+ root: $container,
49
+ listenWindowMessage: false,
50
+ listenWindowResize: true,
51
+ });
52
+ faustUI.paramChangeByUI = (path, value) => faustNode.setParamValue(path, value);
53
+ faustNode.setOutputParamHandler((path, value) => faustUI.paramChangeByDSP(path, value));
54
+ $container.style.minWidth = `${faustUI.minWidth}px`;
55
+ $container.style.minHeight = `${faustUI.minHeight}px`;
56
+ faustUI.resize();
57
+ };
58
+
59
+ (async () => {
60
+
61
+ const { createFaustNode } = await import("./create-node.js");
62
+
63
+ // To test the ScriptProcessorNode mode
64
+ // const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES, true);
65
+ const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES);
66
+ if (!faustNode) throw new Error("Faust DSP not compiled");
67
+
68
+ // Create the Faust UI
69
+ await createFaustUI(faustNode);
70
+
71
+ // Connect the Faust node to the audio output
72
+ faustNode.connect(audioContext.destination);
73
+
74
+ // Connect the Faust node to the audio input
75
+ if (faustNode.getNumInputs() > 0) {
76
+ const { connectToAudioInput } = await import("./create-node.js");
77
+ await connectToAudioInput(audioContext, null, faustNode, null);
78
+ }
79
+
80
+ // Activate sensor listeners
81
+ await faustNode.listenSensors();
82
+
83
+ // Function to initialize MIDI
84
+ function initMIDI() {
85
+ // Check if the browser supports the Web MIDI API
86
+ if (navigator.requestMIDIAccess) {
87
+ navigator.requestMIDIAccess()
88
+ .then(onMIDISuccess, onMIDIFailure);
89
+ } else {
90
+ console.log("Web MIDI API is not supported in this browser.");
91
+ }
92
+ }
93
+
94
+ // Success callback for requesting MIDI access
95
+ function onMIDISuccess(midiAccess) {
96
+ console.log("MIDI Access obtained.");
97
+ // Iterate through all available MIDI inputs
98
+ for (let input of midiAccess.inputs.values()) {
99
+ // Attach the event listener to each input
100
+ input.onmidimessage = handleMIDIMessage;
101
+ console.log(`Connected to input: ${input.name}`);
102
+ }
103
+ }
104
+
105
+ // Failure callback for requesting MIDI access
106
+ function onMIDIFailure() {
107
+ console.error("Failed to access MIDI devices.");
108
+ }
109
+
110
+ // Dummy event handler for MIDI messages
111
+ function handleMIDIMessage(event) {
112
+ faustNode.midiMessage(event.data);
113
+ }
114
+
115
+ // Initialize the MIDI setup
116
+ if (FAUST_DSP_VOICES > 0) {
117
+ initMIDI();
118
+ }
119
+
120
+ })();
121
+
122
+ // Function to resume AudioContext on user interaction
123
+ function resumeAudioContext() {
124
+ if (audioContext.state === 'suspended') {
125
+ audioContext.resume();
126
+ }
127
+ }
128
+
129
+ // Add event listeners for user interactions
130
+ window.addEventListener('click', resumeAudioContext);
131
+ window.addEventListener('touchstart', resumeAudioContext);
132
+
133
+ // Optional: Remove event listeners once the context is resumed
134
+ audioContext.onstatechange = function () {
135
+ if (audioContext.state === 'running') {
136
+ window.removeEventListener('click', resumeAudioContext);
137
+ window.removeEventListener('touchstart', resumeAudioContext);
138
+ }
139
+ };
@@ -2,7 +2,7 @@
2
2
  const FAUST_DSP_VOICES = 0;
3
3
 
4
4
  (async () => {
5
- const { default: createFaustNode } = await import("./create-node.js");
5
+ const { createFaustNode } = await import("./create-node.js");
6
6
 
7
7
  // Create audio context
8
8
  const AudioCtx = window.AudioContext || window.webkitAudioContext;
@@ -37,12 +37,18 @@ const FAUST_DSP_VOICES = 0;
37
37
  const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES);
38
38
  if (!faustNode) throw new Error("Faust DSP not compiled");
39
39
 
40
- // Connect Faust node to audio context
40
+ // Connect the Faust node to the audio output
41
41
  faustNode.connect(audioContext.destination);
42
42
 
43
+ // Connect the Faust node to the audio input
44
+ if (faustNode.getNumInputs() > 0) {
45
+ const { connectToAudioInput } = await import("./create-node.js");
46
+ await connectToAudioInput(audioContext, null, faustNode, null);
47
+ }
48
+
43
49
  // Create Faust node activation button
44
50
  $buttonDsp.disabled = false;
45
-
51
+
46
52
  // Set page title to the DSP name
47
53
  document.title = name;
48
54
  })();
@@ -44,8 +44,10 @@ $buttonDsp.disabled = true;
44
44
  * @param {FaustAudioWorkletNode} faustNode
45
45
  */
46
46
  const buildAudioDeviceMenu = async (faustNode) => {
47
- /** @type {MediaStreamAudioSourceNode} */
48
- let inputStreamNode;
47
+
48
+ const { connectToAudioInput } = await import("./create-node.js");
49
+
50
+ let inputStreamNode = null;
49
51
  const handleDeviceChange = async () => {
50
52
  const devicesInfo = await navigator.mediaDevices.enumerateDevices();
51
53
  $selectAudioInput.innerHTML = "";
@@ -61,31 +63,14 @@ const buildAudioDeviceMenu = async (faustNode) => {
61
63
  navigator.mediaDevices.addEventListener("devicechange", handleDeviceChange)
62
64
  $selectAudioInput.onchange = async () => {
63
65
  const id = $selectAudioInput.value;
64
- const constraints = {
65
- audio: {
66
- echoCancellation: false,
67
- noiseSuppression: false,
68
- autoGainControl: false,
69
- deviceId: id ? { exact: id } : undefined,
70
- },
71
- };
72
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
73
- if (inputStreamNode) inputStreamNode.disconnect();
74
- inputStreamNode = audioContext.createMediaStreamSource(stream);
75
- inputStreamNode.connect(faustNode);
76
- };
77
-
78
- const defaultConstraints = {
79
- audio: {
80
- echoCancellation: false,
81
- mozNoiseSuppression: false,
82
- mozAutoGainControl: false
66
+ if (faustNode.getNumInputs() > 0) {
67
+ inputStreamNode = await connectToAudioInput(audioContext, id, faustNode, inputStreamNode);
83
68
  }
84
69
  };
85
- const defaultStream = await navigator.mediaDevices.getUserMedia(defaultConstraints);
86
- if (defaultStream) {
87
- inputStreamNode = audioContext.createMediaStreamSource(defaultStream);
88
- inputStreamNode.connect(faustNode);
70
+
71
+ // Connect to the default audio input device
72
+ if (faustNode.getNumInputs() > 0) {
73
+ inputStreamNode = await connectToAudioInput(audioContext, null, faustNode, inputStreamNode);
89
74
  }
90
75
  };
91
76
 
@@ -149,7 +134,7 @@ const createFaustUI = async (faustNode) => {
149
134
  };
150
135
 
151
136
  (async () => {
152
- const { default: createFaustNode } = await import("./create-node.js");
137
+ const { createFaustNode } = await import("./create-node.js");
153
138
  // To test the ScriptProcessorNode mode
154
139
  // const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES, true);
155
140
  const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES);
package/build ADDED
@@ -0,0 +1,25 @@
1
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/atomicro/atomicro.dsp /Users/letz/Developpements/sletz.github.io/atomicro -pwa
2
+
3
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/attackey/attackey.dsp /Users/letz/Developpements/sletz.github.io/attackey -pwa
4
+
5
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/baliphone/baliphone.dsp /Users/letz/Developpements/sletz.github.io/baliphone -pwa
6
+
7
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/drone/drone.dsp /Users/letz/Developpements/sletz.github.io/drone -pwa
8
+
9
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/sequenceur/sequenceur.dsp /Users/letz/Developpements/sletz.github.io/sequenceur -pwa
10
+
11
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/shakerxy/shakerxy.dsp /Users/letz/Developpements/sletz.github.io/shakerxy -pwa
12
+
13
+ node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/sinusoide/sinusoide.dsp /Users/letz/Developpements/sletz.github.io/sinusoide -pwa
14
+
15
+
16
+ #node scripts/faust2wasm.js /Users/letz/Developpements/GameLAN/test.dsp /Users/letz/Developpements/sletz.github.io/out -standalone
17
+ #node scripts/faust2wasm.js test/organ.dsp /Users/letz/Developpements/sletz.github.io/organ -poly -standalone
18
+
19
+ #node scripts/faust2wasm.js test/organ1.dsp /Users/letz/Developpements/sletz.github.io/organ1 -poly -standalone
20
+
21
+ #node scripts/faust2wasm.js test/osc2.dsp /Users/letz/Developpements/sletz.github.io/osc2 -standalone
22
+
23
+ #node scripts/faust2wasm.js /Users/letz/Developpements/faust-sampler/sampler.dsp /Users/letz/Developpements/sletz.github.io/sampler -poly -standalone
24
+
25
+ #node scripts/faust2wasm.js /Users/letz/Developpements/faust-sampler/piano.dsp /Users/letz/Developpements/sletz.github.io/piano -poly -standalone
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.4.10",
3
+ "version": "0.5.1",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -2,13 +2,13 @@
2
2
  //@ts-check
3
3
  import * as process from "process";
4
4
  import faust2wasmFiles from "../src/faust2wasmFiles.js";
5
- import { copyWebStandaloneAssets, copyWebTemplateAssets } from "../src/copyWebStandaloneAssets.js";
5
+ import { copyWebStandaloneAssets, copyWebPWAAssets, copyWebTemplateAssets } from "../src/copyWebStandaloneAssets.js";
6
6
 
7
7
  const argv = process.argv.slice(2);
8
8
 
9
9
  if (argv[0] === "-help" || argv[0] === "-h") {
10
10
  console.log(`
11
- faust2wasm.js <file.dsp> <outputDir> [-poly] [-standalone] [-no-template]
11
+ faust2wasm.js <file.dsp> <outputDir> [-poly] [-standalone] [-pwa] [-no-template]
12
12
  Generates WebAssembly and metadata JSON files of a given Faust DSP.
13
13
  `);
14
14
  process.exit();
@@ -22,6 +22,10 @@ const $standalone = argv.indexOf("-standalone");
22
22
  const standalone = $standalone !== -1;
23
23
  if (standalone) argv.splice($standalone, 1);
24
24
 
25
+ const $pwa = argv.indexOf("-pwa");
26
+ const pwa = $pwa !== -1;
27
+ if (pwa) argv.splice($pwa, 1);
28
+
25
29
  const $noTemplate = argv.indexOf("-no-template");
26
30
  const noTemplate = $noTemplate !== -1;
27
31
  if (noTemplate) argv.splice($noTemplate, 1);
@@ -35,6 +39,8 @@ const dspName = fileName.replace(/\.dsp$/, '');
35
39
  const { dspMeta, effectMeta } = await faust2wasmFiles(inputFile, outputDir, argvFaust, poly);
36
40
  if (standalone) {
37
41
  copyWebStandaloneAssets(outputDir, dspName, poly, !!effectMeta);
42
+ } else if (pwa) {
43
+ copyWebPWAAssets(outputDir, dspName, poly, !!effectMeta);
38
44
  } else if (!noTemplate) {
39
45
  copyWebTemplateAssets(outputDir, dspName, poly, !!effectMeta);
40
46
  }
@@ -1,4 +1,5 @@
1
1
  declare const copyWebStandaloneAssets: (outputDir: string, dspName: string, poly?: boolean, effect?: boolean) => void;
2
+ declare const copyWebPWAAssets: (outputDir: string, dspName: string, poly?: boolean, effect?: boolean) => void;
2
3
  declare const copyWebTemplateAssets: (outputDir: string, dspName: string, poly?: boolean, effect?: boolean) => void;
3
4
 
4
- export { copyWebStandaloneAssets, copyWebTemplateAssets };
5
+ export { copyWebStandaloneAssets, copyWebPWAAssets, copyWebTemplateAssets };
@@ -15,7 +15,6 @@ const __filename = fileURLToPath(import.meta.url);
15
15
  */
16
16
  const copyWebStandaloneAssets = (outputDir, dspName, poly = false, effect = false) => {
17
17
  console.log(`Writing assets files.`)
18
- const assetsPath = path.join(__dirname, "../assets/standalone");
19
18
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
20
19
 
21
20
  const findAndReplace = ["FAUST_DSP_NAME", dspName];
@@ -30,7 +29,6 @@ const copyWebStandaloneAssets = (outputDir, dspName, poly = false, effect = fals
30
29
  cpSyncModify(templateJSPath, outputDir + `/index.js`, ...findAndReplace);
31
30
 
32
31
  const templateHTMLPath = path.join(__dirname, "../assets/standalone/index.html");
33
- //cpSyncModify(templateHTMLPath, outputDir + `/${dspName}.html`, "FAUST_DSP_NAME", dspName);
34
32
  cpSyncModify(templateHTMLPath, outputDir + `/index.html`, ...findAndReplace);
35
33
 
36
34
  const templateWorkerPath = path.join(__dirname, "../assets/standalone/service-worker.js");
@@ -49,6 +47,45 @@ const copyWebStandaloneAssets = (outputDir, dspName, poly = false, effect = fals
49
47
  cpSyncModify(templateManifestPath, outputDir + `/manifest.json`, ...findAndReplace);
50
48
  };
51
49
 
50
+ /**
51
+ * @param {string} outputDir - The output directory.
52
+ * @param {string} dspName - The name of the DSP to be loaded.
53
+ * @param {boolean} [poly] - Whether the DSP is polyphonic.
54
+ * @param {boolean} [effect] - Whether the DSP has an effect module.
55
+ */
56
+ const copyWebPWAAssets = (outputDir, dspName, poly = false, effect = false) => {
57
+ console.log(`Writing assets files.`)
58
+ if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
59
+
60
+ const findAndReplace = ["FAUST_DSP_NAME", dspName];
61
+ if (poly) findAndReplace.push("FAUST_DSP_VOICES = 0", "FAUST_DSP_VOICES = 16");
62
+ if (poly && effect) findAndReplace.push("FAUST_DSP_HAS_EFFECT = false", "FAUST_DSP_HAS_EFFECT = true");
63
+
64
+ // Copy some files
65
+ const createNodeJSPath = path.join(__dirname, "../assets/standalone/create-node.js");
66
+ cpSyncModify(createNodeJSPath, outputDir + `/create-node.js`, ...findAndReplace);
67
+
68
+ const templateJSPath = path.join(__dirname, "../assets/standalone/index-pwa.js");
69
+ cpSyncModify(templateJSPath, outputDir + `/index.js`, ...findAndReplace);
70
+
71
+ const templateHTMLPath = path.join(__dirname, "../assets/standalone/index-pwa.html");
72
+ cpSyncModify(templateHTMLPath, outputDir + `/index.html`, ...findAndReplace);
73
+
74
+ const templateWorkerPath = path.join(__dirname, "../assets/standalone/service-worker.js");
75
+ cpSyncModify(templateWorkerPath, outputDir + `/service-worker.js`, ...findAndReplace);
76
+
77
+ const templateIconPath = path.join(__dirname, "../assets/standalone/icon.png");
78
+ cpSync(templateIconPath, outputDir + `/icon.png`);
79
+
80
+ const faustwasmPath = path.join(__dirname, "../assets/standalone/faustwasm");
81
+ cpSync(faustwasmPath, outputDir + "/faustwasm");
82
+
83
+ const faustuiPath = path.join(__dirname, "../assets/standalone/faust-ui");
84
+ cpSync(faustuiPath, outputDir + "/faust-ui");
85
+
86
+ const templateManifestPath = path.join(__dirname, "../assets/standalone/manifest.json");
87
+ cpSyncModify(templateManifestPath, outputDir + `/manifest.json`, ...findAndReplace);
88
+ };
52
89
  /**
53
90
  * @param {string} outputDir - The output directory.
54
91
  * @param {string} dspName - The name of the DSP to be loaded.
@@ -78,5 +115,5 @@ const copyWebTemplateAssets = (outputDir, dspName, poly = false, effect = false)
78
115
  cpSync(faustwasmPath, outputDir + "/faustwasm");
79
116
  };
80
117
 
81
- export { copyWebStandaloneAssets, copyWebTemplateAssets };
118
+ export { copyWebStandaloneAssets, copyWebPWAAssets, copyWebTemplateAssets };
82
119