Copy link to clipboard
Copied
OK Guys, so I tried to make a MP3 player from a tutorial here http://www.republicofcode.com/tutorials/flash/as3musicplayer/
The player and the play, pause, next, previous etc. functions work just fine, but I want to make some improvements
1/I want to have a fully-functional loadbar and seekbar for the player
2/Could it be possible? I want the player to automatically plays a movie clip(that shows the next song in the playlist) at the last 10 second of every song
3/I want to merge both the play and pause buttons, so as to save space
Please guys I'm new to AS3 and all these event listeners thingy (because of my old computer, for the last 2 years I do Flash in AS2 - Flash 8 )
Here's the code:
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.events.MouseEvent;
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var song_position:Number;
var song_paused:Boolean;
var current_song:Number = 0;
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();
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 myAlbum = my_songs[mySong].@ALBUM;
var myURL = my_songs[mySong].@URL;
title_txt.text = myTitle;
artist_txt.text = myArtist;
album_txt.text = myAlbum;
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);
}
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);
play_mc.gotoAndPlay(1);
}
}
next_btn.addEventListener(MouseEvent.CLICK, onNext);
function onNext(e:Event):void{
current_song++;
if (current_song>=my_total){
current_song = 0;
}
playSong(current_song);
play_mc.gotoAndPlay(1);
}
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);
play_mc.gotoAndPlay(1);
}
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_mc.gotoAndStop(1);
Copy link to clipboard
Copied
1. the sound class has a progress event and bytesLoaded/bytesTotal properties you can use for your loadbar. it also has a length property and with the soundchannel's position property, you can create your playbar.
2. to autoplay, call onNext when a soundchannel soundcomplete event is dispatched. (you can pass null or assign it as a default event in onNext.)
3. what's the problem?
Copy link to clipboard
Copied
1. is the code you're talking about similar to this?
this is the loadbar code
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
function prog(e:Event):void{
var loadtime:Number = my_sound.bytesLoaded / my_sound.bytesTotal;
}
if it is, then I'm having trouble converting the loadtime number to the width of the loadbar movieclip, what code should I use? Is it progressbar.width = loadtime ?
2. I mean at the last 10 seconds of every song there should be a movie clip instance playing that shows the next song's name, artist, album... not automatically play the next song when one ends?
Copy link to clipboard
Copied
typically you would have a progressbar with a child fill (eg, fillbar which is, by default, at 100%) and use:
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
function prog(e:Event):void{
var loadtime:Number = my_sound.bytesLoaded / my_sound.bytesTotal; // not a suggestive variable name
progressbar.fillbar.width =loadtime*progressbar.width;
}
2. I mean at the last 10 seconds of every song there should be a movie clip instance playing that shows the next song's name, artist, album... not automatically play the next song when one ends?
use a loop (like enterframe) to compare the sound's length property and the soundchannel's position property.
Copy link to clipboard
Copied
1. OK, so what you're saying is that I have to use progressbar.addChild(fillbar); in the script or create a mc instance with the instance name "fillbar"?
2. To use the enterframe loop, do I use my_sound.addEventListener(Event.ENTER_FRAME) or my_sound.OnEnterFrame and use a while loop?
Sorry If I (have been) bothering you mate, but I'm really stupid in AS3, I just upgraded into CS6 from 8, and I used to do easier things, but this is the first time I have done a project this size, and the first time I use AS3 to coding.
So could you please rewrite the code for me, with the fully-functional seekbar,loadbar (well the automatic movie clip at the last 10 seconds might not be necessary), I want to learn from a pro, and see where did I go wrong.
Copy link to clipboard
Copied
1. no. you create your progressbar movieclip in the ide. progressbar typically is a rectangle with a border and a fill. convert the fill to a movieclip.
2. a sound isn't going to dispatch an enterframe event. use a displayobject (like a movieclip or sprite):
this.addEventListner(Event.ENTER_FRAME,playprogressF);
function playprogressF(e:Event):void{
if(my_sound.length-my_channel.position<10000){
yourmovieclip.visible=true; // change this to suit your code.
}
}
Copy link to clipboard
Copied
I used both of your codes, and this happens on the output panel:
This is from loadbar/progressbar code:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mp3player_fla::MainTimeline/frame1()
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mp3player_fla::MainTimeline/playprogressF()
and the above is from the enterframe code
Copy link to clipboard
Copied
did you pay attention to:
yourmovieclip.visible=true; // change this to suit your code.
????
if yes, copy and paste the code you used.
Copy link to clipboard
Copied
Here is the code I used:
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
function prog(e:Event):void{
var loadtime:Number = my_sound.bytesLoaded / my_sound.bytesTotal;
progressbar.fillbar = loadtime * progressbar.width;
}
this.addEventListener(Event.ENTER_FRAME,playprogressF);
function playprogressF(e:Event):void{
if(my_sound.length-my_channel.position<10000){
next_mc.visible=true;
}
}
and then I tried to make a blank MC instance, with the instance name Fake_MC, and edited the code like this:
this.fakeMC.addEventListener(Event.ENTER_FRAME,playprogressF);
function playprogressF(e:Event):void{
if(my_sound.length-my_channel.position<10000){
next_mc.visible=true;
}
}
but the same error just keeps showing up.
Copy link to clipboard
Copied
click file/publish settings/swf and tick "permit debugging". retest.
the problematic line number will be in the error message. indicate which line of code that is.
Copy link to clipboard
Copied
here are the error codes that I found:
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
and
if(my_sound.length-my_channel.position<10000){
I even tried to edit it like this:
fakeMC.addEventListener(Event.ENTER_FRAME,playprogressF);
function playprogressF(e:Event):void{
var cpoint:Number = my_sound.length-my_channel.position;
if(cpoint<10000){
next_mc.visible=true; // change this to suit your code.
}
}
but it still show that the error is in here:
var cpoint:Number = my_sound.length - my_channel.position;
Copy link to clipboard
Copied
you can't add the two event listeners (progressevent and enterframe) until your sound is instantiated. ie, add those after your
my_sound=new Sound()
line of code.
Copy link to clipboard
Copied
I tried adding the codes after my_sound = new Sound();
this time, no error, but nothing happens! I even tried Simulate Download, but no loadbar, no automatic movie clip
Copy link to clipboard
Copied
use the trace function to determine where your code fails.
Copy link to clipboard
Copied
I traced loadtime, cpoint, next_mc.visible and progressbar.width, progressbar.width*loadtime but only loadtime and cpoint changes, the other stayed at their default variables. Where could I went wrong?
Copy link to clipboard
Copied
copy and paste your updated code and show what each trace returns.
Copy link to clipboard
Copied
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.display.MovieClip;
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var song_position:Number;
var song_paused:Boolean;
var current_song:Number = 0;
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();
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 myAlbum = my_songs[mySong].@ALBUM;
var myURL = my_songs[mySong].@URL;
title_txt.text = myTitle;
artist_txt.text = myArtist;
album_txt.text = myAlbum;
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);
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
function prog(e:Event):void{
var loadtime:Number = my_sound.bytesLoaded / my_sound.bytesTotal;
trace (loadtime);//trace returns numbers ranging from 0.1 to 1
progressbar.fillbar = loadtime * progressbar.width;
trace (loadtime * progressbar.width);//trace always returns the original width of the progressbar: 250
}
this.addEventListener(Event.ENTER_FRAME,playprogressF);
function playprogressF(e:Event):void{
var cpoint:Number = my_sound.length - my_channel.position;
trace (cpoint);//trace returns a range of number counting down
if(cpoint<10000){
next_mc.visible=true;
// change this to suit your code.
}
trace (next_mc.visible);//trace always returns "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);
play_mc.gotoAndPlay(1);
}
}
next_btn.addEventListener(MouseEvent.CLICK, onNext);
function onNext(e:Event):void{
current_song++;
if (current_song>=my_total){
current_song = 0;
}
playSong(current_song);
play_mc.gotoAndPlay(1);
}
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);
play_mc.gotoAndPlay(1);
}
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;
}
}
Copy link to clipboard
Copied
you're nesting named functions. that's not going to work. and your code is a mess. format it so it's legible and you can debug it.
use:
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.display.MovieClip;
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var song_position:Number;
var song_paused:Boolean;
var current_song:Number=0;
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();
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 myAlbum=my_songs[mySong].@ALBUM;
var myURL=my_songs[mySong].@URL;
title_txt.text=myTitle;
artist_txt.text=myArtist;
album_txt.text=myAlbum;
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);
my_sound.addEventListener(ProgressEvent.PROGRESS, prog);
this.addEventListener(Event.ENTER_FRAME,playprogressF);
}
function playprogressF(e:Event):void {
var cpoint:Number=my_sound.length-my_channel.position;
trace(cpoint);//trace returns a range of number counting down
if (cpoint<10000) {
next_mc.visible=true;
// change this to suit your code.
}
trace(next_mc.visible);//trace always returns "true". that's expected because you never assign next_mc.visible=false.
}
function prog(e:Event):void {
var loadtime:Number=my_sound.bytesLoaded/my_sound.bytesTotal;
trace(loadtime);//trace returns numbers ranging from 0.1 to 1
progressbar.fillbar.width=loadtime*progressbar.width;
trace(loadtime * progressbar.width);//trace always returns the original width of the progressbar: 250. that's impossible.
}
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);
play_mc.gotoAndPlay(1);
}
}
next_btn.addEventListener(MouseEvent.CLICK, onNext);
function onNext(e:Event):void {
current_song++;
if (current_song>=my_total) {
current_song=0;
}
playSong(current_song);
play_mc.gotoAndPlay(1);
}
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);
play_mc.gotoAndPlay(1);
}
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;
}
}