Some help with basic Sound functions in actionscript 3 - actionscript-3

I'm working on a mp3 player and I'm super new at all things flash so there are lots of questions. Currently I'm getting stuck on the track change. My variable declaration look like this:
var index:int = -1;
var music:Sound = new Sound(new URLRequest("moe2008-05-24d02t02_vbr.mp3"));
var sc:SoundChannel;
var isPlaying:Boolean = false;
and my change track function looks like this:
function changeTrack(newTrack){
sc.stop();
isPlaying = false;
music = new Sound(new URLRequest(newTrack));
sc = music.play();
isPlaying = true;
index++;
}
Does anyone see any obvious errors???
Thanks

I think you should try to close the Sound connection (Sound.close()) before creating a new one. Also, I would use the same Sound object to load the new file (Sound.load()) to avoid possible GC problems (unless you need to fade in between sounds)...

Looks to me like you're missing the part where you actually load the external sound into a new sound object. Your example seems to be reusing the same sound object. Should be something like:
var sound:Sound = new Sound();
var request:URLRequest = new URLRequest("path/to/your/sound");
sound.load(request);
sc = sound.play();
You need the local sound variable to create a new sound as another sound instance cannot be loaded into an existing one:
Once load() is called on a Sound
object, you can't later load a
different sound file into that Sound
object. To load a different sound
file, create a new Sound object.
You'll probably want to use a Dictionary to keep track of which Sounds are loaded already. So when this method is called, you check if a sound object is registered in the dictionary and if it is, play that instead of loading a file.

As Flash Gordon said: "You're actually
redefing the local variables when you
reset its
property."http://www.actionscript.org/forums/archive/index.php3/t-181659.html
This line looks a bit suspicious.
sc = music.play();
Shouldn't that be:
var musicPlay = music.play();
sc = musicPlay;

Related

How to cache audio stream data and access it in AS3

I'm streaming an MP3 file in AS3. All is working fine (I can play it) but I'm looking to implement a 'seek' bar. This means I will need to cache the file (as it's being downloaded) and then access the cached data when the user seeks a specific time in the song.
The code to actually play the mp3 stream:
function openStream( stream )
{
var s:Sound = new Sound();
var req:URLRequest = new URLRequest(stream);
var context:SoundLoaderContext = new SoundLoaderContext(500, true);
s.load(req, context);
s.play();
}
So how would I cache the file as it's being downloaded and then access the data from the cache?
I know this is pretty far from a trivial task, so I would be grateful if you could even just provide a few links to some tutorials/docs/articles.
You do not need to cache the sound for this.
The downloaded sound data is is available as long as the sound object lives in memory.
So all you need to do is take the sound object outside the function into the class scope..
Also the play function returns the current SoundChannel used by the Sound.
private var snd:Sound = new Sound();
private var channel:SoundChannel;
function openStream( stream ) {
...
channel = snd.play();
}
To implement the seek functionality you may make use of,
bytesLoaded (To know how much of the sound is downloaded)
soundChannel.position (To know current sound position)

as3 Sound Class Unloading Sound

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()
}

How do you loop a sound in flash AS3 when it ends?

What AS3 code is used to loop a sound using AS3?
This won't give you perfect, gapless playback but it will cause the sound to loop.
var sound:Sound = new Sound();
var soundChannel:SoundChannel;
sound.addEventListener(Event.COMPLETE, onSoundLoadComplete);
sound.load("yourmp3.mp3");
// we wait until the sound finishes loading and then play it, storing the
// soundchannel so that we can hear when it "completes".
function onSoundLoadComplete(e:Event):void{
sound.removeEventListener(Event.COMPLETE, onSoundLoadComplete);
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);
}
// this is called when the sound channel completes.
function onSoundChannelSoundComplete(e:Event):void{
e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);
soundChannel = sound.play();
}
If you want the sound to loop many times with a flawless, gapless playback, you can call
sound.play(0, 9999); // 9999 means to loop 9999 times
But you still would need to set up a soundcomplete listener if you want infinite playback after the 9999th play. The problem with this way of doing things is if you have to pause/restart the sound. This will create a soundChannel whose duration is 9999 times longer than the actual sound file's duration, and calling play(duration) when duration is longer than the sound's length causes a horrible crash.
var sound:Sound = whateverSoundYouNeedToPlay;
function playSound():void
{
var channel:SoundChannel = sound.play();
channel.addEventListener(Event.SOUND_COMPLETE, onComplete);
}
function onComplete(event:Event):void
{
SoundChannel(event.target).removeEventListener(event.type, onComplete);
playSound();
}
import flash.media.Sound;
import flash.media.SoundChannel;
var mySound:Sound = new Bgm(); //Bgm() is the class of the internal sound which can be done in the library panel.
playSound();
function playSound():void
{
var channel:SoundChannel = mySound.play();
channel.addEventListener(Event.SOUND_COMPLETE, onComplete);
}
function onComplete(event:Event):void
{
SoundChannel(event.target).removeEventListener(event.type, onComplete);
playSound();
}
This works perfectly.
To expand on #scriptocalypse's gapless playback a bit:
The problem of not having proper gapless playback comes from mp3 including information about the file in either the head or the tail of the file (id3 tags etc), hence the small pause when you try to loop it. There are a few things you can do depending on your situation.
Ignore it, just play as normal, with a small pause at the end of every file. You can also try and mask it with another sound (a beat drop yo), or fade out and fade in.
If your sounds are embedded, and not streaming, then create a fla file, drag your mp3 in there, and set them to export (the same way you'd add a linkage name for a MovieClip etc). It seems that when you export sounds like this, Flash takes the delay into account, or strips it out when it creates the Sound object. Either way, you can just do a simple play() passing the loops that you want for a gapless playback (I've found using a loops parameter is better than waiting on the SOUND_COMPLETE event and playing it again).
You can try some of the ogg libraries to use .ogg files instead of .mp3. A simple google search for "as3 ogg lib" will turn up what you need. Personally, I found them a bit awkward to use, and I couldn't afford the overhead added (as opposed to mp3 decoding, which is done in the player).
If your mp3 files are streaming, then the only way to get gapless playback is to layer them. Determine the gap (depending on what you used to encode them, it'll be different - my files has a gap of about 330ms), and when you reach it, start playing the overlay. It's a proper pain if you're doing fading, but when it works, it works quite nicely. Worst case scenario, you end up with situation (1)
I guess this what you looking for in case the voice/music file is in the library:
var mysound:my_sound = new my_sound();
mysound.play(0,2); // this will repeat the sound 2 times.
This appears to have worked for me:
var nowTime:Number = (new Date()).time;
var timeElapsed:Number = nowTime - _lastTime;
_lastTime = nowTime;
_musicTimeElapsed+=timeElapsed;
if(_musicTimeElapsed >= _musicA.length - GAP_LENGTH)
{
_musicTimeElapsed = 0;
_musicA.play(0);
}
The other answers are great, however if you do not want to use code (for whatever reason), you can put the sound in a movieclip, set the sound property to "Stream", and then add as many frames as you like to the movie clip to ensure it plays fully.
This, of course, is a less preferred way, but for animators I'm sure it may be preferable in some situations (for example when synced with mouth animations that the animator wants looped).
this work for me :
import flash.media.Sound;
import flash.media.SoundChannel;
var soundUrl:String ="music.mp3";
var soundChannel:SoundChannel = new SoundChannel();
var sound:Sound = new Sound();
sound.load(new URLRequest(soundUrl));
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE,onComplete);
function onComplete(e:Event):void{
sound = new Sound();
sound.load(new URLRequest(soundUrl));
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE,onComplete);
}

How would I go about playing a sound object in reverse in Actionscript 3?

For a project I'm working on, it's necessary that I am able to play a sound object in reverse. How would I be able to do this in AS3?
This is doable as of player 10, but it's not a quick/simple implementation. You'll have to build your own custom support. Lets take a look:
var soundSource:Sound; //assuming this actually references a real sound file such as a MP3
var position:int = soundSource.bytesTotal;
var numBytesToReadEachSample:int = 8192;
var snd:Sound = new Sound();
snd.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleData);
snd.play();
function sampleData(e:SampleDataEvent):void {
position -= numBytesToReadEachSample;
//here we read data from our source, and write it to the playing sound
e.data.writeBytes(soundSource.extract(position, numBytesToReadEachSample))
}
That's NOT TESTED AND INCOMPLETE, but is the general idea of what you want to do. Hopefully it points you into the right direction!
More information here: http://www.adobe.com/livedocs/flex/3/langref/flash/events/SampleDataEvent.html#SampleDataEvent%28%29
Best of luck!

Load AS2 SWF Into AS3 SWF and pass vars in URL

I've got an AS3 SWF that I'm going to be loading other SWFs into. These child SWFs all take a single parameter on the URL. I can't seem to get it working when loading an AS2 child, and it needs to be able to handle both.
so I have
var request:URLRequest = new URLRequest();
var loader:URLLoader = new URLLoader();
request.url = "http://domain/as2.swf?param=foo";
loader.load(request);
// etc on to the eventListeners, addChild, etc
When the as2 SWF gets loaded, it can't see the parameter I've passed to it. It's looking for _root.param. Am I doing this wrong or am I attempting the impossible?
EDIT: I should add that I can load a SWF with those URL params from an AS2 loader and it works just fine.
It's not trivial to communicate between AS2 and AS3 since they run in different virtual machines. Check this http://www.gskinner.com/blog/archives/2007/07/swfbridge_easie.html for some hints.
Edit: If you cannot change the loaded as2 content your only options is creating a 'wrapper' as2 loader that uses the linked example above to communicate with the as3 and interfaces with the loaded as2 content using _root.varname This is not pretty but it might just work.
It might be worth trying to assign the variables dynamically after the SWF has loaded but before you add it to the stage. Ie.
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, movieLoaded);
function movieLoadedHandler(event : Event) : void
{
var loaderInfo : LoaderInfo = event.target as LoaderInfo;
var clip : DisplayObject = loaderInfo.content;
for each(var prop in varsToTransfer)
{
clip[prop] = varsToTransfer[prop];
}
// add to parent
}
Let me know how that goes.
AS3 -> AS3
Movie 1(www.domain1.com):
Load the external movie when click a "buy" button...
buy.addEventListener(MouseEvent.CLICK,function(){
var ldr:Loader = new Loader();
var url:String = "http://www.domain2.com/movie.swf?a=b&c=d";
var urlReq:URLRequest = new URLRequest(url);
ldr.load(urlReq);
addChild(ldr);
});
Movie 2(http://www.domain2.com/movie.swf):
var mc:MovieClip = this as MovieClip;
var ldi:LoaderInfo = mc.loaderInfo;
var lobj:Object = ldi.parameters as Object;
for (var l in lobj) {
dumper.htmlText += l+" => "+lobj[l]+"<br />";
}
"dumper" is the name of the Dynamic Textbox field located in Movie2.
The output should look like:
a => b
c => d
Instead of looking for _root.param, use _root._url then parse out your parameters by hand.
var url: String = _root._url;
var param: String = 'param=';
var paramStart: Number = url.lastIndexOf(param);
var paramValue: String = url.substring(paramStart + param.length, url.length);
trace(paramValue);
SWFBridge is awesome and overkill for something like this.
You are doing it wrong.
"http://domain/as2.swf?param=foo"
Is a request for the file named as2.swf, on the server named domain. Any ?param=foo parameters that are part of that http request are lost when the request is complete. If the server needed to do something according to these variables, it would, but you are asking a .swf file to detect these variables, that's just silly.
Put a variable in your Global object (Global namespace) for the flash player, then when the as2 .swf is loaded into that flash player it will have access to the variable you set in your Global object.
I am not proficient in as2, but in as3, the Global object can be accessed with the this keyword, at the package level (probly is the same for as2, just dont worry about setting it at a package level).