Extracting ID3 Data From an MP3 File


Do you think an MP3 file holds nothing but code for playing back an audio file? Think again. Most people are unaware that hidden in most MP3 files are ID3 tags. These tags, known as metadata, contain information such as the following about the MP3 file:

  • Name of the song

  • Artist

  • Genre

  • Year the song was recorded

  • Album from which the song came

  • Lyrics

  • Comments

Most modern MP3 players can read, display, and react to this included data when playing a file. Thankfully, ActionScript also provides access to this information when using MP3 files in your projects. This fact allows you to create sophisticated audio applications.

NOTE

Not all MP3s contain ID3 tags.


When an MP3 is loaded into or attached to a Sound object, that file's ID3 tag information can be read by accessing the Sound object's ID3 property. For example, the ID3 tag representing a song name is TIT2. To extract this data from the MP3 file loaded into a Sound object named music, you would use the following syntax:

 var songName_txt.text = music.ID3.TIT2; 

Other common ID3 tags include TALB (album), TPE1 (artist), TYER (year of recording), TRCK (track), and COMM (comment).

TIP

For more information about ID3 tags, consult the ActionScript dictionary or visit www.id3.org. Many ID3 tag editors are available to help you add your own ID3 tags to MP3 files. A search on www.google.com will return a number of possibilities.


In the following exercise, you'll create an MP3 player that loads MP3 files based on data in an XML file. The MP3 files contain ID3 tag data that will be extracted and displayed on the user interface.

  1. Open mp3Player1.fla in the Lesson18/Assets folder.

    This project contains five layers named Background, Text Fields, Buttons, Components, and Actions. Our project's static graphics are on the Background layer. There are five text fields on the Text Fields layer: song_txt, artist_txt, year_txt, URL_txt, and comments_txt. These fields will eventually be used to display extracted ID3 tag data. The Buttons layer contains two button instances named play_btn and stop_btn. Obviously, these will be used as playback controls for the currently selected MP3 file. The Components layer contains a List component instance named playlist_lb, which will be used to display a list of available MP3 files loaded in from an external XML file (we'll discuss this in a moment). The Actions layer will contain all the script for this project.

    This project will work by loading a list of MP3 files from an external XML file and displaying the list in the playlist_lb instance. When the user selects an MP3 file from the list and clicks the play_btn instance, that MP3 file not only plays, but its ID3 tag data is extracted and displayed in the text fields on the Text Fields layer.

    graphics/18inf21.jpg

    Before we begin scripting, let's review the external files that this project will use.

  2. Using your operating system's directory-exploring application, navigate to the Lesson18/Assets directory and locate the files Agent00.mp3, HardCope.mp3, LoungeJam.mp3, Prosonica.mp3, and playlist.xml.

    There's nothing special about the MP3 files other than the fact that each contains several ID3 tags. We'll access these files in our project.

    The playlist.xml file contains basic information about these four files in a simple structure:

     <Playlist>   <Song URL="Agent00.mp3">Agent 00</Song>   <Song URL="HardCope.mp3">Hard Cope</Song>   <Song URL="LoungeJam.mp3">Lounge Jam</Song>   <Song URL="Prosonica.mp3">Prosonica</Song> </Playlist> 

    The only items identified in this file are the name and the filename (in the form of a URL attribute) for each song. This data will eventually be loaded into the playlist_lb List component instance.

    By placing the information about our MP3 files in this XML file, we can add and delete songs simply by editing this file, and our MP3 player will compensate automatically, as you'll soon see.

  3. Return to Flash. With the Actions panel open, select Frame 1 of the Actions layer and add the following script:

     var playlistXML:XML = new XML(); playlistXML.ignoreWhite = true; var music:Sound = new Sound(); var currentSong:String; 

    Because our project will load the playlist.xml file, the first line of this script creates a new XML object named playlistXML for holding the incoming file. The next line tells that XML object to ignore any spaces within the loaded XML document because keeping these spaces could prevent our script from accurately locating data within the file.

    The next line creates a Sound object named music into which we'll load our external MP3 files, one at a time, as they're selected and played by the user.

    The last line creates a variable named currentSong to store the filename of the last selected song from the playlist_lb instance. The reason for this variable is that selecting a song from the list won't cause it to load and play automatically. This occurs only after the Play button is clicked. This variable is necessary to store the filename of the last selected MP3 from the list until the Play button is clicked and the file is loaded. This principle will become clearer in a moment.

  4. Add the following script below the current script:

     playlistXML.onLoad = function(){   var tempArray = new Array();   for(var i = 0; i < this.firstChild.childNodes.length; ++i){     tempArray[i] = new Object();     tempArray[i].label = this.firstChild.childNodes[i].firstChild.nodeValue;     tempArray[i].data = this.firstChild.childNodes[i].attributes.URL;   }   playlist_lb.dataProvider = tempArray; } playlistXML.load("playlist.xml"); 

    The last line shown here loads the playlist.xml file into the playlistXML object. Before that action occurs, however, the first part of the script creates an onLoad event handler so that the object knows what to do with the data after loading it. Let's look at this event handler in detail.

    It's important to remember that the data loaded in from this XML file contains the name of each song, such as Agent 00, and the filename of the song, such as Agent00.mp3 (go back to Step 2 if you need to review this info). Our goal is to transfer these two pieces of data for each song in the XML file into a list item for the playlist_lb instance, where the name of the song represents the label property for the item, and the filename represents the data property. Because our XML file contains four songs, our playlist_lb instance will eventually contain four items, each with a label and a data property. Remember that the label property for an item represents the text shown (this will be the song's name) for the item; the data property represents a hidden value that can be accessed and used when the item (the song's filename) is selected from the list.

    graphics/18inf22.gif

    To get this data from our XML file into the playlist_lb instance, we need to take the loaded XML data, place it into indexed positions of an array, and set that array as the data provider for the playlist_lb instance. As a result, our loaded XML data appears in the playlist_lb instance.

    The first step in this transfer process is to create an Array object, as shown in the first line of the event handler. The next line uses a for loop to populate the array with data from the loaded XML file. Here's how it works.

    The loop is set up to iterate while i (which is initially set to 0) is less than this.firstChild.childNodes.length. The term this refers to the loaded XML document. firstChild refers to the root node of the file. In this case, the root node is as follows:

     <Playlist> </Playlist> 

    childNodes is an array representing any child nodes within the root node. Because our XML document lists four songs within the root node (firstChild), childNodes has a length of 4; therefore, our for loop will iterate four times. Adding songs to or deleting songs from the XML file will change this value, and thus the number of iterations that the loop makes.

    graphics/18inf23.gif

    With each iteration, an object is created in the current index position of the tempArray array (i). That object is next assigned label and data property values, based on values extracted from the XML object. To understand this better, let's look at an example of what happens during an iteration.

    Let's assume that the loop is about to begin its third iteration and thus i has a value of 2. This would cause the script within the loop to be evaluated this way:

     tempArray[2] = new Object(); tempArray[2].label = this.firstChild.childNodes[2].firstChild.nodeValue; tempArray[2].data = this.firstChild.childNodes[2].attributes.URL; 

    This shows that a new object is created in index position 2 of the tempArray array. Next, that object is given a label property. The value of that property is based on the following expression:

     this.firstChild.childNodes[2].firstChild.nodeValue; 

    As discussed earlier, this.firstChild.childNodes is an array containing the four <Song> nodes in our XML file. The <Song> node at index position 2 of this array is the following:

     <Song URL="LoungeJam.mp3">Lounge Jam</Song> 

    The remaining part of the expression that sets the label value, .firstChild.nodeValue, is a reference to the listed song name within that node (Lounge Jam); therefore:

     tempArray[2].label = "Lounge Jam"; 

    graphics/18inf24.gif

    The value of the data property of the object is set almost the same way, except that it extracts the URL attribute of the currently referenced <Song> node; therefore:

     tempArray[2].data = "LoungeJam.mp3"; 

    By the time the loop is finished, there will be four objects in the tempArray, each with label and data properties representative of song names and song filenames, as just described.

    The last action within the onLoad event handler sets tempArray as the data provider for the playlist_lb instance. The objects within the array are used to populate the list with items.

    Let's test our work up to this point.

  5. Choose Control > Test Movie.

    As soon as the movie appears, you should see the songs contained in the external XML file loaded into the playlist_lb instance. Clicking a song name in the list doesn't do anything yet, but we'll change that situation in the next several steps, as well as improve the look of the List component instance so that it matches our project's design.

  6. Close the test movie to return to Flash. With the Actions panel open, select Frame 1 of the Actions layer, and add the following script at the end of the current script:

     var playlist_lbListener:Object = new Object(); playlist_lbListener.change = function(){   currentSong = playlist_lb.selectedItem.data; } playlist_lb.addEventListener("change", playlist_lbListener); 

    When the user selects a song from the list, we need to store the filename for that song in the currentSong variable. The first line in this step creates a new Listener object named playList_lbListener. The next several lines assign this Listener object a change event handler. The last line registers the Listener object to listen for that event from the playlist_lb instance.

    When fired, the change event handler sets the value of currentSong to the data property of the currently selected item in the playlist_lb instance. As discussed in Step 4, the data property for each item of the list contains the filename of that song. When the Play button is clicked, this value is used to load and play a song. Let's set up that functionality next.

  7. Add the following event handler at the end of the current script:

     play_btn.onRelease = function(){   music.stop();   music = new Sound();   music.onID3 = function(){     song_txt.text = this.id3.TIT2;     artist_txt.text = this.id3.TPE1;     year_txt.text = this.id3.TYER;     URL_txt.htmlText = "<a href=\"" + this.id3.WXXX + "\">" + this.id3.WXXX + "</a>";     comments_txt.text = this.id3.COMM;   }   music.loadSound(currentSong, true); } 

    This script defines what happens when the play_btn instance is clicked. The script handles loading the external MP3 currently stored in the currentSong variable into the music Sound object, as well the displaying the ID3 tag data contained in that file.

    If the music Sound object is playing, the first line stops it, to prevent two sounds from playing at the same time. The next line of the script reinitializes/re-creates a new instance of the music Sound object. The next several lines use the onID3 event to define what should happen when ID3 tag data has been loaded in from the external MP3 file. This data is usually at the beginning of the file, so this event should fire soon after the loading of the file begins. This event handler contains five lines of script for displaying ID3 tag data in the various text fields in our project. Be aware that the URL_txt text field will actually contain a clickable link based on the URL provided in the WXXX tag of the loaded file.

    The last line within the onRelease event handler takes care of loading the selected MP3 file, as defined by the current value of the currentSong variable. As always, the onID3 event handler is defined before the file is actually loaded, so that the Sound object knows ahead of time how to react to incoming ID3 data.

  8. Add the following event handler at the end of the current script:

     stop_btn.onRelease = function(){   music.stop(); } 

    When the stop_btn instance is clicked, the music Sound object is stopped.

    The last thing we need to take care of is the restyling of our playlist_lb instance so that it more closely resembles our project's overall design.

  9. Add the following script at the end of the current script:

     with(playlist_lb){   setStyle("defaultIcon", "CDIcon");   setStyle("alternatingRowColors", [0x4E535C, 0x565B65]);   setStyle("color", 0xFFFFFF);   setStyle("fontWeight", "bold");   setStyle("rollOverColor", 0x6C7380);   setStyle("selectionColor", 0x6C7380);   setStyle("textRollOverColor", 0xFFFFFF);   setStyle("textSelectedColor", 0xFFFFFF);   setStyle("textIndent", 2); } 

    Most of this script's functionality should be familiar to you by now. A with statement efficiently sets several style properties of the playlist_lb instance. The main style change is the first set, named defaultIcon. This style change displays the movie clip identified as CDIcon from the library next to each item listed in the instance.

    graphics/18inf25.gif

    Let's do one final test.

  10. Choose Control > Test Movie.

    As soon as the movie appears, select a song from the playlist_lb instance and then click the Play button. The music file loads, plays, and its embedded ID3 tag data is displayed in the appropriate text fields. Select a different song from the list, click the Play button again, and the interface is updated. Because this application uses an XML document to define available songs, editing that file's data will automatically be reflected in the application when the file is run again.

  11. Close the test movie to return to Flash. Save this file as mp3Player2.fla.

    As you've learned in this exercise, creating a sophisticated, scalable, SWF-based MP3 player is not difficult. At this point in the book, you're armed to add more features such as volume and panning controls, or anything else a good MP3 player application might need.



Macromedia Flash MX 2004 ActionScript(c) Training from the Source
Macromedia Flash MX 2004 ActionScript: Training from the Source
ISBN: 0321213432
EAN: 2147483647
Year: 2005
Pages: 182

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net