Web Audio API append/concatenate different AudioBuffers and play them as one song

后端 未结 2 1716
逝去的感伤
逝去的感伤 2020-12-08 01:17

I\'ve been playing with the Web Audio API and I\'m trying to load multiple parts of a song and append them to a new ArrayBuffer and then use that ArrayBuffer for playing all

相关标签:
2条回答
  • 2020-12-08 01:55

    If you need to append/concatenate a list of buffer from an array (not only 2), here is a solution. I have just tweaked a bit the @Cwilso code (thanks for your help ;)

    function concatBuffer(_buffers) {
        // _buffers[] is an array containig our audiobuffer list
    
        var buflengh = _buffers.length;
        var channels = [];
        var totalDuration = 0;
    
        for(var a=0; a<buflengh; a++){
            channels.push(_buffers[a].numberOfChannels);// Store all number of channels to choose the lowest one after
            totalDuration += _buffers[a].duration;// Get the total duration of the new buffer when every buffer will be added/concatenated
        }
    
        var numberOfChannels = channels.reduce(function(a, b) { return Math.min(a, b); });;// The lowest value contained in the array channels
        var tmp = context.createBuffer(numberOfChannels, context.sampleRate * totalDuration, context.sampleRate);// Create new buffer
    
        for (var b=0; b<numberOfChannels; b++) {
            var channel = tmp.getChannelData(b);
            var dataIndex = 0;
    
            for(var c = 0; c < buflengh; c++) {
                channel.set(_buffers[c].getChannelData(b), dataIndex);
                dataIndex+=_buffers[c].length;// Next position where we should store the next buffer values
            }
        }
        return tmp;
    }
    
    0 讨论(0)
  • 2020-12-08 02:03

    The problem in your code is that you're copying and appending another copy of the MP3 file onto the end of itself. That copy gets effectively ignored by the decoder - it's not raw buffer data, it's just random spurious junk in the file stream, following a perfectly complete MP3 file.

    What you need to do is first decode the audio data into a AudioBuffer, then append the audio buffers together into a new AudioBuffer. This requires a little bit of restructuring of your code.

    What you want to do is this:

    var context = new webkitAudioContext();
    
    function init() {
    
      /**
       * Appends two ArrayBuffers into a new one.
       * 
       * @param {ArrayBuffer} buffer1 The first buffer.
       * @param {ArrayBuffer} buffer2 The second buffer.
       */
      function appendBuffer(buffer1, buffer2) {
        var numberOfChannels = Math.min( buffer1.numberOfChannels, buffer2.numberOfChannels );
        var tmp = context.createBuffer( numberOfChannels, (buffer1.length + buffer2.length), buffer1.sampleRate );
        for (var i=0; i<numberOfChannels; i++) {
          var channel = tmp.getChannelData(i);
          channel.set( buffer1.getChannelData(i), 0);
          channel.set( buffer2.getChannelData(i), buffer1.length);
        }
        return tmp;
      }
    
      /**
       * Loads a song
       * 
       * @param {String} url The url of the song.
       */
      function loadSongWebAudioAPI(url) {
        var request = new XMLHttpRequest();
    
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';
    
        /**
         * Appends two ArrayBuffers into a new one.
         * 
         * @param {ArrayBuffer} data The ArrayBuffer that was loaded.
         */
        function play(data) {
          //decode the loaded data
          context.decodeAudioData(data, function(buf) {
            var audioSource = context.createBufferSource();
            audioSource.connect(context.destination);
    
            // Concatenate the two buffers into one.
            audioSource.buffer = appendBuffer(buf, buf);
            audioSource.noteOn(0);
            audioSource.playbackRate.value = 1;
          });
    
        };
    
        // When the song is loaded asynchronously try to play it.
        request.onload = function() {
          play(request.response);
        }
    
        request.send();
      }
    
    
      loadSongWebAudioAPI('loop.mp3');
    }
    
    window.addEventListener('load',init,false);
    

    There's a slight playback gap - that's because you have nearly 50ms of silence at the beginning of your sound sample, not due to looping issues.

    Hope this helps!

    0 讨论(0)
提交回复
热议问题