Search code examples
safariweb-audio-apiarraybuffer

Slice ArrayBuffer with Safari and play it


I need to load a mp3, slice and play it using web audio , on firefox a slice mp3 any where and decode work fine, but on safari an error with null value occurs. Exist a trick or a way do slice the ArrayBuffer on Safari?

player.loadMp3 = function(url, callback) {

var request = new XMLHttpRequest();

request.open('GET', url, true);

request.responseType = 'arraybuffer';

request.onload = function() {

    var mp3slice = request.response.slice(1000,100000);
    player.context.decodeAudioData(mp3slice); // context is webkitAudioContext on safari
    callback();

};

request.send();

};

I need to create a mp3 player with some especial features:

  1. Time shift the music (like http://codepen.io/eranshapira/pen/mnuoB)
  2. Remove gap between musics ( I got this slicing ArrayBuffers and join then with a Blob but only in safary/IPAD don't work).
  3. Cross platform (IPAD and android. I'm using apache cordova for that).

Solution

player.loadMp3 = function(url, callback) {

    console.log("loading " + url);

    var request = new XMLHttpRequest();

    request.open('GET', url, true);

    request.responseType = 'arraybuffer';

    request.onload = function() {

        console.log("loaded");
        console.log("decoding...");

        player.context.decodeAudioData(request.response, function(buffer) {        

            console.log("decoded");

            player.buffer = player.joinAudioBuffers(player.buffer,buffer,2000000);

            player.duration += player.buffer.duration;

            player.time = minsSecs(player.buffer.duration);

            console.log("concatenated");

            callback();

        });



    }, function() {

        alert("decode failure");

    };

    request.send();
};

Solution

  • The code you've shown shouldn't work on any browser. For one thing you need to provide a callback function to decodeAudioData. You also need to slice the decoded data after decoding it, not the raw mp3-encoded data before decoding it. Some browsers might be able to decode a slice of the mp3 file, but it's not expected. Something like this:

    player.loadMp3 = function(url, callback) {
      var request = new XMLHttpRequest();
      request.open('GET', url, true);
      request.responseType = 'arraybuffer';
    
      request.onload = function() {      
        var mp3slice = request.response.slice(1000,100000);
        player.context.decodeAudioData(mp3slice, function(decoded) {
          var pcmSlice = decoded.slice(1000, 100000);
          callback(pcmSlice);
        });
      };
    
      request.send();
    };
    

    I haven't tested this code.