由于旧的 Webaudio 脚本处理器自 2014 年以来已被弃用,并且 Audioworklets 在 Chrome 64 中出现,我决定尝试一下。但是我在移植我的应用程序时遇到了困难。我将从一篇不错的文章中举两个例子来说明我的观点。
首先是脚本处理器方式:
var node = context.createScriptProcessor(1024, 1, 1);
node.onaudioprocess = function (e) {
var output = e.outputBuffer.getChannelData(0);
for (var i = 0; i < output.length; i++) {
output[i] = Math.random();
}
};
node.connect(context.destination);
另一个填充缓冲区然后播放它:
var node = context.createBufferSource(), buffer =
context.createBuffer(1, 4096, context.sampleRate), data = buffer.getChannelData(0);
for (var i = 0; i < 4096; i++) {
data[i] = Math.random();
}
node.buffer = buffer;
node.loop = true;
node.connect(context.destination);
node.start(0);
两者之间的最大区别是第一个在播放期间用新数据填充缓冲区,而第二个预先生成所有数据。
由于我生成了大量数据,因此我无法事先进行。Audioworklet有很多示例,但它们都使用其他节点,只需在这些节点上运行 .start(),连接它,它就会开始生成音频。当我没有这样的方法时,我无法找到一种方法来做到这一点。
所以我的问题基本上是如何在 Audioworklet 中执行上述示例,当数据在某个数组的主线程中连续生成并且该数据的播放发生在 Webaudio 线程中时。
我一直在阅读有关消息端口的内容,但我也不确定这是否可行。这些例子并没有将我指向我所说的那个方向。我可能需要的是用我自己的数据在 AudioWorkletProcesser 派生类中提供流程函数的正确方法。
我目前基于脚本处理器的代码位于github,特别是 vgmplay-js-glue.js。
我一直在向 VGMPlay_WebAudio 类的构造函数添加一些代码,从示例转到实际结果,但正如我所说,我现在不知道该朝哪个方向移动。
constructor() {
super();
this.audioWorkletSupport = false;
window.AudioContext = window.AudioContext||window.webkitAudioContext;
this.context = new AudioContext();
this.destination = this.destination || this.context.destination;
this.sampleRate = this.context.sampleRate;
if (this.context.audioWorklet && typeof this.context.audioWorklet.addModule === 'function') {
this.audioWorkletSupport = true;
console.log("Audioworklet support detected, don't use the old scriptprocessor...");
this.context.audioWorklet.addModule('bypass-processor.js').then(() => {
this.oscillator = new OscillatorNode(this.context);
this.bypasser = new AudioWorkletNode(this.context, 'bypass-processor');
this.oscillator.connect(this.bypasser).connect(this.context.destination);
this.oscillator.start();
});
} else {
this.node = this.context.createScriptProcessor(16384, 2, 2);
}
}