Files
skills/docs/media/audio/audio-analysis-spectrum/src/algorithms/mel-scale.md
2026-05-29 08:20:56 +01:00

2.2 KiB

mel-scale — hertz↔mel mapping and triangular filterbank

Purpose

The mel-scale module provides the perceptual frequency warp used by MFCC and any caller that wants a psychoacoustically motivated reduction of an FFT magnitude spectrum. It exposes the Slaney/HTK closed-form hzToMel and its inverse melToHz, plus a builder that produces a triangular filterbank for a given (frameSize, sampleRate, melBands, minHz, maxHz) tuple.

Each filterbank is cached so repeated frames pay zero filter-construction cost; applying a filterbank to a magnitude spectrum is then a single dense matrix-vector multiply.

Features

  • Closed-form hertz↔mel mapping that round-trips to machine precision.
  • Triangular filterbank with melBands bands evenly spaced on the mel scale.
  • Per-spec caching keyed by (frameSize, sampleRate, melBands, minHz, maxHz).
  • Boundary validation that melBands is a positive integer.

Usage: Basic

import {
  applyMelFilterbank,
  buildMelFilterbank,
} from "@suaveplan/audio-analysis-spectrum/algorithms/mel-scale";

const fb = buildMelFilterbank({
  frameSize: 2048,
  sampleRate: 48_000,
  melBands: 40,
  minHz: 0,
  maxHz: 24_000,
});
const mel = applyMelFilterbank(spectrum, fb);

Usage: Advanced

import {
  clearMelFilterbankCache,
  hzToMel,
  melToHz,
} from "@suaveplan/audio-analysis-spectrum/algorithms/mel-scale";

const m = hzToMel(1000);
const back = melToHz(m); // ≈ 1000 within 1e-3

clearMelFilterbankCache(); // before a benchmark sweep

API Reference

  • hzToMel(hz): number / melToHz(mel): number — Slaney/HTK closed forms.
  • buildMelFilterbank(spec): MelFilterbank — cached triangular filterbank.
  • applyMelFilterbank(spectrum, bank): Float32Array — dense mel-band vector.
  • clearMelFilterbankCache(): void — drop every cached filterbank.

Implementation Notes

The builder allocates melBands + 2 mel-spaced points so each band has both a lower and an upper neighbour centre. Bin frequencies are computed once as (i * sampleRate) / frameSize to avoid a per-band recomputation. Each band's weights peak at 1 and taper linearly to 0 at the neighbour centres; no per-band energy normalisation is applied because the downstream MFCC log+DCT step is insensitive to global scaling.