javascript - Web Audio API 附加/连接不同的 AudioBuffers 并将它们作为一首歌曲播放

标签 javascript concatenation html5-audio web-audio-api arraybuffer

我一直在使用 Web Audio API,尝试加载歌曲的多个部分并将它们附加到新的 ArrayBuffer,然后使用该 ArrayBuffer 将所有部分作为一首歌曲播放。在下面的示例中,我使用相同的歌曲数据(这是一个小循环)而不是歌曲的不同部分。

问题是它仍然只播放一次而不是两次,我不知道为什么。

Download song

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 tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
    tmp.set( new Uint8Array(buffer1), 0);
    tmp.set( new Uint8Array(buffer2), buffer1.byteLength);
    return tmp;
  }

  /**
   * Loads a song
   * 
   * @param {String} url The url of the song.
   */
  function loadSongWebAudioAPI(url) {
    var request = new XMLHttpRequest();
    var context = new webkitAudioContext();

    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) {
      // Concatenate the two buffers into one.
      var a = appendBuffer(data, data);
      var buffer = a.buffer;
      var audioSource = context.createBufferSource();
      audioSource.connect(context.destination);

      //decode the loaded data
      context.decodeAudioData(buffer, function(buf) {
        console.log('The buffer', buf);
        audioSource.buffer = 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('http://localhost:8282/loop.mp3');
}

window.addEventListener('load',init,false);

最佳答案

您的代码中的问题是您正在复制 MP3 文件的另一个副本并将其附加到自身的末尾。该副本实际上被解码器忽略了 - 它不是原始缓冲区数据,它只是文件流中的随机虚假垃圾,紧跟在一个完美完整的 MP3 文件之后。

您需要做的是首先将音频数据解码到 AudioBuffer 中,然后将音频缓冲区一起附加到一个新的 AudioBuffer 中。这需要对您的代码进行一些重构。

你想要做的是这样的:

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);

存在轻微的播放间隙 - 这是因为在声音样本开始时有将近 50 毫秒的静音,而不是由于循环问题。

希望这对您有所帮助!

关于javascript - Web Audio API 附加/连接不同的 AudioBuffers 并将它们作为一首歌曲播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14143652/

相关文章:

javascript - 事件在数据层中的位置 - 这重要吗?

javascript - $(window).resize 仅在浏览器刷新时触发?

MYSQL 连接时的情况

html - 声音源到听众的距离是否会影响它们在WebAudio API中的播放时间?

javascript - fastSeek 方法在 Firefox OS 设备 Spice MIFX1 中不起作用

javascript - 检测 MAC javascript 中的命令键

javascript - 从应用程序脚本附加菜单打开一个新窗口

JavaScript 用退格键连接字符串

在 C 中递归连接字符串

javascript - 使用 RecordRTC 时的 WebRTC 问题