@grame/faust-web-component 0.4.4 → 0.5.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 +2 -2
- package/dist/faust-web-component.js +444 -172
- package/index.html +1 -0
- package/package.json +3 -3
- package/src/common.ts +102 -45
- package/src/faust-editor.ts +95 -96
- package/src/faust-widget.ts +45 -46
package/src/faust-widget.ts
CHANGED
@@ -12,7 +12,6 @@ import { FaustUI } from "@shren/faust-ui";
|
|
12
12
|
import {
|
13
13
|
faustPromise,
|
14
14
|
audioCtx,
|
15
|
-
get_mono_generator,
|
16
15
|
get_poly_generator,
|
17
16
|
compiler,
|
18
17
|
getInputDevices,
|
@@ -117,40 +116,40 @@ template.innerHTML = `
|
|
117
116
|
// Define the FaustWidget web component
|
118
117
|
export default class FaustWidget extends HTMLElement {
|
119
118
|
constructor() {
|
120
|
-
super()
|
119
|
+
super();
|
121
120
|
}
|
122
121
|
|
123
122
|
// Called when the component is connected to the DOM
|
124
123
|
connectedCallback() {
|
125
124
|
// Extract the Faust code from the inner HTML
|
126
|
-
const code = this.innerHTML.replace("<!--", "").replace("-->", "").trim()
|
127
|
-
this.attachShadow({ mode: "open" }).appendChild(template.content.cloneNode(true))
|
125
|
+
const code = this.innerHTML.replace("<!--", "").replace("-->", "").trim();
|
126
|
+
this.attachShadow({ mode: "open" }).appendChild(template.content.cloneNode(true));
|
128
127
|
|
129
128
|
// Query and initialize various elements in the shadow DOM
|
130
|
-
const powerButton = this.shadowRoot!.querySelector("#power") as HTMLButtonElement
|
131
|
-
const faustUIRoot = this.shadowRoot!.querySelector("#faust-ui") as HTMLDivElement
|
132
|
-
const audioInputSelector = this.shadowRoot!.querySelector("#audio-input") as HTMLSelectElement
|
129
|
+
const powerButton = this.shadowRoot!.querySelector("#power") as HTMLButtonElement;
|
130
|
+
const faustUIRoot = this.shadowRoot!.querySelector("#faust-ui") as HTMLDivElement;
|
131
|
+
const audioInputSelector = this.shadowRoot!.querySelector("#audio-input") as HTMLSelectElement;
|
133
132
|
|
134
133
|
// Enable the power button once Faust is ready
|
135
|
-
faustPromise.then(() => powerButton.disabled = false)
|
134
|
+
faustPromise.then(() => powerButton.disabled = false);
|
136
135
|
|
137
136
|
// State variables
|
138
|
-
let on = false
|
139
|
-
let gmidi = false
|
140
|
-
let gnvoices = -1
|
141
|
-
let node: IFaustMonoWebAudioNode | IFaustPolyWebAudioNode
|
142
|
-
let input: MediaStreamAudioSourceNode | undefined
|
143
|
-
let faustUI: FaustUI
|
144
|
-
let generator: FaustMonoDspGenerator | FaustPolyDspGenerator
|
145
|
-
let sourceNode: AudioBufferSourceNode
|
137
|
+
let on = false;
|
138
|
+
let gmidi = false;
|
139
|
+
let gnvoices = -1;
|
140
|
+
let node: IFaustMonoWebAudioNode | IFaustPolyWebAudioNode;
|
141
|
+
let input: MediaStreamAudioSourceNode | undefined;
|
142
|
+
let faustUI: FaustUI;
|
143
|
+
let generator: FaustMonoDspGenerator | FaustPolyDspGenerator;
|
144
|
+
let sourceNode: AudioBufferSourceNode | undefined;
|
146
145
|
|
147
146
|
// Function to setup the Faust environment
|
148
147
|
const setup = async () => {
|
149
|
-
await faustPromise
|
148
|
+
await faustPromise;
|
150
149
|
|
151
150
|
// Compile Faust code to access JSON metadata
|
152
|
-
await default_generator.compile(compiler, "main", code, "-ftz 2")
|
153
|
-
const json = default_generator.getMeta()
|
151
|
+
await default_generator.compile(compiler, "main", code, "-ftz 2");
|
152
|
+
const json = default_generator.getMeta();
|
154
153
|
let { midi, nvoices } = extractMidiAndNvoices(json);
|
155
154
|
gmidi = midi;
|
156
155
|
gnvoices = nvoices;
|
@@ -171,15 +170,15 @@ export default class FaustWidget extends HTMLElement {
|
|
171
170
|
// Function to start the Faust node and audio context
|
172
171
|
const start = async () => {
|
173
172
|
if (audioCtx.state === "suspended") {
|
174
|
-
await audioCtx.resume()
|
173
|
+
await audioCtx.resume();
|
175
174
|
}
|
176
175
|
|
177
176
|
// Create an audio node from compiled Faust if not already created
|
178
177
|
if (node === undefined) {
|
179
178
|
if (gnvoices > 0) {
|
180
|
-
node = (await (generator as FaustPolyDspGenerator).createNode(audioCtx, gnvoices))
|
179
|
+
node = (await (generator as FaustPolyDspGenerator).createNode(audioCtx, gnvoices))!;
|
181
180
|
} else {
|
182
|
-
node = (await (generator as FaustMonoDspGenerator).createNode(audioCtx))
|
181
|
+
node = (await (generator as FaustMonoDspGenerator).createNode(audioCtx))!;
|
183
182
|
}
|
184
183
|
}
|
185
184
|
|
@@ -198,61 +197,61 @@ export default class FaustWidget extends HTMLElement {
|
|
198
197
|
}
|
199
198
|
|
200
199
|
// Set up parameter handling for Faust UI
|
201
|
-
faustUI.paramChangeByUI = (path, value) => node?.setParamValue(path, value)
|
202
|
-
node.setOutputParamHandler((path, value) => faustUI.paramChangeByDSP(path, value))
|
200
|
+
faustUI.paramChangeByUI = (path, value) => node?.setParamValue(path, value);
|
201
|
+
node.setOutputParamHandler((path, value) => faustUI.paramChangeByDSP(path, value));
|
203
202
|
|
204
203
|
// Enable audio input if necessary
|
205
204
|
if (node.numberOfInputs > 0) {
|
206
|
-
audioInputSelector.disabled = false
|
207
|
-
updateInputDevices(await getInputDevices())
|
208
|
-
await connectInput()
|
205
|
+
audioInputSelector.disabled = false;
|
206
|
+
updateInputDevices(await getInputDevices());
|
207
|
+
await connectInput();
|
209
208
|
} else {
|
210
|
-
audioInputSelector.disabled = true
|
211
|
-
audioInputSelector.innerHTML = "<option>Audio input</option>"
|
209
|
+
audioInputSelector.disabled = true;
|
210
|
+
audioInputSelector.innerHTML = "<option>Audio input</option>";
|
212
211
|
}
|
213
212
|
|
214
213
|
// Connect Faust node to the audio context destination
|
215
|
-
node.connect(audioCtx.destination)
|
216
|
-
powerButton.style.color = "#ffa500"
|
214
|
+
node.connect(audioCtx.destination);
|
215
|
+
powerButton.style.color = "#ffa500";
|
217
216
|
}
|
218
217
|
|
219
218
|
// Function to stop the Faust node
|
220
219
|
const stop = () => {
|
221
|
-
node?.disconnect()
|
220
|
+
node?.disconnect();
|
222
221
|
node?.stopSensors();
|
223
|
-
powerButton.style.color = "#fff"
|
222
|
+
powerButton.style.color = "#fff";
|
224
223
|
}
|
225
224
|
|
226
225
|
// Toggle the Faust node on/off
|
227
226
|
powerButton.onclick = () => {
|
228
227
|
if (on) {
|
229
|
-
stop()
|
228
|
+
stop();
|
230
229
|
} else {
|
231
|
-
start()
|
230
|
+
start();
|
232
231
|
}
|
233
|
-
on = !on
|
232
|
+
on = !on;
|
234
233
|
}
|
235
234
|
|
236
235
|
// Function to update available audio input devices
|
237
236
|
const updateInputDevices = (devices: MediaDeviceInfo[]) => {
|
238
|
-
if (audioInputSelector.disabled) return
|
239
|
-
while (audioInputSelector.lastChild) audioInputSelector.lastChild.remove()
|
237
|
+
if (audioInputSelector.disabled) return;
|
238
|
+
while (audioInputSelector.lastChild) audioInputSelector.lastChild.remove();
|
240
239
|
for (const device of devices) {
|
241
240
|
if (device.kind === "audioinput") {
|
242
|
-
audioInputSelector.appendChild(new Option(device.label || device.deviceId, device.deviceId))
|
241
|
+
audioInputSelector.appendChild(new Option(device.label || device.deviceId, device.deviceId));
|
243
242
|
}
|
244
243
|
}
|
245
|
-
audioInputSelector.appendChild(new Option("Audio File", "Audio File"))
|
244
|
+
audioInputSelector.appendChild(new Option("Audio File", "Audio File"));
|
246
245
|
}
|
247
|
-
deviceUpdateCallbacks.push(updateInputDevices)
|
246
|
+
deviceUpdateCallbacks.push(updateInputDevices);
|
248
247
|
|
249
248
|
// Function to connect selected audio input device
|
250
249
|
const connectInput = async () => {
|
251
|
-
const deviceId = audioInputSelector.value
|
252
|
-
const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId, echoCancellation: false, noiseSuppression: false, autoGainControl: false } })
|
250
|
+
const deviceId = audioInputSelector.value;
|
251
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId, echoCancellation: false, noiseSuppression: false, autoGainControl: false } });
|
253
252
|
if (input) {
|
254
|
-
input.disconnect()
|
255
|
-
input = undefined
|
253
|
+
input.disconnect();
|
254
|
+
input = undefined;
|
256
255
|
}
|
257
256
|
if (node && node.numberOfInputs > 0) {
|
258
257
|
if (deviceId == "Audio File") {
|
@@ -287,7 +286,7 @@ export default class FaustWidget extends HTMLElement {
|
|
287
286
|
}
|
288
287
|
|
289
288
|
// Set input change handler
|
290
|
-
audioInputSelector.onchange = connectInput
|
289
|
+
audioInputSelector.onchange = connectInput;
|
291
290
|
|
292
291
|
// Initial setup
|
293
292
|
setTimeout(() => {
|