actionscript-3adobe-animate

How to STOP looping sound when going into next frame/Errors


I have a flash project broken up into multiple frames, with a button on each frame that goes to play the next frame. (And a movieclip on each frame that plays until you hit next frame button)

On each frame, I want audio to play, and loop. But, I want the audio from one frame to stop when I click the button to go to the next.

On frame 4, I have this code:

import flash.media.SoundChannel;

var sound:Sound = new firt2();
var soundChannel:SoundChannel;

sound.addEventListener(Event.COMPLETE, onSoundLoadComplete);

sound.play();

function onSoundLoadComplete(e:Event):void{
    sound.removeEventListener(Event.COMPLETE, onSoundLoadComplete);
    soundChannel = sound.play();
    soundChannel.addEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);
}

function onSoundChannelSoundComplete(e:Event):void{
    e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);

}

And it works. However, I want to stop it once I click the button to go to the next frame. I have tried: soundChannel.stop(); On the next frame.

However, whenever I do that, the output reads:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at hhh4_fla::MainTimeline/frame5()
at flash.display::MovieClip/gotoAndPlay()
at hhh4_fla::MainTimeline/fl_ClickToGoToAndPlayFromFrame()

All of my buttons and movieclip have instance names.


Solution

  • Rather than figuring why it doesn't work with all these frames and timelines, I think it's better to compose a centralized sound manager class that handles these things.

    Implementation. Keep in mind that I didn't test that so please excuse me for occasional typo if any. The logic of it all should be correct.

    package
    {
        import flash.system.ApplicationDomain;
    
        import flash.media.SoundChannel;
        import flash.media.Sound;
    
        import flash.events.Event;
    
        public class Audio
        {
            // Container to cache Sound objects.
            static private const cache:Object = new Object;
    
            // Variables to hold the current values.
            static private var currentChannel:SoundChannel;
            static private var currentSound:String;
    
            // Stops the current sound playing. If you pass the sound name, it
            // will stop the audio track only if it is the exact one playing.
            // Otherwise it will stop any one currently playing.
            static public function stop(value:String = null):void
            {
                // Do nothing if nothing is playing right now,
                // or if the specific sound requested to stop does not match.
                if (currentSound == null) return;
                if (value) if (value != currentSound) return;
    
                // Unsubscribe from event and stop the audio.
                currentChannel.removeEventListener(Event.SOUND_COMPLETE, onComplete);
                currentChannel.stop();
    
                // Final clean-up.
                currentChannel = null;
                currentSound = null;
            }
    
            // Plays the embedded sound by its class name.
            static public function play(value:String):void
            {
                // Do nothing if the requested sound is already playing.
                if (value == currentSound) return;
    
                // Stop the current audio track playing.
                stop();
    
                // Check if that one sound is valid and/or was previously requested.
                if (!cache[value])
                {
                    try
                    {
                        // Obtain class definition from the project.
                        var aClass:Class = ApplicationDomain.currentDomain.getDefinition(value) as Class;
    
                        // Try instantiating the Sound.
                        if (aClass) cache[value] = new aClass as Sound;
                    }
                    catch (fail:Error)
                    {
                        // Well, do nothing, yet.
                    }
                }
    
                if (cache[value])
                {
                    // Store the id of audio track that is going to be playing.
                    currentSound = value;
    
                    // Play the track and subscribe to it for the SOUND_COMPLETE event.
                    currentChannel = (cache[value] as Sound).play();
                    currentChannel.addEventListener(Event.SOUND_COMPLETE, onComplete);
                }
                else
                {
                    // If there's no such class, or it is not a Sound,
                    trace("ERROR: there's no sound <<" + value + ">> is embedded into the project.");
                }
            }
    
            // Event handler to clean up once the current audio track is complete.
            static private function onComplete(e:Event):void
            {
                // Sanity check.
                if (e.target != currentChannel) return;
    
                stop();
            }
        }
    }
    

    Usage.

    import Audio;
    
    // Any time you want different sound to play.
    // Pass the class name as Sting as an argument.
    Audio.play("firt2");
    
    // Any time you just want to stop the sound;
    Audio.stop();