How to Play Sound Files Sequentially

Flash ActionScript 2.0

Many people use Flash to play background music on their site.  It’s a good use for Flash, especially if the audio is loaded from external MP3s, which keeps the SWF file size low, and if you give your visitors a way to toggle off the sound.  But one song may not be enough.  You may want to play a list of files one after the other.  If so, the next question is, “How easy is that?”  The answer is, “Very.”  Let’s take a look. 

An answer, short and sweet

The “trick” here — and it’s really no trick at all — is to use an Array instance to store your list of audio files, a variable to keep track of which song is current, and the Sound.onSoundComplete event to trigger each new sound.  Type the following ActionScript into a keyframe:

var listOfFiles:Array = new Array("frog.mp3", "loon.mp3", "horse.mp3");
var currentFile:Number = 0;

var audio:Sound = new Sound();
audio.loadSound(listOfFiles[currentFile], true);

audio.onSoundComplete = function():Void {
  currentFile++;
  if (currentFile < listOfFiles.length) {
    audio.loadSound(listOfFiles[currentFile], true);
  }
}

How it works

The first variable, listOfFiles, points to a new Array instance that holds three elements, which are the names of three MP3 files.  We could have populated this array in a series of lines, like this …

var listOfFiles:Array = new Array();
listOfFiles.push("frog.mp3");
listOfFiles.push("loon.mp3");
listOfFiles.push("horse.mp3");

… but in short sequences, the single-line approach takes less effort to type.

The second variable, currentFile, is set to zero and represents the first sound to play (arrays start counting at zero, rather than one).  Finally, a third variable, audio, is declared and set to an instance of the Sound class.

To get things started, the Sound.loadSound() method is immediately invoked on the audio instance, and two parameters are provided.  The first parameter is the expression listOfFiles[currentFile], which in this case resolves to the string "frog.mp3" (remember currentFile is zero, which retrieves the first element of the listOfFiles array).  The second parameter tells Flash to play the file by progressive download, which means the audio will start before the MP3 has fully loaded.

On its own, the code so far would play the first song and then stop when the audio was complete.  The last little bit achieves the original goal, which is to play files sequentially.  When the first song (or narration, or whatever you’re presenting) is complete, the Sound.complete event is dispatched.  Here, we’re writing a function to be performed in response to that event.  The first thing that happens is that the currentFile variable is incremented by one, thanks to the ++ operator.  So now its value is one.  Next, an if statement checks of currentFile’s value is less than the total number of elements inside the listOfFiles array, thanks to the Array.length property for that instance.  There are three elements in the array, and one is less than three, so the final line is executed.

Notice that the last line of code duplicates exactly what we’ve already discussed.  The difference is that, this time, the value if currentFile is different.  When this second song ends, the complete event will fire again, which means this function will again be triggered.  currentFile will increment to two, two is less than three, and the third MP3 will play (element 2 is in the third slot, because arrays start at zero).  When the third songs ends, currentFile increments to four, and because four is no longer less than three, the cycle ends.

Variation

Want to repeat the list of files when all three (or four, or however many) songs have completed?  Update that last block of code like this:

audio.onSoundComplete = function():Void {
  currentFile++;
  if (currentFile == listOfFiles.length) {
    currentFile = 0;
  }
  audio.loadSound(listOfFiles[currentFile], true);
}

35 Responses to “How to Play Sound Files Sequentially”

  1. CMAX Says:

    did You Finished Your knowledge? or this is the end of AS2.0?
    your Posts forging abaft daily !!

    i must thanks to you for every things you bring us but lately it seams there is nothings in your mind to share us.

    any way you are a great Flash Man and i love you also this blog :D

    sorry , i am not as well as you in English but i try to say my mind. ;)

  2. David Stiller Says:

    CMAX,

    Hey, thanks for the encouragement!

    No, no … there is no end to AS2 — not for me, not yet (though I do use AS2 and AS3 now). The simple truth is, I’ve been swamped. I’ve got a book in the works and it’s almost done. A colleague asked me to co-author a Flash reference with him and we’ve become fast friends in the process. But it has been the biggest project I’ve done in a very long time. As soon as the book is finished, I’ll be back. :)

  3. NSurveyor Says:

    You can use ++ in two ways…. expression++ and ++expression. Both increment the expression by 1, except expression++ returns the old value of expression, while ++expression returns the new value of expression. So instead of using:

    currentFile++;
    if (currentFile < listOfFiles.length) {

    you can utilize the other use of ++ to shorten the code:

    if (++currentFile < listOfFiles.length) {

    Also, you can use % (modulo operator) to avoid the need of an if statement for the variation:

    currentFile++;
    if (currentFile == listOfFiles.length) {
    currentFile = 0;
    }

    can be compressed into:

    currentFile = (currentFile+1) % listOfFiles.length;

  4. Nic Says:

    Hi,
    first of all, I discovered your blog recently and so far has been of an immense help for some uni project. Thank you so much.
    Secondly, I tried using this script that does exactly what I wanted to do (thank you) and tried “mixing” it with your “How to Pause Sound and Resume Where it Left Off” script to be able to control the sound at will.
    My aim is to create a little jukebox that would play continuously several mp3 tracks throughout the flash application that the user could control (pause/resume, stop, next , previous.. and possibly progressive volume control..).
    So my question is, how do I “control”/”communicate” with the tracks that are playing with actionscript?

    Thank you in advance for any reply/help and for your blog,
    nic

  5. David Stiller Says:

    Nic,

    So my question is, how do I “control”/”communicate” with the tracks that are playing with actionscript?

    What you’re asking is certainly doable. In fact — and this is a pretty wild coincidence — the audio chapter of Tom Green’s and my upcoming Flash book provides pretty much what you’re looking for in ActionScript 3.0. But the book isn’t quite ready yet [as of April 27, 2007], so in the mean time, the simplest answer to your question is “Use the Sound instance.”

    Now, what does that mean?

    Well, you’re already using the Sound instance in the above sample; it happens to have the instance name audio, but of course, it can be whatever you choose. As an instance of the Sound class, that audio variable acts as your ambassador for sound-related things. That variable brings you all the functionality described by the Sound class (for example, above, it’s calling on the Sound.loadSound() method).

    At any point, you can wire up a button to invoke, say, Sound.stop() on that audio instance — and whatever audio file that instance happens to currently point to will stop. Invoke Sound.start() on it, and that particular audio file will start again. (Here’s a tip on how to restart audio where it left off.)

  6. Nic Says:

    Thank you for that explanation.
    Thanks to you I finally have my mp3 player that’s fully functional.

    Only question is, can I add a snazzy extra: I’d like to display the appropriate track name when it’s playing.
    I understand that i’d have to assign a name to each ‘currentFile’ instance (0,1,2,3 etc..) and then display the value in a text box.
    I did that by creating an external text file that looks like:
    ——————–
    trck1= track name 1
    &trck2 = track name 2
    &trck3 = track name 3
    &trck4 = track name 4
    ——————–

    and my frame script looks like that:
    ——————–
    var listOfFiles:Array = new Array(”tracks/1.mp3″,”tracks/2.mp3″, “tracks/3.mp3″, “tracks/4.mp3″);
    var currentFile:Number = 0;

    var audio:Sound = new Sound();
    audio.loadSound(listOfFiles[currentFile], true);

    audio.onSoundComplete = function():Void {
    currentFile++;
    if (currentFile == listOfFiles.length) {
    currentFile = 0;
    }
    audio.loadSound(listOfFiles[currentFile], true);
    }

    //track name display

    lvLoader = new LoadVars();
    lvLoader.onLoad = function(success)
    {
    if(success)
    {
    if(currentFile == 0)
    {txt_trckName.text = lvLoader.trck1;}
    if(currentFile == 1)
    {txt_trckName.text = lvLoader.trck2;}
    if(currentFile == 2)
    {txt_trckName.text = lvLoader.trck3;}
    if(currentFile == 3)
    {txt_trckName.text = lvLoader.trck3;}

    }
    }
    lvLoader.load(”playlist.txt”); //Load the text file.
    ——————————————————-
    In my flash file i obviously have a text box named ‘txt-trck’ in which the track name should appear.

    So far, it works: the track name is displayed, but only for the first track. So when i switch to the next track the first track name remains.
    Would anybody have any suggestions for my (extremely) long question?
    Once again, thank you for any replies.
    Nic.

  7. Nic Says:

    No worries, I sorted it out myself.

    Anyways, thank you (again) for your blog and keep up the good work.
    Nic

  8. David Stiller Says:

    Nic,

    Glad to hear it! Sorry I wasn’t able to help this time around. I’m working on my very last chapter for the book and simply must get it done, at all costs, by tomorrow evening.

    I’m psyched for you that you figured it out! :)

  9. Charles Says:

    Is there a way to play two sounds, one after the other, and embed the sounds in the swf instead of stream?

  10. Nitin Says:

    Hi David,

    It was a pleasure to come on your site and learn and do so much that I was wanting to do since long. Thanks again.

    Regards,
    Nitin

  11. Johann Says:

    Hi David, my media controller can rewind my movieclip animation, which in this case is a series of fading text, but my audio keeps playing because I’m using the loadSound method. How can I get my audio to rewind along with the animation?

    Best to you,
    Johann

  12. David Stiller Says:

    Johann,

    Somehow or other, you’ll need to reference the Sound instance that loads your external audio. Once you have a reference to the Sound instance, you’ll simply follow the same routine as shown above. I’m not sure how your media controller works — maybe it loads an external SWF (which has its own audio) or maybe it controls an internal movie clip by way of its instance name — regardless, if that Sound instance resides inside a movie clip, you’ll have to reference the clip’s instance name first, then use dot notation to work your way toward the Sound instance.

    Does that make sense? It will likely help you to run your SWF(s) through the debugger panel so you can see the various object instances live behind the scenes. This article on the Adobe Dev Center may help acquaint you with the Debugger panel for AS2:

    http://www.adobe.com/devnet/flash/articles/debugging_actionscript.html

  13. Greg Warger Says:

    Hi Dave,

    Im interested in playing some mp3 files sequentially on our web site… but Id like to tie that to an embedded control.

    What is variable that I use in the embed statement that ties the controller to the array of mp3 files?

  14. David Stiller Says:

    Greg,

    The answer to your question depends on which embedded control you mean. The FLVPlayback component only plays FLV files, but the older Media components can play MP3 files. FLVPlayback does support a subset of the SMIL format, which means you could point to a playlist of audio-only FLVs. That’s a thought. But any which way you slice it, there isn’t a variable to associate these components with an array declared in ActionScript. Unless you’re using SMIL, you’ll probably want to loop through the array, as shown above, based on an appropriate event of the control in question.

  15. Peter Says:

    Thanks so much for the sequential loading…now what I need is to be able to display what song is currently playing…can you help???

  16. David Stiller Says:

    Peter,

    You could take care of that with the same array. If you wanted to display the actual file name, you might populate a dynamic text field with the same string used to load the MP3:

    audio.onSoundComplete = function():Void {
      currentFile++;
      if (currentFile < listOfFiles.length) {
        someTextField.text = listofFiles[currentFile];
        audio.loadSound(listOfFiles[currentFile], true);
      }
    }

    Or if you wanted to use a “friendly name” for that sort of display, I could see populating the original array with objects instead of strings. Check it out, and note the difference in how the onSoundComplete handler accesses the data … they’re not object properties instead of stand-alone strings:

    var listOfFiles:Array = new Array(
      {file:"frog.mp3", name:"Frog"},
      {file:"loon.mp3", name:"Loon"},
      {file:"horse.mp3", name:"Horse"}
    );
    var currentFile:Number = 0;
    
    var audio:Sound = new Sound();
    audio.loadSound(listOfFiles[currentFile].file, true);
    
    audio.onSoundComplete = function():Void {
      currentFile++;
      if (currentFile < listOfFiles.length) {
        someTextField.text = listOfFiles[currentFile].name;
        audio.loadSound(listOfFiles[currentFile].file, true);
      }
    }

    The curly braces {} are a shorthand for the expression new Object(), so the array could have been written like this:

    var listOfFiles:Array = new Array(
      new Object(file:"frog.mp3", name:"Frog"),
      new Object(file:"loon.mp3", name:"Loon"),
      new Object(file:"horse.mp3", name:"Horse")
    );

    … but the other way requires less typing. ;)

  17. Peter Says:

    Oh my…So over my head, but I will try to figure it out. Yes, I want a ‘friendly name’, not that of the actual sound file (song_1.mp3 doesn’t cut it!). So, I guess I go with the second set of code. I can’t thank you enough. I’m not a programmer, just a designer, dealing with ActionScript.

  18. Peter Says:

    One more thing…I need to create a text field with a variable called “name”? is that how I set it up?

  19. David Stiller Says:

    In my suggested code, the instance name of the text field is someTextField — but it doesn’t really matter what instance name you use, as long you’re consistent in your ActionScript. If the original code (in the article itself) made sense to you, at least somewhat, keep in mind that not a whole lot has changed. We’re still dealing with an Array instance — a list — but this time, the list contains objects instead of strings. These objects have two properties, file and name, which have the values shown above.

    Where you used to be pulling an item from the array like this:

    listOfFiles[currentFile]

    … you’re now grabbing this:

    listOfFiles[currentFile].file

    … when loading the MP3, because now the MP3’s name is stored one level deeper. To retrieve the friendly name, the expression is almost the same, except for the final property name:

    listOfFiles[currentFile].name

    Just like the variable audio is an instance name of a given Sound class instance, you’ll need an instance of a given TextField instance (i.e., a dynamic text field), so you can set that instance’s TextField.text property to whatever string value you like — in this case, the string stored in the expression listOfFiles[currentFile].name. Place a text field on the Stage somewhere, give it a meaningful instance name, then use that instance name-dot-text as the reference to your string.

    Another article on this blog, “Objects: Your ActionScript Building Blocks,” may help you get your bearings on objects in general.

  20. Peter Says:

    You’re awesome. And most generous. Could you recommend a book on Actionscript? Something skewed towards a designer, not a programmer?

  21. David Stiller Says:

    Peter,

    Thanks for the kind words! :) There are dozens of books on ActionScript, of course. We’ve entered an interesting time, as Flash geeks, because the advent of Flash CS3 brings ActionScript 3.0 to the table … yet many people are still using ActionScript 2.0 and will continue to do so for a long time. The newest books, for the most part, are focused on AS3. Given the powerful improvements to the language, most of these books are — this is my impression — aimed at programmers.

    Tom Green and I recently published Foundation Flash CS3 for Designers (friends of ED), which goes more into programming than you might think, given the word “designer” in the title. It’s getting good reviews so far on Amazon, and fully half of its 600 pages were written by me, so if my style “clicks” with you, you may find it a useful book. But again, this is a new release and covers ActionScript 3.0 only.

    If you’re interested in AS2 (which is used in this particular blog entry), then … see, that’s a tough one. I like Object-Oriented ActionScript for Flash 8 (friends of ED), by Peter Elst and Todd Yard. It’s definitely a programmer’s book, but at the same time, it’s written in an approachable, encouraging tone.

    I recommend an OOP (object-oriented programming) title because, to me, it’s all about objects. Once that concept sinks in — and it took me a while! — everything about Flash programming gets easier. Suddenly, the Help documents (specifically, the Language Reference) appears for what it is: organized around classes. Each class defines an object. Each class (for the most part) shows one or more of the following three categories: properties (characteristics), methods (what the object can do), and events (what the object can react to).

    See if this article gives you a bit more to go on, “Tackling the ActionScript 2.0 Language Reference.” And good luck in your learning!

  22. Peter Says:

    Ok. NOW I’m a pest…Well, I must be doing something wrong. I created a dynamic text box on the same layer as the code, named it same as in code, but still nothing. Is it more elaborate than that?

    Thanks for book recommendations.

  23. Peter Says:

    I take that back, somewhat…the first song doesn’t show up, but the subsequent ones do.

  24. David Stiller Says:

    Peter,

    Sounds like the ActionScript is doing what it should, but not in the way you expected. Now that some time has passed, I can see why. I should have notice this before. ;) The onSoundComplete event handler is triggered at the end of each song, which means the first song’s name won’t show.

    In the lines that load the first song, add one additional bit of ActionScript to set the text field’s text property. In fact, it’s the same line used inside the event handler (the new line is added at the end):

    var currentFile:Number = 0;
    
    var audio:Sound = new Sound();
    audio.loadSound(listOfFiles[currentFile].file, true);
    someTextField.text = listOfFiles[currentFile].name;
  25. graeme Says:

    Hi David…. I’ve drifted sideways into this sound blog and have been enjoying playing with everything talked about here but am trying to push ahead and get position and duration readings in dynamic text fields happening (or I suppose progress bars), first is it possible to achieve this for each file as it plays, my syntax knowledge is sketchy and I think the things I’ve tried are limited by this…..could you be so kind as to chuck me a clue if you get a spare moment.

    thanks
    Graeme

  26. David Stiller Says:

    graeme,

    It’s definitely possible to populate text fields with Sound info. :) If you check out the TextField class in the ActionScript 2.0 (or 3.0) Language Reference, you’ll find all kinds of information about text fields, of course. One of the most basic features is the the text property, which allows you to get or set the displayed text of any dynamic or input text field. Properties are characteristics an object has, and most classes define public properties you can access. Some are read-only, some not.

    Here, you’ll want to check out the Sound class to see what properties it features (hint: you’ll find both duration and position, which should give you a good start).

    Think of your goal as hooking together a home theater system. You’ve got a DVD player (a ridiculous metaphor for the Sound class) and a TV (an equally preposterous metaphor for the TextField class). Your text field’s reference will be its instance name, as assigned via the Property inspector (this can also be done via ActionScript), and your sound’s reference will be the variable that holds your Sound instance.

    myTextField.text = mySound.position + "/" + mySound.duration;, etc. :)

  27. graeme Says:

    thanks again David..

    looking forward to playing around with that….the notion of experimenting with artwork manipulated by sound loading and streaming also intrigues me and it feels as though this is a good place to start.

    Graeme

  28. David Stiller Says:

    graeme,

    Have fun with it! Flash is wired for multimedia, which is one of the main reasons I love it.

  29. GeePee Says:

    Hi David,

    I think you are the best person which can solve my problem with this flash sound file.
    I am having a text box and from that text box I want to hear sounds corresponding to the letters typed in the box. I dont know I had done perfect on this, but my code still working when I click to play it, but the problem is that it plays the whole sound files at the same time, but I want to play them one after another…. Please have a look at my code and correct it for me

    Here is my code:

    on (release) {
      var i, t, q;
      t=String(txt.text);
      for (i=0; i <150; i++)   {
        q= mbsubstring(t,i,1);
          if (q == "S")      {
            song1 = new Sound();
            song1.attachSound("S1");
            song1.onSoundComplete = function() { song1.duration(1000000) };
            song1.start();
          }
          else if (q == "R")   {
            song2 = new Sound();
            song2.attachSound("R2");
            song2.onSoundComplete = function() { song2.duration(1000000) };
            song2.start();
          }
          else if (q == "G")   {
            song3 = new Sound();
            song3.attachSound("G3");
            song3.onSoundComplete = function() { song3.duration(1000000) };
            song3.start();
          }
          else if (q == "M")   {
            song4 = new Sound();
            song4.attachSound("M4");
            song4.onSoundComplete = function() { song4.duration(1) };
            song4.start();
          }
          else if (q == " ")   {
          gotoAndStop(1);
        }
      }
    }
  30. David Stiller Says:

    GeePee,

    I’m not sure what’s going on in your onSoundComplete handler. The Sound.duration property indicates how long an audio file is, which is determined by the composition of that file itself (you can’t set duration, but only retrieve it — which isn’t what you want to do here anyway).

    Here’s my take on a solution. This is a custom function, playSequence(), that receives an array parameter, spelling out the word “dog” as “d”, “o”, “g”. It assumes those letters are the Linkage identifiers of three audio clips in the Library:

    function playSequence(sounds:Array):Void {
      var s:Sound = new Sound();
      if (sounds.length > 0) {
        var currentSound:Number = 0;
        s.attachSound(sounds[currentSound]);
        s.start();
        s.onSoundComplete = function():Void {
          if (currentSound < sounds.length - 1) {
            currentSound++;
            s.attachSound(sounds[currentSound]);
            s.start();
          }
        }
      }
    }
    
    playSequence(["d", "o", "g"]);

    In this way, it doesn’t matter how many letters you pass in. An arbitrarily named variable, currentSound keeps track of which sound is currently playing (this is a numbered index of the array, sounds). As each comes to an end, the same onSoundComplete handler executes — notice, there’s only one Sound instance, and only one event handler — until the array is run through completely.

  31. Kibo Says:

    Dave,
    thank you for helping us.I am new in ActionScript and your tutorial help me to better understand things that i learn in AC2&3.As you all know,learning script is hard without good exercise.This code is just what I was looking for.
    I will be so daring to ask you help me one more basic thing.I tried to change this code to work with sounds from fla library rather than from URL’s,but I failed.How can I do it?

    thanx
    Kibo

  32. David Stiller Says:

    Kibo,

    Fortunately, there’s not much to change. :) First, your array of sound files will be now be the Linkage identifiers of files in your Library, rather than external file names. To add a Linkage identifier, right-click/Command-click your Library asset and choose Linkage. Give the identifier field a unique name for each sound asset. Then your array might look something like this:

    var listOfFiles:Array = new Array("frog", "loon", "horse");

    — or whatever Linkage IDs you provided.

    Then, wherever the original code says this:

    audio.loadSound(listOfFiles[currentFile], true);

    … you put this:

    audio.attachSound(listOfFiles[currentFile]);
    audio.start();

    Check out my reply to GeePee (just before yours) to see a more detailed example of a similar situation.

  33. David Stiller Says:

    Charles,

    You wrote back on June 9, 2007, and I’m sorry to say I missed your reply until today! At that time, you asked this:

    Is there a way to play two sounds, one after the other, and embed the sounds in the swf instead of stream?

    The answer is yes on both counts, and the answers I gave GeePee and Kibo (the most recent to this reply to you) show you how it’s done. In those cases, I suggested the use of an array, but for two files you could just as easily do it like this. Assuming your linkage identifiers are “songA” and “songB”:

    var audio:Sound = new Sound();
    audio.attachSound("songA");
    audio.start();
    
    audio.onSoundComplete = function():Void {
      this.attachSound("songB");
      this.start();
      delete this.onSoundComplete;
    };

    The onSoundComplete handler is key: when the first song ends, the next one is associated with the same Sound instance by way of the attachSound() method and is instructed to start playing — and the event handler is deleted so that, at the end of the second song, Flash doesn’t do anything else.

  34. david Says:

    how do you create the array where the songs go?

    thanks

  35. David Stiller Says:

    david,

    In the article above, the array is named listOfFiles, but the name isn’t important (you could just as easily name it songs or whatever else makes sense). To create the array, you declare a variable and set that variable to an instance of the Array class, feeding in your songs as parameters:

    var songs:Array = new Array("song1.mp3", "song2.mp3");

Leave a Reply