Javascript - Web Audio API -- Range type Input 在 Firefox 中不是动态的,但在 Chrome 中是动态的 -added reprex

Javascript - Web Audio API -- Range type Input is not dynamic in Firefox, but it is dynamic in Chrome -added reprex

[HTML + Javascript]

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div>
      <button class="button">click</button>
      <input
        class="input"
        type="range"
        step="0.01"
        min="0"
        max="1.20"
        value="0.60"
      />
    </div>
  </body>
  <script src="script.js" type="text/javascript"></script>
</html>
<script type="text/javascript">
  loopify("example.mp3", function (err, loop) {
    // If something went wrong, `err` is supplied
    document.querySelector(".button").dataset.playing = "false";
    if (err) {
      return console.err(err);
    }

    document.querySelector(".button").addEventListener("click", function () {
      if (this.dataset.playing === "false") {
        loop.play();

        this.dataset.playing = "true";
      } else if (this.dataset.playing === "true") {
        setTimeout(loop.stop, 250);
        this.dataset.playing = "false";
      }
    });
  });
</script>

[Javascript]

(function () {
  function loopify(uri, cb) {
    var context = new (window.AudioContext || window.webkitAudioContext)(),
      request = new XMLHttpRequest();
    const gainNode = context.createGain();

    request.responseType = "arraybuffer";
    request.open("GET", uri, true);

    // XHR failed
    request.onerror = function () {
      cb(new Error("Couldn't load audio from " + uri));
    };

    // XHR complete
    request.onload = function () {
      context.decodeAudioData(request.response, success, function (err) {
        // Audio was bad
        cb(new Error("Couldn't decode audio from " + uri));
      });
    };

    request.send();

    function success(buffer) {
      var source;

      // fade-out
      document.querySelector(".button").onclick = function () {
        if (this.dataset.playing === "true") {
          gainNode.gain.setTargetAtTime(0, context.currentTime, 0.25);
        }
      };
      function play() {
        // Stop if it's already playing
        stop();

        // Create a new source (can't replay an existing source)
        source = context.createBufferSource();
        source.connect(gainNode).connect(context.destination);
        // fade-in
        gainNode.gain.value = 0.1;
        gainNode.gain.setTargetAtTime(
          document.querySelector(".input").value,
          context.currentTime,
          0.25
        );
        //gain input assignment
        document.querySelector(".input").addEventListener(
          "input",
          function () {
            gainNode.gain.value = this.value;
          },
          false
        );

        // Set the buffer
        source.buffer = buffer;
        source.loop = true;

        // Play it

        source.start(0);
      }

      function stop() {
        // Stop and clear if it's playing
        if (source) {
          source.stop();
          source = null;
        }
      }

      cb(null, {
        play: play,
        stop: stop,
      });
    }
  }

  loopify.version = "0.1";

  if (typeof define === "function" && define.amd) {
    define(function () {
      return loopify;
    });
  } else if (typeof module === "object" && module.exports) {
    module.exports = loopify;
  } else {
    this.loopify = loopify;
  }
})();

[CSS]

div {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

经过一些实验并尝试重现您的代码后,我偶然发现了一些奇怪的东西。

每当我们使用 gainNode.gain.setTargetAtTime 时,我们都无法使用 setter gainNode.gain.value 更新增益值。我在 setTargetAtTime or value 的文档中找不到关于为什么会发生这种情况的任何解释。

幸运的是,有一个修复程序没有 破坏 setTargetAtTime 提供的 fade-in。
解决方案在于使用 setValueAtTime 而不是 setter.

设置增益值
const input = document.querySelector(".input");

gainNode.gain.value = 0.1;
gainNode.gain.setTargetAtTime(
  input.value,
  context.currentTime,
  0.25
);

input.addEventListener(
  "input",
  function () {
    gainNode.gain.setValueAtTime(
      this.value,
      context.currentTime
    )
  },
  false
);