kittykatattack / sound.js

A micro-library to load, play and generate sound effects and music for games and interactive applications
300 stars 44 forks source link

Sound changes, fades, and then quits #7

Closed harlankoehn closed 8 years ago

harlankoehn commented 8 years ago

I have the following sound that I play many times on my game. After about 100 or 150 plays, the sound starts to sound different and eventually quits completely. I've verified that it is not a speaker issue. Reloading the page makes the sound come back. I'm using Chrome 47.0.2526.106. I'm also seeing high CPU usage.

function gotOneCorrectSound() { soundEffect( 60, //frequency 0, //attack 0.1, //decay "sawtooth", //waveform 0.3, //Volume 0, //pan 0, //wait before playing 600, //pitch bend amount false, //reverse bend 0, //random pitch range 0, //dissonance [0.1, 0.1, 1000], //echo: [delay, feedback, filter] undefined //reverb: [duration, decay, reverse?] ); }

harlankoehn commented 8 years ago

I've been looking into this issue more. It appears to be a garbage collection issue. I'm playing lots of short soundEffects and I don't see any node.stop function getting called.

in the soundEffect function, I added a node.stop statement and it fixed the problem. However, my node.stop statement is hardcoded to a set length and it wouldn't probably work in all circumstances. I'm not sure how the length of the sound effect can be determined, or if it can be. Here's my code:

function play(node) { node.start(actx.currentTime + wait); node.stop(actx.currentTime + wait + 2); //I added this and it fixed my problem. }

kittykatattack commented 8 years ago

Thanks for your detailed report! I think for now we should probably add a default timeout to patch up this memory leak. Do you think 10 seconds would be reasonable to cover most kinds of sound effects? (I can add a 14th parameter to let the user specify a custom timeout.)

Oscillator nodes don't seem to have length or duration properties http://webaudio.github.io/web-audio-api/#the-oscillatornode-interface ... but It might be possible to programmatically figure out when the sound is finished and stop it manually - I will do some more investigation :)

harlankoehn commented 8 years ago

There is an onended event but I attempted to use it and it didn't seem to work. It fires after you call the stop method.

It seems like it would be best just to have a default timeout to make sure Garbage Collection eventually cleans up all of them. Ten seconds sounds longer than necessary but would probably be a safe number since you can run a hundred or more without any GC before it starts to fail (depending on your hardware).

Do you think the duration could somehow be guessed at by looking at things like decay, reverb, echo, etc?

kittykatattack commented 8 years ago

I've done a lot more research and it seems that the setting a default timeout is the best solution. I think your 2 second recommendation is good, because sound effects are rarely longer than that. Users can then override that if they need to.

But, I'm not giving up yet! :) I've posted a StackOverflow question about this:

http://stackoverflow.com/questions/34501535/how-can-i-find-out-if-a-webaudio-oscillator-is-silent?noredirect=1#comment56748272_34501535

I'll add a bounty if we don't get any definitive answers in within the next day.

Ideally it would be nice the WebAudio spec. requires automatic garbage collection for silent oscillators, but there might be a good reason why it doesn't.

kittykatattack commented 8 years ago

There was a really good answer posted in the Stack Overflow link above.

http://stackoverflow.com/a/34529335/1282216

But, because it requires running a sound analysis script on each oscillator, I'm sceptical that it will be performant enough for games. So, I'm going to close this issue for now and set a default timeout of 2 seconds for oscillators, which can be overridden by the user. If anyone would like to suggest a better solution, please let us know and we'll re-open this issue.

bugfreetech commented 8 years ago

i just wanted to thank you for fixing this problem, it is the only one i was having issues with and as such, a deal breaker when trying to make a game. The leak was present in both loaded sounds, and generated ones (which were far worse) and would chew a few MB of memory per play until the browser crashed Thanks again!

-- update: if you go to the demo page and spam press ijkl after a while it starts to lag out, memory usage increases around 100MB, but after about 10 seconds fixes itself up again. great stuff!