问题
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