Skip to content

Spectrogram

Sonoscope provides an easy way to visualize audio using fast, flexible spectrograms.

When connected to navigation, dragging directly on the spectrogram pans across time and frequency, while scrolling or pinching zooms into harmonic detail.

Spectrograms attach to standard HTML <canvas> elements. Calling createSpectrogram without options initializes a GPU-accelerated spectrogram with auto-resizing:

import { Sonoscope } from "@sonoscope/core";
const scope = await Sonoscope.fromUrl("/audio/sample.wav");
// Create a spectrogram using default options
const spectrogram = scope.createSpectrogram(spectrogramCanvas);
// Synchronize drag and zoom interactions across time and frequency
scope.attachNavigation(spectrogramCanvas);

Renders with standard linear frequency scaling and the Viridis colormap:

scope.createSpectrogram(spectrogramCanvas);

Applies the Inferno palette with adjusted decibel floors for enhanced contrast:

scope.createSpectrogram(spectrogramCanvas, {
colorMap: "inferno",
minDb: -80,
maxDb: 0,
});

Compresses higher frequencies to match human pitch perception:

scope.createSpectrogram(spectrogramCanvas, {
frequencyScale: "mel",
});

Distributes octaves equally along the vertical frequency axis:

scope.createSpectrogram(spectrogramCanvas, {
frequencyScale: "log",
});

Uses a smaller window and hop size to emphasize rapid transient events:

scope.createSpectrogram(spectrogramCanvas, {
windowSize: 512,
hopSize: 128,
});

Raises the noise floor to suppress quiet background and expose mid-level detail:

scope.createSpectrogram(spectrogramCanvas, {
minDb: -60,
maxDb: -10,
});

Applies the perceptually uniform Plasma palette:

scope.createSpectrogram(spectrogramCanvas, {
colorMap: "plasma",
minDb: -85,
maxDb: 0,
});

For stylized shader programs and alternative renderers (Halftone, 3D Terrain, Topographic, ASCII), see the Plugins section.


Options accepted by scope.createSpectrogram(canvas, options). Full reference: SpectrogramConfig.

OptionTypeDefaultDescription
autoRenderoptbooleantrueWhether to automatically re-render when viewport or configuration changes.
showLoadingPlaceholdersoptboolean-Whether to draw loading placeholders over tiles that are still computing.
rendereroptRendererMode"auto"Rendering engine: - "auto": Uses WebGL2 if supported, falling back to Canvas 2D. - "webgl" / "webgl2": Hardware-accelerated GPU shader renderer. - "canvas2d": CPU Canvas 2D fallback renderer. - Custom object with shader program (`{ type: "webgl", program: "normal" | "halftone" | "terrain" }`).
backendoptBackendMode"auto"STFT compute execution backend: - "auto": Prefers WebAssembly workers, falling back to main thread. - "wasm": Fast WebAssembly computation. - "worker": Web Worker background thread computation. - "main-thread": Synchronous main thread computation.
channeloptnumber0Audio channel index to analyze (0 for left/mono, 1 for right).
windowSizeoptnumber1024STFT analysis window length in audio samples.
fftSizeoptnumber1024FFT length in samples. Must be a power of two >= windowSize. Spectral magnitudes contain the first `fftSize / 2` bins, normalized by `fftSize`, without one-sided or window coherent-gain compensation.
hopSizeoptnumber256Hop size (step length) in samples between consecutive FFT frames.
windowoptWindowName"hann"Window function applied before FFT: "hann", "hamming", "blackman", or "rectangular".
frequencyScaleoptFrequencyScale"linear"Frequency scale mapping: "linear", "mel", or "log".
valueModeoptValueMode"db"Intensity scale representation: "db" (decibels), "magnitude", or "power". dB values use `20 * log10(max(magnitude, 1e-12))`.
minDboptnumber-100Lower intensity limit mapped to the start of the colormap (always specified in dB; converted internally for non-dB value modes).
maxDboptnumber0Upper intensity limit mapped to the end of the colormap (in dB when valueMode is "db").
valueGammaoptnumber1.0Power-law gamma exponent for dynamic range contrast adjustment.
clampValuesoptbooleantrueWhether to clamp intensity values strictly within [minDb, maxDb].
tileMaxCellsoptnumber131_072Maximum 2D STFT matrix cells (frameCount * binCount) budgeted per computation tile.
maxCachedTilesoptnumber64Maximum number of computed STFT tiles retained in memory cache.
maxCachedBytesoptnumber-Maximum estimated bytes retained by the computed tile cache.
prefetchTilesoptnumber8Number of tiles to prefetch and compute ahead of the visible viewport.
autoResizeoptbooleantrueWhether to automatically resize canvas pixel resolution when container dimensions change.
devicePixelRatiooptboolean | numberwindow.devicePixelRatioDevice pixel ratio scaling factor for HiDPI/Retina displays.
colorMapoptColorMapConfig"viridis"Colormap palette name (such as "inferno", "viridis", "magma", "turbo") or custom palette object.
transformsoptSpectrogramTransform[]undefinedArray of custom matrix transforms applied to STFT data before rendering.

Use scope.attachNavigation(canvas, options) to link panning and zooming across spectrograms, waveforms, and rulers:

  • 2D navigation: By default, spectrogram navigation tracks both horizontal time and vertical frequency axes.
  • Axis constraints: Pass { axis: 'time' } or { axis: 'frequency' } to restrict navigation to a single dimension.
  • Drag & scroll: Dragging pans the visible window; scrolling or pinching zooms into the frequency band or time interval under the cursor.
  • Synchronized views: Navigating on any attached canvas immediately updates all connected spectrograms, waveforms, and rulers.

Play around with the code in the live sandbox below:

  • Drag the spectrogram to pan across time and frequency.
  • Scroll / Pinch over the canvas to zoom in and out.
  • Edit the options in index.ts to test different colormaps, frequency scales, STFT resolutions, or shader programs live.