@grame/faustwasm 0.8.0 → 0.9.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/assets/standalone/create-node.js +46 -9
- 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 +42 -2
- package/assets/standalone/faustwasm/index.js +117 -66
- package/assets/standalone/faustwasm/index.js.map +2 -2
- package/assets/standalone/index-pwa.js +125 -90
- package/assets/standalone/index-template.js +43 -22
- package/assets/standalone/index.js +36 -19
- package/assets/standalone/service-worker.js +58 -5
- package/dist/cjs/index.d.ts +42 -2
- package/dist/cjs/index.js +117 -66
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs-bundle/index.d.ts +42 -2
- package/dist/cjs-bundle/index.js +117 -66
- package/dist/cjs-bundle/index.js.map +2 -2
- package/dist/esm/index.d.ts +42 -2
- package/dist/esm/index.js +117 -66
- package/dist/esm/index.js.map +2 -2
- package/dist/esm-bundle/index.d.ts +42 -2
- package/dist/esm-bundle/index.js +117 -66
- package/dist/esm-bundle/index.js.map +2 -2
- package/package.json +2 -2
- package/src/FaustAudioWorkletNode.ts +14 -30
- package/src/FaustAudioWorkletProcessor.ts +16 -0
- package/src/FaustOfflineProcessor.ts +2 -0
- package/src/FaustScriptProcessorNode.ts +6 -30
- package/src/FaustWebAudioDsp.ts +88 -0
- package/src/copyWebStandaloneAssets.js +14 -0
- 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 +42 -2
- package/test/faustlive-wasm/faustwasm/index.js +117 -66
- package/test/faustlive-wasm/faustwasm/index.js.map +2 -2
- package/test/midi/create-node.js +177 -0
- package/test/midi/dsp-meta.json +133 -0
- package/test/midi/dsp-module.wasm +0 -0
- package/test/midi/faust-ui/index.css +442 -0
- package/test/midi/faust-ui/index.css.map +1 -0
- package/test/midi/faust-ui/index.d.ts +1 -0
- package/test/midi/faust-ui/index.js +3729 -0
- package/test/midi/faust-ui/index.js.map +1 -0
- package/test/midi/faustwasm/index.d.ts +1680 -0
- package/test/midi/faustwasm/index.js +4884 -0
- package/test/midi/faustwasm/index.js.map +7 -0
- package/test/midi/icon.png +0 -0
- package/test/midi/index.html +76 -0
- package/test/midi/index.js +183 -0
- package/test/midi/manifest.json +17 -0
- package/test/midi/service-worker.js +165 -0
- package/test/midi.dsp +8 -1
- package/test/organ1/create-node.js +177 -0
- package/test/organ1/dsp-meta.json +126 -0
- package/test/organ1/dsp-module.wasm +0 -0
- package/test/organ1/faust-ui/index.css +442 -0
- package/test/organ1/faust-ui/index.css.map +1 -0
- package/test/organ1/faust-ui/index.d.ts +1 -0
- package/test/organ1/faust-ui/index.js +3729 -0
- package/test/organ1/faust-ui/index.js.map +1 -0
- package/test/organ1/faustwasm/index.d.ts +1656 -0
- package/test/organ1/faustwasm/index.js +4783 -0
- package/test/organ1/faustwasm/index.js.map +7 -0
- package/test/organ1/icon.png +0 -0
- package/test/organ1/index.html +76 -0
- package/test/organ1/index.js +203 -0
- package/test/organ1/manifest.json +17 -0
- package/test/organ1/service-worker.js +181 -0
|
@@ -29,120 +29,155 @@ const audioContext = new AudioCtx({ latencyHint: 0.00001 });
|
|
|
29
29
|
audioContext.destination.channelInterpretation = "discrete";
|
|
30
30
|
audioContext.suspend();
|
|
31
31
|
|
|
32
|
+
// Declare faustNode as a global variable
|
|
33
|
+
let faustNode;
|
|
34
|
+
|
|
35
|
+
// Called at load time
|
|
32
36
|
(async () => {
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
// Import the create-node module
|
|
39
|
+
const { createFaustNode, createFaustUI } = await import("./create-node.js");
|
|
35
40
|
|
|
36
41
|
// To test the ScriptProcessorNode mode
|
|
37
|
-
//const
|
|
38
|
-
const
|
|
42
|
+
// const result = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES, true, 512);
|
|
43
|
+
const result = await createFaustNode(audioContext, "osc", FAUST_DSP_VOICES);
|
|
44
|
+
faustNode = result.faustNode; // Assign to the global variable
|
|
39
45
|
if (!faustNode) throw new Error("Faust DSP not compiled");
|
|
40
46
|
|
|
41
47
|
// Create the Faust UI
|
|
42
48
|
await createFaustUI($divFaustUI, faustNode);
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
() => console.error("Failed to access MIDI devices.")
|
|
57
|
-
);
|
|
58
|
-
} else {
|
|
59
|
-
console.log("Web MIDI API is not supported in this browser.");
|
|
60
|
-
}
|
|
50
|
+
})();
|
|
51
|
+
|
|
52
|
+
// Synchronous function to resume AudioContext, to be called first in the synchronous event listener
|
|
53
|
+
function resumeAudioContext() {
|
|
54
|
+
if (audioContext.state === 'suspended') {
|
|
55
|
+
audioContext.resume().then(() => {
|
|
56
|
+
console.log('AudioContext resumed successfully');
|
|
57
|
+
}).catch(error => {
|
|
58
|
+
console.error('Error when resuming AudioContext:', error);
|
|
59
|
+
});
|
|
61
60
|
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Function to start MIDI
|
|
64
|
+
function startMIDI() {
|
|
65
|
+
// Check if the browser supports the Web MIDI API
|
|
66
|
+
if (navigator.requestMIDIAccess) {
|
|
67
|
+
navigator.requestMIDIAccess().then(
|
|
68
|
+
midiAccess => {
|
|
69
|
+
console.log("MIDI Access obtained.");
|
|
70
|
+
for (let input of midiAccess.inputs.values()) {
|
|
71
|
+
input.onmidimessage = (event) => faustNode.midiMessage(event.data);
|
|
72
|
+
console.log(`Connected to input: ${input.name}`);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
() => console.error("Failed to access MIDI devices.")
|
|
76
|
+
);
|
|
77
|
+
} else {
|
|
78
|
+
console.log("Web MIDI API is not supported in this browser.");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Function to stop MIDI
|
|
83
|
+
function stopMIDI() {
|
|
84
|
+
// Check if the browser supports the Web MIDI API
|
|
85
|
+
if (navigator.requestMIDIAccess) {
|
|
86
|
+
navigator.requestMIDIAccess().then(
|
|
87
|
+
midiAccess => {
|
|
88
|
+
console.log("MIDI Access obtained.");
|
|
89
|
+
for (let input of midiAccess.inputs.values()) {
|
|
90
|
+
input.onmidimessage = null;
|
|
91
|
+
console.log(`Disconnected from input: ${input.name}`);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
() => console.error("Failed to access MIDI devices.")
|
|
95
|
+
);
|
|
96
|
+
} else {
|
|
97
|
+
console.log("Web MIDI API is not supported in this browser.");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let sensorHandlersBound = false;
|
|
102
|
+
let midiHandlersBound = false;
|
|
103
|
+
|
|
104
|
+
// Function to activate MIDI and Sensors on user interaction
|
|
105
|
+
async function activateMIDISensors() {
|
|
106
|
+
|
|
107
|
+
// Import the create-node module
|
|
108
|
+
const { connectToAudioInput, requestPermissions } = await import("./create-node.js");
|
|
62
109
|
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
for (let input of midiAccess.inputs.values()) {
|
|
71
|
-
input.onmidimessage = null;
|
|
72
|
-
console.log(`Disconnected from input: ${input.name}`);
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
() => console.error("Failed to access MIDI devices.")
|
|
76
|
-
);
|
|
77
|
-
} else {
|
|
78
|
-
console.log("Web MIDI API is not supported in this browser.");
|
|
79
|
-
}
|
|
110
|
+
// Request permission for sensors
|
|
111
|
+
await requestPermissions();
|
|
112
|
+
|
|
113
|
+
// Activate sensor listeners
|
|
114
|
+
if (!sensorHandlersBound) {
|
|
115
|
+
await faustNode.startSensors();
|
|
116
|
+
sensorHandlersBound = true;
|
|
80
117
|
}
|
|
81
118
|
|
|
82
|
-
|
|
83
|
-
|
|
119
|
+
// Initialize the MIDI setup
|
|
120
|
+
if (!midiHandlersBound) {
|
|
121
|
+
startMIDI();
|
|
122
|
+
midiHandlersBound = true;
|
|
123
|
+
}
|
|
84
124
|
|
|
85
|
-
//
|
|
86
|
-
|
|
125
|
+
// Connect the Faust node to the audio output
|
|
126
|
+
faustNode.connect(audioContext.destination);
|
|
87
127
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
128
|
+
// Connect the Faust node to the audio input
|
|
129
|
+
if (faustNode.numberOfInputs > 0) {
|
|
130
|
+
await connectToAudioInput(audioContext, null, faustNode, null);
|
|
131
|
+
}
|
|
93
132
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
133
|
+
// Resume the AudioContext
|
|
134
|
+
if (audioContext.state === 'suspended') {
|
|
135
|
+
await audioContext.resume();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
99
138
|
|
|
100
|
-
|
|
101
|
-
|
|
139
|
+
// Function to suspend AudioContext, deactivate MIDI and Sensors on user interaction
|
|
140
|
+
async function deactivateAudioMIDISensors() {
|
|
102
141
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
142
|
+
// Suspend the AudioContext
|
|
143
|
+
if (audioContext.state === 'running') {
|
|
144
|
+
await audioContext.suspend();
|
|
145
|
+
}
|
|
107
146
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
147
|
+
// Deactivate sensor listeners
|
|
148
|
+
if (sensorHandlersBound) {
|
|
149
|
+
faustNode.stopSensors();
|
|
150
|
+
sensorHandlersBound = false;
|
|
112
151
|
}
|
|
113
152
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (audioContext.state === 'running') {
|
|
119
|
-
await audioContext.suspend();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Deactivate sensor listeners
|
|
123
|
-
if (sensorHandlersBound) {
|
|
124
|
-
faustNode.stopSensors();
|
|
125
|
-
sensorHandlersBound = false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Deactivate the MIDI setup
|
|
129
|
-
if (midiHandlersBound && FAUST_DSP_VOICES > 0) {
|
|
130
|
-
stopMIDI();
|
|
131
|
-
midiHandlersBound = false;
|
|
132
|
-
}
|
|
153
|
+
// Deactivate the MIDI setup
|
|
154
|
+
if (midiHandlersBound && FAUST_DSP_VOICES > 0) {
|
|
155
|
+
stopMIDI();
|
|
156
|
+
midiHandlersBound = false;
|
|
133
157
|
}
|
|
158
|
+
}
|
|
134
159
|
|
|
135
|
-
|
|
160
|
+
// Event listener to handle user interaction
|
|
161
|
+
function handleUserInteraction() {
|
|
136
162
|
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
window.addEventListener('touchstart', activateAudioMIDISensors);
|
|
163
|
+
// Resume AudioContext synchronously
|
|
164
|
+
resumeAudioContext();
|
|
140
165
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
deactivateAudioMIDISensors();
|
|
145
|
-
}
|
|
166
|
+
// Launch the activation of MIDI and Sensors
|
|
167
|
+
activateMIDISensors().catch(error => {
|
|
168
|
+
console.error('Error when activating audio, MIDI and sensors:', error);
|
|
146
169
|
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Activate AudioContext, MIDI and Sensors on user interaction
|
|
173
|
+
window.addEventListener('click', handleUserInteraction);
|
|
174
|
+
window.addEventListener('touchstart', handleUserInteraction);
|
|
175
|
+
|
|
176
|
+
// Deactivate AudioContext, MIDI and Sensors on user interaction
|
|
177
|
+
window.addEventListener('visibilitychange', function () {
|
|
178
|
+
if (window.visibilityState === 'hidden') {
|
|
179
|
+
deactivateAudioMIDISensors();
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
147
183
|
|
|
148
|
-
})();
|
|
@@ -1,18 +1,49 @@
|
|
|
1
1
|
// Set to > 0 if the DSP is polyphonic
|
|
2
2
|
const FAUST_DSP_VOICES = 0;
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Declare faustNode as a global variable
|
|
5
|
+
let faustNode;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
// Create audio context activation button
|
|
8
|
+
/** @type {HTMLButtonElement} */
|
|
9
|
+
const $buttonDsp = document.getElementById("button-dsp");
|
|
10
|
+
|
|
11
|
+
// Create audio context
|
|
12
|
+
const AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
13
|
+
const audioContext = new AudioCtx({ latencyHint: 0.00001 });
|
|
14
|
+
|
|
15
|
+
// Activate AudioContext and Sensors on user interaction
|
|
16
|
+
$buttonDsp.disabled = true;
|
|
17
|
+
let sensorHandlersBound = false;
|
|
18
|
+
$buttonDsp.onclick = async () => {
|
|
19
|
+
|
|
20
|
+
// Import the requestPermissions function
|
|
21
|
+
const { requestPermissions } = await import("./create-node.js");
|
|
22
|
+
|
|
23
|
+
// Request permission for sensors
|
|
24
|
+
await requestPermissions();
|
|
25
|
+
|
|
26
|
+
// Activate sensor listeners
|
|
27
|
+
if (!sensorHandlersBound) {
|
|
28
|
+
await faustNode.startSensors();
|
|
29
|
+
sensorHandlersBound = true;
|
|
30
|
+
}
|
|
7
31
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
32
|
+
// Activate or suspend the AudioContext
|
|
33
|
+
if (audioContext.state === "running") {
|
|
34
|
+
$buttonDsp.textContent = "Suspended";
|
|
35
|
+
await audioContext.suspend();
|
|
36
|
+
} else if (audioContext.state === "suspended") {
|
|
37
|
+
$buttonDsp.textContent = "Running";
|
|
38
|
+
await audioContext.resume();
|
|
39
|
+
if (FAUST_DSP_VOICES) play(faustNode);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
12
42
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
43
|
+
// Called at load time
|
|
44
|
+
(async () => {
|
|
45
|
+
|
|
46
|
+
const { createFaustNode, connectToAudioInput } = await import("./create-node.js");
|
|
16
47
|
|
|
17
48
|
const play = (node) => {
|
|
18
49
|
node.keyOn(0, 60, 100);
|
|
@@ -21,21 +52,10 @@ const FAUST_DSP_VOICES = 0;
|
|
|
21
52
|
setTimeout(() => node.allNotesOff(), 5000);
|
|
22
53
|
setTimeout(() => play(node), 7000);
|
|
23
54
|
}
|
|
24
|
-
// Function to activate audio context
|
|
25
|
-
$buttonDsp.disabled = true;
|
|
26
|
-
$buttonDsp.onclick = async () => {
|
|
27
|
-
if (audioContext.state === "running") {
|
|
28
|
-
$buttonDsp.textContent = "Suspended";
|
|
29
|
-
await audioContext.suspend();
|
|
30
|
-
} else if (audioContext.state === "suspended") {
|
|
31
|
-
$buttonDsp.textContent = "Running";
|
|
32
|
-
await audioContext.resume();
|
|
33
|
-
if (FAUST_DSP_VOICES) play(faustNode);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
55
|
|
|
37
56
|
// Create Faust node
|
|
38
|
-
const
|
|
57
|
+
const result = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES);
|
|
58
|
+
faustNode = result.faustNode; // Assign to the global variable
|
|
39
59
|
if (!faustNode) throw new Error("Faust DSP not compiled");
|
|
40
60
|
|
|
41
61
|
// Connect the Faust node to the audio output
|
|
@@ -51,4 +71,5 @@ const FAUST_DSP_VOICES = 0;
|
|
|
51
71
|
|
|
52
72
|
// Set page title to the DSP name
|
|
53
73
|
document.title = name;
|
|
74
|
+
|
|
54
75
|
})();
|
|
@@ -41,6 +41,10 @@ audioContext.suspend();
|
|
|
41
41
|
|
|
42
42
|
$buttonDsp.disabled = true;
|
|
43
43
|
|
|
44
|
+
// Declare faustNode as a global variable
|
|
45
|
+
let faustNode;
|
|
46
|
+
|
|
47
|
+
// Called at load time
|
|
44
48
|
(async () => {
|
|
45
49
|
|
|
46
50
|
const { createFaustNode, connectToAudioInput, createFaustUI } = await import("./create-node.js");
|
|
@@ -111,7 +115,8 @@ $buttonDsp.disabled = true;
|
|
|
111
115
|
|
|
112
116
|
// To test the ScriptProcessorNode mode
|
|
113
117
|
// const { faustNode, dspMeta: { name } } = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES, true);
|
|
114
|
-
const
|
|
118
|
+
const result = await createFaustNode(audioContext, "FAUST_DSP_NAME", FAUST_DSP_VOICES);
|
|
119
|
+
faustNode = result.faustNode; // Assign to the global variable
|
|
115
120
|
if (!faustNode) throw new Error("Faust DSP not compiled");
|
|
116
121
|
|
|
117
122
|
// Create the Faust UI
|
|
@@ -128,22 +133,34 @@ $buttonDsp.disabled = true;
|
|
|
128
133
|
if (navigator.requestMIDIAccess) await buildMidiDeviceMenu(faustNode);
|
|
129
134
|
else $spanMidiInput.hidden = true;
|
|
130
135
|
|
|
131
|
-
// Set the title and enable the DSP button
|
|
132
|
-
$buttonDsp.disabled = false;
|
|
133
|
-
document.title = name;
|
|
134
|
-
let sensorHandlersBound = false;
|
|
135
|
-
$buttonDsp.onclick = async () => {
|
|
136
|
-
// Activate sensor listeners
|
|
137
|
-
if (!sensorHandlersBound) {
|
|
138
|
-
await faustNode.startSensors();
|
|
139
|
-
sensorHandlersBound = true;
|
|
140
|
-
}
|
|
141
|
-
if (audioContext.state === "running") {
|
|
142
|
-
$buttonDsp.textContent = "Suspended";
|
|
143
|
-
await audioContext.suspend();
|
|
144
|
-
} else if (audioContext.state === "suspended") {
|
|
145
|
-
$buttonDsp.textContent = "Running";
|
|
146
|
-
await audioContext.resume();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
136
|
})();
|
|
137
|
+
|
|
138
|
+
// Set the title and enable the DSP button
|
|
139
|
+
$buttonDsp.disabled = false;
|
|
140
|
+
document.title = name;
|
|
141
|
+
let sensorHandlersBound = false;
|
|
142
|
+
|
|
143
|
+
// Activate AudioContext and Sensors on user interaction
|
|
144
|
+
$buttonDsp.onclick = async () => {
|
|
145
|
+
|
|
146
|
+
// Import the requestPermissions function
|
|
147
|
+
const { requestPermissions } = await import("./create-node.js");
|
|
148
|
+
|
|
149
|
+
// Request permission for sensors
|
|
150
|
+
await requestPermissions();
|
|
151
|
+
|
|
152
|
+
// Activate sensor listeners
|
|
153
|
+
if (!sensorHandlersBound) {
|
|
154
|
+
await faustNode.startSensors();
|
|
155
|
+
sensorHandlersBound = true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Activate or suspend the AudioContext
|
|
159
|
+
if (audioContext.state === "running") {
|
|
160
|
+
$buttonDsp.textContent = "Suspended";
|
|
161
|
+
await audioContext.suspend();
|
|
162
|
+
} else if (audioContext.state === "suspended") {
|
|
163
|
+
$buttonDsp.textContent = "Running";
|
|
164
|
+
await audioContext.resume();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -5,8 +5,15 @@ const FAUST_DSP_VOICES = 0;
|
|
|
5
5
|
// Set to true if the DSP has an effect
|
|
6
6
|
const FAUST_DSP_HAS_EFFECT = false;
|
|
7
7
|
|
|
8
|
-
const CACHE_NAME = "
|
|
8
|
+
const CACHE_NAME = "FAUST_DSP_NAME_VERSION_DATE"; // Cache name with versioning
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* List of essential resources required for the **Mono DSP** version of the application.
|
|
12
|
+
*
|
|
13
|
+
* - These files are cached to enable offline functionality and improve loading speed.
|
|
14
|
+
* - Includes the main HTML, JavaScript, and CSS files required for the app.
|
|
15
|
+
* - Contains Faust-related files needed for DSP processing.
|
|
16
|
+
*/
|
|
10
17
|
const MONO_RESOURCES = [
|
|
11
18
|
"./index.html",
|
|
12
19
|
"./index.js",
|
|
@@ -18,11 +25,23 @@ const MONO_RESOURCES = [
|
|
|
18
25
|
"./dsp-meta.json"
|
|
19
26
|
];
|
|
20
27
|
|
|
28
|
+
/**
|
|
29
|
+
* List of resources for the **Polyphonic DSP** version of the application.
|
|
30
|
+
*
|
|
31
|
+
* - Extends the mono resource list by adding a **mixer module**.
|
|
32
|
+
* - The mixer module is required to handle multiple simultaneous voices used in a polyphonic instrument.
|
|
33
|
+
*/
|
|
21
34
|
const POLY_RESOURCES = [
|
|
22
35
|
...MONO_RESOURCES,
|
|
23
36
|
"./mixer-module.wasm",
|
|
24
37
|
];
|
|
25
38
|
|
|
39
|
+
/**
|
|
40
|
+
* List of resources for the **Polyphonic DSP with Effects** version.
|
|
41
|
+
*
|
|
42
|
+
* - Extends the polyphonic resource list by adding an **effect module**.
|
|
43
|
+
* - The effect module allows applying audio effects to the polyphonic instrument.
|
|
44
|
+
*/
|
|
26
45
|
const POLY_EFFECT_RESOURCES = [
|
|
27
46
|
...POLY_RESOURCES,
|
|
28
47
|
"./effect-module.wasm",
|
|
@@ -33,13 +52,16 @@ const POLY_EFFECT_RESOURCES = [
|
|
|
33
52
|
const serviceWorkerGlobalScope = self;
|
|
34
53
|
|
|
35
54
|
/**
|
|
36
|
-
* Install the service worker and
|
|
55
|
+
* Install the service worker, cache essential resources, and prepare for immediate activation.
|
|
56
|
+
*
|
|
57
|
+
* - Opens the cache and stores required assets based on the app's configuration.
|
|
58
|
+
* - Ensures resources are preloaded for offline access.
|
|
37
59
|
*/
|
|
38
60
|
serviceWorkerGlobalScope.addEventListener("install", (event) => {
|
|
39
61
|
console.log("Service worker installed");
|
|
40
62
|
event.waitUntil((async () => {
|
|
41
63
|
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;
|
|
64
|
+
const resources = (FAUST_DSP_VOICES && FAUST_DSP_HAS_EFFECT) ? POLY_EFFECT_RESOURCES : (FAUST_DSP_VOICES ? POLY_RESOURCES : MONO_RESOURCES);
|
|
43
65
|
try {
|
|
44
66
|
return cache.addAll(resources);
|
|
45
67
|
} catch (error) {
|
|
@@ -48,6 +70,16 @@ serviceWorkerGlobalScope.addEventListener("install", (event) => {
|
|
|
48
70
|
})());
|
|
49
71
|
});
|
|
50
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Handles the activation of the Service Worker.
|
|
75
|
+
*
|
|
76
|
+
* - Claims control over all clients immediately, bypassing the default behavior that
|
|
77
|
+
* requires a page reload before the new service worker takes effect.
|
|
78
|
+
* - Once claimed, it finds all active window clients and reloads them to ensure they are
|
|
79
|
+
* controlled by the latest version of the service worker.
|
|
80
|
+
* - This approach ensures that updates to the service worker take effect immediately
|
|
81
|
+
* across all open pages, preventing potential inconsistencies.
|
|
82
|
+
*/
|
|
51
83
|
serviceWorkerGlobalScope.addEventListener("activate", (event) => {
|
|
52
84
|
console.log("Service worker activated");
|
|
53
85
|
event.waitUntil(
|
|
@@ -61,7 +93,20 @@ serviceWorkerGlobalScope.addEventListener("activate", (event) => {
|
|
|
61
93
|
);
|
|
62
94
|
});
|
|
63
95
|
|
|
64
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Adjusts response headers to enforce Cross-Origin Opener Policy (COOP) and Cross-Origin Embedder Policy (COEP).
|
|
98
|
+
*
|
|
99
|
+
* - Ensures that the response is served with `Cross-Origin-Opener-Policy: same-origin`
|
|
100
|
+
* and `Cross-Origin-Embedder-Policy: require-corp`.
|
|
101
|
+
* - Required for enabling **cross-origin isolated** environments in web applications.
|
|
102
|
+
* - Necessary for features like **SharedArrayBuffer**, WebAssembly threads, and
|
|
103
|
+
* high-performance APIs that require isolation.
|
|
104
|
+
* - Creates a new `Response` object with the modified headers while preserving
|
|
105
|
+
* the original response body and status.
|
|
106
|
+
*
|
|
107
|
+
* @param {Response} response - The original HTTP response object.
|
|
108
|
+
* @returns {Response} A new response with updated security headers.
|
|
109
|
+
*/
|
|
65
110
|
const getCrossOriginIsolatedResponse = (response) => {
|
|
66
111
|
// Modify headers to include COOP & COEP
|
|
67
112
|
const headers = new Headers(response.headers);
|
|
@@ -79,7 +124,15 @@ const getCrossOriginIsolatedResponse = (response) => {
|
|
|
79
124
|
};
|
|
80
125
|
|
|
81
126
|
/**
|
|
82
|
-
*
|
|
127
|
+
* Intercepts fetch requests and enforces COOP and COEP headers for security.
|
|
128
|
+
*
|
|
129
|
+
* - Checks if the requested resource is available in the cache:
|
|
130
|
+
* - If found, returns a cached response with `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` headers.
|
|
131
|
+
* - If not found, fetches the resource from the network, applies COOP/COEP headers, and caches the response (for GET requests).
|
|
132
|
+
* - Ensures cross-origin isolation, required for APIs like `SharedArrayBuffer` and WebAssembly threading.
|
|
133
|
+
* - Handles network errors gracefully by returning a 503 "Service Unavailable" response when needed.
|
|
134
|
+
*
|
|
135
|
+
* @param {FetchEvent} event - The fetch event triggered by the browser.
|
|
83
136
|
*/
|
|
84
137
|
serviceWorkerGlobalScope.addEventListener("fetch", (event) => {
|
|
85
138
|
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -618,6 +618,20 @@ export interface IFaustBaseWebAudioDsp {
|
|
|
618
618
|
* @param value - the MIDI controller value (0..16383)
|
|
619
619
|
*/
|
|
620
620
|
pitchWheel(chan: number, value: number): void;
|
|
621
|
+
/**
|
|
622
|
+
* Handle MIDI keyOn messages.
|
|
623
|
+
* @param channel
|
|
624
|
+
* @param pitch
|
|
625
|
+
* @param velocity
|
|
626
|
+
*/
|
|
627
|
+
keyOn(channel: number, pitch: number, velocity: number): void;
|
|
628
|
+
/**
|
|
629
|
+
* Handle MIDI keyOn messages.
|
|
630
|
+
* @param channel
|
|
631
|
+
* @param pitch
|
|
632
|
+
* @param velocity
|
|
633
|
+
*/
|
|
634
|
+
keyOff(channel: number, pitch: number, velocity: number): void;
|
|
621
635
|
/**
|
|
622
636
|
* Set parameter value.
|
|
623
637
|
*
|
|
@@ -767,6 +781,24 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
|
|
|
767
781
|
min: number;
|
|
768
782
|
max: number;
|
|
769
783
|
}[][];
|
|
784
|
+
protected fMidiKeyLabel: {
|
|
785
|
+
path: string;
|
|
786
|
+
chan: number;
|
|
787
|
+
min: number;
|
|
788
|
+
max: number;
|
|
789
|
+
}[][];
|
|
790
|
+
protected fMidiKeyOnLabel: {
|
|
791
|
+
path: string;
|
|
792
|
+
chan: number;
|
|
793
|
+
min: number;
|
|
794
|
+
max: number;
|
|
795
|
+
}[][];
|
|
796
|
+
protected fMidiKeyOffLabel: {
|
|
797
|
+
path: string;
|
|
798
|
+
chan: number;
|
|
799
|
+
min: number;
|
|
800
|
+
max: number;
|
|
801
|
+
}[][];
|
|
770
802
|
protected fPathTable: {
|
|
771
803
|
[address: string]: number;
|
|
772
804
|
};
|
|
@@ -826,6 +858,8 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
|
|
|
826
858
|
getNumOutputs(): number;
|
|
827
859
|
midiMessage(data: number[] | Uint8Array): void;
|
|
828
860
|
ctrlChange(channel: number, ctrl: number, value: number): void;
|
|
861
|
+
keyOn(channel: number, pitch: number, velocity: number): void;
|
|
862
|
+
keyOff(channel: number, pitch: number, velocity: number): void;
|
|
829
863
|
pitchWheel(channel: number, wheel: number): void;
|
|
830
864
|
setParamValue(path: string, value: number): void;
|
|
831
865
|
getParamValue(path: string): number;
|
|
@@ -835,11 +869,11 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
|
|
|
835
869
|
getUI(): FaustUIDescriptor;
|
|
836
870
|
getDescriptors(): FaustUIInputItem[];
|
|
837
871
|
hasSoundfiles(): boolean;
|
|
872
|
+
startSensors(): void;
|
|
873
|
+
stopSensors(): void;
|
|
838
874
|
start(): void;
|
|
839
875
|
stop(): void;
|
|
840
876
|
destroy(): void;
|
|
841
|
-
startSensors(): void;
|
|
842
|
-
stopSensors(): void;
|
|
843
877
|
}
|
|
844
878
|
export declare class FaustMonoWebAudioDsp extends FaustBaseWebAudioDsp implements IFaustMonoWebAudioDsp {
|
|
845
879
|
private fInstance;
|
|
@@ -1180,6 +1214,8 @@ export declare class FaustOfflineProcessor<Poly extends boolean = false> {
|
|
|
1180
1214
|
midiMessage(data: number[] | Uint8Array): void;
|
|
1181
1215
|
ctrlChange(chan: number, ctrl: number, value: number): void;
|
|
1182
1216
|
pitchWheel(chan: number, value: number): void;
|
|
1217
|
+
keyOn(channel: number, pitch: number, velocity: number): void;
|
|
1218
|
+
keyOff(channel: number, pitch: number, velocity: number): void;
|
|
1183
1219
|
setParamValue(path: string, value: number): void;
|
|
1184
1220
|
getParamValue(path: string): number;
|
|
1185
1221
|
getParams(): string[];
|
|
@@ -1374,6 +1410,8 @@ export declare class FaustAudioWorkletNode<Poly extends boolean = false> extends
|
|
|
1374
1410
|
midiMessage(data: number[] | Uint8Array): void;
|
|
1375
1411
|
ctrlChange(channel: number, ctrl: number, value: number): void;
|
|
1376
1412
|
pitchWheel(channel: number, wheel: number): void;
|
|
1413
|
+
keyOn(channel: number, pitch: number, velocity: number): void;
|
|
1414
|
+
keyOff(channel: number, pitch: number, velocity: number): void;
|
|
1377
1415
|
get hasAccInput(): boolean;
|
|
1378
1416
|
propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
|
|
1379
1417
|
get hasGyrInput(): boolean;
|
|
@@ -1441,6 +1479,8 @@ export declare class FaustScriptProcessorNode<Poly extends boolean = false> exte
|
|
|
1441
1479
|
midiMessage(data: number[] | Uint8Array): void;
|
|
1442
1480
|
ctrlChange(chan: number, ctrl: number, value: number): void;
|
|
1443
1481
|
pitchWheel(chan: number, value: number): void;
|
|
1482
|
+
keyOn(channel: number, pitch: number, velocity: number): void;
|
|
1483
|
+
keyOff(channel: number, pitch: number, velocity: number): void;
|
|
1444
1484
|
setParamValue(path: string, value: number): void;
|
|
1445
1485
|
getParamValue(path: string): number;
|
|
1446
1486
|
getParams(): string[];
|