Nie*_*iek 5 javascript scriptprocessor web-audio-api
由于旧的 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);
Run Code Online (Sandbox Code Playgroud)
另一种填充缓冲区然后播放它:
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);
Run Code Online (Sandbox Code Playgroud)
两者之间的最大区别是第一个在播放期间用新数据填充缓冲区,而第二个则预先生成所有数据。
由于我生成了大量数据,因此我无法提前完成。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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 3
所以我的问题基本上是如何在 Audioworklet 中执行上面的示例,
对于您的第一个示例,已经有一个 AudioWorklet 版本: https://github.com/GoogleChromeLabs/web-audio-samples/blob/gh-pages/audio-worklet/basic/js/noise-generator.js
我不推荐第二个示例(又名缓冲区拼接),因为它会创建大量源节点和缓冲区,因此可能导致 GC,从而干扰主线程中的其他任务。如果计划的开始时间不在样本上,则两个连续缓冲区的边界处也可能发生不连续性。话虽如此,在这个特定示例中您将听不到故障,因为源材料是噪声。
当数据在主线程中的某个数组中连续生成并且该数据的播放发生在 Webaudio 线程中时。
您应该做的第一件事是将音频生成器与主线程分开。音频生成器必须在AudioWorkletGlobalScope. 这就是 AudioWorklet 系统的全部目的 - 更低的延迟和更好的音频渲染性能。
在您的代码中,
VGMPlay_WebAudio.generateBuffer()应在回调中调用AudioWorkletProcessor.process()以填充处理器的输出缓冲区。这与您的onaudioprocess回调的作用大致匹配。
我一直在阅读有关消息端口的内容,但我也不确定这是否可行。这些例子并没有指出我所说的方向。我可能需要的是用我自己的数据在 AudioWorkletProcesser 派生类中提供处理函数的正确方法。
我认为您的用例不需要MessagePort. 我在代码中看到了其他方法,但除了启动和停止节点之外,它们实际上没有做太多事情。这可以通过在主线程中连接/断开 AudioWorkletNode 来完成。无需跨线程消息传递。
最后的代码示例可以是 AudioWorklet 的设置。我很清楚,设置和实际音频生成之间的分离可能很棘手,但这是值得的。
有几个问题想请教您:
VGMPlay在工作线程上运行而不与主线程进行任何交互吗?除了启动和停止之外,我在代码中没有看到任何交互。XMLHttpRequest上必不可少的吗VGMPlay?或者可以在其他地方完成吗?| 归档时间: |
|
| 查看次数: |
2727 次 |
| 最近记录: |