由于自2014年起就不再使用旧的Webaudio脚本处理器,并且Audioworklets出现在Chrome 64中,因此我决定尝试一下。但是,我在移植应用程序时遇到困难。我将通过一个很好的article给出2个示例来说明我的观点。
首先是脚本处理器方式:
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有很多examples,但是它们都使用其他节点,可以在其上运行.start()并将其连接起来,它将开始生成音频。当我没有这样的方法时,我无法解决这个问题。
因此,我的问题基本上是在音频工作集中执行上面的示例时,当数据在某个数组的主线程中连续生成并且该数据的回放在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);
}
}
最佳答案
所以我的问题主要是如何在Audioworklet中执行上述示例,
对于第一个示例,已经有一个AudioWorklet版本:
https://github.com/GoogleChromeLabs/web-audio-samples/blob/gh-pages/audio-worklet/basic/js/noise-generator.js
我不建议使用第二个示例(也称为缓冲区缝合),因为它会创建很多源节点和缓冲区,因此可能导致GC干扰主线程中的其他任务。如果计划的开始时间不落在样本上,则两个连续缓冲区的边界处也会发生不连续性。话虽如此,您将无法在此特定示例中听到毛刺,因为源材料是噪音。
当在某个数组的主线程中连续生成数据时,并且在Webaudio线程中发生了该数据的回放。
您应该做的第一件事是将音频生成器与主线程分开。音频生成器必须在AudioWorkletGlobalScope
上运行。那就是AudioWorklet系统的全部目的-更低的延迟和更好的音频渲染性能。
在your code中,
应该在VGMPlay_WebAudio.generateBuffer()
回调中调用AudioWorkletProcessor.process()
来填充处理器的输出缓冲区。这与您的onaudioprocess
回调函数大致匹配。
我一直在阅读有关消息端口的内容,但我不确定这也不是必经之路。这些例子并没有指出我要说的那个方向。我可能需要的是在AudioWorkletProcesser派生类中为处理功能提供我自己的数据的正确方法。
我认为您的用例不需要MessagePort
。我已经在代码中看到了其他方法,但是除了启动和停止节点之外,它们实际上并没有做其他事情。这可以通过在主线程中连接/断开AudioWorkletNode来完成。无需跨线程消息传递。
最后的代码示例可以是AudioWorklet的设置。我很清楚,设置和实际音频生成之间的分离可能很棘手,但这是值得的。
几个问题给您:
游戏图形引擎如何将消息发送到VGM生成器?VGMPlay
类可以在不与主线程进行任何交互的情况下驻留在工作线程上吗?除了启动和停止之外,我在代码中看不到任何交互。XMLHttpRequest
是VGMPlay
类所必需的吗?还是可以在其他地方完成?
关于javascript - 将基于脚本处理器的应用程序移植到audioworklet,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48874118/