Flash MX MP3 player, Tweaks

source: http://www.thegoldenmean.com

Modify the Basic Player

Simple Customizations

Once upon a time I made a small, spartan MP3 player for my personal web site. After a little while I started getting emails from a wide cross section of individuals who wanted to know how I did it and if they could they have the .fla for their own uses. I didn’t mind giving the player away but I got tired of answering the same questions repeatedly so in self-defense I started writing what turned out to be an eleven page tutorial.

You can guess what’s coming. Within the first weeks and months of posting the tutorial I started getting even more email! “Love your player. How can I make it do this?” “Great tutorial. How can I get it to do that?”

Knowing that people are reading my words is gratifying. Realizing that this tutorial speaks to a real need in the internet community is too. However, much of the email has been about the same questions so again in self-defense I find myself tacking on a final page to cover the most commonly asked questions. I hope you will find an answer to your question here. I’m confident you will write to me if you don’t. I just ask that before you write you at least try to figure it out yourself first!

In order sort of from simple to complicated, here are the questions I’ve gotten most often, with the solutions I provided:

  1. I want to use this to distribute and sell music. Is there an easy way to put a “download” or “purchase” graphic in the list along with the title, and have that link to [insert some external asset]?
  2. How can I make the first track start playing immediately?
  3. If I use a ComboBox instead of a ListBox it starts playing immediately. How can I prevent that from happening?
  4. How can I limit the playback of each track to only play [insert arbitrary number of seconds]?
  5. How can I display the title and artist above the volume slider?
  6. What do I need to do to display the lyrics to the songs?
  7. How can I make “continuous play” the default behavior instead of an option?
  8. How can I add a shuffle (random track) option?
  9. How can I display album artwork?

Download/Purchase Icons

No.

Not to be a smart aleck about it, but I made this to be a fast, simple and lightweight player, not the front end to an ecommerce site. The ListBox does not support graphics, much less graphics that behave as buttons. Maybe version three of this will player will eliminate the ListBox component and provide much more flexibility, but then maybe version three of this player won’t be free.
;)

Autostart

First of all, think about this before you act on it. I personally do not like web sites that unexpectedly make noise. That’s just me. Sort of a control freak I guess. If I want noise, I want to decide when and where. (Maybe you work at a job where no one cares where you’re surfing!) I built this to meet my own preferences.

If, after giving it some sober consideration, you still want the player to start immediately, where would you guess the code to do this should be placed?

I concluded the best place was in the function which starts everything in motion initially: the songListLoaded() function (the callback function which is called when the xml file finishes loading). Accordingly, add the following line to the end of the songListLoaded() function:

songList_lb.setSelectedIndex(0);

Prevent Autostart with Combobox

Evidently the ComboBox calls the first item when it loads. (I haven’t done this myself, but this is the sense I have gotten from readers.) To prevent the first track from playing immediately, the first item in the xml file should not have an MP3 track associated with it. I suggested starting the xml file with the following:

<song display="Select a Song" url="" />

Limit Play Length

Let’s say you want your player to only play a “teaser”, limited to maybe 20 seconds of each track. If you don’t want to make the actual tracks short (or don’t know how to), you need to be monitoring how long the song has been playing and then end it at the length you predetermine. If you have read the tutorial, you know Flash looks to the Sound object’s “position” property to determine how far into the track the playhead is currently. You need something to monitor the “position” property continuously and then do something when some condition is met.

As luck would have it, we have already written a function that is doing this continuous monitoring: displayPosition(). Adding a simple conditional to this function will do the trick. Keeping in mind that “position” is expressed in milliseconds, the new version of the function will look like this:

function displayPosition(theSource){ 
   if(theSource.position > 0){ 
      if(theSource.position > 20000){ 
         nextTrack(); 
      }else{ 
         mainTL.displayPosition_txt.text = "current position: " 
         +formatTime(theSource.position); 
         } 
      } 
}

You would of course replace 20000 (representing 20 seconds) with whatever limit you wish. Also note that the behavior of this function is to move on to the next track when the condition is met. If instead you wish just to stop the music you could replace the call to nextTrack() with

         myTunes.stop();
         delete myTunes;

Display More Information

You might wish to display additional information such as the name of the artist. Some readers have written asking how to get a text field somewhere below the scrolling ListBox which would display this.

This requires three steps: modify the xml file, create a new dynamic text field and populate that text field.

Of course you can’t display information if it doesn’t exist. Because this player obtains its information from an xml file which is hand made, you will have to enter this additional information by hand. Each entry in the xml file as presented in the tutorial contains two attributes: “display” (which is the title of the track and is what shows in the ListBox) and “url” (which is the path to the asset so Flash knows where to look to load the track). If you wish to make more information available you will need to add new attributes. An example might be as follows:

<?xml version="1.0" ?> 
   <songs> 
      <song display="Song Title 1" artist="Artist One" album="Album One"
                        url="file1.mp3" />
   </songs>

Create a new dynamic text field in the “displays” layer. Size and position it appropriately for your player’s interface. Be sure to give the text field an instance name. Let us call the new text field “trackinfo_txt”.

The new data has to be extracted from the xml and written to the new text field. But when? When a new track is selected. That suggests that the doPlay() function is the most appropriate place to add this new functionality. Following is the modification to doPlay() I came up with. This bit of code should be inserted in the doPlay() function just before the call to the onSoundComplete() callback function:

   var trackNum = songList_lb.getSelectedIndex(); 
   var mainNode = songList_xml.firstChild; 
   trackinfo_txt.text = "Title: "+
             mainNode.childNodes[trackNum].attributes.display + 
             "; Artist: "+ mainNode.childNodes[trackNum].attributes.artist +
             "; Album: "+ mainNode.childNodes[trackNum].attributes.album; 

Display Song Lyrics

A reader named Jon was building a site for his brother’s band. The lyrics are in important part of each song’s message and he wanted to be able to present the lyrics along with the music.

I have constructed the xml file so that all the content for each song is contained in attributes of self-closing nodes. Recall that each entry follows the form:

<song display="Menu entry" url="path to asset" />

where “display” is what shows in the ListBox and “url” is the path to the actual MP3 file. This is nice, readable and compact but clearly stuffing a song’s lyrics into an attribute is pushing things. Plus, we weren’t able to get the lines to break where we wanted them to.

The solution required an overhaul of the xml structure. Specifically, we added a child node to each “song” node. The form of the new xml document is now this:

<?xml version="1.0" ?>
<songs>
   <song display="Title of Song" url="path_to_file.mp3.mp3">
      <lyric>First line of song
        Second line of song
        Third line of song
        And so on</lyric>
   </song>
   etc...
</songs>

Note the use of hard returns to delimit each line and the closing tags “</lyrics>” and “</song>”. Remember that every tag in an xml document must be closed!

Now follow the instructions that pertain to the version of Flash you use.

If you use Flash 8 or MX 2004 with version 2 Components:

First, increase the dimensions of your movie to make room for the lyrics. Now add a TextArea component to your fla, size it with the transform tool and give it an instance name of "lyric_ta".

Next, modify the last line of the "songListLoaded()" function so that one more item gets stuffed into the listData array:

listData.addItem({label:i+1+". "+mainNode.childNodes[i].attributes.title, 
	data:mainNode.childNodes[i].attributes.url, 
	lyric:mainNode.childNodes[i].firstChild.firstChild.nodeValue});

Then just before the onSoundComplete() function in the doPlay() function grab the "lyric" data and put it into the text area:

//populate lyric_ta with song lyrics
lyric_ta.text = eventSrc.target.selectedItem.lyric;

If you use Flash MX and version 1 Components:

As we did in the previous tip, we need to make a new text field to contain the lyrics, but this will need to be multi-line and most likely will need to include a scrollbar component. For purposes of this discussion let’s call this new text field “lyrics_txt”.

As with the previous tip, we don’t want the lyrics to show up until its track has been selected. We will use essentially the same technique as before by modifying the doPlay() function just before the call to the onSoundComplete() callback function, but we need to use different syntax to get at the new child node. Let’s assume you want to keep the same display as in the previous tip and extend the movie by adding the lyrics. One way of doing it follows:

   var trackNum = songList_lb.getSelectedIndex(); 
   var mainNode = songList_xml.firstChild; 
   trackinfo_txt.text = "Title: "+
             mainNode.childNodes[trackNum].attributes.display + 
             "; Artist: "+ mainNode.childNodes[trackNum].attributes.artist +
             "; Album: "+ mainNode.childNodes[trackNum].attributes.album;
   //display lyrics
   lyrics_txt.text = mainNode.childNodes[trackNum].firstChild.
      firstChild.nodeValue;

(The last line should not break as shown but rather should appear all on one line.)

Make “Continuous Play” the default behavior

Making your jukebox keep playing each track in turn after the first one starts is fairly simple. First of course you need to remove the original mechanisms that made “continuous” an option. That means removing the CheckBox component, references to the CheckBox in the “button code” layer and the global variable in the “logic” layer which had read

mainTL.continuous = false;

Finally, in the “functions” layer, shorten the end of the doPlay() function to simply call the nextTrack() function thus:

   myTunes.onSoundComplete = function () { 
      nextTrack (); 
   };

Random or “Shuffle” Play Mode

This is a little trickier, but not a whole lot. First of all, let’s agree to have “shuffle” as our only play mode option. By that I mean that we will now have a CheckBox that allows us to toggle “shuffle” on or off and that is the only alternative we give our visitors. The default play mode will now be “continuous” unless the CheckBox is checked, in which case it still plays continuously but in a random order.

Note that the more tracks you have, the more “random” it will appear. Although the random function is pulling numbers at random it is entirely possible for the same track to play twice in a row, or to play the fourth track, then the sixth track and then the fourth again. Sooner or later it gets to all of them, but the fewer tracks you have the more likely it is to repeat.

Following is a summary of the changes I made to the original code. First, rename the instance of the CheckBox component to “shuffle_ch”. Next, make the following modifications in the “button code” layer:

//code for checkbox 
shuffle_ch.setLabel("shuffle"); 
shuffle_ch.setValue(false); 
shuffle_ch.setChangeHandler("playMode"); 

We no longer need the global variable “continuous” because that is now assumed, but we do need something to track whether “shuffle” is true or not, so modify the line in the “logic” layer to read

mainTL.randomPlay=false; 

Everything else happens in the “functions” layer. Begin by writing a brand new function named shufflePlay():

//shufflePlay() is called if global variable randomPlay is true 
function shufflePlay() { 
   var totalTracks = songList_lb.getLength(); 
   var surpriseMe = random(totalTracks); 
   songList_lb.setSelectedIndex (surpriseMe); 
}

The older global “random” function is less commonly used since Flash MX introduced the Math.random() function. However, the “random” function does exactly what we want with an absolute minimum of fuss. Briefly, “random” will return an integer between zero and one less than the number supplied as an argument. We supply totalTracks as the argument. Because songList_lb is a zero-based array, this is about as perfect a match as could be imagined - a number between zero (the first item in the array) and one less than the total number of items. If you have 10 tracks total, the array would store them as 0-9.

Now make modifications to the playMode() function as shown here:

//function playMode() - called by checkbox's change handler 
//it modifies the global variable "randomPlay" 
//if randomPlay is true, doPlay calls the randomTrack() function 
   function playMode() { 
      mainTL.randomPlay = shuffle_ch.getValue(); 
}

The final step is to modify the doPlay() function. When a track has finished playing, what should happen? We look to the value of the global variable “randomPlay” (which you recall is initially set to “false” and can be modified by the CheckBox component). If the value of this variable is false, the player calls the nextTrack() function. If the value of the variable is true, the new function we wrote, shufflePlay(), is called. Here is how the variation of doPlay() should be modified:

   myTunes.onSoundComplete = function () { 

      //default behavior is to play tracks in order
      if (!mainTL.randomPlay) {
      
         //call the nextTrack() function
            nextTrack();
            
      } else if (mainTL.randomPlay) {
      
         //if set to shuffle mode, call the shufflePlay() function
         shufflePlay();
         }
      };
}

Add Album Artwork

  1. For the original MX demo version:
    1. Create a placeholder movieclip named "artholder_mc", and place it on stage where you wish the artwork to appear.
    2. Modify a node in your XML like this:
      <?xml version="1.0" ?>
        <songs>
          <song display="Song Title 1" url="file1.mp3" art="song1.jpg" />
        </songs>
    3. Modify the createResourceList function to add art to the array like this:
      createResourceList = function (resource_array) {
        var listData = new DataProviderClass ();
        var resourceCount = resource_array.length;
        var resource, display, url, artwork;
        for (var i = 0; i < resourceCount; i++) {
        	resource = resource_array[i];
        	//add a consecutive number in front of each title
        	display = i+1+". "+resource.attributes.display;
        	url = resource.attributes.url;
        	artwork = resource.attributes.art;
        	listData.addItem ({label:display, data:url, art:artwork});
        }
        return listData;
      };
    4. Find the section of the doPlay function that begins
      "//grab data parameter from ListBox"
      The last line of this example should be added:
      var theSong = songList_lb.getSelectedItem ().data;
      myTunes = new Sound ();
      myTunes.loadSound (theSong, true);
      myTunes.setVolume (Math.floor(volume_mc.slider_mc._x/2));
      artholder_mc.loadMovie(songList_lb.getSelectedItem().art);
  2. For the MX 2004 upgrade demo:
    1. First, make a movie clip into which your album art will be loaded. I don't know what size your photos will be, so I'm going to just assume 150x150 pixels. Make a layer on your main timeline for this and draw a square with no stroke 150x150 px placed where you want the photos to show up. Select this square and press F8 to make it a movieclip. Give it a name in the dialog that appears, and then be sure to give the instance on stage a name too - something like "artholder_mc".
    2. Next, add the path to the photo for each song as a new attribute in your XML. For example, what might have previously read:
      <song title="Clearing" url="tracks/Clearing.mp3" />
      would become something like:
      <song title="Clearing" url="tracks/Clearing.mp3" art="artwork/clearing.jpg" />
      (assumes you have made a new folder named "artwork", and in that folder have a jpeg file named "clearing.jpg")
    3. Now modify the "for" loop in the songListLoaded function to include this new attribute. Insert something like the following into that long string:
      artwork:mainNode.childNodes[i].attributes.artwork
    4. Finally, in the doPlay function find the lines that read
      myTunes = new Sound();
      myTunes.loadSound(eventSrc.target.selectedItem.data, true);
      and insert a new line between them. It should now read something like:
      myTunes = new Sound();
      mainTL.artholder_mc.loadMovie(eventSrc.target.selectedItem.artwork);
      myTunes.loadSound(eventSrc.target.selectedItem.data, true);

It’s All Yours Now

I hope this page has answered some of your questions and more importantly illustrated how I went about figuring out how to make the basic player do different things. Perhaps you will be inspired to tinker with it on your own and come up with even more creative solutions!

go to page: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
divider ornament

--top--