【问题标题】:Should I disconnect nodes that can't be used anymore?我应该断开不能再使用的节点吗?
【发布时间】:2021-11-13 19:26:35
【问题描述】:

我正在尝试使用网络音频,并制作了一个播放音符的功能。

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) 线,振荡器消失,但增益永远保持连接到 AudioDestination。

我不想因为连接很多旧东西而导致内存泄漏或性能下降。 创建节点后需要清理到什么程度?我应该停止振荡器吗?断开一切?两者都有?

【问题讨论】:

    标签: web-audio-api


    【解决方案1】:

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

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

    只需将此回调添加到您的 make_triangle 函数中的振荡器就足够了:

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

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

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

    提示

    另外,让一个增益节点保持连接到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);
    

    【讨论】:

      【解决方案2】:

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

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

      如果这没有发生,那就是实现中的错误。

      可能是 Firefox 的 WebAudio 开发人员选项卡中出现增益节点的错误。但这也可能是 Firefox 实现中的错误。

      【讨论】:

      • 您对这种自动断开连接行为有任何参考吗?
      • webaudio.github.io/web-audio-api/#DynamicLifetime。这不是规范,但我相信每个浏览器都会这样做。当已停止的源节点可以与下游节点断开连接时,它可以节省大量 CPU。
      猜你喜欢
      • 2013-12-26
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 2021-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多