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);
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?
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?
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.
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.
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.
}
}
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
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.
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;
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;
}
}
![]()
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;
}
}
North America
Europe, Middle East and Africa
Asia Pacific