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.
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();