Copy link to clipboard
Copied
Hey guys,
I've almost finished my flash website for a friend and just want to add a simple MP3 player.
I have the following code which reads an XML file and loads the mp3s referred to in it and plays them... this is all cool...(i've removed the bits for the buttons as i didnt think they were relevant)
what I really really want to be able to do is buffer the MP3 files so that they begin playing when 1/2 loaded or similar (ideally preload 1/2 of track 1, play track 1, when track 1 loading is complete start preloading track 2 etc.)
I just cant work out how to do it...
Any advice would be very gratefully received!
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number = 0;
var song_position:Number;
var song_paused:Boolean;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
playSong(0); // Simply remove this line to stop automatic playback.
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
Copy link to clipboard
Copied
you can use a progressevent to detect when the mp3 is 1/2 loaded.
Copy link to clipboard
Copied
Hey, thanks for the prompt reply,
I was trying to go that route but think I am doing something very silly (i havent used flash before... last website i did was director ;p)
here's what i tried... (at this point i was just trying to get a dynamic txtbox called "bytes" to display how many bytes of the file had loaded - i figured once i got that variable updating correctly I could go from there)
any pointers?
all code is as before other than the playsong function:
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
function MP3_LOADING(event:ProgressEvent):void {
var loaded:Number=my_sound.bytesLoaded
bytes.text=int(loaded)+"%";
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
Copy link to clipboard
Copied
sorry missing a right brace in the code below (at the end of the MP3Loader function)... still the same issue though!
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
function MP3_LOADING(event:ProgressEvent):void {
var loaded:Number=my_sound.bytesLoaded
bytes.text=int(loaded)+"%";
}
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
Copy link to clipboard
Copied
i'm not sure what you're trying to do with that code but, if you want to start your sound when it's 1/2 loaded, you should use something like:
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
var alreadyStarted:Boolean=false;
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
bytes.text=int(loaded*100/total)+"%";
if(loaded*2>=total&&!alreadyStarted){
alreadyStarted=true;
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
}
Copy link to clipboard
Copied
hey dude,
I tried that and it's not working...
it shows the track name/artist name etc. but nothing in the bytes box and it doesnt start playing...
(it was missing a Right Brace which i added at the bottom... dunno if that's right?)
any more advice (sorry for being such a n00b, I program quite a bit in VB and PHP and what you've done looks right so I'm struggling to see where the issue is here!)
also... where does the value for "e" come from in this code? - excuse my stupidity!
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
var alreadyStarted:Boolean=false;
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
bytes.text=int(loaded*100/total)+"%";
if(loaded*2>=total&&!alreadyStarted){
alreadyStarted=true;
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
}
}
Copy link to clipboard
Copied
you should not need the extra bracket unless you're nesting functions. and you should never nest named functions.
Copy link to clipboard
Copied
Ok,
I checked my code and I did have the MP3LOADING function inside the playsong function (d'oh)
I've split them up as below...
I'm now getting the bytes text box displaying 100% straight away (i guess this is possible as im testing locally on my pc not with a remote server... BUT im also getting the error: "TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mp3_fla::MainTimeline/MP3_LOADING()" and no music...
I'm sure I'm still doing something very stupid!
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
}
}
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
var alreadyStarted:Boolean=false;
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
bytes.text=int(loaded*100/total)+"%";
if(loaded*2>=total&&!alreadyStarted){
alreadyStarted=true;
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
}
Copy link to clipboard
Copied
click file/publish settings/flash, tick "permit debugging" and retest. the line number with the problem will be displayed in the error message so you can, more easily, debug your code.
Copy link to clipboard
Copied
Awesome, I was going to say there isnt much help with debugging 😜
i'm getting an error at frame1:48 which i assume is line 48:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mp3_fla::MainTimeline/MP3_LOADING()[mp3_fla.MainTimeline::frame1:48]
which is:
my_channel = my_sound.play();
I guess its saying either my_channel or my_sound are null right? but they're both being set in the stage before in the following statements:
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
}
so I dont know how either can be null at that point?
Copy link to clipboard
Copied
some place in your code (outside those functions) should be:
var my_channel:SoundChannel;
Copy link to clipboard
Copied
I already have that at the top of my actionscript with t'other variables heres the whole lot:
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number = 0;
var song_position:Number;
var song_paused:Boolean;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
playSong(0); // Simply remove this line to stop automatic playback.
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
next_btn.addEventListener(MouseEvent.CLICK, onNext);
function onNext(e:Event):void{ //This used to have MouseEvent, change it to Event.
current_song++;
if (current_song>=my_total){
current_song=0;
}
playSong(current_song);
}
prev_btn.addEventListener(MouseEvent.CLICK, onPrev);
function onPrev(e:MouseEvent):void{
current_song--;
if (current_song<0){
current_song = my_total-1;
}
playSong(current_song);
}
pause_btn.addEventListener(MouseEvent.CLICK, onPause);
function onPause(e:MouseEvent):void{
if (my_channel){
song_position = my_channel.position;
my_channel.stop();
song_paused=true;
}
}
play_btn.addEventListener(MouseEvent.CLICK, onPlay);
function onPlay(e:MouseEvent):void{
if (song_paused){
my_channel = my_sound.play(song_position);
song_paused=false;
} else if (!my_channel){
playSong(current_song);
}
}
Copy link to clipboard
Copied
remove my_sound = new Sound(); in playSong() and create your new sound where you currently declare my_sound:
var my_sound:Sound=new Sound();
Copy link to clipboard
Copied
thanks for the help but I now have another error :*(
slightly different error:
ArgumentError: Error #2068: Invalid sound.
at flash.media::Sound/play()
at mp3_fla::MainTimeline/MP3_LOADING()[mp3_fla.MainTimeline::frame1:47]
Copy link to clipboard
Copied
how large is that mp3?
and use trace(myURL) to see if the output is what you expect.
Copy link to clipboard
Copied
What I've understood from from your problem is that you want to show the progress of a streaming sound file. If that is the case the n you should check this link from adobe help: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d25.html
Here in the "Monitoring the sound loading process" they have mentioned how to work with the progress of loading large files into the application.
COMPLETE event doesn't works fine in case of streaming large files.
In addition to that, http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d22.html explains how you can preload a part of the song and then start playing it.
Hope this helps..
Copy link to clipboard
Copied
Hey Kglad,
There are 3 files around 5MB each (they'll be smaller when i publish the site, im just testing with dummy mp3s from my itunes library atm)
I'll try the trace thing today and see what it says...
Hey rjoshicool,
Thanks for that, I'll have a proper read of that stuff now, the feedback on the loading isnt that important (i was just trying to display it to check that the rest of the code was working properly), I just wanted to preload 50% of the mp3 file before playing then hopefully preload the next mp3 file in the playlist in the background while the first one played
dan
Copy link to clipboard
Copied
Hey guys,
I read the adobe stuff and tryed the following code...
It wont play any music and doesnt show anything in the bytes text box!
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
title_txt.text = info;
var myURL = my_songs[mySong].@URL;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
my_sound.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
my_sound.addEventListener(Event.COMPLETE, onLoadComplete);
my_sound.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
my_sound.load(new URLRequest(myURL));
}
}
function onLoadProgress(event:ProgressEvent):void
{
var loadedPct:uint = Math.round(100 * (event.bytesLoaded / event.bytesTotal));
trace("The sound is " + loadedPct + "% loaded.");
bytes.text=int(loadedPct)+"%";
}
function onLoadComplete(event:Event):void
{
// trace(myURL);
var localSound:Sound = event.target as Sound;
localSound.play();
}
function onIOError(event:IOErrorEvent)
{
trace("The sound could not be loaded: " + event.text);
}
Copy link to clipboard
Copied
hey kglad,
baaa. ignore my last couple of posts, I had something stoopid in my code.
I've got the following code in the mp3 loading function (I've changed it a bit just to test it)
the bytes textbox shows the bytes loaded / total bytes then when its 100% loaded it displays "PLAYME" so its definitely hitting the if statement.. but it wont play the song.
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
// bytes.text=int(loaded*100/total)+"%";
bytes.text=int(loaded)+" / "+(total)
//if(loaded*2>=total&&!alreadyStarted){
if(loaded==total){
bytes.text=("PLAYME!!!");
alreadyStarted=true;
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, onNext);
}
}
Dan
Copy link to clipboard
Copied
use the complete event to trigger the start of your sound.
Copy link to clipboard
Copied
sorry to be so clueless... i know what you mean but not how to do it..
I've tried something like this:
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
bytes.text=int(loaded)+" / "+(total)
if(loaded==(total/2)){
bytes.text=("PLAYME");
alreadyStarted=true;
my_channel.addEventListener(Event.SOUND_COMPLETE, playme);
}
}
function playme(e:Event):void
my_sound.play();
bytes.text=("HITTING PLAYME");
but it doesnt like this... it gives me an error about missing a right brace at a completely unrelated part of my code (i.e. on another layer in a different frame!)
I assume i'm doing something fundemantally wronge here...
does this line : "my_channel.addEventListener(Event.SOUND_COMPLETE, playme);" mean when the event completes goto playme?
and then i need a function called playme which does the my_sound.play(); command?
Copy link to clipboard
Copied
not the soundcomplete event, the complete event of your loader. use the onLoadComplete() function that you had a few messages above.
Copy link to clipboard
Copied
Along these lines?
It's not hitting the new Complete event though..
function playSong(mySong:Number):void{
var myTitle = my_songs[mySong].@TITLE;
var myArtist = my_songs[mySong].@ARTIST;
var info = myTitle+" - "+myArtist;
var myURL = my_songs[mySong].@URL;
title_txt.text = info;
if (my_channel){
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, onNext);
my_sound.load(new URLRequest(myURL));
}
}
this.loaderInfo.addEventListener(
ProgressEvent.PROGRESS, MP3_LOADING
);
my_sound.addEventListener(Event.COMPLETE,onLoadComplete);
var alreadyStarted:Boolean=false;
function MP3_LOADING(e:ProgressEvent):void {
var loaded:Number =e.bytesLoaded;
var total:Number=e.bytesTotal;
// bytes.text=int(loaded*100/total)+"%";
bytes.text=int(loaded)+" / "+(total)
//if(loaded*2>=total&&!alreadyStarted){
if(loaded==(total)){
bytes.text=("PLAYME");
alreadyStarted=true;
}
}
function onLoadComplete(event:Event):void
{
bytes.text=("LOADED");
var localSound:Sound = event.target as Sound;
localSound.play();
}
Find more inspiration, events, and resources on the new Adobe Community
Explore Now