AS3 Sound Channel Bug
I don't know if this has been documented or not.
If you set a Sound to loop, it's channel.position property returns a number out of range of the Sound.length after it loops. The position property just keeps on incrementing beyond the length when you loop a sound.
If you try to play a Sound from that out of range position, the Sound glitches out, because that position is invalid, even though Flash returns it to you, implying it's valid. Flash should not return an invalid position to you.
This all revolves around the fact that Sound has absolutely no way to pause right now. I don't know why Adobe did not give us a channel.pause() method. Because they chose not to, this bug has bad consequences.
The only way to pause and unpause a sound in Flash is to store the current position of the channel and call channel.stop(), and when you unpause, you call sound.play(position). This works fine if you're only playing the sound once. If you're looping, however, it doesn't at all.
If the sound is looping, the position returned will eventually be higher than the length, which means the Sound glitches because you're passing an out of range position; a position, once again, that Flash returned to you as valid.
Wait, it gets worse. If you unpause a looping sound by passing its position, when it loops, it will loop from that position, not the beginning of the Sound. Problem!
There is no pause method for channel, and without a pause method, there is no workaround for the above bug and issue except to manually loop a Sound by adding an event listener to the sound complete event (which can be unreliable), calling play on it again and managing the looping manually, which undermines the loops argument of the Sound.play() method and requires a fair amount of code.
Adobe, we need a channel.pause(flag:Boolean) method.
Posted in Actionscript, Bugs, Flash, Rants
August 7th, 2008 at 6:40 am
currentPosition = position%length;
November 9th, 2008 at 11:11 pm
Does AS3 not have a modulus function? If so, position [mod] length would return the position you're looking for.
December 6th, 2008 at 5:48 pm
Please explain the modulus solution a little more? I can only get it to loop from the start not from where I paused it.
December 19th, 2008 at 9:34 am
Use it in good health!
pausePosition = channel.position%this.music.length;
February 4th, 2009 at 10:19 am
There is one "workaround"…
Do not use repating sound clip (set it to 1) and then add listener to SOUND_COMPLETE where you will play sound from position 0 again).
Below is a function that plays hides this and plays from a given position (so that you can play/pause). This function also preserves current soundTransgorm (i.w., volue and pan).
function playClip(snd:Sound, chn:SoundChannel, pos:Number):void {
chn = snd.play(pos, 1, (chn != null ? chn.soundTransform : null));
chn.addEventListener(Event.SOUND_COMPLETE, function(event:Event):void {playClip(0)});
}
I hope that this helps…
March 30th, 2009 at 11:12 pm
Nice idea Vladimir,
Thanks for your solution.
Unfortunately, I have found another AS3 Sound bug during use your solution. The the SOUND_COMPLETE event gose crazy after call over 4~500 times the snd.play() method. The SOUND_COMPLETE event raises too slow, it raise when flash want.
May 22nd, 2009 at 6:18 am
This is a bit of an oversight from Adobe.
So the upshot is you can't pause a looping sound without handcoding an onComplete handler with your own manual loop counter, making things much more complex than they need to be.
And if you want the loop to be seamless, forget it. Ouch.
October 26th, 2009 at 1:15 pm
@vladimir & @ joshua
I like Vladimir's solution. I think the reason you might be getting errors is that each time it loops it adds a listener.
I just added a removeEventListener before before the addEventListener (seems to work)
Although I have not figured out how to change the volume once this loop has started… I think I have tried everything, but if anyone has a tip I would appreciate it.
@others
I have tried the formula -
newPosition = channel.position % sound.length
This has constantly failed for me no matter how I work with it… I still get weird loops. It actually cuts my loops in half each time i pause and start… which after a few times leaves me with a really loud annoying noise.
January 22nd, 2010 at 9:17 am
@all
You may be pleased to know that this issue appears to be addressed in Flash CS5.
I just put together a test, and on EnterFrame, displayed the channel.position of the looping clip. The looping was set during channel.play(lastposition, 999);
It resets the position to 0(zero) each time it enters a new loop, so my pause button (which stores the current position) works properly each time I resume.
February 15th, 2010 at 9:10 am
I found a satisfactory solution @ http://tudway.blogspot.com/2008/04/sound-in-flash-cs3-part-2-pause.html