Since I occasionally need some background noise while working or to check audio equipment, and common tools are increasingly leaning towards paid SaaS models, I decided to create a simple noise generator in JavaScript myself. The tool can generate either white or pink noise. Additionally, it features a fully configurable cut-off filter that can also be automated to create sweeps that mimic natural phenomena such as the sound from ocean waves.

Comparison of the frequency spectrum of pink noise (left) and white noise (right) on a linear x-scale

With this setup, it’s possible to generate background noise quite efficiently in terms of CPU usage, making it suitable even for purposes like falling asleep. Since the noise is generated locally there is no need for looping binary samples or loading external assets. (As a nice side effect: The tool will also not interrupt you with ad breaks or other annoyances.)

Implementation of the Voss-McCartney algorithm

For the pink noise, I opted for an implementation of the Voss-McCartney algorithm for 1/f noise, which resolves with an accuracy of +/-0.05 dB. 1

function generatePinkNoise() {
  const bufferSize = 2 * audioContext.sampleRate; // 2 seconds of audio
  const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate);
  const output = noiseBuffer.getChannelData(0);

  // Variables for the Voss-McCartney algorithm (7 random generators)
  let b0, b1, b2, b3, b4, b5, b6;
  b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0;

  for (let i = 0; i < bufferSize; i++) {
      let white = Math.random() * 2 - 1;  // Generate white noise

      // Voss-McCartney Pink Noise Algorithm
      b0 = 0.99886 * b0 + white * 0.0555179;
      b1 = 0.99332 * b1 + white * 0.0750759;
      b2 = 0.96900 * b2 + white * 0.1538520;
      b3 = 0.86650 * b3 + white * 0.3104856;
      b4 = 0.55000 * b4 + white * 0.5329522;
      b5 = -0.7616 * b5 - white * 0.0168980;
      let pink = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
      b6 = white * 0.115926;

      // Normalize the output to ensure it's between -1 and 1
      output[i] = pink * 0.11;
      }

 return noiseBuffer;
 }

I’m aware that more efficient implementations exist, with resolutions around +/-0.5 dB, which would be sufficient for my use case. However, I found that the performance gain on a reasonably modern machine is so minimal that the higher-resolution version of the algorithm can be used without issue.

The tool is a simple webpage, doesn’t load any external resources, and, at under 50 kB for HTML, CSS, and JS combined, is sufficiently lightweight. The visualization of the frequency chart was done using the Web Audio API.2

You can access this tool here:

Direct link: https://scinotes.org/noise/


Footnotes

  1. Source: https://www.firstpr.com.au/dsp/pink-noise/ ↩︎
  2. https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Visualizations_with_Web_Audio_API ↩︎