views:

2847

answers:

4

Hi there, I'm having some issues with looping a sound in flash AS3, in that when I tell the sound to loop I get a slight delay at the end/beginning of the audio.

The audio is clipped correctly and will play without a gap on garage band.

I know that there are issues with sound in general in flash, bugs with encodings and the inaccuracies with the SOUND_COMPLETE event (And Adobe should be embarrassed with their handling of these issues)

I have tried to use the built in loop argument in the play method on the Sound class and also react on the SOUND_COMPLETE event, but both cause a delay.

But has anyone come up with a technique for looping a sound without any noticeable gap?

+1  A: 

Here is how id did it, with no noticeable delay. Main app:

package {

import flash.display.MovieClip; 
import flash.events.*;
import flash.utils.*;

public class MainApp extends MovieClip {
  private var player:Player;
  ..........

  public function MainApp() {
      .......
      player = new Player();
      player.addEventListener(Player.EVENT_SOUND_COMPLETED, handleSoundCompleted);
      ......
  }

  private function handleSoundCompleted(event:Event):void {
      player.setPosition(0);
      player.play();
  }

  .................

Player class:

package {

import flash.events.*;
import flash.media.*;
import flash.net.*;

public class Player extends EventDispatcher {

    private var sound:Sound;
    private var channel:SoundChannel;
    private var position:Number;

    static const SOUND_VOLUME:Number = 0.75;
    static const EVENT_SOUND_COMPLETED:String = "SOUND_COMPLETED";

    public function Player() {

        // init
        sound = new ThemeSong();
        position = 0;

        // listeners
        sound.addEventListener(IOErrorEvent.IO_ERROR, function(event:Event){trace(event)});

        trace("Player initialized...");
    }

    public function play():void {
        channel = sound.play(position);
        channel.soundTransform = new SoundTransform(SOUND_VOLUME);
        channel.addEventListener(Event.SOUND_COMPLETE, function(event:Event){dispatchEvent(new Event(EVENT_SOUND_COMPLETED));});
        trace("Player playing..");
    }

    public function pause():void {
        if (channel != null) {
            channel.stop();
            position = channel.position;
        }
        trace("Player paused..");
    }

    public function setPosition(pos:Number):void {
        position = pos;
    }

    public function getPosition():Number {
        if (channel == null) {
            return 0;
        } else {
            return channel.position;
        }
    }
}
}

You did say that the mp3 file has no delay at beginning/end, but I suggest opening it with audacity, and make sure there is no delay.

Mercer Traieste
Hey there Mercer, this is essentially the approach I've been using, expect it do not re-position the audio each time the sounds completes. I'll give that a go and see how it works out. Thanks
Brian Heylin
Hey Mercer, I've tried this just now and the gap is too noticeable for looping music. Thanks for sharing your code, tho!
aaaidan
Oh actually, reverse that. It may be that this method works. The sound I was using had tiny gaps at the start and end. Cheers
aaaidan
+4  A: 

The most reliable method, if you can use Flash Player 10, is to use the new SampleDataEvent.SAMPLE_DATA event.

Specifically, what you do is to first instantiate the sound you want, then use the new extract method to convert the sound into raw PCM data encoded in a ByteArray. Then you can create a new Sound object, and setup to listen for it's SampleDataEvent.SAMPLE_DATA event. When that event is called you'll push 2-8k (a lower amount reduces latency, but increases the possibility of audible artifacts) of data from the ByteArray. You'll just make sure that as you run off the end of the ByteArray you'll just loop back to the beginning.

This method ensures that you'll have fully gapless playback.

Branden Hall
This is a cool feature and it's made possible some awesome stuff (like hobnox), but it's a shame one must resort to low level byte manipulation just to play a sound loop smoothly. The audio support in the player and the sound API suck big time.
Juan Pablo Califano
It is too bad, but these problems all lie in the fact that the Flash Player sound engine is really old, and simply needs an update, which should be coming in player 11.
Tyler Egeto
Certainly is more involved than calling play() :) But sounds like a deterministic solution. I'll give it a try Brandon and get back to you on it.
Brian Heylin
Man, that gets me so pissed off that you have to resort to this! Such a ludicrously CPU and memory intensive thing to do just to get music to loop seamlessly!
aaaidan
A: 

According to this guy, you have to import the music loop as a wav, and have the Flash IDE itself compress to mp3. Having Flash use imported mp3 data means that it won't know how to loop it properly.

aaaidan
+3  A: 

Gapless looping of mp3's is not trivial due to the way the format works. To simplify a bit; the sound is fitted to a number of frames, this number cannot be chosen arbitrarily, instead some padding (with silence) is required. Mp3 has no way of storing how much padding was added, so this information is lost once the file is encoded.

The flash IDE get's around this by embedding this metadata, and you can too. You just need to know how much delay is added by the encoder.

Andre Michelle explains this way better than I can on his blog.

grapefrukt