javascript - 是否可以最好使用 javascript 将多个音频文件叠加在一起

标签 javascript

我想合并音频片段,将它们叠加在一起,以便它们同步播放并保存在一个新的音频文件中。任何帮助将非常感激。我在网上做了一些挖掘,但找不到关于 Javascript 音频编辑库(例如 Mix.js)的许多可用工具是否有能力的明确答案。

最佳答案

是的,可以使用 OfflineAudioContext() AudioContext.createChannelMerger()并创建一个 MediaStream .参见 Phonegap mixing audio files , Web Audio API .

您可以使用 fetch()XMLHttpRequest()ArrayBuffer 形式检索音频资源, AudioContext.decodeAudioData()创建一个 AudioBufferSourceNode来自回应; OfflineAudioContext()呈现合并的音频,AudioContext , AudioContext.createBufferSource() , AudioContext.createMediaStreamDestination() , MediaRecorder()记录流; Promise.all() , Promise()构造函数,.then()处理对 fetch() 的异步请求, AudioContext.decodeAudioData() ,传递生成的混合音频 Blobstop MediaRecorder的事件.

连接每个AudioContext AudioBufferSourceNodeOfflineAudioContext.destination , 调用 .start()在每个节点上;调用OfflineAudioContext.startRendering() ;新建 AudioContext节点,连接 renderedBuffer ;调用.createMediaStreamDestination()AudioContext创建一个 MediaStream从合并的音频缓冲区中,传递 .streamMediaRecorder() , 在 stop MediaRecorder的事件, 创建 Blob URLBlobURL.createObjectURL() 混合录制的音频,可以使用 <a> 下载带有 download 的元素属性和 href设置为 Blob URL .

var sources = ["https://upload.wikimedia.org/wikipedia/commons/b/be/"
               + "Hidden_Tribe_-_Didgeridoo_1_Live.ogg"
               , "https://upload.wikimedia.org/wikipedia/commons/6/6e/" 
               + "Micronesia_National_Anthem.ogg"];

var description = "HiddenTribeAnthem";
var context;
var recorder;
var div = document.querySelector("div");
var duration = 60000;
var chunks = [];
var audio = new AudioContext();
var mixedAudio = audio.createMediaStreamDestination();
var player = new Audio();
player.controls = "controls";

function get(src) {
  return fetch(src)
    .then(function(response) {
      return response.arrayBuffer()
    })
}

function stopMix(duration, ...media) {
  setTimeout(function(media) {
    media.forEach(function(node) {
      node.stop()
    })
  }, duration, media)
}

Promise.all(sources.map(get)).then(function(data) {
    var len = Math.max.apply(Math, data.map(function(buffer) {
      return buffer.byteLength
    }));
    context = new OfflineAudioContext(2, len, 44100);
    return Promise.all(data.map(function(buffer) {
        return audio.decodeAudioData(buffer)
          .then(function(bufferSource) {
            var source = context.createBufferSource();
            source.buffer = bufferSource;
            source.connect(context.destination);
            return source.start()
          })
      }))
      .then(function() {
        return context.startRendering()
      })
      .then(function(renderedBuffer) {
        return new Promise(function(resolve) {
          var mix = audio.createBufferSource();
          mix.buffer = renderedBuffer;
          mix.connect(audio.destination);
          mix.connect(mixedAudio);              
          recorder = new MediaRecorder(mixedAudio.stream);
          recorder.start(0);
          mix.start(0);
          div.innerHTML = "playing and recording tracks..";
          // stop playback and recorder in 60 seconds
          stopMix(duration, mix, recorder)

          recorder.ondataavailable = function(event) {
            chunks.push(event.data);
          };

          recorder.onstop = function(event) {
            var blob = new Blob(chunks,  {
              "type": "audio/ogg; codecs=opus"
            });
            console.log("recording complete");
            resolve(blob)
          };
        })
      })
      .then(function(blob) {
        console.log(blob);
        div.innerHTML = "mixed audio tracks ready for download..";
        var audioDownload = URL.createObjectURL(blob);
        var a = document.createElement("a");
        a.download = description + "." + blob.type.replace(/.+\/|;.+/g, "");
        a.href = audioDownload;
        a.innerHTML = a.download;
        document.body.appendChild(a);
        a.insertAdjacentHTML("afterend", "<br>");
        player.src = audioDownload;
        document.body.appendChild(player);
      })
  })
  .catch(function(e) {
    console.log(e)
  });
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <div>loading audio tracks.. please wait</div>
</body>

</html>

您也可以使用 AudioContext.createChannelMerger() , AudioContext.createChannelSplitter()

var sources = ["/path/to/audoi1", "/path/to/audio2"];    
var description = "mix";
var chunks = [];
var channels = [[0, 1], [1, 0]];
var audio = new AudioContext();
var player = new Audio();
var merger = audio.createChannelMerger(2);
var splitter = audio.createChannelSplitter(2);
var mixedAudio = audio.createMediaStreamDestination();
var duration = 60000;
var context;
var recorder;
var audioDownload;

player.controls = "controls";

function get(src) {
  return fetch(src)
    .then(function(response) {
      return response.arrayBuffer()
    })
}

function stopMix(duration, ...media) {
  setTimeout(function(media) {
    media.forEach(function(node) {
      node.stop()
    })
  }, duration, media)
}

Promise.all(sources.map(get)).then(function(data) {
    return Promise.all(data.map(function(buffer, index) {
        return audio.decodeAudioData(buffer)
          .then(function(bufferSource) {
            var channel = channels[index];
            var source = audio.createBufferSource();
            source.buffer = bufferSource;
            source.connect(splitter);
            splitter.connect(merger, channel[0], channel[1]);
            return source
          })
      }))
      .then(function(audionodes) {
        merger.connect(mixedAudio);
        merger.connect(audio.destination);
        recorder = new MediaRecorder(mixedAudio.stream);
        recorder.start(0);
        audionodes.forEach(function(node) {
          node.start(0)
        });

        stopMix(duration, ...audionodes, recorder);

        recorder.ondataavailable = function(event) {
          chunks.push(event.data);
        };

        recorder.onstop = function(event) {
          var blob = new Blob(chunks, {
            "type": "audio/ogg; codecs=opus"
          });
          audioDownload = URL.createObjectURL(blob);
          var a = document.createElement("a");
          a.download = description + "." + blob.type.replace(/.+\/|;.+/g, "");
          a.href = audioDownload;
          a.innerHTML = a.download;
          player.src = audioDownload;
          document.body.appendChild(a);
          document.body.appendChild(player);
        };
      })
  })
  .catch(function(e) {
    console.log(e)
  });

关于javascript - 是否可以最好使用 javascript 将多个音频文件叠加在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40570114/

相关文章:

javascript - 了解 TypeScript 封装

javascript - Flot JS 将目标变成菱形

javascript - 在Vue上到达div时添加动画效果或类

javascript - HTML:如何使文本中的 URL 可点击?

javascript - jquery 表格行点击功能

javascript - 用于访问下一个 html 页面的静态 4 位密码

javascript - Threejs - 仅使用 THREE.Points 动态计算相机位置

javascript - Bootstrap + 弹出窗口 - skype href 链接不起作用

javascript - 删除 function.prototype 对象

javascript - 获取 float 在下一行的第一个元素