【问题标题】:Create Seamless Loop of Audio - Web创建音频的无缝循环 - 网络
【发布时间】:2018-04-06 03:59:36
【问题描述】:

我想创建音频文件的无缝循环。但到目前为止,在我使用的所有方法中,结束和开始之间都有明显的差距。


这是我目前尝试过的:

第一种方法是使用 HTML 中的音频并循环播放,但从曲目结尾到开头时仍然存在明显的延迟。

<audio loop autoplay>
    <source src="audio.mp3" type="audio/mpeg">
<audio>

然后我从 JavaScript 中尝试了相同的结果:

let myAudio = new Audio(file);
myAudio.loop = true; 
myAudio.play();

之后我尝试了这个(根据this answer

myAudio.addEventListener(
    'timeupdate',
    function() {
        var buffer = .44;
        if (this.currentTime > this.duration - buffer) {
            this.currentTime = 0;
            this.play();
        }
     },
     false
);

我玩弄了缓冲区,但我只是为了减少间隙而不是完全忽略它。

我求助于库 SeamlessLoop (GitHub) 并让它在 Chromium 浏览器中无缝循环(但在最新的 Safari 中没有。没有在其他浏览器中测试)。我用于此的代码:

let loop = new SeamlessLoop();
// My File is 58 Seconds long. Btw there aren't any gaps in the file.
loop.addUri(file, 58000, 'sound1');
loop.callback(soundsLoaded);
function soundsLoaded() {
    let n = 1;
    loop.start('sound' + n);
}

编辑:我尝试了另一种方法:通过两个不同的音频元素循环播放:

var current_player = "a";
var player_a = document.createElement("audio");
var player_b = document.createElement("audio");

player_a.src = "sounds/back_music.ogg";
player_b.src = player_a.src;

function loopIt(){
    var player = null;

    if(current_player == "a"){
        player = player_b;
        current_player = "b";
    }
    else{
        player = player_a;
        current_player = "a";
    }

    player.play();

    /*
        3104.897 is the length of the audio clip in milliseconds.
        Received from player.duration. 
        This is a different file than the first one
    */
    setTimeout(loopIt, 3104.897); 
}

loopIt();

但由于浏览器中的毫秒数不一致或不够精细,这并不能很好地工作,但它确实比音频的正常“循环”属性好得多。


谁能引导我正确地循环播放音频?

【问题讨论】:

  • 今天尝试了另一个格式为 wav 的文件。文件的结尾/开头没有间隙。仍然有明显的延迟。
  • 再次检查文件是否真的没有间隙。但事实并非如此。我在音频播放器中播放并在那里循环播放,过渡非常无缝。
  • 我可以在问题中改进什么?
  • “再次检查文件是否真的没有间隙。它没有。我在音频播放器中播放并在那里循环播放,过渡非常无缝。” 我很困惑...这是否意味着您已经解决了问题?
  • @zer00ne 我的意思是音频播放器(如 Windows Media Player / iTunes)中的过渡非常无缝,但在浏览器中却不是。

标签: javascript html audio html5-audio web-audio-api


【解决方案1】:

对此有一个非常简单的解决方案,只需使用loopify,它利用了 html5 网络音频 api,并且可以很好地处理多种格式,而不仅仅是开发人员所说的 wav。

<script src="loopify.js" type="text/javascript"></script>
<script>
    loopify("yourfile.mp3|ogg|webm|flac",ready);

    function ready(err,loop){
      if (err) {
        console.warn(err);
      }

        loop.play();
    }
</script>

这将自动播放文件,如果你想有开始和停止按钮,例如看看他的demo

【讨论】:

  • 这在后台执行的操作与接受的答案完全相同。
【解决方案2】:

您可以改用Web Audio API。这有一些注意事项,但它可以让您准确地循环到单个样本级别。

需要注意的是,您必须将整个文件加载到内存中。这对于大文件可能不实用。如果文件只有几秒钟,那应该没问题。

第二个是您必须手动(如果需要)编写控制按钮,因为 API 具有低级方法。这意味着播放、暂停/停止、静音、音量等。扫描和可能的暂停本身就是一个挑战。

最后,并非所有浏览器都support Web Audio API - 在这种情况下,您将不得不回退到常规的音频 API 甚至 Flash,但如果您的目标是现代浏览器,这应该不是现在的主要问题。

示例

这将加载一个 4 小节的鼓循环并在循环时无任何间隙地播放。主要步骤是:

  • 它从启用了 CORS 的源加载音频(这很重要,要么使用与您的页面相同的域,要么设置外部服务器以允许跨域使用,就像 Dropbox 在本示例中为我们所做的那样)。李>
  • AudioContext 然后解码加载的文件
  • 解码后的文件用于源节点
  • 源节点连接到输出
  • 循环已启用,缓冲区从内存中播放。

var actx = new (AudioContext || webkitAudioContext)(),
    src = "https://dl.dropboxusercontent.com/s/fdcf2lwsa748qav/drum44.wav",
    audioData, srcNode;  // global so we can access them from handlers

// Load some audio (CORS need to be allowed or we won't be able to decode the data)
fetch(src, {mode: "cors"}).then(function(resp) {return resp.arrayBuffer()}).then(decode);

// Decode the audio file, then start the show
function decode(buffer) {
  actx.decodeAudioData(buffer, playLoop);
}

// Sets up a new source node as needed as stopping will render current invalid
function playLoop(abuffer) {
  if (!audioData) audioData = abuffer;  // create a reference for control buttons
  srcNode = actx.createBufferSource();  // create audio source
  srcNode.buffer = abuffer;             // use decoded buffer
  srcNode.connect(actx.destination);    // create output
  srcNode.loop = true;                  // takes care of perfect looping
  srcNode.start();                      // play...
}

// Simple example control
document.querySelector("button").onclick = function() {
  if (srcNode) {
    srcNode.stop();
    srcNode = null;   
    this.innerText = "Play";
  } else {
    playLoop(audioData);
    this.innerText = "Stop";
  }
};
&lt;button&gt;Stop&lt;/button&gt;

【讨论】:

  • 今晚我会试试这个。无论如何,我都有自己的控件。这也适用于移动 chrome / 移动 safari 吗?
  • @Marimba 如果浏览器支持 Web Audio API(and they seem to be 尽管处于实验状态)它应该可以工作,但是在特定版本中总是存在实现错误的风险,因此必须对其进行测试每个人。
  • 好的,很好。这适用于您的文件。您是如何获得这种 Dropbox 网址的?
  • @Marimba 没有方便的方法来获取 Dropbox 链接 afaik。我只是手动替换子+域以获得资源的直接链接。
  • @Marimba 是的,VS 有点资源消耗 :) 恐怕你做不了太多 - Chrome(和 FF)节流选项卡不活动意味着这些选项卡无法访问与它们处于活动状态时一样多的“cpu”(影响帧速率、视频、音频等)。我们无权直接访问它来做点什么……:-/
猜你喜欢
  • 2023-03-17
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2014-01-12
  • 2015-05-03
  • 1970-01-01
  • 2019-05-13
相关资源
最近更新 更多