Search code examples
javascripthtmldomaudioweb-audio-api

Play button works only once in Web Audio API, how to make it work multiple times?


i am working with web audio api and i got this probllem

Description:

I'm working on a simple web page that uses the Web Audio API to generate sound with a frequency slider and play/stop buttons. The issue I'm facing is that the "Play" button (#playButton) works only once. After the first play, subsequent clicks on the "Play" button do not produce any sound.

Here is a simplified version of my code:

<!DOCTYPE html>
<html lang="en">
<head>
  <!-- Meta tags -->
  <title>Frequency Slider</title>
  <!-- CSS styles -->
</head>
<body>
  <label for="frequencySlider">Frequency:</label>
  <input type="range" id="frequencySlider" min="20" max="2000" step="1" value="440">
  <span id="frequencyDisplay">440 Hz</span>
  <button id="playButton">Play</button>
  <button id="stopButton">Stop</button>
  <!-- Canvas for waveform visualization -->
  <script>
    // Web Audio API setup
    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
    let frequencyValue = 440;
    let waveform = "sawtooth";

    const osc = audioContext.createOscillator();
    osc.type = waveform;
    osc.frequency.value = frequencyValue;

    const analyser = audioContext.createAnalyser();
    analyser.fftSize = 2048;
    const dataArray = new Uint8Array(analyser.fftSize);

    // DOM elements
    const frequencySlider = document.getElementById('frequencySlider');
    const frequencyDisplay = document.getElementById('frequencyDisplay');
    const playButton = document.getElementById('playButton');
    const stopButton = document.getElementById('stopButton');

    const canvasContext = waveformCanvas.getContext('2d'); // Assuming you have a canvas, if not, you can omit this

    // Event listeners
    frequencySlider.addEventListener('input', updateFrequency);
    playButton.addEventListener('click', playSound);
    stopButton.addEventListener('click', stopSound);

    // Functions
    function updateFrequency() {
      frequencyValue = parseInt(frequencySlider.value);
      osc.frequency.value = frequencyValue;
      frequencyDisplay.textContent = frequencyValue + ' Hz';
    }

    function playSound() {
      osc.connect(analyser);
      analyser.connect(audioContext.destination);
      osc.start(audioContext.currentTime);
      requestAnimationFrame(drawWaveform);
    }

    function stopSound() {
      osc.stop(audioContext.currentTime);
      osc.disconnect(analyser);
      analyser.disconnect(audioContext.destination);
      canvasContext.clearRect(0, 0, waveformCanvas.width, waveformCanvas.height); // Assuming you have a canvas, if not, you can omit this
    }

    // Assuming you have a drawWaveform function, if not, you can omit this
    function drawWaveform() {
      analyser.getByteTimeDomainData(dataArray);
      // Drawing logic for the waveform visualization
      // ...
      requestAnimationFrame(drawWaveform);
    }
  </script>
</body>
</html>

I've noticed that after clicking the "Play" button once, subsequent clicks don't produce any sound. I suspect there might be an issue with how I'm handling the Web Audio API or the oscillator. Could someone please help me figure out why the "Play" button works only once and how to make it work multiple times?

Thank you in advance for your assistance!


Solution

  • You can only call start on an oscillator once. See https://www.w3.org/TR/webaudio/#AudioScheduledSourceNode-methods. There should be console error messages about that when you press "play" a second time.

    What you need to do is create a new oscillator each time you press play. When you stop the oscillator, be sure to drop any references to it so it can be collected. You shouldn't need to disconnect it from the analyser; that should happen automatically when the oscillator is collected.