How to Play Sound Files Sequentially
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);
}
April 17th, 2007 at 6:25 pm
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
sorry , i am not as well as you in English but i try to say my mind.
April 17th, 2007 at 9:57 pm
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.
April 22nd, 2007 at 5:42 pm
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;
April 27th, 2007 at 7:45 am
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
April 27th, 2007 at 8:34 am
Nic,
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
Soundinstance.”Now, what does that mean?
Well, you’re already using the
Soundinstance in the above sample; it happens to have the instance nameaudio, but of course, it can be whatever you choose. As an instance of theSoundclass, thataudiovariable acts as your ambassador for sound-related things. That variable brings you all the functionality described by theSoundclass (for example, above, it’s calling on theSound.loadSound()method).At any point, you can wire up a button to invoke, say,
Sound.stop()on thataudioinstance — and whatever audio file that instance happens to currently point to will stop. InvokeSound.start()on it, and that particular audio file will start again. (Here’s a tip on how to restart audio where it left off.)April 27th, 2007 at 2:31 pm
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.
April 28th, 2007 at 10:12 am
No worries, I sorted it out myself.
Anyways, thank you (again) for your blog and keep up the good work.
Nic
April 28th, 2007 at 10:50 am
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!
June 9th, 2007 at 9:49 pm
Is there a way to play two sounds, one after the other, and embed the sounds in the swf instead of stream?
June 13th, 2007 at 3:28 am
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
August 5th, 2007 at 12:18 am
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
August 5th, 2007 at 7:06 pm
Johann,
Somehow or other, you’ll need to reference the
Soundinstance that loads your external audio. Once you have a reference to theSoundinstance, 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 thatSoundinstance 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 theSoundinstance.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
September 28th, 2007 at 4:50 pm
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?
October 1st, 2007 at 1:22 pm
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.
October 1st, 2007 at 3:10 pm
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???
October 2nd, 2007 at 12:29 pm
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:
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
onSoundCompletehandler accesses the data … they’re not object properties instead of stand-alone strings:The curly braces
{}are a shorthand for the expressionnew Object(), so the array could have been written like this:… but the other way requires less typing.
October 3rd, 2007 at 10:44 am
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.
October 3rd, 2007 at 10:49 am
One more thing…I need to create a text field with a variable called “name”? is that how I set it up?
October 3rd, 2007 at 11:00 am
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 anArrayinstance — a list — but this time, the list contains objects instead of strings. These objects have two properties,fileandname, 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].nameJust like the variable
audiois an instance name of a givenSoundclass instance, you’ll need an instance of a givenTextFieldinstance (i.e., a dynamic text field), so you can set that instance’sTextField.textproperty to whatever string value you like — in this case, the string stored in the expressionlistOfFiles[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.
October 4th, 2007 at 6:38 am
You’re awesome. And most generous. Could you recommend a book on Actionscript? Something skewed towards a designer, not a programmer?
October 4th, 2007 at 8:36 am
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!
October 4th, 2007 at 3:22 pm
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.
October 4th, 2007 at 3:26 pm
I take that back, somewhat…the first song doesn’t show up, but the subsequent ones do.
October 4th, 2007 at 4:03 pm
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
onSoundCompleteevent 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
textproperty. In fact, it’s the same line used inside the event handler (the new line is added at the end):October 20th, 2007 at 2:26 am
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
October 23rd, 2007 at 8:45 pm
graeme,
It’s definitely possible to populate text fields with Sound info.
If you check out the
TextFieldclass 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 thetextproperty, 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
Soundclass to see what properties it features (hint: you’ll find bothdurationandposition, 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
Soundclass) and a TV (an equally preposterous metaphor for theTextFieldclass). 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 yourSoundinstance.myTextField.text = mySound.position + "/" + mySound.duration;, etc.October 31st, 2007 at 8:37 pm
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
November 1st, 2007 at 1:32 pm
graeme,
Have fun with it! Flash is wired for multimedia, which is one of the main reasons I love it.
January 8th, 2008 at 12:46 pm
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:
January 14th, 2008 at 4:38 pm
GeePee,
I’m not sure what’s going on in your
onSoundCompletehandler. TheSound.durationproperty indicates how long an audio file is, which is determined by the composition of that file itself (you can’t setduration, 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:In this way, it doesn’t matter how many letters you pass in. An arbitrarily named variable,
currentSoundkeeps track of which sound is currently playing (this is a numbered index of the array,sounds). As each comes to an end, the sameonSoundCompletehandler executes — notice, there’s only oneSoundinstance, and only one event handler — until the array is run through completely.February 11th, 2008 at 5:53 pm
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
February 22nd, 2008 at 9:28 pm
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:
— or whatever Linkage IDs you provided.
Then, wherever the original code says this:
… you put this:
Check out my reply to GeePee (just before yours) to see a more detailed example of a similar situation.
October 9th, 2008 at 7:28 pm
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:
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”:
The
onSoundCompletehandler is key: when the first song ends, the next one is associated with the sameSoundinstance by way of theattachSound()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.May 25th, 2009 at 4:26 am
how do you create the array where the songs go?
thanks
May 25th, 2009 at 8:55 am
david,
In the article above, the array is named
listOfFiles, but the name isn’t important (you could just as easily name itsongsor whatever else makes sense). To create the array, you declare a variable and set that variable to an instance of theArrayclass, feeding in your songs as parameters: