开发者

How can I queue a series of sound HTML5 <audio> sound clips to play in sequence?

I'm experimenting with porting a simple audio utility called VoiceWalker to Javascript. VoiceWalker is a tool to help people transcribe audio, and it works like this:

How can I queue a series of sound HTML5 <audio> sound clips to play in sequence?

http://i.imgur.com/rafgl.png

So the idea there is that it plays a bit, repeats it, scoots forward, plays another bit, repeats that, scoots forward开发者_如何学运维, etc.

I've cobbled together a function to play a sound clip, it looks like this:

function clip(audio, start, stop){
    audio.currentTime = start;
    audio.play();
    int = setInterval(function() {
        if (audio.currentTime > stop) {
            audio.pause();
            clearInterval(int);
        }
    }, 10);
}    

It's an easy proposition to come up with a list of start/stop times that match the pattern above, but there's one problem: how do I queue up my clip() calls so that one will only run after the other has stopped?


Make clip call itself:

function clip(audio, start, stop){
    audio.currentTime = start;
    audio.play();
    int = setInterval(function() {
        if (audio.currentTime > stop) {
            audio.pause();
            clearInterval(int);
            // Play it again, 2 seconds further.
            clip(audio, start + 2, stop + 2);
        }
    }, 10);
}


Follow the structure of other API's in JavaScript: have your clip function also take in a "what to do next" function. (More technical term: "callback"). The idea is that your clip function knows when it's done with its work, and can then call the callback at the right time.

As an example, let's say that we have a function that will slowly spell out a word to the document's body:

var spell = function(word, onSuccess) {
    var i = 0;
    var intervalId = setInterval(function() { 
                    if (i >= word.length) { 
                        clearInterval(intervalId);
                        onSuccess();
                    } else {
                        document.body.appendChild(
                            document.createTextNode(word.charAt(i)));
                        i++;
                    }
                }, 100)
};

When this computation finishes spelling out the word, it will call onSuccess, which is going to be our callback. Once we have spell(), we can try to use it:

var startIt = function() {
    spell("hello", afterHello);
};

var afterHello = function() {
    spell("world", afterHelloWorld);
};

var afterHelloWorld = function() {
    alert("all done!"); 
};

Try calling startIt and you'll see it do its thing.

This approach allows us to chain together these asynchronous computations. Every good JavaScript asynchronous API allows you to define "what to do next" after the computation succeeds. You can write your own functions to do the same.


var count = 1;  //initialize and set counter
var clipstart = [0,10,20,30,40,50,60]; //initialize and set array of starting points
var clipend   = [5,15,25,35,45,55,65]; //initialize and set array of ending points
var clip = document.getElementById('clip'); //the clip you want to work with
var end; //initialize the current end point
var start; //initialize the current start point

function stop(){ //function to check if the clip needs to be stopped and asks for next track
  if(clip.currentTime >= end){
    clip.pause(); //pause playback
      //if it's not on the 2 iteration, and the there are still cues left ask for next track.
      if(!(count == 1 && clipstart.length == 0)){ 
          skip();
      }
  }
}

function play(){ //skip to start and play
  clip.currentTime = start;
  clip.play();
}

function skip(){ //sets the start and end points
  count++;
  if(count == 2){
    count = 0;
    start = clipstart.shift();
    end = clipend.shift();
  }  
  play();
}

skip();
clip.addEventListener('timeupdate', stop); //listens for if the clip is playing, and if it is, every second run the stop function.

take a look at it here, it can be applied to an audio or video element.


Here is a module which will do what you want.

It is set up to play two seconds of the clip twice, with a short pause in between, then advance the starting point half a second, pause briefly again, and then play the next two seconds from the new starting point, and so on. (You can change these settings very easily in the properties at the top).

This code expects there to be an html element with id "debug" - I used a paragraph for this. You can delete all reference to this element if you wish. (There are four of these, the line which begins var d..., and the three lines which begin d.innerHTML...).

var VOICEWALKER = (function () {
// properties
var d = document.getElementById("debug");
var audio = document.getElementsByTagName('audio')[0];
var start = 0;
var stop = 2;
var advanceBy = 0.5;
var pauseDuration = 500; // milliseconds between clips
var intv; // reference to the setInterval timer
var clipCount = 0; // how many times we have played this part of the clip
var clipMax = 2; // how many times we shall play this part of the clip

// methods
var pauseFinished = function () {
    d.innerHTML = "Pause finished";
    clip();
};

var pollClip = function () {

    d.innerHTML = String(audio.currentTime);

    if (audio.currentTime > stop) {
        audio.pause();
        d.innerHTML = "Pause";
        clearInterval(intv);

        clipCount += 1;
        if (clipCount === clipMax) {
            clipCount = 0;
            // advance clip
            start += advanceBy;
            stop += advanceBy;
        }

        // pause a little
        setTimeout(pauseFinished, pauseDuration);
    }


};

var clip = function () {
    audio.currentTime = start;
    audio.play();
    intv = setInterval(pollClip, 10);
};

var init = function () {
    audio.addEventListener('canplaythrough', clip, false);
};

return {
    init : init
};
}());

VOICEWALKER.init();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜