HTML5 暂停后再播放后声音变大

HTML5 Audio gets louder after pausing then playing again

我正在用 JavaScript 制作一个音频播放器,在我添加声音可视化器之前一切正常。当我暂停歌曲然后再次播放时,每次播放时声音都会变得更大声,直到失真。

我是 HTML5 音频 API 的新手,我尝试将音量设置为固定值,但不起作用。

可视化工具的代码是:

function visualizer(audio) {
    let context = new AudioContext();

    const gainNode = context.createGain();
    gainNode.gain.value = 1; // setting it to 100%
    gainNode.connect(context.destination);

    let src = context.createMediaElementSource(audio);
    let analyser = context.createAnalyser();

    let canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    let ctx = canvas.getContext("2d");

    src.connect(analyser);
    analyser.connect(context.destination);

    analyser.fftSize = 2048;

    let bufferLength = analyser.frequencyBinCount;

    let dataArray = new Uint8Array(bufferLength);

    let WIDTH = ctx.canvas.width;
    let HEIGHT = ctx.canvas.height;

    let barWidth = (WIDTH / bufferLength) * 1.5;
    let barHeight;
    let x = 0;

    let color = randomColor();

    function renderFrame() {
      requestAnimationFrame(renderFrame);
      x = 0;
      analyser.getByteFrequencyData(dataArray);
      ctx.clearRect(0, 0, WIDTH, HEIGHT);

      for (let i = 0; i < bufferLength; i++) {
        barHeight = dataArray[i];

        ctx.fillStyle = color;
        ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
        x += barWidth + 1;

      }
    }

    musicPlay();
    renderFrame();
  }

并且:

  function musicPlay() {
    status = 'playing';
    audio.play();
  }

所以,我不知道我是否在音频分析器上做错了什么,我尝试创建一个全局上下文并且每次输入时都不会执行 new AudioContext();函数,我也尝试指定一个固定的音量:

audio.volume = 1; 

或如您在函数中看到的 GainNode,但它不起作用。

我的错误在哪里,为什么声音变大了?

此致!

--- 更新 1 ---

从 URL:

加载的音频
function loadAudioElement(url) {
    return new Promise(function (resolve, reject) {
      let audio = new Audio();
      audio.addEventListener('canplay', function () {
        /* Resolve the promise, passing through the element. */
        resolve(audio);
      });
      /* Reject the promise on an error. */
      audio.addEventListener('error', reject);
      audio.src = url;
    });
  }

我的播放器上有:

let playButtonFunction = function () {
      if (playstatus === 'pause') {
        loadAudioElement(audio.src).then(
          visualizer(audio)
        );
      } else if (playstatus === 'playing') {
        musicPause();
      }
    };

好吧,正如 Get Off My Lawn 指出的那样,我错误地添加了多个音频元素。

解决方案是在 playButtonFunction 之外使用加载歌曲的代码,并且只执行:

let playButtonFunction = function () {
      if (playstatus === 'pause') {
        musicPlay();
      } else if (playstatus === 'playing') {
        musicPause();
      }
    };

但是我还有一个问题,就是 next/previous 函数。在这些情况下,我需要调用 loadAudioElement 函数,因为歌曲正在改变(当您按 play/pause 时,不,这是同一首歌)但是我又遇到了同样的问题。

好吧,经过一番挖掘,我发现如果您想一直播放播放列表并可视化音乐,您必须在加载新歌曲之前释放旧上下文。不仅避免歌曲音量增加,cpu 和内存也会在 3 - 4 首歌曲后增加,浏览器将开始慢慢 运行 取决于机器。所以:

1 - 我创建了一个名为 clearContextAudio = false;

的全局变量

2 - 在我的 next/previous 函数中,我添加了以下代码:

if (closeAudioContext) { //MANDATORY RELEASE THE PREVIOUS RESOURCES TO AVOID OBJECT OVERLAPPING AND CPU-MEMORY USE
      context.close();
      context = new AudioContext();
}
loadAudioElement(audio.src).then(
   visualizer(audio)
);

3 - 在我的 visualizer(audio) 函数上,我更改了:

let context = new AudioContext();

closeAudioContext = true; //MANDATORY RELEASE THE PREVIOUS RESOURCES TO AVOID OBJECT OVERLAPPING AND CPU-MEMORY USE

这个值被初始化为false,因为第一次没有播放歌曲,播放完歌曲后总是需要释放旧的资源,所以这个变量会一直设置为true。现在,你可以跳过所有你想要的歌曲,而不用担心内存和重叠问题。

希望这可以帮助其他人尝试实现同样的目标!此致!

我遇到了类似的问题,您是否尝试将音频上下文设置为全局对象?

这是我在这里找到的:

https://developer.mozilla.org/en-US/docs/Web/API/AudioContext

建议创建一个AudioContext并重复使用,而不是每次都初始化一个新的

AudioContext 接口表示一个 audio-processing 图形,该图形由链接在一起的音频模块构建而成,每个模块由一个 AudioNode 表示。

音频上下文控制其包含的节点的创建以及音频处理或解码的执行。您需要在执行任何其他操作之前创建一个 AudioContext,因为一切都发生在上下文中。 建议创建一个 AudioContext 并重复使用它,而不是每次都初始化一个新的,并且可以同时为多个不同的音频源和管道使用一个 AudioContext。