我应该断开不再使用的节点吗?

时间:2017-09-13 17:03:23

标签: web-audio

我正在尝试使用网络音频,我发挥了一个功能来播放音符。

var context = new (window.AudioContext || window.webkitAudioContext)()

var make_triangle = function(destination, frequency, start, duration) {
    var osc = context.createOscillator()
    osc.type = "triangle"
    osc.frequency.value = frequency

    var gain = context.createGain()

    osc.connect(gain)
    gain.connect(destination)

    // timing
    osc.start(start)
    osc.stop(start + 2*duration) // this line is discussed later
    gain.gain.setValueAtTime(0.5, start)
    gain.gain.linearRampToValueAtTime(0, start+duration)
}

用法是这样的:

make_triangle(context.destination, 440, context.currentTime+1, 1)

这很好用。

Firefox的开发者控制台中有一个Web Audio标签。当我播放声音时,振荡器和增益显示在图表中。如果没有osc.stop(start + 2*duration)行,这些就永远存在。使用osc.stop(start + 2*duration)行,振荡器会消失,但Gain会永远与AudioDestination保持连接。

我不希望因为仍然连接了许多旧东西而导致内存泄漏或性能损失。 创建节点后我需要在多大程度上清理?我应该停止振荡器吗?断开一切?既?

2 个答案:

答案 0 :(得分:1)

如果您不希望振荡器永远存在,您肯定需要安排它最终停止。否则它将永远发挥,消耗资源。一个非常聪明的实现可能能够做一些聪明的事情,但我不会依赖它,因为这不是必需的。

当振荡器停止时,它应自动断开自身与任何下游节点的连接。如果没有其他对振荡器或任何下游节点的引用,那么它们最终都应该被收集而不必做任何事情。

如果不发生这种情况,这是实施中的错误。

Firefox的WebAudio开发人员标签中可能存在增益节点仍然出现的错误。但它也可能是Firefox实施中的一个错误。

答案 1 :(得分:1)

Web Audio API旨在让振荡器在“注释”结束后立即停止[1]。如果使用行osc.stop(start + 2*duration),则振荡器将与增益断开连接并立即销毁。

如果您不打算重新使用振荡器所连接的增益节点,那么我建议将其断开以便可以对其进行垃圾回收。

只需将此回调添加到make_triangle功能中的振荡器即可:

  ...

  osc.onended = function() {
    gain.disconnect();
  };
};

一旦振荡器结束其生命周期(即:调用stop方法或使用时序参数调度时),就会触发回调。

如果您在Firefox的Web Audio选项卡打开的情况下尝试此操作,您将看到断开连接的增益节点最终被垃圾收集(只要没有其他连接到增益节点)。

提示

此外,拥有一个与AudioContext连接的单个增益节点并不是一个坏主意,以便其他节点可以连接到它。这种“最终增益”对于混合所有其他连接节点并防止它们被削波(即:超过幅度1)非常有用。您可以将此节点作为参数传递到make_triangle函数中,如下所示:

var context = new (window.AudioContext || window.webkitAudioContext)()

// Gain that will remain connected to `AudioContext` 
var finalGain = context.createGain();
finalGain.connect(context.destination);

var make_triangle = function(destination, frequency, start, duration) {
    var osc = context.createOscillator()
    osc.type = "triangle"
    osc.frequency.value = frequency

    var gain = context.createGain()

    osc.connect(gain)
    gain.connect(destination)

    // timing
    osc.start(start)
    osc.stop(start + 2*duration) // destroy osc and disconnect from gain
    gain.gain.setValueAtTime(0.5, start)
    gain.gain.linearRampToValueAtTime(0, start+duration)


    // Added for cleanup:
    osc.onended = function() {
        gain.disconnect();
    };
};

// Connect a new triangle osc to the finalGain 
make_triangle(finalGain, 440, context.currentTime, 1);