logo

Sue Feng Design

‹ Back to blog

JavaScript AudioContext, OscillatorNode, GainNode troubleshooting

Recently I made a piano using JavaScript. There's a lot of resources I used in order to make it, and a lot of trial and error went into it as well. I want to put together a list of those issues I ran into, as well as the solutions I went with. Perhaps this may help others as well, who may run into some of those issues when making their own app that uses the AudioContext, OscillatorNode, and GainNode to generate sounds. I'll also keep this post updated whenever I continue working on my piano app.

Contents

The audio quality degrades over time

When playing notes over a period of time, if you notice the sound quality degrading—such as sounding more static-y and muffled—then check where the AudioContext is declared.

I learned that you only need one AudioContext for all the oscillators and gains. Creating new ones each time makes the audio quality degrade over time, and is a lot less efficient. That helped with the sound creation being more consistent.

There's a clicking noise after an oscillator stops

When an oscillator stops, it makes a clicking noise if it's in the middle of the wave, and hasn't completed one cycle.

I learned that using a exponentialRampToValueAtTime or linearRampToValueAtTime to gradually turn down the volume and then stop the oscillator helps, but isn't perfect. I ended up going with linearRampToValueAtTime since it's more gradual. This is still a learning process, so I'll probably tweak it as I learn more.

There's no sound at the lower frequencies

When the frequency is super low, for octaves 0-1 for example, it may be hard to hear the sound. Try changing the oscillator type and see if it helps. For me, changing from sine to triangle helped make those frequencies more audible.

The sound is too ear-piercingly loud at higher frequencies

When the frequency is super high, for octaves 6-8 for example, it may help to decrease the gain value. For example, having something similar to this may help:

const volume =
  frequency < 130
    ? 2
    : frequency < 261
      ? 1
      : frequency < 500
        ? 0.4
        : frequency < 1000
          ? 0.2
          : frequency < 2000
            ? 0.07
            : 0.04;

// whatever you have your gain node defined as
gainNode.value = volume;

Example snippet:

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
const note = keyElement.getAttribute('data-note');
const octave = keyElement.getAttribute('data-octave');

oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
gainNode.gain.value = volume;
oscillator.frequency.value = frequency;
oscillator.type = 'triangle';
oscillator.start(0);

iPhone after using headphones, audio no longer works

The audio was working fine without headphones plugged in, then after using headphones, it no longer works when headphones are unplugged. If this happens to you, try playing a silent audio file to unmute when headphones are not in.

This is a hacky way to get the JavaScript generated audio to play again, but as of now, I don't know of a better solution. If anyone has any ideas, please feel free to let me know.

Sources

More info as well as resources can be found in the Github repo.

Posted on: October 14, 2023Categories: codingTags: AudioContext, OscillatorNode, GainNode, troubleshooting
‹ Back to blog