← All tutorials

MFCC and Other Audio Features

From a spectrogram to model inputs.

On this page

1 The mel scale 2 The mel filterbank 3 Why the log 4 Why the DCT 5 Deltas and normalization 6 Other features 7 Which feature when 8 In practice 9 When features go wrong 10 References

A speech model rarely reads raw samples or a full spectrogram. Feature extraction turns each short STFT frame, one every 10 ms or so, into a few dozen numbers that keep the smooth outline of the spectrum (its envelope), which tells sounds apart, and drop most of the pitch. The usual chain is a power spectrum, a mel filterbank that bends frequency the way ears hear, and a log, which gives the log-mel features; for MFCCs (mel-frequency cepstral coefficients) a cosine transform then orders the result from broad shape to fine detail.

frames(STFT)powerspectrummelfilterbanklogDCTkeep thefirst 13deltasmodels uselog-mel
Figure 1. The MFCC chain, 1 to 7. Most neural models stop at log-mel, after 4.

1 The mel scale

Ears hear pitch in roughly equal steps of ratio, not of hertz; 100 to 200 Hz sounds like a big jump, 7,100 to 7,200 Hz like almost none. The mel scale bends frequency so that equal mel steps sound like equal pitch steps.

Frequency in hertz to mels (the HTK formula).
m = 2595 log10(1 + f700)
f in Hz in, m in mels out; 2595 and 700 are the formula’s fixed constants (O’Shaughnessy 1987).
Well below 700 Hz it is nearly a straight line, well above it it grows like a log, so high frequencies get squeezed together.
The scale is pinned so a 1 kHz tone is 1000 mels (f = 1000 gives m ≈ 1000), the reference point of Stevens et al. (1937). Section 2 lays its triangles evenly on this scale.

Slaney’s version of the scale, from his Auditory Toolbox and the default in librosa unless you pass htk=True, is a straight line below 1 kHz. Its units differ, 15 at 1 kHz instead of 1000, so Figure 2 scales it up to meet the HTK curve there and compares the shapes.

02k4k6k8 kHz0100020003000frequency fmelHTK formulaSlaney, rescaled
Figure 2. HTK and Slaney mels, Slaney rescaled to meet at 1 kHz. 1Slaney is straight below it.

2 The mel filterbank

Lay triangles evenly along the mel axis, so they come out narrow at low frequencies and wide at high ones, and let each one sum the power under it.

02k4k6k8 kHzmel trianglesspectrum
Figure 3. 1A vowel-like spectrum. 2Ten triangles evenly spaced in mel; the tools use 40.
The energy in mel band ℓ.
Eℓ = Σk Fℓ[k] · |X[k]|²
|X[k]|² is the power in FFT bin k of one frame (Fourier Transform and the FFT).
Fℓ[k] is triangle ℓ’s weight on bin k, zero outside the triangle.
Eℓ is band ℓ’s energy, ℓ running over the Nmel bands (40 in the tools).

3 Why the log

Loudness is heard roughly on a log scale, and a louder voice or another microphone multiplies the spectrum, as any filter does (How FIR and IIR Filters Shape Magnitude and Phase).

before the logband ℓ (low to high)after the log (dB)band ℓ (low to high)loud4 times quieter
Figure 4. A frame (solid), 4 times quieter (dashed). 1Sizes differ. 2One shape, shifted.
A gain on the spectrum becomes an offset.
log(gEℓ) = log g + log Eℓ
g is a gain on the whole spectrum (louder voice, different microphone). After the log it adds the same constant to every band. It builds on the band energies of Section 2; the DCT of Section 4 works on these logs, and Section 5 removes the offset.

4 Why the DCT

Neighboring mel bands rise and fall together. The DCT (discrete cosine transform) rewrites the 40 log energies as amounts of cosines across the bands, ordered from slow to fast change; like principal component analysis (PCA) it packs correlated numbers into a few that matter most. Applied to the log spectrum it gives a spectrum of a spectrum, hence the name cepstrum (Fourier Transform and the FFT). Davis and Mermelstein (1980) found these coefficients the best of the representations they compared for word recognition.

The cepstrum splits a spectrum into its slow shape, the envelope, and its fine detail; that split is also one way to remove a room’s echo (Anushiravani 2016; Reverberation and Dereverberation, section 8).

Forty bands at one level give only the first coefficient, c0, the overall level; a straight tilt from 3 down to 1 across them puts almost everything else into the second, c1, one slow tilt.

MFCC number q of one frame.
cq = Σℓ log Eℓ · bq[ℓ]
cq is coefficient q, how much the log band energies look like cosine number q across the bands. q = 0 is the overall level, small q slow changes across frequency (the envelope), large q fast ones (the pitch ripple).
bq[ℓ] = cos( π q ( ℓ + ½ )Nmel )
Cosine number q sampled at band ℓ. librosa uses this DCT-II with orthonormal scaling (norm='ortho') on dB values, which only rescales each cq. It builds on the log energies of Section 3, and Section 5 tracks how these coefficients change.

The cards of Sections 2 to 4, one step at a time on one frame.
Eℓ = Σk Fℓ[k] · |X[k]|²
The band energy card of Section 2.
log(gEℓ) = log g + log Eℓ
The log card of Section 3.
cq = Σℓ log Eℓ · bq[ℓ]
The DCT card of Section 4; Section 5 adds deltas to the result.

Figure 5. A vowel-like frame. 1Mel bands. 2Log band energies. 3DCT coefficients.

The test sound is synthetic, harmonics under an envelope peaking near 700, 1,200 and 2,600 Hz over a breath-noise floor 20 dB down. The lowest of the 40 bands are about 45 Hz apart, so the harmonics of a 220 Hz voice show as ripple there. In Figure 6 a few coefficients rebuild only the envelope; many bring the pitch ripple back.

13

Figure 6. Green, 40 log band energies; red, rebuilt from the first coefficients.

5 Deltas and normalization

One frame is a snapshot. Deltas add how each coefficient is changing, and cepstral mean normalization removes what never changes. A coefficient that rises by 0.5 every frame, as at a vowel onset, has a delta of 0.5.

Deltas and mean normalization for one coefficient at frame t.
Δct = Σ i(ct+i − ct−i)60
For one coefficient, ct at frame t, the slope of a straight line fitted to the 9 frames t − 4 to t + 4; i runs from 1 to 4, and 60 is 2(1 + 4 + 9 + 16). librosa computes the same slope with a Savitzky-Golay filter, a sliding least-squares polynomial fit, of width 9.
c̃t = ct − meant ct
Subtracting each coefficient’s average over the clip removes a fixed microphone color, the constant log g from Section 3.

6 Other features

Simpler numbers each pick out one property of a frame. A 1 kHz tone sampled at 16 kHz changes sign at 0.125 of its neighboring sample pairs, white noise at about half.

Six simpler features of one frame of N samples x[n], whose spectrum X[k] has bin k at frequency fk.
RMS = √1N Σn x[n]²
The root mean square of the samples, a measure of loudness, used for voice activity and levels.
ZCR = mean 1[x[n] x[n−1] < 0]
The zero-crossing rate, the share of neighboring sample pairs that change sign; x[n] is sample n, 1[·] is 1 when the condition holds, else 0, and the mean runs over the N − 1 neighbor pairs. It is high for hiss like “s”, so it separates voiced from unvoiced sounds.
centroid = Σk fk |X[k]|Σk |X[k]|
The center of mass of the magnitude spectrum, which reads as brightness.
Σk≤r |X[k]| = 0.85 Σ|X[k]|
The roll-off is fr, the frequency of bin r, below which 85% of the magnitude sits (librosa’s default), high for bright sounds and low for dull ones.
flatness = emean log Pmean P
The geometric mean (e to the mean log) over the arithmetic mean of the power P = |X[k]|², both means taken over the bins. It is near 0 for a tone and high for noise, about 0.56 for one frame of white noise and near 1 only after averaging (Power Spectral Density).
chromap = Σk→p |X[k]|²
The energy folded into the 12 pitch classes p = C to B, adding every bin whose frequency rounds to that note in any octave; used for key and chords.

Figure 7. 1Zero crossings, 2centroid, 3roll-off, 4chroma, telling the sounds apart.

One librosa call per feature on one second of noise; each returns shape (1, frames), except chroma’s 12 rows.

import numpy as np
import librosa

SR = 16000
y = np.random.default_rng(0).standard_normal(SR)
feature = librosa.feature
rms = feature.rms(y=y)
zcr = feature.zero_crossing_rate(y)
centroid = feature.spectral_centroid(y=y, sr=SR)
rolloff = feature.spectral_rolloff(y=y, sr=SR, roll_percent=0.85)
flatness = feature.spectral_flatness(y=y)
chroma = feature.chroma_stft(y=y, sr=SR)     # (12, frames)
  1. 1One second of white noise at 16 kHz; feature is short for librosa.feature.
  2. 2RMS energy, line 1 of the eq card in Section 6.
  3. 3Zero-crossing rate, line 2.
  4. 4Spectral centroid, line 3.
  5. 5Roll-off at 85%, line 4.
  6. 6Flatness, line 5.
  7. 7Chroma, line 6; 12 rows, one per note.

7 Which feature when

TaskUsual input
Speech recognition with a networkLog-mel, stopping after the log so the network learns the rest
Older speech recognitionMFCC with deltas
Speaker identityMFCC with mean normalization; a Gaussian mixture can model the cloud of MFCC frames

The Conformer (Gulati et al. 2020, Conformer) reads 80-channel log-mel frames from 25 ms windows every 10 ms, trained with SpecAugment, which blanks out random blocks of bands and of time steps. The CTC speech experiments of Graves et al. (2006, CTC Loss) used 12 MFCCs plus log energy and their first derivatives, 26 numbers per frame.

8 In practice

StepHow often, on what dataState it keepsCost
Mel filterbankbuilt once at design time, on sample rate and band countnoneone-off
Log mel and MFCConce per frame, on that frame’s power spectrumnoneone filterbank product, a log and a DCT
Deltasonce per frame, on neighboring frames (librosa uses 9)the neighbor framesa few adds per coefficient
Mean normalizationonce per recording, or a running mean when streaming, on all framesone mean per coefficientone mean per coefficient

Rates, state and cost come from the sources in References.

MFCCs with deltas and mean normalization in librosa, on one second of noise.

import numpy as np
import librosa

SR, N_FFT, HOP, N_MELS, N_MFCC = 16000, 400, 160, 40, 13
y = np.random.default_rng(0).standard_normal(SR)
S = np.abs(librosa.stft(y, n_fft=N_FFT, hop_length=HOP))**2
fb = librosa.filters.mel(sr=SR, n_fft=N_FFT, n_mels=N_MELS, htk=True)
mel = fb @ S
log_mel = librosa.power_to_db(mel)
mfcc = librosa.feature.mfcc(S=log_mel, n_mfcc=N_MFCC)
delta = librosa.feature.delta(mfcc)
mfcc_cmn = mfcc - mfcc.mean(axis=1, keepdims=True)
  1. 1The settings and one second of white noise.
  2. 2Power spectrum of each frame, marker 2 in Figure 1.
  3. 340 HTK mel triangles (eq card in Section 2).
  4. 4Band energies Eℓ, triangles times power.
  5. 5Log band energies in dB (eq card in Section 3).
  6. 6The DCT, first 13 coefficients (eq card in Section 4).
  7. 7Deltas over 9 frames (eq card in Section 5, line 1).
  8. 8Mean normalization (eq card in Section 5, line 2).
SettingDefaultSource
Kaldi MFCCpre-emphasis 0.97, each sample minus 0.97 times the one before, which lifts the high frequenciestorchaudio.compliance.kaldi.mfcc
librosa MFCC20 coefficients at 22,050 Hz, DCT type 2librosa.feature.mfcc

Pre-emphasis is one more fixed filter in the chain after the room and the microphone, and the order of such filters does not change the result (LTI Systems and Convolution).

Knob, where it entersRaise itLower itDefault
Mel bands Nmel, the sum over ℓ in the band cardFiner frequency detail; each band is narrower and noisierCoarser bands that blur nearby formants; one band is just the frame’s energy23 (torchaudio kaldi.mfcc); 40 in the tools here
Number of MFCCs, how many q are keptKeeps faster ripple across bands, up to the pitch harmonics; all Nmel give back the log band energiesOnly the envelope; one coefficient is just the level c013 (torchaudio kaldi.mfcc); 20 in librosa.feature.mfcc
Window length, the samples in each frameFiner frequency detail, blurrier timing; one window over the whole clip gives a single frameSharper timing, coarser frequency detail; a window shorter than a pitch period loses the harmonics25 ms (torchaudio kaldi.mfcc); 2,048 samples (n_fft) in librosa
Hop, the step between framesFewer frames, coarser timing, less compute; a hop longer than the window skips samplesMore frames and compute; neighbors overlap more and repeat each other10 ms (torchaudio kaldi.mfcc); 512 samples (hop_length) in librosa

8.1 Gotchas

9 When features go wrong

What you seeLikely causeWhat to do
Features shift between training and useDifferent sample rates put each triangle on different HzResample to one rate first
Small, steady mismatchHTK and Slaney mel mixedPass the same htk setting everywhere
Model struggles with loudnessLog forgotten, so a gain stays a multiplierTake the log, in decibels
Offsets between toolsDifferent dB references (ref=1.0 by default vs ref=np.max)Fix one reference
Great test score, poor in useNormalization statistics taken from the test setUse training statistics only
Top bands always emptyNarrowband audio upsampled to 16 kHz leaves the bands above 4 kHz emptyUse fewer bands or a lower top frequency

How does a model turn these frames into words? Conformer walks through one speech model that reads them.

10 References