Cool audio player solution for pages with multiple audio clips
This tutorial demonstrates one way of setting up an audio player for a page with multiple audio clips. The end result is the following.
Here's a little background on what led to this solution. Some time ago, I was asked to build a small site that included dozens of audio clips on one page. The client suggested I base this site on an existing site of hers that also had a page with dozens of audio clips. Visitors to the site could play different audio clips by clicking on a play button for each clip. The play buttons for the clips were laid out in a table similar to the one depicted below:

The problem with the existing implementation was that the page loaded a separate audio player for each audio clip. In other words, the browser had to download a separate copy of the Flash-based audio player application for each audio clip (in this case, the "Button Player" version of the XSPF Web Music Player). That much Flash takes a while to download and hogs a lot of memory. Even worse, the new site had more than twice as many audio clips per page as the existing one. I initially tried cloning the audio page from the old site to the new one, but when I added all of the audio clips using the old method, the page loaded sooooo slooooowly!
Using Flowplayer as an audio player
I decided to experiment with using Flowplayer as my audio player, having wanted to try it out for some time. Out of the box, Flowplayer is a video player for the web, but it also includes an audio plugin that can turn it into an audio player. I downloaded both Flowplayer itself and the Flowplayer audio plugin. According to the Flowplayer documentation, one creates players by creating a container element in the HTML, such as an <a> or <div>, and then using JavaScript to dynamically insert the code for the player itself inside of the container elements. Here is a code example from Flowplayer's web site:
<!-- setup player container -->
<div id="audio" style="display:block;width:750px;height:30px;" href="http://releases.flowplayer.org/data/fake_empire.mp3"></div>
<script type="text/javascript" src="js/flowplayer-3.2.4.min.js"></script>
<script type="text/javascript">
// install flowplayer into container
$f("audio", "http://releases.flowplayer.org/swf/flowplayer-3.2.5.swf", {
// fullscreen button not needed here
plugins: {
controls: {
fullscreen: false,
height: 30,
autoHide: false
}
},
clip: {
autoPlay: false,
// optional: when playback starts close the first audio playback
onBeforeBegin: function() {
$f("player").close();
}
}
});
</script>
After loading the flowplayer JavaScript API library flowplayer-3.2.4.min.js, the flowplayer() function, and its shorthand equivalent $f(), become available. To set up a player instance, pass the ID of the container element as the first argument to the function (in this example, "audio"), the path to the flowplayer SWF file as the second argument, and the configuration as the third argument. The code syntax of the Flowplayer API looks like jQuery, which I think makes it super-easy to use.
Loading Flowplayer's audio plugin
In general, when you want to load one of Flowplayer's optional plugins, you would have to declare it explicitly. For example, to load the audio plugin, you would add something like the following to the player configuration:
plugins: {
audio: {
url: 'includes/flowplayer.audio-3.2.1.swf'
}
}
Notice that in the above example taken from Flowplayer's web site, no such declaration of the audio plugin exists. This is because, according to the Flowplayer documentation:
Flowplayer can automatically load the audio plugin when it encounters a clip whose file name ends with MP3 or mp3. It loads the [audio plugin SWF] file from the same folder from which the player [SWF file] was loaded.
Well, I recommend you do NOT rely on Flowplayer loading the audio plugin automatically. I learned this the hard way. This might work OK in simple implementations, but if you try to do anything slightly fancy with the player (as I did), the player might not load the plugin. From an end user perspective, the result is that one can click on the play button all day, but the audio will never play.
Here is the initialization function I used. Note that I loaded two plugins: the audio plugin and a different controlbar, named flowplayer.controls-tube-3.2.3.swf. I thought the play/pause button, timeline/progress bar, time display, mute button, etc. of the Tube Skin controlbar were aesthetically a better fit for the site on which I was working than the default controlbar. Also, since Flowplayer is serving as an audio player rather than a video player, fullscreen and auto-hide are both disabled. In case you were wondering, auto-hide is the property that determines whether or not the controlbar disappears a few seconds after the user stops interacting with it.
var mainAudioPlayer = flowplayer("mainaudioplayer", "includes/flowplayer-3.2.5.swf", {
plugins: {
controls: {
url: 'includes/flowplayer.controls-tube-3.2.3.swf',
fullscreen: false,
height: 30,
autoHide: false,
backgroundGradient: 'none'
},
audio: {
url: 'includes/flowplayer.audio-3.2.1.swf'
}
},
clip: {
autoPlay: true
}
});
Notice that we assign this player to the variable mainAudioPlayer. Doing so will allow us to perform other actions on the audio player using JavaScript later on.
To ensure that only the controlbar portion of the player is visible, add a CSS style setting the height of the container element to match the height of the controls in the player configuration:
<style type="text/css">
#mainaudioplayer {
height:30px;
}
</style>
Setting up the player for multiple audio clips: HTML and CSS
The above code demonstrates how to set up an audio player for one clip, assuming that in the HTML code, the container element with ID #mainaudioplayer has an href attribute pointing to an audio clip:
<div id="mainaudioplayer" href="path/to/audio/myaudioclip.mp3"></div>
Our goal, however, is to set up a page with multiple audio clips. Although we could create multiple players on the page by making a few minor changes to the code, a better solution is create a list of available audio clips, and to load any of them that the user clicks into the one Flowplayer instance. We can create buttons by setting up anchor tags that link to each audio clip MP3 file, and then using CSS to style those anchor tags to look like buttons. Let's start with the HTML.
<div id="mainaudioplayer"></div><div class="audioclip"><a href="path/to/audio/rain-and-thunder.mp3"></a> Rain and thunder </div><div class="audioclip"><a href="path/to/audio/elevator-door.mp3"></a> Elevator door </div><div class="audioclip"><a href="path/to/audio/door-handle-creaking.mp3"></a> Door handle creaking </div><div class="audioclip"><a href="path/to/audio/applause.mp3"></a> Applause </div><div class="audioclip"><a href="path/to/audio/school-bell.mp3"></a> School bell </div>
<br clear="all" />
Each clip in the above list consists of an anchor <a> element and a label for the audio clip, wrapped inside a <div> of class .audioclip. We also have a container <div> for the Flowplayer itself, <div id="mainaudioplayer"></div>, but this time we do not give it any MP3 clip URL.
Now let's add the CSS to make the anchor tags look like buttons. For the button image, you can use the simple play-button.gif image
I whipped up in Photoshop, or you can create your own.
.audioclip {
clear:both;
height:20px;
}
.audioclip a { background:url("path/to/image/play-button.gif") repeat-none; display:block; float:left; height:17px;
margin:0px 5px; width:17px; }
The above code affects all anchor tags inside of container elements of class .audioclip. The style causes these anchor tags to display as block-level elements rather than their default inline style. This difference allows us to assign height and width values to these elements, so that they match the size of the button image. However, since we want the text labels to appear next to the buttons, we must also set the buttons to float left, otherwise as block-level elements they would not appear on the same line as the text. To prevent all of the buttons from stacking up next to each other, we also set the container <div> to clear both right and left floats for all preceding elements. We also include a <br clear="all" /> element at the end of the list in the HTML to clear the float of the last clip. A more elegant solution than adding extra markup, of course, would be to add the clear:both CSS property to whatever element follows the list.
We should also hide the Flowplayer when the page first loads, because it will not have any clips loaded until a user clicks on one of the buttons. Thus, we change the style for the audio player to:
#mainaudioplayer { display:none; height:30px;
}
Setting up the player for multiple audio clips: JavaScript
If we wrote the above code and stopped, we would get a list of clips with buttons, but the Flowplayer would not load whenever a user clicked on one of the buttons. Instead, the browser would load the MP3 file as a new page, which would consist of the browser's default audio player playing the file, centered in an otherwise blank page. To prevent the browser from loading the MP3 file in a new page and cause the file to load into Flowplayer instead, we need to write some JavaScript to intercept the buttons' click event.
To make this task easier, let's write the JavaScript code using jQuery syntax. If you don't already have jQuery enabled on your site, download jQuery and add it to the <head> section of your page:
<script type="text/javascript" src="path/to/js/jquery.min.js"></script>
Next, add the Flowplayer JavaScript file so that Flowplayer can load:
<script type="text/javascript" src="path/to/js/flowplayer-3.2.4.min.js?i"></script>
Then, add the code to intercept the click event on any <a> tag with class .audioclip.
$(".audioclip a").click(function(e){
if(e.preventDefault) e.preventDefault(); else e.returnValue = false;
var clipUrl = $(this).attr("href");
if(!mainAudioPlayer.isLoaded()) mainAudioPlayer.load();
$("#mainaudioplayer").css("display", "block");
mainAudioPlayer.play(clipUrl);
});
The above code works as follows. First, we prevent the browser from opening the MP3 file in a new page, which is the browser's default behavior. To do so, we test whether the current browser supports the preventDefault() method on click event e. If so, we run that method on e; otherwise, we set the returnValue property of e to false to prevent a new page from loading. Next, we grab the value of the button's href attribute, which is URL to the audio clip MP3 file, and assign it to the variable clipURL.
The next several steps use methods from Flowplayer's JavaScript API. We use Flowplayer's isLoaded() method to determine whether or not the player has been loaded into the container element; that is, whether or not any of the other buttons have been clicked, yet. If not, we load the player using the load() method. Since we hid the audio player when the page first loaded by using the display:none CSS property, we now reveal the player by setting the display to block. Finally, we call Flowplayer's play() method on the player object, passing it the clipURL. This causes the player to start playing the selected clip.
Putting it all together
The combined code to generate this multi-clip audio player solution looks as follows.
<style type="text/css">
#mainaudioplayer { display:none; height:30px; }
.audioclip {
clear:both;
height:20px;
}
.audioclip a { background:url("path/to/image/play-button.gif") repeat-none; display:block; float:left; height:17px;
margin:0px 5px; width:17px; }
</style><script type="text/javascript" src="path/to/js/jquery.min.js"></script>
<script type="text/javascript" src="path/to/js/flowplayer-3.2.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var mainAudioPlayer = flowplayer("mainaudioplayer", "includes/flowplayer-3.2.5.swf", {
plugins: {
controls: {
url: 'includes/flowplayer.controls-tube-3.2.3.swf',
fullscreen: false,
height: 30,
autoHide: false,
backgroundGradient: 'none'
},
audio: {
url: 'includes/flowplayer.audio-3.2.1.swf'
}
},
clip: {
autoPlay: true
}
}); $(".audioclip a").click(function(e){
if(e.preventDefault) e.preventDefault(); else e.returnValue = false;
var clipUrl = $(this).attr("href");
if(!mainAudioPlayer.isLoaded()) mainAudioPlayer.load();
$("#mainaudioplayer").css("display", "block");
mainAudioPlayer.play(clipUrl);
});});
</script>
<div id="mainaudioplayer"></div><div class="audioclip"><a href="path/to/audio/rain-and-thunder.mp3"></a> Rain and thunder </div><div class="audioclip"><a href="path/to/audio/elevator-door.mp3"></a> Elevator door </div><div class="audioclip"><a href="path/to/audio/door-handle-creaking.mp3"></a> Door handle creaking </div>
<div class="audioclip"><a href="path/to/audio/applause.mp3"></a> Applause </div><div class="audioclip"><a href="path/to/audio/school-bell.mp3"></a> School bell </div>
<br clear="all" />
Obviously, if this were on a production site you would move all of the CSS and JavaScript code to separate files and include them in the <head> or, in the case of the JavaScript, directly above the closing </body> tag. If you have thoughts or questions about the above, please post a comment.
Note: The audio clips used in this demonstration are in the public domain. Thanks to PDSounds.org for providing me with these clips: Thunder and Rain on a Veranda, Elevator Door Closing, Door Handle Creaking, Applause I, Old School Bell 5.

