Hey All,
So i have a sound class that i wrote to handle the playing of music files. Basically at any time I will have 3 tracks ready to be played with one playing at 100% volume and the other two stopped and not playing.
When i press buttons on the keyboard i can fade into the next track and fade out of the current track. Now this all works well until after I’ve changed tracks about 30 -35 times.
Then all of a sudden, my computer freezes up and I have to cold restart it.
Am i not cleaning up my timers or sound objects properly? Here’s the code for the Music Class (apologies for the length, but it’s pretty straightforward).
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.events.IOErrorEvent;
import flash.net.URLRequest;
import flash.media.SoundLoaderContext;
import flash.utils.Timer;
import flash.events.TimerEvent;
class Sound_MusicTrack {
//the path for loading the file
private var filePath:String;
//the actual music data
private var track:Sound;
//the percentage loaded
private var loadedPercent:uint;
//the context for streaming
private var context:SoundLoaderContext;
//the position of the playhead
private var position:int;
//whether we are going to repeat or not
private var repeat:Boolean;
//the channel reference
private var channel:SoundChannel;
//the sound transform reference
private var trans:SoundTransform;
//timer for fading in or out
private var fadeTimer:Timer;
//constructor
public function Sound_MusicTrack(_filePath:String, _vol:Number) {
//construct this bad boy
//make sure it knows where to load from
filePath = _filePath;
//reference to the soundChannel that plays this sound
channel = new SoundChannel();
//by default we want the music to loop when finished.
repeat = true;
//by default we want the music to start at the beginning (0ms).
position = 0;
//create a new sound transform object with passed volume and center pan.
trans = new SoundTransform(_vol, 0);
}
//function to get the position
function getPosition() {
//returns the position
return channel.position;
}
//function to set the position
function setPosition(_pos:int) {
//sets the position
position = _pos;
}
function setTrans(_trans:SoundTransform) {
trans = _trans;
}
//function to load the Musical Track - should only run once
public function loadTrack() {
//creates a new sound
track = new Sound();
//adds the event listeners for progress, errors, and when completed.
track.addEventListener(ProgressEvent.PROGRESS, whileLoading);
track.addEventListener(Event.COMPLETE, whenComplete);
track.addEventListener(IOErrorEvent.IO_ERROR, ifIOError);
//allows for 5 seconds of music to be loaded before playing
context = new SoundLoaderContext(5000, false);
//loads the Music Track from the specified filePath
var req:URLRequest = new URLRequest(filePath);
//creates a sound object and defaults to playing the file
track.load(req, context);
}
//function for while loading to display the progress...
private function whileLoading(event:ProgressEvent):void {
//updates the loaded percentage
loadedPercent = Math.round(100* (event.bytesLoaded / event.bytesTotal));
trace("Sound is " + loadedPercent + "% loaded.");
}
//function for when the track is loaded
private function whenComplete(event:Event):void {
trace("SOUND LOADED COMPLETE");
//cleanup, we don't need the listeners anymore.
track.removeEventListener(ProgressEvent.PROGRESS, whileLoading);
track.removeEventListener(Event.COMPLETE, whenComplete);
track.removeEventListener(IOErrorEvent.IO_ERROR, ifIOError);
}
//function in case there is an Input/Output Error
private function ifIOError(event:IOErrorEvent) {
trace("This sound could not be loaded: " + event.text);
}
//plays the track
public function playTrack() {
//if we have a repeating track...
if (repeat == true) {
//start from the position and repeat forever.
//Technically if they play longer than 70 years the sound will stop.
channel = track.play(position, int.MAX_VALUE, trans);
}
//otherwise...
else {
//just start from the position
channel = track.play(position, 0, trans);
}
}
//pauses the track
public function pauseTrack() {
//get the current position of the track and update the variable
position = channel.position;
//stops the track from playing.
channel.stop();
}
//function to change the volume down
private function changeVolumeDown(e:TimerEvent) {
//decrement the volume
trans.volume -= 0.05;
//just in case we go below 0
if (trans.volume < 0) {
trans.volume = 0;
killFadeOut();
}
//set the transform in order to update the volume
channel.soundTransform = trans;
trace("FADE OUT VOLUME " + filePath + " " + trans.volume);
}
private function changeVolumeUp(e:TimerEvent) {
trans.volume += 0.05;
if (trans.volume > 1) {
trans.volume = 1;
killFadeIn();
}
channel.soundTransform = trans;
trace("FADE IN VOLUME " + filePath + " " + trans.volume);
}
public function fadeOut() {
if (fadeTimer != null) {
killFadeOut();
}
var count:int = int(trans.volume/0.05);
//we want the whole thing to take approximatley 5 seconds to do.
var time:int = int(5000/count);
fadeTimer = new Timer(time, count);
fadeTimer.addEventListener(TimerEvent.TIMER, changeVolumeDown);
fadeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, cleanFadeOut);
fadeTimer.start();
}
private function cleanFadeOut(e:TimerEvent) {
if (fadeTimer != null) {
killFadeOut();
pauseTrack();
}
}
public function fadeIn() {
if (fadeTimer != null) {
killFadeIn();
}
var count:int = int(1/0.05);
//we want the whole thing to take approximatley 5 seconds to do.
var time:int = int(5000/count);
fadeTimer = new Timer(time, count);
fadeTimer.addEventListener(TimerEvent.TIMER, changeVolumeUp);
fadeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, cleanFadeIn);
fadeTimer.start();
}
private function cleanFadeIn(e:TimerEvent) {
if (fadeTimer != null) {
killFadeIn();
}
}
private function killFadeIn() {
//stops the timer
fadeTimer.stop();
//removes all event listeners
fadeTimer.removeEventListener(TimerEvent.TIMER, changeVolumeUp);
fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, cleanFadeIn);
fadeTimer = null;
}
private function killFadeOut() {
//stops the timer
fadeTimer.stop();
//removes all event listeners
fadeTimer.removeEventListener(TimerEvent.TIMER, changeVolumeDown);
fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, cleanFadeOut);
fadeTimer = null;
}
/*
Quirk in Flash when Streaming sounds. Pausing the sound will cause the sound
to stop for 1 frame and then play again. Must use Sound.close() to stop
both playing and loading... Can we resume loading from the same location?
*/
}
And what calls it (when pressing on the keyboard):
public function switchTracks(_type:String) {
trace(_type);
if (_type == "attack") {
//Set the position of the track to be the same as the position in the current track
attackTrack.setPosition(current.getPosition());
//start playing the track (Volume will be 0)
attackTrack.playTrack();
//fade out the current track
current.fadeOut();
//fade in the new track
attackTrack.fadeIn();
//assign the new track to be the current track
current = attackTrack;
}
else if (_type == "talk") {
talkTrack.setPosition(current.getPosition());
talkTrack.playTrack();
current.fadeOut();
talkTrack.fadeIn();
current = talkTrack;
}
else if (_type == "normal") {
normalTrack.setPosition(current.getPosition());
normalTrack.playTrack();
current.fadeOut();
normalTrack.fadeIn();
current = normalTrack;
}
}
Any help or ideas would be greatly appreciated. Am i doing this right? In terms of cleaning up after myself and changing the volume of a playing music track on the fly?
Thanks!