Creating and Seamless Audio Stream in AS3
February 18th, 2010I was frustrated that there was no ActionScript3 equivalent for setting an audio clip to Stream as you can inside of Flash. I wanted to create a seamless audio loop that was synced with a corresponding looping MovieClip. Because the audio never quite lined up on the last frame of the MovieClip inside Flash CS4, there was always an audible seam. I created a class called AudioStreamController which takes a MovieClip and a Sound object as parameters. On ENTER_FRAME the playback of the MovieClip seeks to the frame of the corresponding Sound position (assuming that the MovieClip is roughly the length of your Sound).
{
import flash.events.*;
import flash.media.*;
import flash.display.*;
public class AudioStreamController extends EventDispatcher
{
/** The sound channel to control sound playback */
private var __channel:SoundChannel;
/** The sound object */
private var __sound:Sound;
/** The number of times to loop the animation */
public var loops:int = 1;
/** The animatino to sync to audio */
public var __clip:MovieClip;
/** The total number of frames */
public var __frames:int;
/** The last paused position */
public var __lastPosition:int;
/**
* The purpose of this class is to replicate the syncing that
* you can do in Flash using the audio "Stream" setting
* @param clip The animation you want to sync
* @param sound The sound object you want to play
*/
public function AudioStreamController(clip:MovieClip, sound:Sound): void
{
__sound = sound;
__clip = clip;
__frames = clip.totalFrames;
stop();
}
/**
* Start the playback of the audio and listen for new frame enter
* to seek to the correct frame of the animation
*/
public function play(): void
{
__channel = __sound(__lastPosition, loops);
__clip.addEventListener(Event.ENTER_FRAME, update);
}
/**
* Stop and return to the beginning
*/
public function stop(): void
{
if (__channel)
{
__channel.stop();
}
__lastPosition = 0;
__clip.gotoAndStop(1);
__clip.removeEventListener(Event.ENTER_FRAME, update);
}
/**
* Pause the playback and save the current position
*/
public function pause(): void
{
__clip.removeEventListener(Event.ENTER_FRAME, update);
__lastPosition = __channel.position;
__channel.stop();
}
/**
* Update event called on entering new frame of the animation
* @param ev Enter frame event
*/
protected function update(ev:Event): void
{
// This is the percentage of progress of all the loops
var percent:Number = __channel.position / (__sound.length * loops);
// The current frame over all the loops
var f:int = Math.round((__frames - 1) * loops * percent) + 1;
// The current frame gets converted into a frame on a single loop
f = f - int(f / __frames) * __frames;
__clip.gotoAndStop(f);
if (percent > 0.999)
{
__clip.removeEventListener(Event.ENTER_FRAME, update);
__clip.gotoAndStop(__frames);
dispatchEvent(new Event(Event.COMPLETE));
}
}
/**
* Destroy this controller object
* don't use after this point
*/
public function destroy(): void
{
__clip.removeEventListener(Event.ENTER_FRAME, update);
stop();
__clip = null;
__sound = null;
__channel = null;
}
}
}














