Lasse Munk
Lasse Munk

Reputation: 23

Web Audio API Best Practice, simple synth, system optimisation / garbage collection

Im coming from max/msp and trying to figure out the best practices of programming web audio in terms of optimising my code / getting better performance.

I'm reading about the fact that one cannot call .start(), then .stop() then .start() on an oscillator for optimisation reasons. I would like to know what the best design pattern is if I would like to make a simple 1 oscillator synth class.

I would like to instantiate the synth before I need to play it. This way I imagine I get the best timing, if I would like to play the synth at a later time, so the system don't have to create the oscillator / synth pattern, every time I hit 'play note'.

But it would be great to not use processing power on oscillators I don't hear because e.g. the amplitude envelope is not open.

Here is a simple synth, without amplitude envelope. How could I make a similar pattern, where I only use processing power when the synth is actually playing?

Best, Lasse

<!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>How to optimize CPU usage</title>
</head>
<body>

  <a href="#" id="playButton">Play Note</a> <br><br>
  <a href="#" id="stopButton">Stop Note</a>

  <script>
    class Synth {
      constructor () {
        this.context = new AudioContext();
        this.osc = this.context.createOscillator();
        this.osc.connect(this.context.destination);
      }

      play(freq) {
        this.osc.frequency.value = freq;
        this.osc.start(0);
      }

      stop() {
        this.osc.stop(0);
      }
    }

    let synth = new Synth();

    const playButton = document.getElementById('playButton')
      .addEventListener('click', () => {synth.play(440)});
    
      const stopButton = document.getElementById('stopButton')
      .addEventListener('click', () => {synth.stop()}); 
  </script>
</body>
</html>

Upvotes: 2

Views: 328

Answers (1)

Raphael Serota
Raphael Serota

Reputation: 2197

I think this is a little closer to what you want:

let context = new AudioContext();

class Synth {
  constructor () {}

  play(freq) {
    this.osc = context.createOscillator();
    this.osc.connect(context.destination);
    this.osc.frequency.value = freq;
    this.osc.start(0);
  }

  stop() {
    this.osc.stop(0);
  }
}

First of all, you only need one audioContext. You shouldn't be creating a new one each time the oscillator plays. As far as your concerns about the performance, I wouldn't worry too hard about that. Oscillators are designed to be cheap and disposable. It's fine to create them on the fly, and forget about them after they play once.

Upvotes: 1

Related Questions