Gabriel Ratener
Gabriel Ratener

Reputation: 605

Playing audio backwards with HTMLMediaElement

I am trying to load and play an audio file in chrome successfully, but I can't play it backwards:

      audio = new Audio('http://mathweirdo.com/bingo/audio/buzzer.mp3');
      audio.playbackRate = -1;
      audio.currentTime = audio.duration; // I have tried ommiting this line
      audio.play()

This produces no sound and only one timeupdate event firing.

Upvotes: 6

Views: 2534

Answers (1)

user1693593
user1693593

Reputation:

Using negative values is currently not supported so you will have to load and reverse the buffers manually.

Note that this will require CORS enabled audio source (the one in the example isn't, so I couldn't set up a live demo). Here is one way of doing this:

  • Load the data via AJAX (this requires CORS enabled for the audio file)
  • Let the browser parse the buffer into an audio buffer
  • Get the channel buffer(s) (references)
  • Reverse the buffer(s)
  • Initialize the audio buffer and play

This will of course limit you some as you cannot use the Audio element anymore. You will have to support the features you want by adding controls and code for them manually.

// load audio as a raw array buffer:
fetch("http://mathweirdo.com/bingo/audio/buzzer.mp3", process);

// then process the buffer using decoder
function process(file) {
  var actx = new (window.AudioContext || window.webkitAudioContext);
  actx.decodeAudioData(file, function(buffer) {

      var src = actx.createBufferSource(),      // enable using loaded data as source
          channel, tmp, i, t = 0, len, len2;

      // reverse channels
      while(t < buffer.numberOfChannels) {      // iterate each channel
        channel = buffer.getChannelData(t++);   // get reference to a channel
        len = channel.length - 1;               // end of buffer
        len2 = len >>> 1;                       // center of buffer (integer)
        for(i = 0; i < len2; i++) {             // loop to center
            tmp = channel[len - i];             // from end -> tmp
            channel[len - i] = channel[i];      // end = from beginning
            channel[i] = tmp;                   // tmp -> beginning
        }
      }

      // play
      src.buffer = buffer;
      src.connect(actx.destination);
      if (!src.start) src.start = src.noteOn;
      src.start(0);
    },
    function() {alert("Could not decode audio!")}
  )
}

// ajax loader
function fetch(url, callback) {
  var xhr = new XMLHttpRequest();
  try {
    xhr.open("GET", url);
    xhr.responseType = "arraybuffer";
    xhr.onerror = function() {alert("Network error")};
    xhr.onload = function() {
      if (xhr.status === 200) callback(xhr.response);
      else alert(xhr.statusText);
    };
    xhr.send();
  } catch (err) {alert(err.message)}
}

Upvotes: 7

Related Questions