VCB424 Advanced Interactive Design IV

MP3 Player

This is the second of two music playing Flash objects that we are making, both of which read information (data) from an external source. The first one took a "juke box" approach—a variety of songs are available in any order, but one must press the appropriate button to make it work. The object we will build in this exercise will be more of a stripped-down "iTunes/Winamp" style player—it plays the songs in sequence but there is only one play/pause button and you can skip ahead and backward.

As with the juke box, you will need more than just a Flash file; you will also need several mp3 files (obviously) a data file, and something new—an external actionscript file that will contain a class object (more on that later). If you don't have any songs handy I've put five song snippets along with a sample data file, object file and a Flash file with some ready-made buttons together in a zip file that you can download and use. If you downloaded the songs for the previous exercise, you can download a zip file that contains just the Flash & data files instead.

This exercise draws heavily upon Lee Brimelow's mp3 player tutorials found at gotoandlearn.com.

Part 1: Music & XML

  1. Create a folder for this project called “yourName_mp3player" (if you prefer, you can use the same folder we created in the last exercise, that way you can easily reuse the same songs).
  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 (these are the same songs that we used in the previous exercise, so you don't need to download them twice; see step 1).
  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.
  5. 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"?>

     

  6. Now we need to create a root element to contain the song data. We'll call that element songs:
  7. <songs>

    </songs>

     

  8. 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 (track), artist name & URL to the song file (the new code is between the <songs> tags):
  9. <songs>
    <song url="tunes/BachEdit.mp3" artist="J.S. Bach" track="Toccata in D" />
    <song url="tunes/BeethovenEdit.mp3" artist="L.V. Beethoven" track="5th Symphony" />
    <song url="tunes/CoplandEdit.mp3" artist="A. Copland" track="Rodeo/Hoedown" />
    <song url="tunes/MouretEdit.mp3" artist="J.J. Mouret" track="Rondeau" />
    <song url="tunes/OrffEdit.mp3" artist="C. Orff" track="Carmina Burana" />

    </songs>

    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 (which is a big improvement over the jukebox which was limited by the number of buttons).

  10. Save this file as songs.xml into the project folder.

Part 2: Custom Class

  1. Next we're going to create a custom class; a class is a way of organizing data by putting it into a single object that Flash can use. I won't go into the details (partly because I barely understand how classes work myself); simply create the file described herein and trust that it will work!
  2. Open a new blank text document (in TextEdit for example). On the document write:
  3. class Song
    {
    public var earl:String;
    public var artist:String;
    public var track:String;

    public function Song(e:String, a:String, t:String)
    {
    earl = e;
    artist = a;
    track = t;
    }

    }

    Essentially, this creates three variables called "earl" (to hold the url—get it? We can't use "url" for a variable name because it's a reserved term—it's an Actionscript command), "artist," and "track." Then it reads the data from the XML file and assigns the three corresponding data nodes to the three variables. Simple, right?

  4. Save the file as Song.as and put it in the project folder. The file must have that name (class files must have the same name of the class they contain. In this case we named the class "Song" in the first line).

Part 3: Flash Layout

  1. Open a new file in Flash. Feel free to change the size. Save your file as mp3player.fla.
  2. For this player we're not going to create standard button symbols. Instead, we're going to make movie clip symbols and make then behave like buttons. Why? Well buttons are limited in the number of states that can contain: normal, over, press and hit only. If we make a movie clip we can create as many states as we like, and that will come in handy for we want a button that will be both a play and pause button—you can't do that with standard button symbols.
  3. So create a simple graphic to represent a "pause" button. Something like this:

  4. Turn the graphic into a movie clip symbol called playPause_mc.
  5. Open the movie clip timeline. Place a new keyframe at frame 10. Change the graphic at that point to an "over state," like this:
  6. At frame 20 add another keyframe. Replace the graphic with a "play" graphic like this:
  7. At frame 30 add one more keyframe and replace the graphic with a "play" over state.
  8. At each keyframe add a label (I added another layer for my labels and actions). The label for frame 1 should be "pause," the next one (frame 10) should be "pauseOver," then "play (20)," and finally "playOver (30)."
  9. Finally add a stop(); to the first frame. That takes care of the play/pause button.
  10. Now create a next and back button. The procedure is similar to that used to make the play/pause button; however we don't need four states, just two in each. So for the next button create a new movie clip ( called next_mc) with just two keyframes. In the first keyframe will be the "next" graphic, a label that says "next" and a stop(); action. The second keyframe will contain the "next over state" graphic, and a label that says "nextOver" (no stop(); needed).
  11. For the back button do the same, just use different graphics and call the labels "back" and "backOver."
  12. Place an instance of each button movie clip on the stage. Give them the following instance names: "playPause," "nextButton," and "goBackButton."
  13. You will also need a dynamic text field with the instance name "trackInfo" (not a Var name!).
  14. Finally you can add a volume slider. See the jukebox exercise for details on how to make the graphics (I provide the code below).

Part 4 Flash: Actionscript

  1. Create an actions layer. In frame one write the following script:
  2. // Set up the sound object

    var mySong:Sound = new Sound();

    mySong.onSoundComplete = playSong;

    mySong.setVolume(50);

     

    This first section creates an empty sound holder called mySong (we'll fill it later), sets the master volume to 50(%), and tells the player to execute the function playSong (which we will create further down) once mySong is finished playing. Actually, if you plan on adding the volume slider you don't need to set the volume (the code for the slider will do that); just leave off the bottom line.

  3. Below the first chunk of code (step 1), write the following block of code:
  4. // Set up the array and some variables

    var songArray:Array = new Array();

    var playingSong:Number = -1;

    var pos:Number;

    var xml:XML = new XML();

    xml.ignoreWhite = true;

    xml.onLoad = function() {
    var nodes:Array = this.firstChild.childNodes;
    for(var i=0;i<nodes.length;i++)
    {
    songArray.push(new Song(nodes[i].attributes.url, nodes[i].attributes.artist, nodes[i].attributes.track));
    }
    playSong();
    // If you want the first song to autoplay,
    // remove the next two lines before the closing }
    pauseIt();
    playPause.gotoAndStop("play");

    }

    xml.load("songs.xml");

    Okay this section is probably the trickiest part to grasp. First, it creates an empty array called songArray. An array is like a variable, but instead of storing one piece of information, it contains a list of data. Next it sets up a couple of variables: playingSong holds the track number of the song that is playing (initially it will be song 0 since computer programs always begin counting at zero, not 1). The second variable, pos, will be used to record the position of the playhead within the song that is playing (the "counter"). After the array is created, it is filled with the data in the XML file we created earlier. Once the array is filled, it executes the playSong function (which we haven't written yet). Note that I added two lines at the bottom that stop the song from playing (so the user must hit the "play" button to start the music). If you want your player to start automatically, remove the two lines after the comment.

  5. After that block of code, add the next chunk:
  6. //Play the mp3 file

    function playSong():Void {
    mySong = new Sound();
    mySong.onSoundComplete = playSong;
    if(playingSong == songArray.length - 1)
    {
    playingSong = 0;
    mySong.loadSound(songArray[playingSong].earl, true);
    }
    else
    {
    mySong.loadSound(songArray[++playingSong].earl, true);
    }
    trackInfo.text=songArray[playingSong].artist+" • "+songArray[playingSong].track;
    playPause.gotoAndStop("pause");

    }

    Now we get to the function that actually plays a song. The mySong holder is filled with a song from the array that corresponds to the variable playingSong (the track number) starting with 0. But if the number of the song exceeds the total number of songs, it goes back and starts over at song 0 again. In addition, the trackInfo field is filled with the appropriate data, and the playPause movie clip is jumped to the "pause" label (causing the pause button to appear on stage).

  7. Now add even more code:
  8. // Go back one song

    function goBack():Void {
    mySong = new Sound();
    mySong.onSoundComplete = playSong;
    if(playingSong == 0)
    {
    playingSong = songArray.length - 1;
    mySong.loadSound(songArray[playingSong].earl, true);
    }
    else
    {
    mySong.loadSound(songArray[--playingSong].earl, true);
    }
    trackInfo.text=songArray[playingSong].artist+" • "+songArray[playingSong].track;
    playPause.gotoAndStop("pause");

    }

    Now we create a function that jumps backward to the previous song. I'm particularly proud of this function, I wrote it all by myself (the tutorial I based this on had no back button).

  9. Yet more code:
  10. // Pauses the music

    function pauseIt():Void {
    pos = mySong.position;
    mySong.stop();
    }

     

    // Unpauses the music

    function unPauseIt():Void {
    mySong.start(pos/1000);
    }

     

    This code creates the pauseIt function and the unPause function. The pauseIt function doesn't just stop the music, it makes a note of the playhead's position and stores that in the pos variable. Then the unPause function plays the music from that spot.

  11. We're not done yet. Add this code after the stuff you've already written:
  12. // Music controls

    // Play/Pause toggle button

    playPause.onRollOver = function() {
    if(this._currentframe == 1) this.gotoAndStop("pauseOver");
    else this.gotoAndStop("playOver");

    }

    playPause.onRollOut = playPause.onReleaseOutside = function() {
    if(this._currentframe == 10) this.gotoAndStop("pause");
    else this.gotoAndStop("play");

    }

    playPause.onRelease = function() {
    if(this._currentframe == 10)
    {
    this.gotoAndStop("playOver");
    this._parent.pauseIt();
    }
    else
    {
    this.gotoAndStop("pauseOver");
    this._parent.unPauseIt();
    }

    }

    This code sets up the playPause button. Recall that we made the "button" out of a movie clip, not a button symbol. This piece of code specifies different functions for the movie clip depending on the action taken. On a "rollover" the button changes to the over state. On a "rollout" (rolling off the button), the button reverts to its normal appearance. But on a "release" (the button is pressed), the button changes to the either the "play" or "pause" state (depending on what state it was in when pressed), and it either plays or pauses the music (again, depending on the state it was in initially) by executing the specified function.

  13. Last bit of code! (sort of):
  14. // Next button

    nextButton.onRollOver = function() {
    this.gotoAndStop("nextOver");
    }

    nextButton.onRollOut = next.onReleaseOutside = function() {
    this.gotoAndStop("next");
    }

    nextButton.onRelease = function() {
    this._parent.playSong();
    }

     

    // Back button

    goBackButton.onRollOver = function() {
    this.gotoAndStop("backOver");
    }

    goBackButton.onRollOut = next.onReleaseOutside = function() {
    this.gotoAndStop("back");
    }

    goBackButton.onRelease = function() {
    this._parent.goBack();
    }

    These last two blocks of code set up the next and back buttons. As with the play/pause button, the functions performed depend on the action taken.

  15. Okay I lied, there's a bit more code. But this code does not go in the frame with everything else. Instead, put this code on the volume slider knob:
  16. onClipEvent(load) {
    this._x=_root.hBase._x + _root.hBase._width/2 - this._width/2;
    left=this._x - _root.hBase._width/2;
    top=this._y;
    right=this._x + _root.hBase._width/2;
    bottom=this._y;
    volCalc=_root.hSlider._x - _root.hBase._width/2

    }

     

    onClipEvent(enterFrame) {
    this.onPress = function () {
    startDrag(this, false, left , top , right, bottom)
    }
    this.onRelease = this.onReleaseOutside = function () {
    this.stopDrag();

    }

     

    sliderx=_root.hSlider._x;
    songVolume=(sliderx-volCalc);
    _root.mySong.setVolume(songVolume);
    _root.currentVolume="Volume " + _root.mySong.getVolume();

    }

    If you did the previous jukebox exercise with the volume slider you will note that this is the exact same code we used in that one; if it ain't broke, don't fix it.

Finishing Touches.

  1. Try it out, does it work?
  2. Make your player pretty. Add some color, some pizzazz... you get the idea.
  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 or class object).
  4. Export a .swf file.
  5. Embed the .swf file into an html page (called mp3player.html for example).
  6. FTP the entire mp3player folder to your server space (make sure the folder contains the data (xml) file, class file and the "tunes" folder with the songs.
  7. Make a link to the html file from your home page.

References

Point Breakdown

4 pts

Portfolio quality design; great mp3 player.

3 pts

Good looking; above average work.

2 pts

It works, but it's nothing fancy.

1 pts

Something's not working right.

0 pts

Poor showing; mostly incomplete or full of errors.

 

Course Outline

Syllabus

Student Resources