淡入和淡出网络音频循环

Fading in and out Web Audio Loop

我正在浏览器中录制一些音频,然后想无缝循环播放,避免在开始时出现点击等问题。这意味着淡出它。

我可以将音量调高和调低一次,但无论如何我都找不到在每次循环再次开始时触发网络音频的 'ramp to value at time'。

有没有简单的方法来做到这一点?我有 10 个这样的缓冲区循环,所以我想尽可能避免大量昂贵的 setinterval 检查...

            let source = audioContext.createBufferSource();
            let gain = audioContext.createGain();
            gain.gain.value = 0.01;

            source.buffer = decodedData;
            songLength = decodedData.duration;

            source.loop = true;
            source.connect(gain);
            gain.connect(audioContext.destination);
            source.start(0);
        
            // fade in and out
            gain.gain.exponentialRampToValueAtTime(0.2, audioContext.currentTime + 1);
            gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + songLength);

考虑收听 ended 事件和 re-trigger 回放:

class FadeInLoop {
  ctx
  audioBuffer
  gainNode
  isPlaying = true

  constructor(ctx, url) {
    this.ctx = ctx
    this.audioBuffer = fetch(url)
      .then(response => response.arrayBuffer())
      .then(arrayBuffer => ctx.decodeAudioData(arrayBuffer))

    this.gainNode = ctx.createGain()
    this.gainNode.connect(ctx.destination)
  }

  async start() {
    this.isPlaying = true
    const source = ctx.createBufferSource()
    this.source = source
    source.addEventListener('ended', e => {
      if (this.isPlaying) { // repeat unless stop() was called
        this.start()
      }
    })

    source.connect(this.gainNode)
    source.buffer = await this.audioBuffer
    const now = this.ctx.currentTime
    this.gainNode.gain.setValueAtTime(Number.EPSILON, now);
    this.gainNode.gain.exponentialRampToValueAtTime(1, now + 0.055)
    source.start(0)
  }

  stop() {
    this.isPlaying = false
    this.source?.stop()
  }
}

const ctx = new AudioContext({ latencyHint: 'interactive' })
const loop = new FadeInLoop(ctx, 'https://batman.dev/static/71474264/loop.mp3')
<button onclick="loop.start()">Start</button>
<button onclick="loop.stop()">Stop</button>