Search code examples
javascripthtmldom-eventsmobile-safarihtml5-audio

HTML5 Audio: How to Play only a Selected Portion of an Audio File (audio sprite)?


I'm working on an iOS metronome web app. Since mobile Safari can only play one sound at a time, I'm attempting to create an 'audio sprite' - where I can use different segments of a single audio track to generate different sounds. I have a 1 second clip with 2 half-second sounds on it.

<audio id="sample" src="sounds.mp3"></audio>

<a href="javascript:play1();">Play1</a>
<a href="javascript:play2();">Play2</a>
<a href="javascript:pauseAudio();">Pause</a>

<script>
var audio = document.getElementById('click');

function play1(){
    audio.currentTime = 0;
    audio.play();

    // This is the problem area
    audio.addEventListener('timeupdate', function (){
        if (currentTime >= 0.5) {
            audio.pause();
        }
    }, false);
}   

function play2(){
    audio.currentTime = 0.5;
    audio.play();
}

function pause(){
    audio.pause();
}
</script>

See it on JSFiddle.

As you can see, I've attempted to use the 'timeupdate' event (jPlayer example) with no avail.

I've seen Remy Sharp's post on audio sprites, but (A) I wasn't able to get it to work for me, and (B) I would prefer to stay away from a library dependency.

Any ideas?


Update

I now have it working using setInterval:

function play1(){
    audio.currentTime = 0;
    audio.play();
    int = setInterval(function() {
        if (audio.currentTime > 0.4) {
            audio.pause();
            clearInterval(int);
        }
    }, 10);
}    

function play2(){
    clearInterval(int);
    audio.currentTime = 0.5;
    audio.play();
}

There are some issues with sequence and setting/clearing intervals, but for my purpose - it seems to work.

JSFiddle

P.S. If anyone has a fix for this, this could be used in Games and Interface Sound FX.


Solution

  • I think there are a couple of problems here.

    Firstly, you're adding an event listener every time the user clicks Play 1.

    Also I think

    if (currentTime >= 0.5) { ...
    

    should be

    if (audio.currentTime >= 0.5) { ...
    

    This also works:

    <audio id="sample" src="http://dl.dropbox.com/u/222645/click1sec.mp3" controls preload></audio>
    
    <a href="javascript:playSegment(0.0, 0.5);">Play1</a>
    <a href="javascript:playSegment(0.5);">Play2</a>
    
    <script>
    var audio = document.getElementById('sample');
    var segmentEnd;
    
    audio.addEventListener('timeupdate', function (){
        if (segmentEnd && audio.currentTime >= segmentEnd) {
            audio.pause();
        }   
        console.log(audio.currentTime);
    }, false);
    
    function playSegment(startTime, endTime){
        segmentEnd = endTime;
        audio.currentTime = startTime;
        audio.play();
    }
    </script>