Fading Sound

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!