@grame/faustwasm 0.7.3 → 0.7.4

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.
Binary file
@@ -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,149 @@
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
+ (async () => {
33
+
34
+ const { createFaustNode } = await import("./create-node.js");
35
+ // To test the ScriptProcessorNode mode
36
+ //const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES, true, 512);
37
+ const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES);
38
+ if (!faustNode) throw new Error("Faust DSP not compiled");
39
+
40
+ // Create the Faust UI
41
+ const { createFaustUI } = await import("./create-node.js");
42
+ await createFaustUI($divFaustUI, faustNode);
43
+
44
+ // Connect the Faust node to the audio output
45
+ faustNode.connect(audioContext.destination);
46
+
47
+ // Connect the Faust node to the audio input
48
+ if (faustNode.numberOfInputs > 0) {
49
+ const { connectToAudioInput } = await import("./create-node.js");
50
+ await connectToAudioInput(audioContext, null, faustNode, null);
51
+ }
52
+
53
+ // Function to start MIDI
54
+ function startMIDI() {
55
+ // Check if the browser supports the Web MIDI API
56
+ if (navigator.requestMIDIAccess) {
57
+ navigator.requestMIDIAccess().then(
58
+ midiAccess => {
59
+ console.log("MIDI Access obtained.");
60
+ for (let input of midiAccess.inputs.values()) {
61
+ input.onmidimessage = (event) => faustNode.midiMessage(event.data);
62
+ console.log(`Connected to input: ${input.name}`);
63
+ }
64
+ },
65
+ () => console.error("Failed to access MIDI devices.")
66
+ );
67
+ } else {
68
+ console.log("Web MIDI API is not supported in this browser.");
69
+ }
70
+ }
71
+
72
+ // Function to stop MIDI
73
+ function stopMIDI() {
74
+ // Check if the browser supports the Web MIDI API
75
+ if (navigator.requestMIDIAccess) {
76
+ navigator.requestMIDIAccess().then(
77
+ midiAccess => {
78
+ console.log("MIDI Access obtained.");
79
+ for (let input of midiAccess.inputs.values()) {
80
+ input.onmidimessage = null;
81
+ console.log(`Disconnected from input: ${input.name}`);
82
+ }
83
+ },
84
+ () => console.error("Failed to access MIDI devices.")
85
+ );
86
+ } else {
87
+ console.log("Web MIDI API is not supported in this browser.");
88
+ }
89
+ }
90
+
91
+ let sensorHandlersBound = false;
92
+ let midiHandlersBound = false;
93
+
94
+ // Function to resume AudioContext, activate MIDI and Sensors on user interaction
95
+ async function activateAudioMIDISensors() {
96
+
97
+ // Resume the AudioContext
98
+ if (audioContext.state === 'suspended') {
99
+ await audioContext.resume();
100
+ }
101
+
102
+ // Activate sensor listeners
103
+ if (!sensorHandlersBound) {
104
+ await faustNode.startSensors();
105
+ sensorHandlersBound = true;
106
+ }
107
+
108
+ // Initialize the MIDI setup
109
+ if (!midiHandlersBound && FAUST_DSP_VOICES > 0) {
110
+ startMIDI();
111
+ midiHandlersBound = true;
112
+ }
113
+ }
114
+
115
+ // Function to suspend AudioContext, deactivate MIDI and Sensors on user interaction
116
+ async function deactivateAudioMIDISensors() {
117
+
118
+ // Suspend the AudioContext
119
+ if (audioContext.state === 'running') {
120
+ await audioContext.suspend();
121
+ }
122
+
123
+ // Deactivate sensor listeners
124
+ if (sensorHandlersBound) {
125
+ faustNode.stopSensors();
126
+ sensorHandlersBound = false;
127
+ }
128
+
129
+ // Deactivate the MIDI setup
130
+ if (midiHandlersBound && FAUST_DSP_VOICES > 0) {
131
+ stopMIDI();
132
+ midiHandlersBound = false;
133
+ }
134
+ }
135
+
136
+ // Add event listeners for user interactions
137
+
138
+ // Activate AudioContext, MIDI and Sensors on user interaction
139
+ window.addEventListener('click', activateAudioMIDISensors);
140
+ window.addEventListener('touchstart', activateAudioMIDISensors);
141
+
142
+ // Deactivate AudioContext, MIDI and Sensors on user interaction
143
+ window.addEventListener('visibilitychange', function () {
144
+ if (window.visibilityState === 'hidden') {
145
+ deactivateAudioMIDISensors();
146
+ }
147
+ });
148
+
149
+ })();
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Faust max_bug",
3
+ "short_name": "max_bug",
4
+ "start_url": "./index.html",
5
+ "description": "Progressive Web App for max_bug",
6
+ "display": "standalone",
7
+ "background_color": "#ffffff",
8
+ "theme_color": "#000000",
9
+ "orientation": "portrait",
10
+ "icons": [
11
+ {
12
+ "src": "./icon.png",
13
+ "sizes": "390x390",
14
+ "type": "image/png"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,73 @@
1
+ /// <reference lib="webworker" />
2
+
3
+ // Set to > 0 if the DSP is polyphonic
4
+ const FAUST_DSP_VOICES = 0;
5
+ // Set to true if the DSP has an effect
6
+ const FAUST_DSP_HAS_EFFECT = false;
7
+
8
+ const CACHE_NAME = "max_bug-static"; // Cache name without versioning
9
+
10
+ const MONO_RESOURCES = [
11
+ "./index.html",
12
+ "./index.js",
13
+ "./create-node.js",
14
+ "./faust-ui/index.js",
15
+ "./faust-ui/index.css",
16
+ "./faustwasm/index.js",
17
+ "./dsp-module.wasm",
18
+ "./dsp-meta.json"
19
+ ];
20
+
21
+ const POLY_RESOURCES = [
22
+ ...MONO_RESOURCES,
23
+ "./mixer-module.wasm",
24
+ ];
25
+
26
+ const POLY_EFFECT_RESOURCES = [
27
+ ...POLY_RESOURCES,
28
+ "./effect-module.wasm",
29
+ "./effect-meta.json",
30
+ ];
31
+
32
+ /**@type {ServiceWorkerGlobalScope} */
33
+ const serviceWorkerGlobalScope = self;
34
+
35
+ /**
36
+ * Install the service worker and cache the resources
37
+ */
38
+ serviceWorkerGlobalScope.addEventListener("install", (event) => {
39
+ console.log("Service worker installed");
40
+ event.waitUntil((async () => {
41
+ const cache = await caches.open(CACHE_NAME);
42
+ const resources = (FAUST_DSP_VOICES && FAUST_DSP_HAS_EFFECT) ? POLY_EFFECT_RESOURCES : FAUST_DSP_VOICES ? POLY_RESOURCES : MONO_RESOURCES;
43
+ try {
44
+ return cache.addAll(resources);
45
+ } catch (error) {
46
+ console.error("Failed to cache resources during install:", error);
47
+ }
48
+ })());
49
+ });
50
+
51
+ serviceWorkerGlobalScope.addEventListener("activate", () => console.log("Service worker activated"));
52
+
53
+ serviceWorkerGlobalScope.addEventListener("fetch", (event) => {
54
+ event.respondWith((async () => {
55
+ const cache = await caches.open(CACHE_NAME);
56
+ const cachedResponse = await cache.match(event.request);
57
+ if (cachedResponse) {
58
+ return cachedResponse;
59
+ } else {
60
+ try {
61
+ const fetchResponse = await fetch(event.request);
62
+ // Ensure the response is valid before caching it
63
+ if (event.request.method === "GET" && fetchResponse && fetchResponse.status === 200 && fetchResponse.type === "basic") {
64
+ cache.put(event.request, fetchResponse.clone());
65
+ }
66
+ return fetchResponse;
67
+ } catch (e) {
68
+ // Network access failure
69
+ console.log("Network access error", e);
70
+ }
71
+ }
72
+ })());
73
+ });
@@ -0,0 +1,13 @@
1
+ import("stdfaust.lib");
2
+ freqs = (100.00, 300.00, 500.00, 1000.00, 1500.00, 2000.00, 2700.00, 3500.00, 5000.00, 6000.00, 8000.00);
3
+ N = 12;
4
+ split(signal) = signal : fi.filterbank(1, freqs);
5
+ display_peak(i, x) = attach(x, x : abs : vbargraph("h:peaks/%2i", 0, 1));
6
+ peak_bands(signal) = split(signal) : par(i, N, _ : display_peak(i));
7
+
8
+ calc_max(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) = max(v2, max(v3, max(v4, max(v5, max(v6, max(v7, max(v8, max(v9, max(v10, v11)))))))));
9
+
10
+ process(signal, side) = mono with {
11
+ side_bands = peak_bands(side);
12
+ mono = side_bands : calc_max : hbargraph("max", 0, 2);
13
+ };