How to Use Tone.js Analyser for Audio Visualization

This article provides a comprehensive guide on using Tone.Analyser in Tone.js to extract real-time frequency data for audio visualizers. You will learn what the Analyser node is, how to configure it within your audio graph, and how to retrieve and format frequency data to create dynamic, real-time visual displays.

What is Tone.Analyser?

Tone.Analyser is a node in the Tone.js framework that acts as a bridge to the Web Audio API’s native AnalyserNode. It allows you to analyze the audio signal passing through it in real-time without altering the sound output.

The analyser can extract two main types of data: * FFT (Fast Fourier Transform): Splits the audio signal into its individual frequency components (bass, mids, treble). This is ideal for creating frequency bar visualizers. * Waveform: Captures the amplitude of the audio signal over time. This is ideal for creating oscilloscope-style visualizers.

Setting Up Tone.Analyser

To analyze audio, you must route your audio source through the Tone.Analyser node before sending it to the speakers (Tone.Destination).

Here is how to initialize and connect an analyser:

// Create an analyser of type "fft" with a buffer size of 256
const analyser = new Tone.Analyser("fft", 256);

// Create a sound source (e.g., a synth)
const synth = new Tone.Synth().toDestination();

// Connect the synth to the analyser
synth.connect(analyser);

Key Parameters:

  1. Type: Can be "fft" or "waveform". To retrieve frequency data, use "fft".
  2. Size: The FFT size must be a power of two (e.g., 32, 64, 128, 256, 512, 1024). It determines the frequency resolution. A higher number provides more detailed frequency bins but requires more processing power.

Retrieving Frequency Data

To get the frequency data at any given moment, call the .getValue() method on the analyser. This returns a Float32Array containing decibel values for each frequency bin. The values typically range from -140 dB (silence) to 0 dB (maximum volume).

const frequencyData = analyser.getValue();
console.log(frequencyData); 
// Output: Float32Array representing amplitude levels at different frequencies

Creating a Real-Time Visualizer Loop

To build a continuous visualization, you must query the frequency data repeatedly using a render loop. The standard web API for this is requestAnimationFrame.

Below is a complete implementation showing how to fetch frequency data and map it to a visual display, such as an HTML5 Canvas:

const canvas = document.getElementById("visualizer");
const ctx = canvas.getContext("2d");

function draw() {
  // Schedule the next update
  requestAnimationFrame(draw);

  // Retrieve the current frequency data array
  const data = analyser.getValue();

  // Clear the canvas for the new frame
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const barWidth = canvas.width / data.length;

  for (let i = 0; i < data.length; i++) {
    // Convert dB value to a positive height scale
    // e.g., mapping -140dB to 0dB into a height value
    const dbValue = data[i];
    const normalizedValue = Math.max(0, dbValue + 140); 
    const barHeight = (normalizedValue / 140) * canvas.height;

    const x = i * barWidth;
    const y = canvas.height - barHeight;

    // Draw the frequency bar
    ctx.fillStyle = `rgb(${barHeight + 100}, 50, 250)`;
    ctx.fillRect(x, y, barWidth - 1, barHeight);
  }
}

// Start the loop
draw();

By connecting any active Tone.js instrument or player to the analyser, the Float32Array values will dynamically change with the music, providing the exact data needed to power your custom visualizers.