Pure JavaScript offline audio player

With the upcoming new HTML standard HTML5 a lot of really cool features like audio and video will come to our browsers without the need of third party plugins. JavaScript gets some exciting features, too: Canvas to draw pictures with JavaScript, WebWorkers for running scripts in the background, and FileAPI to read local files, to name just a few.

Today we will use the FileAPI together with the audio-tag to build a web based audio player. First let’s take a look at the FileAPI. The easiest way to access a local file is to use a form input of type file, like this one:

<input id="files" type="file" /> 
<div><ul id="output"></ul></div>

The multiple attribute is also new in HTML5. It allows us to select multiple files in the file select dialog. To access some basic information related to the file the user chose, use the new property of type FileList named files.

var files = document.getElementById('files').files, 
    i, f, output = []; 
for(i=0; f = files[i]; i++) { 
    output.push('
	<li>', f.name, ' - ', f.size, ' Bytes</li>
'); 
} 
document.getElementById('output').innerHTML += output.join('');

The FileList files exposes an array of files selected by the user. The single files are of type File which is inherits from Blob. That means we can read the name, the size, the type, and the urn of the file (at the time of writing Webkit supports all but the urn property).

Now we know how to get some basic information about local files, but using the file input form element is so boring and filling a playlist that way is very cumbersome, even with the multiple attribute. Drag & Drop like Google did in GMail for the attachments would be nice and it’s not that hard to implement at all. First we change the input element from above into a div

<div id="files">Drop zone</div>

and attach the ondragover and the ondrop to our file handling from above:

function handleDrop(e) { 
    e.stopPropagation(); 
    e.preventDefault(); 
 
    var files = e.dataTransfer.files, 
        output = [], i, f, audiofiles; 
 
    for(i=0; f = files[i]; i++) { 
        if(f.type === 'audio/mp3' || f.type === 'audio/mpeg') { 
            output.push('
	<li>', f.name, ' - ', f.size, ' bytes</li>
'); 
            audiofiles.push(f); 
        } 
    } 
    document.getElementById('output').innerHTML += output.join(''); 
} 
 
function handleDragOver(e) { 
    e.stopPropagation(); 
    e.preventDefault(); 
} 
var file_drop = document.getElementById('files'); 
file_drop.addEventListener('dragover', handleDragOver, false); 
file_drop.addEventListener('drop', handleDrop, false);

Reading files

To read the contents of a local file we need to create a FileReader object

var freader = new FileReader();

attach an onload event handler

freader.onload = function(e) { 
    // read the file contents 
}

and initiate the reading process

freader.readAsDataURL(audiofiles[0]);

Other methods to read files are readAsBinaryString and readAsText. The advantage of using readAsDataURL is that the HTML5 audio tag can read audio data encoded in a data URI via it’s src attribute, just like image resources. Hence, to

Play the audio

we first add an audio tag

<audio id="player">Your browser does not support the marvelous HTML5 audio tag! Go get a better one.</audio>

and change the onload method of the FileReader object from above to

freader.onload = function(e) { 
    document.getElementById('player').src = e.target.result; 
    document.getElementById('player').play(); 
}

That’s all! Try it out or grab the source code at github.