将基于脚本处理器的应用程序移植到audioworklet

时间:2018-02-19 21:02:11

标签: javascript web-audio web-audio-api scriptprocessor

由于旧的Webaudio脚本处理器自2014年以来已被弃用,而且Audioworklets在Chrome 64中出现,我决定尝试一下。但是我在移植我的应用程序时遇到了困难。我将从一个不错的article中给出两个例子以表明我的观点。

首先是脚本处理器方式:

1   886620  rs201016776    T    A    1:886620-TG
1   879576  rs115979567    C    T
1   886817  rs111748052;rs10465241    C    CATTTT    JHU_1.886816
1   889255  rs150003341    C    T    Variant37585
1   891659  rs116557519    G    A    JHU_1.891658

另一个填充缓冲区然后播放它的人:

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);

两者之间的最大区别是第一个在播放期间用缓冲区填充新数据,而第二个在事先生成所有数据。

由于我生成了大量数据,所以我事先无法做到。 Audioworklet有很多examples,但它们都使用其他节点,人们可以在其上运行.start(),连接它并开始生成音频。当我没有这样的方法时,我无法绕过一种方法来做这件事。

所以我的问题基本上是如何在Audioworklet中执行上述示例,当数据在某个数组的主线程中连续生成并且该数据的回放发生在Webaudio线程中时。

我一直在阅读有关消息端口的事情,但我不确定这是否可行。这些例子并没有指出我会说的那个方向。我可能需要的是使用我自己的数据在AudioWorkletProcesser派生类中提供过程函数的正确方法。

我当前基于脚本处理器的代码位于github,特别是在vgmplay-js-glue.js中。

我一直在为VGMPlay_WebAudio类的构造函数添加一些代码,从示例转到实际结果,但正如我所说,我不知道现在要向哪个方向移动。

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);

1 个答案:

答案 0 :(得分:1)

  

所以我的问题基本上是如何在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的设置。我很清楚,设置和实际音频生成之间的分离可能很棘手,但值得。

很少有人问你:

  1. 游戏图形引擎如何向VGM生成器发送消息?
  2. VGMPlay类是否可以在工作线程上运行而不与主线程进行任何交互?除了启动和停止之外,我在代码中看不到任何交互。
  3. XMLHttpRequest课程必不可少VGMPlay?或者可以在其他地方完成吗?