Skip to main content

WebAudio Oscillators

Live Code Example​

Oscillators Audio Example using WebAudio API only, no WebGPU.

Live Editor

function WebAudioOscillators() {
  const [playing, setPlaying] = useState(false);
  const [oscillator, setOscillator] = useState(null);
  const [freq, setFreq] = useState(440);

  const { volume, frequency, waveForm } = useControls({
    waveForm: {options: ["sine", "triangle", "square", "sawtooth"]},
    frequency: {
      value: 60,
      min: 0,
      max: 100,
      step: 0.0001,
      onChange: (v) => {
        const minIn = 0;
        const maxIn = 100;
        const minOut = Math.log(40);
        const maxOut = Math.log(3000);
        const scale = (maxOut - minOut) / (maxIn - minIn);
        setFreq(Math.exp(minOut + scale * (v - minIn)));
      },
    },
    string: {value: 'Hz', label: freq.toFixed(3), editable: false},
    volume: {
      value: 0.15,
      min: 0.0,
      max: 1.0,
      step: 0.01,
    },
    [playing ? "Stop Sound" : "Play Sound"]: button(() => {
      setPlaying(!playing)
    }, {order: -2})
  }, [playing, freq]);
  
  useEffect(() => {
    if (playing) {
      setOscillator(new WebAudioOscillator()); // see class code below
    } else if (oscillator) {
      oscillator.stop();
      setOscillator(null);
    }
  }, [playing])

  useEffect(() => {
    if (oscillator) {
      oscillator.setVolume(volume);
      oscillator.setFrequency(freq);
      oscillator.setWaveForm(waveForm);
    }
  }, [volume, freq, waveForm, oscillator])
  
  return (
    <Leva fill flat oneLineLabels />
  )
}
Result
Loading...
export default class WebAudioOscillator {
constructor() {
this.audioContext = new AudioContext();
this.oscillator = this.audioContext.createOscillator();
this.gain = this.audioContext.createGain();
this.oscillator.connect(this.gain);
this.gain.gain.value = 0;
this.gain.connect(this.audioContext.destination);
this.oscillator.start();
}

setVolume(volume) {
this.gain.gain.setTargetAtTime(volume, this.audioContext.currentTime, 0.01);
}

setFrequency(frequency) {
this.oscillator.frequency.setTargetAtTime(frequency, this.audioContext.currentTime, 0.01);
}

setWaveForm(waveForm) {
this.oscillator.type = waveForm;
}

stop() {
this.gain.gain.setTargetAtTime(0.0, this.audioContext.currentTime, 0.01);
setTimeout(() => {
this.oscillator.stop();
this.oscillator.disconnect();
this.gain.disconnect();
if (this.audioContext) this.audioContext.close();
if (this.audioContext) this.audioContext = undefined;
}, 100);
}
}