Should I disconnect nodes that can't be used anymore?

风流意气都作罢 提交于 2019-12-14 03:55:41

问题


I'm experimenting with Web Audio, and I made a function to play a note.

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

Usage is something like this:

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

This works just fine.

Firefox has a Web Audio tab in its developer console. When I play the sound, the Oscillator and Gain show up in the graph. Without the osc.stop(start + 2*duration) line, these linger forever. With the osc.stop(start + 2*duration) line, the Oscillator goes away, but the Gain stays connected to the AudioDestination forever.

I don't want to cause a memory leak or performance hit from having lots of old things still connected. To what extent do I need to clean up after creating nodes? Should I stop the oscillator? Disconnect everything? Both?


回答1:


If you don't want the oscillator to live forever, you definitely need to schedule it to stop eventually. Otherwise it will play forever, consuming resources. A really smart implementation might be be able to do something clever, but I wouldn't depend on that because that's not required.

When the oscillator stops it should automatically disconnect itself from any downstream nodes. If there are no other references to the oscillator or any of the downstream nodes either, then they should all be eventually collected without you having to do anything.

It is a bug in the implementation if this doesn't happen.

It could be a bug in Firefox's WebAudio developer tab that the gain node still appears. But it could also be a bug in Firefox's implementation.




回答2:


The Web Audio API is designed for oscillators to stop as soon as their 'note' finishes [1]. If you use the line osc.stop(start + 2*duration) then the oscillator will be disconnected from the gain and destroyed immediately.

If you don't plan on reusing the gain node that your oscillator was connected to, then I would suggest disconnecting it so that it can be garbage-collected.

Simply adding this callback to the oscillator within your make_triangle function would suffice:

  ...

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

The callback is triggered as soon as the oscillator has ended its lifetime (ie: when the stop method has been called or scheduled with a timing parameter)

If you try this with Firefox's Web Audio tab open, you'll see that disconnected gain nodes are eventually garbage-collected (as long as nothing else is connected to the gain node).

Tip

Also, it's not a bad idea to have a single gain node that you keep connected to the AudioContext so that other nodes can connect up to it. This 'final-gain' is useful for mixing all other connected nodes and keeping them from clipping (ie: exceeding an amplitude of 1). You could pass this node into your make_triangle function as a parameter like so:

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


来源:https://stackoverflow.com/questions/46203191/should-i-disconnect-nodes-that-cant-be-used-anymore

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!