Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

118
Views
Fading in and out Web Audio Loop

I'm recording some audio in the browser and then want to loop it seamlessly, avoiding clicks etc when starting. This means fading it and out.

I can ramp the volume up and down once, but I can't find anyway to trigger Web Audio's 'ramp to value at time' every time the loop starts again.

Is there an easy way to do this? I've got 10 of these buffers looping so I'd like to avoid lots of costly setinterval checks if possible...

            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);
about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

Consider listening to the ended event and re-trigger the playback:

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>

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!