as3 Sound Class Unloading Sound - actionscript-3

I have tried this for HOURS. There must be a simple solution to stop the sound and unload it in as3.
This is not all of my code, but in short I am loading random sounds. I need certian vars to be outside of the function so I can reference them with other functions for a progress bar.
How do I unload a sound so I can load a new one using the same names without getting an error the second time its called?
I have two buttons in this test. A play Sound and a Stop Sound Button.
here is my code:
var TheSound:Sound = new Sound();
var mySoundChannel:SoundChannel = new SoundChannel();
PlayButton.addEventListener(MouseEvent.CLICK, PlaySound);
StopButton.addEventListener(MouseEvent.CLICK, Stopsound);
function PlaySound(e:MouseEvent)
{
TheSound.load(new URLRequest("http://www.MyWebsite.com/Noel.mp3"));
mySoundChannel = TheSound.play(0);
}
function StopSound(e:MouseEvent)
{
delete TheSound;
}
HERE IS THE ERROR I GET:
Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
at flash.media::Sound/_load()
at flash.media::Sound/load()
at Untitled_fla::MainTimeline/PlaySound()[Untitled_fla.MainTimeline::frame1:21]
UPDATE.... I TRIED STOPING THE SOUND AND THEN UNLOADING IT AS FOLLOWS
mySoundChannel.stop();
TheSound.close();
BUT NOW I GET THIS ERROR:
Error: Error #2029: This URLStream object does not have a stream opened.
at flash.media::Sound/close()
at Untitled_fla::MainTimeline/shut1()[Untitled_fla.MainTimeline::frame1:35]
I believe I am closer. Thanks so much for your help so far.

In order to stop the sound from playing, you first have to tell the SoundChannel instance to stop like so :
mySoundChannel.stop();
Once you did that, you can close the stream used by the sound instance by invoking the close method like so :
TheSound.close();
Also, the delete keyword is rarely used in as3 and you should not it while some methods are trying to access the variable you are deleting. If you want to dispose of the instance that is currently assigned to your TheSound variable, you should set its value to null. This way, flash will properly garbage collect the old Sound instance that is no longer used when it finds the appropriate time to do so.

You can initialise the variable outside of the function, but define it as a new Sound object each time the function is called. That way it has global scope, and you can load a new URL at any time.
var TheSound:Sound;
var mySoundChannel:SoundChannel = new SoundChannel();
PlayButton.addEventListener(MouseEvent.CLICK, PlaySound);
StopButton.addEventListener(MouseEvent.CLICK, StopSound);
function PlaySound(e:MouseEvent)
{
TheSound = new Sound();
TheSound.load(new URLRequest("http://www.MyWebsite.com/Noel.mp3"));
mySoundChannel = TheSound.play(0);
}
function StopSound(e:MouseEvent)
{
mySoundChannel.stop();
TheSound.close()
}

Related

AS3 Simple way to check if sound is finished

I have a sound that plays whenever I rollover an object. To make it less annoying I want the sound to play only if it's not playing already. Since I need this with a couple of different sounds I don't want to use a timer (if not absolutely necessary). I found this:
var channel:SoundChannel = snd.play();
channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
public function onPlaybackComplete(event:Event)
{
trace("The sound has finished playing.");
}
but I'm not sure I can use it since I have a background music as well. Any tips?
You can use such a trick selectively. Still, if you plan to have a lot of such objects that trigger sounds on mouse-overs, you might decide to have a manager class or data table that would have an entry per such an object, and its field would have a true if the sound is played, and a listener assigned as such would clear the value in that field, deriving the correct entry from registered set of SoundChannels. A premade sound manager would do, but you'd better make a tailored one. An example:
public class SoundManager {
private var _fhOPO:Dictionary;
private var _bhOPO:Dictionary;
// going sophisticated. Names stand for "forward hash once per object" and "backward"
// forward hash stores links to SoundChannel object, backward stores link to object from
// a SoundChannel object.
// initialization code skipped
public static function psOPO(snd:Sound,ob:Object):void
{
// platy sound once per object
if (_fhOPO[ob]) return; // sound is being played
var sc:SoundChannel=snd.play();
_fhOPO[ob]=sc;
_bhOPO[sc]=ob;
sc.addEventListener(Event.SOUND_COMPLETE, _cleanup);
}
private static function _cleanup(e:Event):void
{
var sc:SoundChannel=event.target as SoundChannel;
if (!sc) return; // error handling
var ob:Object=_bhOPO[sc];
_bhOPO[sc]=null;
_fhOPO[ob]=null; // clean hashes off now obsolete references
sc.removeEventListener(Event.SOUND_COMPLETE, _cleanup);
// and clean the listener to let GC collect the SoundChannel object
}
}
Then, whenever you need to play a sound but limit to one instance of channel per object, you call SoundManager.psOPO(theSound,this); providing a button reference instead of this if need be. You can use normal Sound.play() alongside this kind of sound management should you need to, or use another type of management for BGM or other types of sounds should you need to.

stopping a soundchannel through a movieclip

my question is as follows. I have a sound triggered by clicking on a movieclip, like this:
var audioPlayer: SoundChannel = new SoundChannel();
var SndJuichen : Sound = new Juichen();
bootje.addEventListener(MouseEvent.CLICK, bootjeClick);
function bootjeClick (e:MouseEvent):void{
audioPlayer = SndJuichen.play();
}
}
and i want to stop this by clicking on another movieclip. for the time being, i have not been able to do this.
so I tried it by clicking on a button. like this:
stop_btn.addEventListener(MouseEvent.CLICK, audioStop);
function audioStop (e:MouseEvent):void{
addEventListener(MouseEvent.MOUSE_DOWN, mousedown);
function mousedown (e:MouseEvent){
audioPlayer.stop();
}
}
At first this worked but, but when i tried it later without changing the code it didn't work anymore.
so my question is how do i get the soundchannel to stop?
I have searched for hours already, if you think you have a link that can easily fix my problem its okay too.
sincerely
Drop the very first line var audioPlayer: SoundChannel = new SoundChannel(); and make sure this code is run in the context of some persistent MovieClip, this way audioPlayer will turn into a property of that MovieClip and be accessible from another frame where you decide to stop the sound.

Streaming FLV videos

I have 3 flv videos that I'm streaming. The first one is the intro. Then the second one is playing after the intro right after the intro ends. And the second video is looping. Everything seemed to be fine. But some times when i load the swf it starts from the second video. Any ideas why ?
import flash.events.MouseEvent
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
loader.vid.Video_1.attachNetStream(ns);
var listener:Object = new Object();
listener.onMetaData = function(evt:Object):void {};
ns.client = listener;
ns.play("video_1.flv");
ns.addEventListener(NetStatusEvent.NET_STATUS, NCListener);
function NCListener(e:NetStatusEvent){
if (e.info.code == "NetStream.Buffer.Empty") {
ns.play("video_2.flv");
}
};
loader.button_01.addEventListener(MouseEvent.CLICK, play_video_01);
loader.button_01.addEventListener(MouseEvent.ROLL_OVER, play_effect_01);
function play_video_01 (event:Event):void{
ns.play("video_3.flv");
loader.button_01_mc.gotoAndPlay (21);
}
function play_effect_01 (event:Event):void{
loader.button_01_mc.gotoAndPlay (2);
}
In your code, playback of your second video is triggered by the message NetStream.Buffer.Empty. That message can get dispatched for several reasons, as well as when playback of a video ends. For example when streaming (which I know you're not doing), NetStream.Buffer.Empty can get dispatched when there is a network problem. This is definitely the cause of your problem, but it's not clear why sometimes the buffer empty message gets dispatched right away.
The first thing I would do is modify your NetStatusEvent listener so that it traces out all of the messages that are being dispatched. That way you can see the sequence of events that occurs when this problem happens.
And second, you should try using another message to trigger playback of the second video. I'm not 100% sure, but I think the message NetStream.Play.Stop is what you want (this gets dispatched when the end of the video is reached, as well as when you programmatically stop playback). The full list of messages you get from a NetStatusEvent is here.
Incorporating both of these suggestions, your NetStatusEvent handler might look like this:
function NCListener(e:NetStatusEvent)
{
var code:String = e.info.code;
trace("code: ", code);
if (code == "NetStream.Record.Stop"
ns.play("video_2.flv");
}
Finally, you might want to add other event listeners to the NetStream. It dispatches an IOErrorEvent and AsyncErrorEvent ... perhaps you're getting one of these when the problem happens.

multiple instance of class in as3

i have a function to load sound in main document class in as3,this function accept input link and begin to load this path for example same function :
private function loadSound(url:String):void{
var req:String = 'sound/'+url+'.mp3'
sound_path = new URLRequest(req)
main_sound = new Sound()
main_sound.load(sound_path)
main_sound.play()
}
when this function call, sound object multiple start playing,how i solve this problem for play only sound class in this time ?
Place this at beginning of your loadSound() function:
flash.media.SoundMixer.stopAll(); //Stops all music already playing
If you have this code in a keyframe make sure you are calling stop() to prevent it from executing the code over and over.
If you have it in a class file (.as) it sounds like it is getting called twice

AS3: return array from event listener?

I have an event listener applied to an xml load and it currently traces out the values it grabs which is fine, but what I want it to do is return an array for me to use. I have the Array creation and return working from "LoadXML" (it returns the array) but I can't get this to work with an event listener.
The event listener runs the "LoadXML" function fine, but I have no idea how to take the returned array for use, this is an example of how my event listener works right now:
xmlLoader.addEventListener(Event.COMPLETE, LoadXML());
and my assumption of how I would take the array (this doesn't work):
var rArray:Array = xmlLoader.addEventListener(Event.COMPLETE, LoadXML());
so instead I tried the following:
xmlLoader.addEventListener(Event.COMPLETE, function():Array{
var rData:Array = LoadXML(datahere);
return rData;
}
but that doesn't worth either.
So: How do I return an array from an eventlistener? Thanks!
I think there is some confusion of how event listeners work. Actually, I'm surprised your not getting compile errors with your current code.
When adding an event listener, what you should be passing in is a reference to a function to be called at a later time. Then when that function gets called, it will pass an Event object with any retrived data for working with. Here is a example:
xmlLoader.addEventListener(Event.COMPLETE, handleLoadComplete/*Note: No brackets, this is a reference*/);
//will be called at a later time, not instantly.
function handleLoadComplete(e:Event):void {
var xml:XML = xmlLoader.data as XML;
//do what ever you want this the XML...
}
Hopefully that makes things clearer for you.
Happy Coding!
Why not just use a component-level object and set its value (xml contents in your LoadXML() method)?
var rArray:Array;
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
private function LoadXML(event:Event=null):void {
// set this.rArray in here...
}
It's possible to make returnedArray contain an array created by convertXML, but not in the way you're trying to do it. Flash simply doesn't work that way.
This is roughly what happen when you run the code from pastebin:
Start running function loadInformation()
var returnedArray:Array = loadinformation("http://website.com/xml.xml");
Tell Flash that when xmlLoader loads completely, it should run LoadXML()
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
Start loading an XML file
xmlLoader.load(new URLRequest(xmlurl));
Tell Flash what LoadXML() is (and convertXML())
function LoadXML(e:Event):void {...}
Stop running function loadInformation()
Flash goes off and does other stuff while waiting for the XML file to load
The XML file finishes loading. Flash calls LoadXML() like it was told to.
Note that LoadXML() is being called by Flash, not by loadInformation().
LoadXML() processes the XML file.
To get the converted array data, you need to do something like clownbaby's answer: set the value of returnedArray directly while inside LoadXML.
var returnedArray:Array;
loadinformation("http://website.com/xml.xml");
function loadinformation(xmlurl:String):Array{
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML = new XML();
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
xmlLoader.load(new URLRequest(xmlurl));
}
function LoadXML(e:Event):void {
xmlData = new XML(e.target.data);
returnedArray = convertXML(xmlData);
}
function convertXML(xml):Array{
// Does some stuff with the XML and returns an array
return rArray;
}