Skip to main content

Home

Daniel C. Fergus

Artist & Educator

VCB-324 Rich Media 2

MP3 Player with XML Playlist (AS3)

Introduction

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

In order to build an mp3 player, you will need a Flash file, several mp3 files (obviously) and an XML file to store the playlist data. If you don't have any songs handy I've put five song snippets along with a Flash file with some ready-made buttons together in a zip file that you can download and use.

Part 1: Music and XML

  1. Create a folder for this project called “yourName_mp3player."
  2. Find some mp3 files (or use the ones I provide, see link above). Put them in a folder called "tunes" inside the jukebox folder created in step 1. Hint: make sure that there are no spaces in the names of the mp3 files.
  3. Launch textEdit or Dreamweaver or similar text editing application. If you use textEdit be sure to disable "rich text." If you're using Dreamweaver create a new XML file.
  4. For this project we will create an XML file to contain the song data. XML files are a lot like HTML files—they both use tags. But in XML files you can create & define your own tags, so it's more flexible. We will list the data that pertains to the songs—song name, artist name, & URL to the file—as XML data nodes. First, we need to type a line of code that declares that this is an XML file; write the following:
    <?xml version="1.0" encoding="UTF-8"?>  
  5. Now we need to create a root element to contain the song data. We'll call that element "playlist":
    <playlist>    
    
    
    </playlist> 
  6. Now inside that element we'll create a song tag for each song on the playlist. Inside of each tag we will include three attributes: the song name (songName), artist name & URL to the song file:
    <playlist>
        <song url="tunes/BachEdit.mp3" songName="Toccata in D" artist="J.S.Bach" />
        <song url="tunes/BeethovenEdit.mp3" songName="5th Symphony" artist="L.V.Beethoven"/>
        <song url="tunes/CoplandEdit.mp3" songName="Rodeo/Hoedown" artist="A.Copland" />
        <song url="tunes/MouretEdit.mp3" songName="Rondeau" artist="J.J.Mouret"/>
        <song url="tunes/OrffEdit.mp3" songName="Carmina Burana" artist="C.Orff" />
    </playlist> 

    Bear in mind that if your songs are in a different location, or if you're using different songs you will have to update the data. You can also have as many songs as you like.

  7. Save this file as playlist.xml into the project folder.

Part 2: Flash Layout

  1. Open a new file in Flash. Feel free to change the size. Save your file as yourName_mp3player.fla.
  2. Use the provided graphics or create your own (see below).
  3. For this player you'll need a "next" and "previous" button, a "play/pause" button, and a volume slider (see example above). The "next" and "previous" buttons are pretty straightforward. Create two graphics and give them the instance names "next_btn" and "prev_btn."
  4. The play/pause button will actually be a movie clip with two frames. In one frame create a circle filled with two vertical lines (pause). In the second frame duplicate the circle, but change the shape to a triangle (play). One more thing—put a stop(); in frame 1 of the movie clip; otherwise it'll flash between both frames repeatedly while the movie plays. Put an instance of the play/pause button on stage and call it "playPause_mc."
  5. For detailed instructions on creating a volume slider see this tutorial.
  6. You will also need two dynamic text fields with the instance names "title_txt" and "artist_txt."

Part 3 Flash: Actionscript

  1. Create a new layer called "actions." We'll start by setting up a bunch of variables and class instances:
    var mySongList:XMLList;    
    var myTotal:Number;    
    var mySound:Sound;    
    var myChannel:SoundChannel;    
    var currentSong:Number=0;    
    var lastPosition:Number=0;    
    var dragging:Boolean=false;    
    var boundingBox:Rectangle=new Rectangle(0,0,175,0);    

    The first item is an instance of the XMLList object which we'll use to store the XML data. Then we create a variable to hold the total number of songs (which will be counted by the code later on). Then instances of both Sound and SoundChannel objects. "CurrentSong" and "lastPosition" are variables we will use later. Next is a Boolean variable we'll use to check the status of the volume slider (if it's being dragged). The boundingBox will be used to constrain the volume slider knob.

  2. Next, let's turn our attention to loading the XML data:
    var myXMLLoader:URLLoader = new URLLoader();    
    myXMLLoader.load(new URLRequest("playlist.xml"));    
    myXMLLoader.addEventListener(Event.COMPLETE, processXML);  

    Here we created an instance of the XMLLoader class and then use it to load the XML data. Note that if your XML file has a different name, or is in a different location, you'll have to change the url. The third line uses a listener to check if the load is complete. Once it is, the "processXML" function is called.

  3. Before we get to the "processXML" function we need to set up listeners for the buttons and volume slider. And we need to turn on the button nodes for the slider knob and playPause_mc:
    next_btn.addEventListener(MouseEvent.CLICK, nextSong);    
    prev_btn.addEventListener(MouseEvent.CLICK, prevSong);    
    playPause_mc.addEventListener(MouseEvent.CLICK, playPauseSong);    
    slider_mc.knob_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragKnob);    
    stage.addEventListener(MouseEvent.MOUSE_UP, releaseKnob);    
    slider_mc.knob_mc.buttonMode=true;    
    playPause_mc.buttonMode=true;  
  4. Now the processXML function:
    function processXML(myEvent:Event):void { 
        var myXML:XML=new XML(myXMLLoader.data); 
        mySongList=myXML.song; 
        myTotal=mySongList.length(); 
        myXMLLoader.removeEventListener(Event.COMPLETE, processXML); 
        myXMLLoader=null; 
        playSong(currentSong); 
    }    

    This function takes the loaded data and puts it in the "myXML" object. Then the data is further parsed—"mySongList" stores the song nodes data, "myTotal" counts the number of nodes, and then the loader is removed as it is no longer needed. Finally, the function calls the "playSong" function. Note that the call to the playSong function includes an argument—it's passing along to the function the value of "currentSong," which initially is zero.

  5. Now the "playSong" function:
    function playSong(mySong:Number):void { 
        var myTitle=mySongList[mySong].@songName; 
        var myArtist=mySongList[mySong].@artist; 
        var myURL=mySongList[mySong].@url; 
        title_txt.text=myTitle; 
        artist_txt.text=myArtist; 
    
        if (myChannel) { 
            myChannel.stop(); 
            myChannel=null; 
        }
           
        mySound = new Sound(); 
        mySound.load(new URLRequest(myURL)); 
        myChannel=mySound.play(lastPosition); 
        myChannel.addEventListener(Event.SOUND_COMPLETE, nextSong); 
        playPause_mc.gotoAndStop(1);    
    }  

    Now we get to the function that actually plays a song. In the playSong constructor, the value of "currentSong" is assigned to "mySong." The next three lines use "mySong" to mine the proper song title, artist and url from the XMLList (so if "mySong" was 2 (the 3rd place in an array), the third song title, artist and url would be grabbed and stored in their corresponding variables).

    With this data now in hand, the function writes the song name and artist in the text fields, then loads and plays the song. However, before it starts playing a song it checks to see if there's already one playing. If so, it stops that song and clears out "myChannel." The "lastPosition" variable is used when a song is paused (more on that later). An event listener is added that listens for the end of the song, at which time it calls the "nextSong" function. Finally, the playhead in the playPause_mc moves back to the "playing" state (a visible pause icon).

  6. The next function, "advanceSong" will be called when a user hits either the "next" or "previous" button while the music is paused. In these situations, we want the song number to increase or decrease, and the text display to change accordingly, without the music starting:
    function advanceSong(mySong:Number):void { 
        var myTitle=mySongList[mySong].@songName; 
        var myArtist=mySongList[mySong].@artist; 
        var myURL=mySongList[mySong].@url; 
        title_txt.text=myTitle; 
        artist_txt.text=myArtist; 
    }  
  7. Now the button functions. We'll begin with the playPause function:
    function playPauseSong(myEvent:MouseEvent):void { 
        if (myChannel) { 
            lastPosition=myChannel.position; 
            myChannel.stop(); 
            myChannel=null; 
            playPause_mc.gotoAndStop(2);
        } else { 
            playSong(currentSong); 
        } 
    }    

    A fairly simple function—if a song is already playing, the song is stopped, the position of the playhead is stored in "lastPosition," the channel is cleared, and the playPause_mc playhead moves to frame 2, displaying the "play" symbol.

    And if a song is not playing, the "playSong" function is called.

  8. Now the "nextSong" function:
    function nextSong(myEvent:Event):void { 
        currentSong++; 
        lastPosition=0;
    
        if (currentSong>=myTotal) { 
            currentSong=0; 
        } 
    
        if (myChannel) { 
            playSong(currentSong); 
    
        } else { 
            advanceSong(currentSong); 
        }
    }  

    Essentially, this function simply adds one to the "currentSong" value and then calls either the "playSong" function or "advanceSong" function depending on whether or not there is already a song playing. In addition we need to add a conditional to make sure that we don't exceed the number of available songs (if so we loop back around to the beginning).

  9. Now the "prevSong" function:
    function prevSong(myEvent:Event):void { 
        currentSong--; 
        lastPosition=0;
    
        if (currentSong<0) { 
            currentSong=myTotal-1; 
        } 
    
        if (myChannel) { 
            playSong(currentSong); 
    
        } else { 
            advanceSong(currentSong); 
        }
    }  

    Almost identical to the "nextSong" function except it counts backwards.

  10. That last three functions control the volume slider. The code is pretty much identical to that found in my earlier sound tutorial, so I'll refer you there for a detailed explanation as to how it works. For now you can cut'n'paste:
    function dragKnob(myEvent:MouseEvent):void { 
        slider_mc.knob_mc.startDrag(false, boundingBox); 
        dragging=true; 
        slider_mc.knob_mc.addEventListener(Event.ENTER_FRAME, adjustVolume);    
    }    
    
    function releaseKnob(myEvent:MouseEvent):void { 
        if (dragging) { 
            slider_mc.knob_mc.stopDrag(); 
            dragging=false; 
        }    
    }    
    
    function adjustVolume(myEvent:Event):void {
        var myVolume:Number=slider_mc.knob_mc.x/175; 
        var myTransform:SoundTransform=new SoundTransform(myVolume); 
        if (myChannel) { 
            myChannel.soundTransform=myTransform; 
        }    
    }  

Variation

Right now the player begins playing the first song automatically. But what if you wanted the player to begin in the paused state? It's a simple tweak of the code. Find the "processXML" function and remove the play command (I've commented it out below) and add a line that sets the playPause button to the proper appearance:

    function processXML(myEvent:Event):void { 
        var myXML:XML=new XML(myXMLLoader.data); 
        mySongList=myXML.song; 
        myTotal=mySongList.length(); 
        myXMLLoader.removeEventListener(Event.COMPLETE, processXML); 
        myXMLLoader=null; 
        //playSong(currentSong); 
        playPause_mc.gotoAndStop(2);
    }    

Finishing Touches.

  1. Try it out, does it work?
  2. Make your player pretty. Design your own controls, your interface.
  3. Customize your playlist—add your own songs. You'll need to update the XML file (but you shouldn't have to touch either the Flash file).
decorative thumbnail

All text, images, and multimedia pieces (unless otherwise specified) copyright 2005–2011 Daniel C. Fergus. All rights reserved. No reproduction without permission.