Как я могу импортировать модуль в AudioWorkletProcessor, который был изменен в другом месте?
Я пытаюсь изменить значение, которое используется AudioWorkletProcessor из другого модуля, но из контекста AudioWorkletProcessor значение не изменяется и остается неизменным. Но из модуля, который изменяет данные, при запросе данные фактически изменились там. Это похоже на полностью отдельный экземпляр / состояние модуля, в котором хранятся данные (functions.js) для модификатора (main.js) и считывателя (audio-processor.js).
Здесь у нас есть audio-processor.js
import { sawWave } from "/src/functions.js";
var tick = 0
class AudioProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
const output = outputs[0]
output.forEach(channel => {
// emphasis on sawWave function
var value = sawWave(tick) * 0.1;
for (let i = 0; i < channel.length; i++) {
channel[i] = value
}
});
tick++
return true
}
}
registerProcessor('audio-processor', AudioProcessor)
Здесь у нас есть functions.js
, который содержит sawWave(), который импортируется в audio-processor.js
let variables = {
// emphasis on this variable
sawWaveFrequency: 1
}
export function setSawFrequency(freq) {
variables.sawWaveFrequency = freq
}
export function sawWave(tick) {
console.log(variables.sawWaveFrequency)
// this function uses the variable defined above and is imported by audio-processor.js
// variables.sawWaveFrequency doesn't change for audio-processor.js when modified from main.js
// so the output will will always be as if variables.sawWaveFrequency = 1
return tick * variables.sawWaveFrequency % 10;
}
Здесь у нас есть main.js
, который обрабатывает ввод с HTML-страницы
import { setSawFrequency } from "/src/functions.js";
var audioContext
var whiteNoiseNode
async function init() {
audioContext = new AudioContext()
await audioContext.audioWorklet.addModule("/src/audio-processor.js")
whiteNoiseNode = new AudioWorkletNode(audioContext, 'audio-processor')
}
function play() {
whiteNoiseNode.connect(audioContext.destination)
}
function main() {
document.querySelector("#play").onclick = play;
document.querySelector("#init").onclick = init;
document.querySelector("#slider-mult").oninput = function() {
// this is supposed to change the value, but only does so in the context of main.js and not audio-processor.js
setSawFrequency(this.value);
}
}
main();
РЕДАКТИРОВАТЬ: я так понимаю, вы должны использовать только AudioWorkletProcessor.port
и parameters
параметр в функции процесса для связи с ним?
2 ответа
Вы уже на правильном пути. Чтобы изменить значение внутри вашегоAudioWorkletProcessor
вы можете использовать индивидуальный AudioParam
или отправьте сообщение через MessagePort
.
Причина, по которой ваш код не работает, заключается в том, что вы технически получаете два экземпляра одного и того же модуля. AudioWorkletProcessor работает в другом потоке и не имеет доступа к модулям, которые загружены в основной поток. Следовательно/src/functions.js
загружается дважды. Один экземпляр живет в основном потоке, а другой - в аудиопотоке. Каждый из них не знает о существовании другого.
Вы также можете использовать SharedArrayBuffer
Создайте объект общей памяти в одном модуле.
const length = 100;
const size = Int32Array.BYTES_PER_ELEMENT * length;
this.sab = new SharedArrayBuffer(size);
this.sharedArray = new Int32Array(this.sab);
Отправить это AudioWorkletProcessor
this.worker.port.postMessage({
sab: this.sab
});
в AudioWorkletProcessor
this.port.onmessage = event => {
this.sharedArray = new Int32Array(event.data.sab);
}
Теперь оба модуля используют один и тот же массив (this.sharedArray
).