MVA · Course notes

Audio Signal Analysis, Indexing and Transformations

M2 MVA · Semester 2 · Modelling · 5 ECTS

Contents

Introduction and overview

Module Audio Signal Analysis, Indexing and Transformations
Official title Audio signal Analysis, Indexing and Transformations
Instructors G. RICHARD, R.BADEAU (master-mva.com, 2026–2027)
Period Semester 2 · period 2 (04/01/2027 – 02/04/2027)
Credits and volume 5 ECTS · 24 h (lectures 14 h, labs 10 h) per the Université Paris-Saclay programme table
Label Modelling · domains on master-mva.com: Signal processing
Language Lectures are planned in French, with slides in English (master-mva.com)
Assessment Papers reading and analysis, with a written report and an oral presentation (master-mva.com); Université Paris-Saclay: “Evaluation Continue non Intégrale” (partial continuous assessment)
Prerequisites Basics of signal processing (master-mva.com)
Organisation 13.5 h of theoretical lectures and 10.5 h of practical sessions (TP) in Matlab, or in Python if preferred (master-mva.com)

Audience: a student with a good M1 in mathematics, computer science or physics, who knows the Fourier transform and linear filters, and wants to analyse, index, separate and transform real audio signals.

Empirical first: two microphones record three people talking at once. No linear demixing matrix can undo a mixture with more sources than sensors, yet the DUET algorithm of ch. 8 raises the signal-to-distortion ratios of the three voices from −4.6, −3.1 and −1.6 dB to 14.7, 10.7 and 14.9 dB.

In the same spirit, two tones closer than the Fourier resolution of a 64-sample frame give a periodogram with two peaks at the wrong frequencies, while ESPRIT (ch. 10) finds both within 0.0003 cycles per sample.

This course covers four families of audio problems. Indexing, or machine listening, extracts descriptors from a recording to recognise its genre, its instruments, its tempo and its bars. Transformations change a sound: digital effects, reverberation, time stretching, pitch shifting, and 3D rendering over headphones or loudspeaker arrays.

Source separation recovers individual sources from a mixture. High-resolution spectral analysis estimates the frequencies of a sum of sinusoids beyond the Fourier limit. The course is taught by Gaël Richard and Roland Badeau (Télécom Paris, per master-mva.com).

It shares tools with Audio Signal Processing: Time–Frequency Analysis, Algorithms for Speech and Natural Language Processing and Machine Learning for Time Series.

What you will be able to do

Official objectives and syllabus (2026–2027)

The course description on master-mva.com states that the course aims to span several domains of audio signal analysis. It names audio indexing (or machine listening), high-resolution audio spectral analysis, audio source separation, and audio transformations: 3D sound rendering, sound effects and sound modifications.

It announces 13.5 h of theoretical lectures and 10.5 h of practical sessions in Matlab, or Python if preferred; this page uses Python throughout. Assessment is by papers reading and analysis, with a written report and an oral presentation. The Université Paris-Saclay course detail gives only the assessment type, and no programme of its own.

The table has one row per item of the “Thèmes abordés” list, split at its listed sub-topics, and one row per announced organisation item. The list ends with an item “Les intervenants” (the teachers), a heading rather than a topic, which is why it has no row.

Official topic Course section
Audio indexing (machine listening): audio signal analysis for content-based information retrieval ch. 1 (Definitions 1.1–1.7: STFT, mel, MFCC, chroma, descriptors); ch. 2 (Definition 2.1, the bag-of-frames pipeline)
Automatic music genre recognition ch. 2: Example 2.5 (genre features and the GTZAN lessons), Proposition 2.7 (artist and album filters)
Automatic musical instrument identification ch. 2: Definition 2.6 (timbre descriptors, taxonomies), Definitions 2.2–2.3 (GMM and SVM classifiers), classification code
Tempo estimation ch. 3: Definition 3.2, Proposition 3.3 (octave errors), tempo code
Downbeat estimation ch. 3: Definition 3.6 (bar position), downbeat code
Audio indexing: onset detection and beat tracking (the “…” of the list) ch. 3: Definition 3.1, Definition 3.4 and Proposition 3.5 (dynamic programming)
Audio transformations, physical and perceptual approaches ch. 6: Definition 6.1 (interaural cues), physical rendering by Theorem 6.4
Binaural techniques ch. 6: binaural synthesis (Definition 6.2), localisation cues
Transaural techniques ch. 6: Proposition 6.3 (crosstalk cancellation)
Head-related transfer functions ch. 6: Definition 6.2, databases and individualisation
Wave field synthesis ch. 6: Theorem 6.4 (Kirchhoff–Helmholtz), Rayleigh integral, Proposition 6.5 (spatial aliasing)
Digital sound effects: flanger ch. 4: Definitions 4.1 and 4.3, Proposition 4.2
Digital sound effects: phaser ch. 4: Definition 4.4, Proposition 4.5
Digital sound effects: distortion ch. 4: Definition 4.6, Proposition 4.7 (harmonics and aliasing)
Digital sound effects: artificial reverberation ch. 4: Definition 4.8, Propositions 4.9–4.10 (Schroeder reverberator); ch. 11: Proposition 11.2 (feedback delay networks), convolution reverberation
Timbral modifications ch. 5: Definition 5.6 (source–filter model, envelope-preserving pitch shift, formant shifting, envelope transfer), envelope code; ch. 11: Proposition 11.3 (linear prediction)
Scale modifications (time-scale) ch. 5: Definitions 5.2–5.3, Proposition 5.4 (phase vocoder)
Pitch modifications ch. 5: Proposition 5.1, Definition 5.5 (pitch shifting)
Audio source separation: audio demixing ch. 7: Definition 7.1, Proposition 7.2, Definition 7.8 (SDR, SIR, SAR)
Linear mixing models ch. 7: Propositions 7.3 and 7.6, Theorem 7.4, Definition 7.5 (independent component analysis, FastICA); ch. 11: maximum-likelihood ICA
Convolutive mixing models ch. 7: Proposition 7.7 (narrowband approximation), frequency-domain ICA and the permutation problem
Underdetermined models ch. 8: Definition 8.1, Proposition 8.2
Sparse models ch. 8: Proposition 8.2 (ℓ1 recovery), Proposition 8.6 (Wiener masks); ch. 11: Definition 11.6 and Proposition 11.7 (NMF)
DUET ch. 8: Proposition 8.3, Algorithm 8.4, Proposition 8.5, DUET code
High-resolution analysis: sinusoidal models ch. 9: Definition 9.1, Propositions 9.4–9.7
Beyond Fourier analysis ch. 9: Proposition 9.2 (Rayleigh limit), Theorem 9.3 (Cramér–Rao bound, proved in ch. 11), Algorithm 9.5 (Prony)
Spectral MUSIC ch. 10: Theorem 10.2, Definition 10.3
ESPRIT ch. 10: Theorem 10.4, Algorithm 10.5, Definition 10.6 (ESTER order selection)
Organisation: 13.5 h of theoretical lectures Session plan: one 3 h lecture and seven lectures of 1.5 h
Organisation: 10.5 h of practical sessions (TP) in Matlab, or Python if preferred Session plan: seven labs of 1.5 h, in Python, on the code of ch. 1–10
Organisation: lectures planned in French, slides in English Fiche (Language); these notes are in English
Assessment: papers reading and analysis, written report, oral presentation Projects and assessment: paper-study subjects

Every official topic has a section in these notes. The extensions beyond the syllabus are the review of ch. 0, the self-study complements of ch. 11 (EM, feedback delay networks, linear prediction, STFT inversion, amplitude panning and Ambisonics, NMF, harmonic–percussive separation, the Cramér–Rao bound, neural models) and the research directions of ch. 12.

Where this course fits in the programme

Official prerequisite: basics of signal processing. In practice the course also uses linear algebra (eigendecompositions, least squares), elementary probability (Gaussian models, maximum likelihood) and some Python; ch. 0 reviews the signal-processing part.

Course outline

Session plan

24 h in class = 8 sessions of 3 h. The 24 h come from the Université Paris-Saclay programme table (14 h of lectures, 10 h of labs). master-mva.com announces the same total, split into 13.5 h of lectures and 10.5 h of practical sessions; the plan follows that split, with one 3 h lecture and seven sessions of 1.5 h of lecture plus 1.5 h of lab. The split into sessions is a proposal.

Level 1 = foundations, 2 = core methods, 3 = advanced and research-level material. The level never goes down from one session to the next.

Session Hours Level Content Practice
1 3 h 1 ch. 1 STFT and overlap-add, perceptual scales, cepstrum and MFCC, descriptors, chroma (3 h lecture) Ex. 2, 3
2 3 h 2 ch. 2 Bag-of-frames indexing, Gaussian mixtures, genre and instrument recognition, evaluation Lab 1 (1.5 h): features and instrument classification (code of ch. 1–2); Ex. 9
3 3 h 2 ch. 3 Onset detection, tempo, beat tracking by dynamic programming, downbeats Lab 2: rhythm analysis (code of ch. 3); Ex. 4, 16
4 3 h 2 ch. 4 Comb filters, flanger, phaser, distortion, artificial reverberation Lab 3: effects and a Schroeder reverberator; Ex. 5, 6, 10
5 3 h 2 ch. 5 Overlap-add, phase vocoder, pitch shifting, spectral envelopes Lab 4: phase vocoder and envelope-preserving pitch shift; Ex. 11
6 3 h 2 ch. 6 Interaural cues, HRTFs, binaural and transaural rendering, wave field synthesis Lab 5: crosstalk cancellation and WFS simulation; Ex. 7, 8, 14
7 3 h 3 ch. 7 Mixing models, ICA, convolutive mixtures; ch. 8 Sparsity, ℓ1 recovery, DUET, Wiener masks Lab 6: ICA and DUET; Ex. 12, 13
8 3 h 3 ch. 9 Sinusoidal models, Prony, Hankel structure; ch. 10 MUSIC, ESPRIT, ESTER Lab 7: Prony, MUSIC and ESPRIT; Ex. 15, 17

Self-study, outside the 24 h (about 10 h in total): ch. 0 Review of the signal-processing prerequisites, before session 1 (≈ 3 h, with Ex. 1) · ch. 11 Complements for self-study (≈ 4 h, with Ex. 18) · ch. 12 Research directions and open problems (≈ 3 h, with Ex. 19).

How to study this module

0. Review: signals, Fourier analysis, filters and random signals

Every chapter of this course computes spectra, filters signals and reasons about noise. This chapter collects the facts it uses, with the two that matter most for audio: the Fourier resolution limit and the leakage of windows.

The discrete Fourier transform

A digital audio signal is a sequence x(n) sampled at f_s hertz, typically 16 kHz for speech and 44.1 kHz for music. A normalised angular frequency \omega (radians per sample) corresponds to f = \omega f_s / 2\pi hertz.

Definition 0.1 — DTFT and DFT The discrete-time Fourier transform of a summable sequence and the discrete Fourier transform of a block of N samples are X(\omega) = \sum_{n \in \mathbb{Z}} x(n)\, e^{-i \omega n}, \qquad X(k) = \sum_{n=0}^{N-1} x(n)\, e^{-2 i \pi k n / N}, \quad 0 \le k < N . The DFT samples the DTFT of the block at the N frequencies \omega_k = 2\pi k / N, and the FFT computes it in O(N \log N) operations.

By the sampling theorem, a continuous signal whose spectrum vanishes above f_s / 2 is determined by its samples. Frequencies above f_s / 2 fold back, or alias, which matters for the distortion effects of ch. 4.

Proposition 0.2 — Convolution theorem The DTFT of a convolution is the product of the DTFTs: y(n) = \sum_{m} h(m)\, x(n - m) \quad \Longrightarrow \quad Y(\omega) = H(\omega)\, X(\omega) . For the DFT the same identity holds with circular convolution. A linear convolution of lengths N_x and N_h is obtained exactly with DFTs of size at least N_x + N_h - 1.

Proof. Substitute n = m + p in the definition of Y(\omega); the double sum factorises into \sum_m h(m) e^{-i\omega m} \sum_p x(p) e^{-i\omega p}. For the DFT, indices are taken modulo N. Zero-padding both sequences to N_x + N_h - 1 samples removes the wrap-around terms. ∎

Linear filters

Definition 0.3 — Linear time-invariant filter A causal filter given by a difference equation, y(n) = \sum_{p=0}^{P} b_p\, x(n - p) - \sum_{q=1}^{Q} a_q\, y(n - q), has the transfer function H(z) = B(z) / A(z), with B(z) = \sum_p b_p z^{-p} and A(z) = 1 + \sum_q a_q z^{-q}. It is FIR when Q = 0 and IIR otherwise.

It is stable when all the poles (roots of A) lie strictly inside the unit circle. Its frequency response is H(e^{i\omega}), with gain |H| and phase \arg H.

Windows, leakage and resolution

A frame of N samples is the product of the signal with a window w supported on \{0, \dots, N - 1\}. By Proposition 0.2, the spectrum of the frame is the spectrum of the signal convolved with that of the window.

Proposition 0.4 — Spectrum of a windowed exponential If x(n) = \alpha\, e^{i \omega_0 n}, the windowed frame has the spectrum X_w(\omega) = \alpha\, W(\omega - \omega_0) . For the rectangular window, |W(\omega)| = |\sin(N\omega/2) / \sin(\omega/2)|: its main lobe has half-width 2\pi/N and its first sidelobe is 13 dB below the peak.

For the Hann window w(n) = \tfrac12 - \tfrac12 \cos(2\pi n / N), the main lobe is twice as wide (4\pi/N), but the first sidelobe is 31 dB down and the sidelobes decay as 1/\omega^3, that is 18 dB per octave.

Proof. For the rectangle, W(\omega) = \sum_{n=0}^{N-1} e^{-i\omega n} is a geometric sum, equal to e^{-i\omega(N-1)/2} \sin(N\omega/2) / \sin(\omega/2). It vanishes first at \omega = 2\pi/N.

The Hann window is a sum of three exponentials, so its transform is a sum of three shifted copies of the rectangular one. The shifts by \pm 2\pi/N cancel the sidelobes to leading order and move the first zero to 4\pi/N. ∎

Two consequences organise the rest of the course.

The code below adds a tone 50 dB below a strong one, 150 Hz away, in a 50 ms frame.

import numpy as np

fs, N = 8000, 400                         # a 50 ms analysis window, fs/N = 20 Hz
n = np.arange(N)
strong = np.cos(2 * np.pi * 1000 * n / fs)
weak = 10 ** (-50 / 20) * np.cos(2 * np.pi * 1150 * n / fs)   # 50 dB below

def level_db(x, w, f0, pad=16):
    X = np.abs(np.fft.rfft(x * w, pad * N))   # zero padding interpolates only
    f = np.fft.rfftfreq(pad * N, 1 / fs)
    X_db = 20 * np.log10(X / X.max())
    return X_db[np.argmin(np.abs(f - f0))]

for name, w in [("rectangular", np.ones(N)), ("Hann", np.hanning(N))]:
    without = level_db(strong, w, 1150)
    with_ = level_db(strong + weak, w, 1150)
    print(f"{name:12s} level at 1150 Hz: {without:6.1f} dB without the weak tone,"
          f" {with_:6.1f} dB with it")

With the rectangular window the level at 1150 Hz is −27.0 dB without the weak tone and −26.9 dB with it: the weak tone stays invisible under a sidelobe. With the Hann window it rises from −62.2 dB to −49.9 dB: the weak tone appears at its true level.

Random signals

Definition 0.5 — Stationary signals and power spectral density A random signal is wide-sense stationary when its mean is constant and its autocorrelation depends only on the lag: r_x(k) = \mathbb{E}\big[x(n + k)\, \overline{x(n)}\big] . Its power spectral density is S_x(\omega) = \sum_k r_x(k)\, e^{-i\omega k} (Wiener–Khinchin). White noise of variance \sigma^2 has r_x(k) = \sigma^2 \delta(k) and a flat spectrum.

Filtering a stationary signal by H multiplies its spectral density by |H(e^{i\omega})|^2. The covariance matrix \mathbf{R} of L consecutive samples is Hermitian, Toeplitz and positive semidefinite.

Chapters 7, 9 and 10 also use two facts from linear algebra. A Hermitian matrix has an orthonormal basis of eigenvectors with real eigenvalues. Any matrix has a singular value decomposition \mathbf{X} = \mathbf{U} \boldsymbol{\Sigma} \mathbf{V}^H, and its first K left singular vectors span the column space of its best rank-K approximation.

Key takeaways — chapter 0

  • The DFT samples the spectrum of a block; convolution becomes a product, circular for the DFT.
  • A filter is stable when its poles lie inside the unit circle; its frequency response is H(e^{i\omega}).
  • Windowing convolves the spectrum with the window’s transform: main-lobe width limits resolution to about f_s / N, sidelobes cause leakage.
  • Stationary signals are described by their autocorrelation or their power spectral density.

1. Time–frequency representations and audio features

Audio signals are not stationary: notes start and stop, voices glide. This chapter builds the short-time Fourier transform, proves when it can be inverted, and derives from it the descriptors used for indexing in ch. 2–3.

The short-time Fourier transform

Definition 1.1 — Short-time Fourier transform With an analysis window w of length N and a hop of R samples, the STFT of x is X(m, k) = \sum_{n=0}^{N-1} x(n + mR)\, w(n)\, e^{-2 i \pi k n / N}, for the frame index m and the frequency bin k. Its squared modulus |X(m, k)|^2 is the spectrogram.

The window length sets a trade-off. At 16 kHz, N = 1024 gives frames of 64 ms and bins 15.6 Hz apart: good for pitch, poor for drum attacks. Speech analysis typically uses frames of 20–40 ms and music analysis 40–100 ms.

Proposition 1.2 — Overlap-add reconstruction Let y_m(n) be the inverse DFT of frame m, multiplied by a synthesis window w_s, and placed back at time mR by overlap-add. If the windows satisfy the condition below, the overlap-add \sum_m y_m equals x exactly.

Key result — perfect reconstruction by overlap-add \sum_{m \in \mathbb{Z}} w(n - mR)\, w_s(n - mR) = 1 \quad \text{for all } n

Proof. The inverse DFT of frame m returns x(n + mR)\, w(n) for 0 \le n < N. After the synthesis window and the shift, frame m contributes at time n the sample x(n)\, w(n - mR)\, w_s(n - mR) . Summing over m and using the condition gives x(n). ∎

For the periodic Hann window and R = N/4, the shifted windows sum to 2 and their squares to 3/2. So w_s = \tfrac{2}{3} w reconstructs exactly; the code below normalises by \sum_m w^2(n - mR), which is the same thing.

A modified STFT (masked in ch. 8, re-phased in ch. 5) is generally not the STFT of any signal; ch. 11 explains what overlap-add then returns.

Perceptual scales

The ear resolves low frequencies finely and high frequencies coarsely: its critical bands are about 100 Hz wide below 500 Hz and about 20 % of the centre frequency above, roughly a third of an octave. Audio descriptors imitate this with nonlinear frequency scales.

Definition 1.3 — Mel scale and mel filterbank The mel scale maps a frequency f in hertz to \mathrm{mel}(f) = 2595 \log_{10}\Big(1 + \frac{f}{700}\Big) . A mel filterbank has J triangular filters H_j(k) whose centres are equally spaced in mel; each filter rises from the centre of its left neighbour to its own centre and falls to the centre of its right neighbour. The log-mel spectrogram is \log \sum_k H_j(k)\, |X(m, k)|^2.

The constant-Q transform follows the same idea with geometrically spaced bins, f_k = f_{\min}\, 2^{k / b} with b bins per octave, so that every bin spans the same musical interval.

Definition 1.4 — Mel-frequency cepstral coefficients The MFCCs of frame m are the first coefficients (typically 13) of the type-II discrete cosine transform of the log-mel energies E_j(m): c_q(m) = \sum_{j=1}^{J} \log E_j(m)\, \cos\Big(\frac{\pi q (j - \tfrac12)}{J}\Big), \qquad q = 0, \dots, 12 .

The cosine transform of a logarithm comes from the source–filter view of sound production.

Proposition 1.5 — The cepstrum separates source and filter If a frame spectrum factorises as an excitation times a spectral envelope, X(\omega) = E(\omega)\, H(\omega), then \log |X(\omega)| = \log |E(\omega)| + \log |H(\omega)| . When H varies slowly with frequency and E is a harmonic comb of spacing \omega_0, the inverse Fourier transform of \log |X| (the cepstrum) concentrates the envelope at quefrencies below 2\pi / \omega_0 samples and the excitation at multiples of 2\pi / \omega_0.

Proof. The logarithm turns the product into a sum, and the inverse transform is linear. A smooth function of \omega has a transform concentrated near zero. A comb of spacing \omega_0 in \log|E| is periodic in \omega, so its transform is supported near the multiples of the period 2\pi/\omega_0. ∎

Keeping the low quefrencies (liftering) keeps the envelope, which carries timbre and vowel identity, and discards pitch. MFCCs do the same on the mel scale.

Descriptors and chroma

Definition 1.6 — Spectral and temporal descriptors For a frame with power spectrum P(k) = |X(m, k)|^2 and bin frequencies f_k:

  • the spectral centroid \sum_k f_k P(k) / \sum_k P(k), correlated with perceived brightness;
  • the roll-off, the frequency below which 85 % (or 95 %) of the energy lies;
  • the spectral flux, the distance between consecutive normalised spectra (ch. 3);
  • the zero-crossing rate of the waveform, high for noisy sounds;
  • the attack time and the energy envelope of a note (ch. 2).

Definition 1.7 — Chroma Chroma features fold the spectrum onto the 12 pitch classes of Western music. With a reference f_{\mathrm{ref}} = 440 Hz (the class A), bin k goes to the class p(k) = \mathrm{round}\big(12 \log_2(f_k / f_{\mathrm{ref}})\big) \bmod 12, and C_p(m) = \sum_{k : p(k) = p} |X(m, k)|^2. Chroma is invariant to octave and largely to timbre: it describes harmony.

The code computes an STFT, checks the reconstruction of Proposition 1.2, then extracts MFCCs and chroma from four notes a semitone apart, starting on A3 (220 Hz).

import numpy as np
from scipy.fft import dct

fs, N, R = 16000, 1024, 256                  # window 64 ms, hop 16 ms
w = np.hanning(N + 1)[:N]                    # periodic Hann window
print("COLA sum (hop N/4):", np.round(sum(np.roll(w, k * R) for k in range(N // R))[:3], 6))

def stft(x):
    frames = [x[i:i + N] * w for i in range(0, len(x) - N + 1, R)]
    return np.fft.rfft(np.array(frames), axis=1)            # shape (M, N/2 + 1)

def istft(X, length):
    y, norm = np.zeros(length), np.zeros(length)
    for m, frame in enumerate(np.fft.irfft(X, n=N, axis=1)):
        y[m * R:m * R + N] += frame * w                      # synthesis window
        norm[m * R:m * R + N] += w ** 2
    return y / np.maximum(norm, 1e-12)

def mel(f):  return 2595 * np.log10(1 + f / 700)
def imel(m): return 700 * (10 ** (m / 2595) - 1)

def mel_filterbank(n_mels=40, fmin=0.0, fmax=fs / 2):
    edges = imel(np.linspace(mel(fmin), mel(fmax), n_mels + 2))
    f = np.fft.rfftfreq(N, 1 / fs)
    H = np.zeros((n_mels, len(f)))
    for j in range(n_mels):
        lo, c, hi = edges[j], edges[j + 1], edges[j + 2]
        H[j] = np.clip(np.minimum((f - lo) / (c - lo), (hi - f) / (hi - c)), 0, None)
    return H

rng = np.random.default_rng(0)
t = np.arange(2 * fs) / fs
f0 = 220 * 2 ** (np.floor(t / 0.5) / 12)                     # four notes, a semitone apart
x = sum(np.sin(2 * np.pi * k * np.cumsum(f0) / fs) / k for k in range(1, 9))
x += 0.01 * rng.standard_normal(len(x))

X = stft(x)
y = istft(X, len(x))
inner = slice(N, len(x) - N)
print("reconstruction error:", f"{np.max(np.abs(x[inner] - y[inner])):.1e}")

logmel = np.log(np.abs(X) ** 2 @ mel_filterbank().T + 1e-10)    # (M, 40)
mfcc = dct(logmel, type=2, norm="ortho", axis=1)[:, :13]
print("frames:", X.shape[0], "| MFCC shape:", mfcc.shape)
f = np.fft.rfftfreq(N, 1 / fs)
pc = np.round(12 * np.log2(np.maximum(f, 1) / 440)) % 12      # pitch class, 0 = A
keep = (f > 50) & (f < 2000)
chroma = np.stack([(np.abs(X[:, keep]) ** 2)[:, pc[keep] == p].sum(1) for p in range(12)], 1)
names = "A A# B C C# D D# E F F# G G#".split()
centres = ((np.arange(4) * 0.5 + 0.25) * fs - N / 2) // R   # one frame inside each note
print("dominant pitch class per note:", [names[np.argmax(chroma[int(m)])] for m in centres])

The shifted windows sum to 2, the reconstruction error is 1.1 \times 10^{-15} (rounding only), the 2 s signal gives 122 frames of 13 MFCCs, and the chroma follows the notes A, A#, B, C.

Key takeaways — chapter 1

  • The STFT trades time resolution for frequency resolution through the window length; overlap-add inverts it when the shifted products of analysis and synthesis windows sum to one.
  • Mel and constant-Q scales imitate the frequency resolution of hearing.
  • The cepstrum separates a slowly varying envelope (timbre) from a harmonic excitation (pitch); MFCCs are a mel-scale cepstrum.
  • Spectral descriptors summarise brightness, noisiness and change; chroma summarises harmony.

2. Audio indexing I: classifying genres and instruments

Content-based indexing labels a recording from its signal alone: its genre, the instruments playing, the sound events it contains. This chapter builds the classical pipeline on the features of ch. 1 and shows how easily its evaluation can be fooled.

The bag-of-frames pipeline

Definition 2.1 — Bag-of-frames classifier A recording is cut into frames of 20–100 ms, each described by a feature vector \mathbf{x}_m (MFCCs, descriptors, chroma).

Features are then integrated over texture windows of about 1–5 s, typically by their mean and standard deviation. A classifier labels each window, and window decisions are aggregated (majority vote or summed log-probabilities) into a label for the recording.

It ignores the order of frames, hence its name: it suits timbre-driven tasks (instrument, genre, acoustic scene), not rhythm, which ch. 3 treats separately.

Gaussian mixture models

Definition 2.2 — GMM classifier Each class c has a density on feature vectors, a mixture of G Gaussians: p(\mathbf{x} \mid c) = \sum_{g=1}^{G} \pi_{cg}\, \mathcal{N}(\mathbf{x};\, \boldsymbol{\mu}_{cg}, \boldsymbol{\Sigma}_{cg}) . Treating the frames \mathbf{x}_1, \dots, \mathbf{x}_M of a window as independent, the Bayes rule picks \hat c = \arg\max_c \Big( \log p(c) + \sum_{m=1}^{M} \log p(\mathbf{x}_m \mid c) \Big) .

The independence assumption is false (consecutive frames overlap), which makes the posterior probabilities overconfident, but the argmax is often still good.

The class densities are fitted to the training frames of each class by the EM algorithm, whose updates and monotonicity are proved in ch. 11.

Discriminative classifiers and feature selection

Definition 2.3 — Support vector machine A kernel SVM labels a feature vector by the sign of g(\mathbf{x}) = \sum_i \alpha_i y_i\, K(\mathbf{x}_i, \mathbf{x}) + b, where the \alpha_i \ge 0 solve a convex quadratic problem that maximises the margin, and K is often the Gaussian kernel. Several classes are handled by one-versus-one or one-versus-all votes. The theory is in Kernel Methods.

Definition 2.4 — Fisher discriminant ratio With hundreds of candidate descriptors, a simple filter keeps those with a large ratio of between-class to within-class spread. For one feature, two classes with means \mu_1, \mu_2 and variances \sigma_1^2, \sigma_2^2, F = \frac{(\mu_1 - \mu_2)^2}{\sigma_1^2 + \sigma_2^2} .

Genre recognition and instrument identification

Example 2.5 — Genre recognition Tzanetakis and Cook (2002) introduced automatic genre classification with three feature sets: timbral texture (centroid, roll-off, flux, zero crossings, MFCCs), rhythmic content (a beat histogram built from the autocorrelation of ch. 3) and pitch content. Their data set, GTZAN, has 1000 excerpts of 30 s in 10 genres.

Sturm (2014) later showed that GTZAN contains repeated excerpts, mislabelled ones and many excerpts by the same artists. Part of the published accuracies measured artist recognition or plain duplication rather than genre.

Definition 2.6 — Timbre descriptors for instruments Instrument recognition relies on descriptors of timbre, for example:

  • the attack time of the energy envelope (short for plucked strings and percussion);
  • the spectral centroid and its evolution;
  • the odd-to-even harmonic energy ratio, high for the clarinet, whose cylindrical bore weakens even harmonics;
  • the inharmonicity of partials (pianos, bells) and MFCC statistics.

In polyphonic music, Essid, Richard and David (2006) classify combinations of instruments, organised in a hierarchical taxonomy learned from the data.

Evaluating an indexing system

Proposition 2.7 — Artist, album and session filters Suppose that each recording session (artist, album, room, microphone) adds to all its excerpts a signature that a classifier can learn. Suppose also that sessions are nested in classes, as albums are in genres.

Then, under a random split of excerpts into training and test sets, a classifier can reach a high test accuracy by recognising the signature alone, an accuracy that does not carry over to new sessions. Splitting by session (an artist filter) removes this bias.

Proof. Under a random split, a test excerpt from session s has, with high probability, training excerpts from the same session and thus the same label. A rule that recognises sessions, then outputs their label, is then correct on the test set without using any class information. On new sessions its signature carries no label information, so the same rule falls to chance level on that part. ∎

The code builds three synthetic instruments recorded in 18 sessions (one instrument per session, each with its own random equaliser), describes each note by the mean and standard deviation of 13 MFCCs, and compares a random split with a session-disjoint split.

import numpy as np
from scipy.fft import dct
from sklearn.mixture import GaussianMixture
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import StratifiedKFold, StratifiedGroupKFold

fs, N, R = 16000, 512, 256
rng = np.random.default_rng(0)
w = np.hanning(N + 1)[:N]
f = np.fft.rfftfreq(N, 1 / fs)
mel = lambda x: 2595 * np.log10(1 + x / 700)
edges = 700 * (10 ** (np.linspace(0, mel(fs / 2), 42) / 2595) - 1)
H = np.array([np.clip(np.minimum((f - a) / (b - a), (c - f) / (c - b)), 0, None)
              for a, b, c in zip(edges[:-2], edges[1:-1], edges[2:])])   # 40 mel filters

def note(kind, f0, eq):
    """Synthetic note: harmonic amplitudes and envelope depend on the instrument."""
    t = np.arange(int(0.5 * fs)) / fs
    k = np.arange(1, 21)
    amp = [np.where(k % 2 == 1, 1 / k, 0.3 / k),       # 'clarinet': weak even harmonics
           1 / k,                                       # 'bowed string': all harmonics
           1 / k ** 1.5][kind]                          # 'flute': steeper spectral slope
    amp = amp * eq(k * f0) * (k * f0 < fs / 2)          # recording-session colouring
    attack = (0.06, 0.12, 0.04)[kind] * np.exp(0.3 * rng.standard_normal())
    env = np.minimum(t / attack, 1) * np.exp(-t * (1.0, 0.5, 2.0)[kind])
    x = env * (amp[:, None] * np.sin(2 * np.pi * np.outer(k, f0 * t)
                                     + rng.uniform(0, 2 * np.pi, (20, 1)))).sum(0)
    return x + (0.002, 0.01, 0.03)[kind] * env * rng.standard_normal(len(t))

def features(x):
    frames = np.array([x[i:i + N] * w for i in range(0, len(x) - N, R)])
    P = np.abs(np.fft.rfft(frames, axis=1)) ** 2
    mfcc = dct(np.log(P @ H.T + 1e-10), norm="ortho", axis=1)[:, 1:14]
    return np.concatenate([mfcc.mean(0), mfcc.std(0)])  # temporal integration: 26 numbers

X, y, groups = [], [], []
for s in range(18):                                     # 18 sessions, one instrument each
    kind = s % 3
    a, ph = rng.standard_normal(4), rng.uniform(0, 2 * np.pi, 4)
    eq = lambda fr, a=a, ph=ph: np.exp(0.4 * sum(a[j] * np.cos((j + 1) * np.log2(fr / 100) + ph[j])
                                                 for j in range(4)))
    for _ in range(20):
        f0 = 196 * 2 ** (rng.integers(0, 19) / 12)      # G3 to C#5
        X.append(features(note(kind, f0, eq))); y.append(kind); groups.append(s)
X, y, groups = np.array(X), np.array(y), np.array(groups)

def gmm_predict(Xtr, ytr, Xte, k=2):                    # one GMM per class + Bayes rule
    sc = StandardScaler().fit(Xtr)
    L = [GaussianMixture(k, covariance_type="diag", random_state=0)
         .fit(sc.transform(Xtr[ytr == c])).score_samples(sc.transform(Xte)) for c in range(3)]
    return np.argmax(L, axis=0)                         # equal priors

def svm_predict(Xtr, ytr, Xte):
    return make_pipeline(StandardScaler(), SVC(C=10)).fit(Xtr, ytr).predict(Xte)

splits = {"random split": StratifiedKFold(3, shuffle=True, random_state=0).split(X, y),
          "session-disjoint": StratifiedGroupKFold(3, shuffle=True, random_state=0).split(X, y, groups)}
for split, folds in splits.items():
    folds = list(folds)
    for name, predict in [("GMM", gmm_predict), ("SVM", svm_predict)]:
        acc = [np.mean(predict(X[tr], y[tr], X[te]) == y[te]) for tr, te in folds]
        print(f"{split:16s} {name}: accuracy {np.mean(acc):.3f}")

The random split reports 0.828 for the GMM and 0.983 for the SVM. On sessions never seen in training, the accuracies drop to 0.758 and 0.925: the gap is the part of the score that recognised sessions rather than instruments.

Key takeaways — chapter 2

  • Bag-of-frames indexing extracts frame features, integrates them over texture windows and classifies them; GMMs with the Bayes rule and SVMs are the classical classifiers.
  • Genre recognition mixes timbre, rhythm and pitch features; instrument recognition relies on timbre descriptors such as attack time and the odd-to-even harmonic ratio.
  • Any shared signature (artist, album, session) must be confined to one side of the split, or the accuracy is inflated.

3. Audio indexing II: onsets, tempo, beats and downbeats

Rhythm is the temporal side of indexing: where notes start, how fast the pulse is, where each beat falls and where each bar begins. The chain goes from an onset detection function to a tempo, then to beat times and downbeats.

Onset detection

Definition 3.1 — Spectral-flux onset detection function With the STFT magnitudes |X(m, k)| and a compression constant \gamma > 0, the log-spectral flux is O(m) = \sum_k \Big[ \log\big(1 + \gamma |X(m, k)|\big) - \log\big(1 + \gamma |X(m - 1, k)|\big) \Big]_+ , where [u]_+ = \max(u, 0) keeps energy increases only. Onsets are the peaks of O above an adaptive threshold, such as a local median plus a constant.

The logarithm makes soft and loud notes comparable, and the half-wave rectification ignores decays. Bello et al. (2005) compare this function with energy-, phase- and complex-domain variants.

Tempo estimation

Definition 3.2 — Tempo by autocorrelation Let the onset function be sampled at F_r frames per second, with mean removed. Its autocorrelation r(\ell) = \sum_m O(m)\, O(m + \ell) peaks at lags that are multiples of the beat period. The tempo estimate in beats per minute (BPM) is \hat T = \frac{60\, F_r}{\ell^\star}, \qquad \ell^\star = \arg\max_{\ell} \; r(\ell)\, \pi(\ell), where the prior \pi favours lags near 120 BPM, for example a Gaussian in \log_2 of the tempo.

Proposition 3.3 — Octave errors Let O be periodic with period P frames, and compute r circularly over a whole number of periods. Then r is periodic with period P and takes the same value at every multiple of P. An unweighted maximisation over lags cannot distinguish the tempo from its half, a third, and so on.

If moreover the first beat of each bar is accented, with bars of 3P or 4P frames, then r has larger peaks at multiples of the bar period.

Proof. Shifting the lag by P shifts one factor of each product by a period, which leaves it unchanged, and the circular sum keeps the same number of terms; so r(\ell + P) = r(\ell) and r(kP) = r(0). Accents repeating every bar add a component of period 3P or 4P to O, whose autocorrelation peaks at multiples of the bar. ∎

Hence the prior \pi. Comb-filter banks (Scheirer, 1998) and Fourier tempograms (Grosche and Müller, 2011) replace the autocorrelation in other systems and face the same ambiguity.

Beat tracking by dynamic programming

Definition 3.4 — Beat-tracking objective (Ellis, 2007) Given the onset function O (normalised to unit variance) and the beat period \tau in frames, a beat sequence t_1 < \dots < t_B scores C(t_1, \dots, t_B) = \sum_{i=1}^{B} O(t_i) + \alpha \sum_{i=2}^{B} F(t_i - t_{i-1}), \qquad F(\Delta) = -\Big(\log \frac{\Delta}{\tau}\Big)^2 . The first sum rewards beats on onsets; the second penalises intervals far from \tau, with a tightness \alpha.

Proposition 3.5 — Exact optimisation Let C^\star(t) be the best score of a beat sequence ending at frame t. Then C^\star(t) = O(t) + \max\Big(0,\; \max_{\tau/2 \le \Delta \le 2\tau} \big[ \alpha F(\Delta) + C^\star(t - \Delta) \big]\Big), and back-tracking from the best final frame recovers an optimal sequence. With T frames the cost is O(T \tau).

Proof. A sequence ending at t is either the single beat t or a sequence ending at some t - \Delta followed by t. The score is additive along the sequence, so the best extension uses the best sequence ending at t - \Delta (optimal substructure).

Storing the maximising \Delta for each t allows back-tracking. Each frame examines O(\tau) predecessors. ∎

The restriction to \Delta \in [\tau/2, 2\tau] is part of the model: a slowly changing tempo is followed, but a tempo change by more than a factor 2 is not.

Downbeat estimation

Definition 3.6 — Meter, bar position and downbeats In a meter of B beats per bar (often B = 4), each beat has a bar position \phi \in \{0, \dots, B - 1\}; the beats with \phi = 0 are the downbeats.

Given beats t_1, t_2, \dots, a simple estimator picks the phase \hat p = \arg\max_{p \in \{0, \dots, B-1\}} \frac{1}{|I_p|} \sum_{i \in I_p} D(t_i), \qquad I_p = \{ i : i \equiv p \bmod B \}, for a downbeat salience D: low-frequency onsets (bass drum, bass notes) or harmonic change measured on chroma.

Probabilistic models make the bar position a hidden state that advances with each beat, decoded by the Viterbi algorithm (Klapuri, Eronen and Astola, 2006). Current systems learn the salience with neural networks and decode beats and downbeats jointly (Böck, Krebs and Widmer, 2016; Durand et al., 2017).

Evaluation

A detected beat is correct if it lies within ±70 ms of an annotated one, and precision, recall and their harmonic mean, the F-measure, follow. Tempo accuracy is reported with a 4 % tolerance, with or without accepting factors 2 and 3. The mir_eval library (Raffel et al., 2014) implements these measures.

The code synthesises 10 bars of a drum pattern at 128 BPM with 5 ms timing jitter (kick drum on beat 1 and between beats 2 and 3, snare on beats 2 and 4, hi-hat on eighth notes), then runs the whole chain.

import numpy as np

fs, N, R = 16000, 1024, 160                       # ODF frame rate fs/R = 100 Hz
rng = np.random.default_rng(1)
bpm, n_bars = 128, 10
beat = 60 / bpm
t = np.arange(int((4 * n_bars + 1) * beat * fs)) / fs
x = 0.003 * rng.standard_normal(len(t))

def hit(t0, kind):
    i = int(t0 * fs); L = int(0.25 * fs); tt = np.arange(L) / fs
    if kind == "kick":  s = np.sin(2 * np.pi * (50 + 80 * np.exp(-tt / 0.03)) * tt) * np.exp(-tt / 0.12)
    if kind == "snare": s = 0.5 * rng.standard_normal(L) * np.exp(-tt / 0.06)
    if kind == "hat":   s = 0.15 * np.diff(rng.standard_normal(L + 1)) * np.exp(-tt / 0.02)
    x[i:i + L] += s[:len(x) - i]

beats = []
for b in range(4 * n_bars):
    tb = b * beat + 0.005 * rng.standard_normal()   # 5 ms human timing jitter
    beats.append(tb)
    if b % 4 == 0: hit(tb, "kick")                  # kick on beat 1 ...
    if b % 4 == 1: hit(tb + beat / 2, "kick")       # ... and on the "and" of 2
    if b % 2 == 1: hit(tb, "snare")                 # snare on 2 and 4
    hit(tb, "hat"); hit(tb + beat / 2, "hat")       # eighth-note hi-hats
beats = np.array(beats)

# 1. Onset detection function: half-wave rectified log-spectral flux
w = np.hanning(N)
S = np.abs(np.array([np.fft.rfft(x[i:i + N] * w) for i in range(0, len(x) - N, R)]))
L = np.log1p(100 * S)
odf = np.maximum(np.diff(L, axis=0), 0).sum(1)
odf = np.concatenate([[0], (odf - odf.mean()) / odf.std()])
times = (np.arange(len(odf)) * R + N / 2) / fs

# 2. Tempo: autocorrelation weighted by a log-Gaussian prior around 120 BPM
lags = np.arange(25, 101)                           # 60 to 240 BPM at 100 frames/s
ac = np.array([odf[:-l] @ odf[l:] for l in lags])
prior = np.exp(-0.5 * np.log2(6000 / lags / 120) ** 2)
lag = lags[np.argmax(ac * prior)]
print(f"tempo estimate: {6000 / lag:.1f} BPM (true {bpm})")

# 3. Beat tracking by dynamic programming (Ellis, 2007)
alpha, tau = 100.0, lag
C, back = odf.copy(), np.zeros(len(odf), int)
for n in range(len(odf)):
    prev = np.arange(n - 2 * tau, n - tau // 2 + 1)
    prev = prev[prev >= 0]
    if len(prev):
        score = C[prev] - alpha * np.log((n - prev) / tau) ** 2
        k = np.argmax(score); C[n] += score[k]; back[n] = prev[k]
n = np.argmax(C[-2 * tau:]) + len(C) - 2 * tau
path = [n]
while back[path[-1]] > 0: path.append(back[path[-1]])
est = times[np.array(path[::-1])]

def f_measure(est, ref, tol=0.07):
    hits = sum(np.min(np.abs(ref - e)) < tol for e in est)
    p, r = hits / len(est), hits / len(ref)
    return 2 * p * r / (p + r)
print(f"beats found: {len(est)} (true {len(beats)}), F-measure at 70 ms: {f_measure(est, beats):.3f}")

# 4. Downbeat: the bar position whose beats carry the most low-frequency onset energy
low = np.maximum(np.diff(L[:, :8], axis=0), 0).sum(1)       # 0 to 125 Hz
energy = np.interp(est, times[1:], low)
phase = np.argmax([energy[p::4].mean() for p in range(4)])
down_est, down_ref = est[phase::4], beats[::4]
print(f"downbeats: {len(down_est)} estimated, F-measure at 70 ms: {f_measure(down_est, down_ref):.3f}")

The autocorrelation peaks at a lag of 47 frames, that is 127.7 BPM. The dynamic programme finds 39 of the 40 beats (F-measure 0.987), and the low-frequency salience selects the right bar position (downbeat F-measure 0.947). The simplified code always keeps the best predecessor, a slight departure from the \max(0, \cdot) of Proposition 3.5.

Key takeaways — chapter 3

  • The log-spectral flux, half-wave rectified, is a robust onset detection function.
  • Its autocorrelation reveals the beat period, up to octave errors that a tempo prior resolves.
  • Ellis’s objective trades onset strength against regular intervals, and dynamic programming optimises it exactly.
  • Downbeats are the beats of a fixed bar position, chosen by a salience such as bass onsets or harmonic change; evaluation uses F-measures with a 70 ms tolerance.

4. Digital audio effects

Most studio effects are small systems whose behaviour follows from their transfer function. This chapter builds delay-based effects, the phaser, distortion and artificial reverberation from the filters of ch. 0.

Comb filters, flanger and chorus

Definition 4.1 — Comb filters With a delay of D samples and a gain g, the feedforward and feedback comb filters are y(n) = x(n) + g\, x(n - D), \qquad y(n) = x(n) + g\, y(n - D), with transfer functions 1 + g z^{-D} and 1 / (1 - g z^{-D}). The feedback comb is stable if and only if |g| < 1.

Proposition 4.2 — Notches and peaks The feedforward comb has the squared gain |H(e^{i\omega})|^2 = 1 + g^2 + 2 g \cos(\omega D) . For 0 < g \le 1 it has notches of gain 1 - g and maxima of gain 1 + g at the frequencies f_{\text{notch}} = \frac{(2k + 1) f_s}{2D}, \qquad f_{\text{max}} = \frac{k f_s}{D}, \qquad k = 0, 1, \dots The feedback comb has peaks of gain 1 / (1 - g) at the frequencies k f_s / D.

Proof. Expand |1 + g e^{-i\omega D}|^2. The cosine equals -1 when \omega D = (2k + 1)\pi and +1 when \omega D = 2k\pi.

For the feedback comb, |1 - g e^{-i\omega D}| is smallest, equal to 1 - g, when \omega D = 2k\pi. ∎

Definition 4.3 — Flanger, chorus and vibrato A flanger is a feedforward comb whose delay is swept by a low-frequency oscillator (LFO), typically between 0 and 10 ms at 0.1–1 Hz: y(n) = x(n) + g\, x\big(n - D(n)\big) . The fractional delay is interpolated, for example linearly between the two nearest samples. A chorus uses longer delays (10–30 ms) with a slow random modulation and several voices; a vibrato outputs the modulated delayed signal alone.

By Proposition 4.2 the flanger’s notches are harmonically spaced and sweep together. A delay varying at the rate D'(t) also scales the instantaneous frequency by 1 - D'(t): this Doppler effect is the pitch modulation of vibrato and chorus.

Phaser

Definition 4.4 — All-pass section and phaser For a real a with |a| < 1, the first-order all-pass section is A(z) = \frac{a + z^{-1}}{1 + a z^{-1}} . A phaser mixes the input with its output through M cascaded sections, y = \tfrac12 (x + A^M x), and modulates a with an LFO.

Proposition 4.5 — Phaser notches The all-pass section has unit gain at every frequency, and its phase decreases continuously from 0 at \omega = 0 to -\pi at \omega = \pi.

Consequently the phaser has a notch wherever the phase of A^M is an odd multiple of -\pi. For even M there are M/2 notches, not harmonically spaced, which move with a.

Proof. Since a is real, a + e^{-i\omega} = e^{-i\omega}(1 + a e^{i\omega}), the product of a unit-modulus factor and the conjugate of the denominator; so |A(e^{i\omega})| = 1.

At \omega = 0, A = 1; at \omega = \pi, A = -1. The phase is continuous in \omega, and its derivative is negative for |a| < 1 (the group delay of a stable all-pass is positive).

The total phase of A^M thus covers [-M\pi, 0], and 1 + e^{i M \varphi} = 0 exactly when M\varphi is an odd multiple of -\pi. ∎

Distortion

Definition 4.6 — Memoryless distortion A waveshaper applies a fixed nonlinear function to each sample, y(n) = f(x(n)): soft clipping f(x) = \tanh(\kappa x), hard clipping to [-1, 1], or a polynomial. Valve and transistor stages are often modelled by an asymmetric f, possibly between linear filters.

Proposition 4.7 — Harmonics and aliasing Let x(n) = A \cos(\omega_0 n).

  1. The output f(A \cos\theta), a 2\pi-periodic function of \theta = \omega_0 n, contains only harmonics k\omega_0; if f is odd, only odd harmonics.
  2. If f is a polynomial of degree d, the harmonics stop at d\,\omega_0; the Chebyshev polynomial T_k maps \cos\theta to \cos(k\theta).
  3. A harmonic above the Nyquist frequency aliases to |k\omega_0 - 2\pi m|, for the integer m that brings it into [0, \pi]; it is in general inharmonic.

Proof.

  1. An even, 2\pi-periodic function of \theta has a cosine series in k\theta. If f is odd, replacing \theta by \theta + \pi changes the sign of the output, which cancels every even coefficient.

  2. Powers \cos^j\theta with j \le d expand into \cos(k\theta), k \le j; and T_k(\cos\theta) = \cos k\theta is the definition of T_k.

  3. The samples of \cos(k\omega_0 n) do not change when 2\pi m is subtracted from the frequency. ∎

Since \tanh is not a polynomial, its harmonics never stop, and digital distortion is computed at an oversampled rate, then low-pass filtered and decimated.

Artificial reverberation

Definition 4.8 — Room impulse response and reverberation time A room impulse response contains the direct path, sparse early reflections (the first 50–80 ms) and a dense late reverberation whose energy decays exponentially. The reverberation time T_{60} is the time for that energy to decay by 60 dB.

Sabine’s formula estimates it from the volume V (m³) and the absorption area A = \sum_i S_i \alpha_i (m²), the sum of the wall areas S_i weighted by their absorption coefficients \alpha_i: T_{60} \approx 0.161\, \frac{V}{A} \ \text{seconds} .

For a 10 × 8 × 4 m room with \alpha = 0.2 everywhere, V = 320 m³ and A = 0.2 \times 304 = 60.8 m², so T_{60} \approx 0.85 \text{ s}.

Proposition 4.9 — Comb gain for a reverberation time A feedback comb of delay D decays by 60 dB in T_{60} seconds if and only if its gain is

Key result — comb gain for a reverberation time g = 10^{-3 D / (T_{60} f_s)}

Proof. Its impulse response equals g^j at n = jD, so the level drops by -20 \log_{10} g dB every D / f_s seconds. Requiring a drop of 60 dB in T_{60} seconds gives -20 \log_{10} g = 60 D / (T_{60} f_s). ∎

Proposition 4.10 — Schroeder all-pass The filter H(z) = (-g + z^{-D}) / (1 - g z^{-D}), with |g| < 1, has unit gain at every frequency, while its impulse response is a train of echoes every D samples.

Proof. On the unit circle, set u = e^{-i\omega D}; then |{-g} + u| = |u|\,|1 - g \bar u| = |1 - g u| since g is real, so the numerator and the denominator have equal modulus. ∎

Schroeder’s reverberator (1962) combines both: four parallel feedback combs with mutually prime delays of 30–45 ms, tuned by Proposition 4.9, then two short all-pass filters that multiply the echo density without colouring the spectrum.

Feedback delay networks and convolution with measured responses, the modern alternatives, are treated in ch. 11.

import numpy as np
from scipy.signal import lfilter, freqz

fs = 16000
# 1. Flanger at one instant: y = x + g x(n - D), D = 2 ms -> notches at odd multiples of 250 Hz
D, g = int(0.002 * fs), 0.9
f, Hc = freqz(np.r_[1, np.zeros(D - 1), g], worN=8192, fs=fs)
notch = f[1:-1][(np.abs(Hc[1:-1]) < np.abs(Hc[:-2])) & (np.abs(Hc[1:-1]) < np.abs(Hc[2:]))]
print("flanger notches (Hz):", np.round(notch[:4]))

# 2. Phaser: y = (x + A(z) x) / 2 with 4 first-order all-pass sections
a = -0.6
num, den = np.array([1.0]), np.array([1.0])
for _ in range(4):
    num, den = np.convolve(num, [a, 1]), np.convolve(den, [1, a])
f, A = freqz(num, den, worN=8192, fs=fs)
P = np.abs(1 + A) / 2
notch = f[1:-1][(P[1:-1] < P[:-2]) & (P[1:-1] < P[2:])]
print("all-pass |A| in [", np.abs(A).min().round(6), ",", np.abs(A).max().round(6), "]")
print("phaser notches (Hz):", np.round(notch))

# 3. Distortion: tanh soft clipping of a 500 Hz tone, harmonic levels
n = np.arange(fs)
y = np.tanh(4 * np.sin(2 * np.pi * 500 * n / fs))
Y = np.abs(np.fft.rfft(y * np.hanning(fs)))
lev = [20 * np.log10(Y[500 * k] / Y[500]) for k in range(2, 8)]
print("harmonics 2..7 (dB re fundamental):", np.round(lev, 1))

# 4. Schroeder reverberator: 4 parallel combs + 2 all-pass, target T60 = 1.5 s
T60 = 1.5
x = np.zeros(2 * fs); x[0] = 1.0
wet = np.zeros_like(x)
for ms in (29.7, 37.1, 41.1, 43.7):
    d = int(ms * fs / 1000)
    gc = 10 ** (-3 * d / (T60 * fs))          # -60 dB after T60 seconds
    wet += lfilter([1.0], np.r_[1, np.zeros(d - 1), -gc], x)
for ms, ga in ((5.0, 0.7), (1.7, 0.7)):
    d = int(ms * fs / 1000)
    wet = lfilter(np.r_[-ga, np.zeros(d - 1), 1], np.r_[1, np.zeros(d - 1), -ga], wet)
edc = 10 * np.log10(np.cumsum(wet[::-1] ** 2)[::-1] / np.sum(wet ** 2))  # Schroeder integration
i5, i35 = np.argmax(edc < -5), np.argmax(edc < -35)
print(f"measured T60 (from the -5 to -35 dB decay): {2 * (i35 - i5) / fs:.2f} s")

The flanger’s notches fall at 250, 750, 1250 and 1750 Hz (Proposition 4.2), and the four all-pass sections give 2 notches, at 525 and 2766 Hz.

The tanh distortion has odd harmonics only (−11.3, −18.8 and −25.7 dB for the 3rd, 5th and 7th; even ones below −190 dB). The reverberator decays in the target 1.50 s, measured on Schroeder’s backward integral (ch. 11).

Key takeaways — chapter 4

  • Comb filters have harmonically spaced notches or peaks; sweeping their delay gives flanging, longer modulated delays give chorus.
  • All-pass sections change only the phase; mixed with the dry signal, M of them give M/2 movable, inharmonic notches: the phaser.
  • A memoryless nonlinearity creates harmonics, odd ones only if it is odd; harmonics above Nyquist alias unless the effect runs oversampled.
  • Schroeder’s reverberator combines feedback combs tuned by g = 10^{-3D/(T_{60} f_s)} with all-pass diffusers of unit gain.

5. Time-scale, pitch and timbre modifications

Playing a recording faster raises its pitch: duration and frequency are coupled. This chapter decouples them, first in time (time-scale modification), then in pitch, then in timbre, by working on the STFT of ch. 1 and on the spectral envelope.

Resampling couples time and pitch

Proposition 5.1 — Resampling Playing a signal at the rate \beta f_s instead of f_s (equivalently, resampling it by 1/\beta) gives y(t) = x(\beta t) . Every frequency is multiplied by \beta and the duration is divided by \beta: substitute \beta t for t in \cos(2\pi f t).

A pitch shift by s semitones uses \beta = 2^{s/12}; four semitones (a major third) give \beta = 1.26. To keep the duration, the signal must first be stretched by \beta without changing its pitch.

Time-scale modification by overlap-add

Definition 5.2 — Overlap-add time-scale modification Frames are taken every R_a samples and overlap-added every R_s = \alpha R_a samples, which multiplies the duration by \alpha.

Plain overlap-add breaks the periodicity of the waveform at each frame junction. WSOLA shifts each analysis frame by up to \pm\Delta samples to maximise its cross-correlation with the natural continuation of the previous frame. PSOLA places the frames pitch-synchronously, which suits monophonic speech.

On polyphonic music no single shift aligns every component; the phase vocoder works per frequency bin instead.

The phase vocoder

Definition 5.3 — Phase vocoder Let \varphi(m, k) be the phase of the STFT with hop R_a at the bin frequency \omega_k = 2\pi k / N. Let \operatorname{princarg} reduce an angle to (-\pi, \pi].

The instantaneous frequency of bin k is estimated as \hat\omega(m, k) = \omega_k + \frac{1}{R_a}\, \operatorname{princarg}\big(\varphi(m, k) - \varphi(m - 1, k) - \omega_k R_a\big) . The synthesis phases advance at the synthesis hop: \psi(m, k) = \psi(m - 1, k) + R_s\, \hat\omega(m, k) . The modified STFT, with magnitude |X(m, k)| and phase \psi(m, k), is inverted by overlap-add every R_s samples.

Proposition 5.4 — Exactness for a stationary sinusoid Let x(n) = A\cos(\omega_0 n + \phi_0) and let bin k lie in the main lobe of \omega_0, with no other component nearby. If |\omega_0 - \omega_k|\, R_a < \pi, then \hat\omega(m, k) = \omega_0 exactly, up to the negligible leakage of the negative-frequency image. For the Hann window, whose main lobe has half-width 4\pi/N, the condition holds over the whole lobe when

Key result — phase vocoder hop for a Hann window R_a \le \frac{N}{4}

Proof. By Proposition 0.4, near \omega_0 the STFT of frame m is X(m, k) = \tfrac{A}{2}\, e^{i(\omega_0 m R_a + \phi_0)}\, W(\omega_k - \omega_0) . The window term does not depend on m, so the phase advances by exactly \omega_0 R_a between frames, modulo 2\pi.

Subtracting \omega_k R_a leaves (\omega_0 - \omega_k) R_a modulo 2\pi. When this lies in (-\pi, \pi), the function \operatorname{princarg} returns it unchanged. Dividing by R_a gives the offset to the bin frequency.

On the main lobe, |\omega_0 - \omega_k| < 4\pi / N, so R_a \le N/4 gives a product below \pi. ∎

Each bin is thus re-synthesised at its true frequency with a phase consistent at the new hop. The method still smears transients and adds a reverberant “phasiness”, because the phases of neighbouring bins of one partial drift apart. Phase locking (Laroche and Dolson, 1999) propagates the phase of each spectral peak and keeps the bins around it locked to it.

Pitch shifting and the spectral envelope

Definition 5.5 — Pitch shifting To shift the pitch by the factor \beta at constant duration, stretch the signal in time by \alpha = \beta with the phase vocoder, then resample it by 1/\beta (Proposition 5.1). The two duration changes cancel, and every frequency is multiplied by \beta.

This moves the spectral envelope along with the partials: the formants of a voice shift too, and a voice raised by an octave sounds like a cartoon character. Preserving timbre requires the source–filter view of Proposition 1.5.

Definition 5.6 — Source–filter model and envelope-preserving modifications Model each frame as X(\omega) = H(\omega)\, E(\omega): a smooth spectral envelope H (the formants, the timbre) times an excitation E (the partials, the pitch).

  • Envelope-preserving pitch shift: estimate H, divide it out, shift the pitch of E, multiply by the original H.
  • Formant shifting: multiply by the warped envelope H(\omega / \gamma) instead, which changes the perceived size of the speaker.
  • Envelope transfer (cross-synthesis): multiply the excitation of one sound by the envelope of another.

The envelope is estimated by cepstral liftering (Proposition 1.5) or by linear prediction (LPC), which fits an all-pole filter G / |A(e^{i\omega})| by solving the Yule–Walker equations (ch. 11).

import numpy as np

fs, N, Ra = 16000, 1024, 256                  # Hann window, analysis hop N/4
w = np.hanning(N + 1)[:N]
omega = 2 * np.pi * np.arange(N // 2 + 1) / N  # bin centre frequencies (rad/sample)
princarg = lambda p: (p + np.pi) % (2 * np.pi) - np.pi

def phase_vocoder(x, alpha):
    """Time-scale modification by a factor alpha (> 1 = slower), pitch unchanged."""
    Rs = int(round(alpha * Ra))
    frames = [np.fft.rfft(x[i:i + N] * w) for i in range(0, len(x) - N, Ra)]
    y = np.zeros(Rs * len(frames) + N); norm = np.zeros_like(y)
    psi = np.angle(frames[0])
    for m, X in enumerate(frames):
        if m > 0:
            dphi = np.angle(X) - np.angle(frames[m - 1]) - omega * Ra
            inst = omega + princarg(dphi) / Ra       # instantaneous frequency per bin
            psi = psi + Rs * inst                    # phase propagation at the synthesis hop
        frame = np.fft.irfft(np.abs(X) * np.exp(1j * psi), n=N) * w
        y[m * Rs:m * Rs + N] += frame; norm[m * Rs:m * Rs + N] += w ** 2
    return y / np.maximum(norm, 1e-3)

def peaks(x, k=2):
    X = np.abs(np.fft.rfft(x * np.hanning(len(x)), 8 * len(x)))
    f = np.fft.rfftfreq(8 * len(x), 1 / fs)
    loc = [i for i in range(1, len(X) - 1) if X[i] >= X[i - 1] and X[i] > X[i + 1]]
    return np.sort(f[sorted(loc, key=lambda i: -X[i])[:k]]).round(1)

t = np.arange(fs) / fs                             # 1 s of a two-note chord
x = np.sin(2 * np.pi * 440 * t) + 0.5 * np.sin(2 * np.pi * 660 * t + 1)
y = phase_vocoder(x, 1.5)
print(f"duration {len(x) / fs:.2f} s -> {len(y) / fs:.2f} s; peaks {peaks(x)} -> {peaks(y[N:-N])} Hz")

beta = 2 ** (4 / 12)                               # pitch shift by a major third
z = phase_vocoder(x, beta)
z = np.interp(np.arange(0, len(z) - 1, beta), np.arange(len(z)), z)   # resample by 1/beta
print(f"pitch shift: duration {len(z) / fs:.2f} s, peaks {peaks(z[N:-N])} Hz "
      f"(expected {np.round(440 * beta, 1)} and {np.round(660 * beta, 1)})")

The stretched chord lasts 1.48 s (1.5 s minus the edge frames) with its peaks still at 440 and 660 Hz. The pitch-shifted version lasts 1.00 s with peaks at 554.4 and 831.5 Hz, as predicted.

The second block estimates the envelope of a synthetic vowel (formants at 700 and 1200 Hz, pitch 120 Hz) both ways.

import numpy as np
from scipy.signal import lfilter, freqz
from scipy.linalg import solve_toeplitz

fs, f0 = 16000, 120
# Source-filter vowel: impulse train through two resonances (formants at 700 and 1200 Hz)
poles = []
for F, B in ((700, 80), (1200, 100)):
    r = np.exp(-np.pi * B / fs)
    poles += [r * np.exp(2j * np.pi * F / fs), r * np.exp(-2j * np.pi * F / fs)]
a_true = np.real(np.poly(poles))
e = np.zeros(fs // 2); e[::fs // f0] = 1.0
x = lfilter([1.0], a_true, e)

seg = x[2000:2000 + 1024] * np.hanning(1024)
# 1. Cepstral envelope: keep quefrencies below the pitch period (fs/f0 = 133 samples)
logS = np.log(np.abs(np.fft.fft(seg, 4096)) + 1e-9)
c = np.fft.ifft(logS).real
lifter = np.zeros(4096); lifter[:50] = 1; lifter[-49:] = 1
env_cep = np.exp(np.fft.fft(c * lifter).real[:2049])
# 2. LPC envelope of order 8 (autocorrelation method, Yule-Walker equations)
r = np.correlate(seg, seg, "full")[1023:1023 + 9]
a = solve_toeplitz(r[:8], -r[1:9])
f, Hl = freqz([1.0], np.r_[1, a], worN=2049, fs=fs)
for name, env in (("cepstrum", env_cep), ("LPC", np.abs(Hl))):
    pk = [i for i in range(1, 600) if env[i] > env[i - 1] and env[i] > env[i + 1]]
    print(f"{name:8s} envelope peaks below 2400 Hz: {np.round(f[pk])} Hz")

The cepstral envelope peaks at 726 and 1163 Hz and the LPC envelope at 711 and 1199 Hz. A shorter lifter (20 coefficients) smooths the two formants into a single peak, the usual trade-off between smoothness and detail.

Key takeaways — chapter 5

  • Resampling scales time and frequency together; pitch shifting is a time stretch followed by resampling.
  • The phase vocoder re-synthesises each bin at its instantaneous frequency; it is exact for stationary sinusoids when R_a \le N/4 with a Hann window.
  • Phase locking reduces phasiness; WSOLA and PSOLA are time-domain alternatives for speech.
  • Timbre lives in the spectral envelope, estimated by cepstral liftering or linear prediction; separating it from the excitation preserves formants or transfers timbre.

6. Spatial audio: binaural, transaural and wave field synthesis

3D rendering makes a listener hear a sound at a chosen position. Perceptual approaches reproduce the signals at the two eardrums; physical approaches reproduce the sound field over a whole area. This chapter derives both, with their limits.

Localisation cues

Definition 6.1 — Interaural cues A source at azimuth \theta reaches the two ears with an interaural time difference (ITD) and an interaural level difference (ILD). For a rigid spherical head of radius a and a distant source, Woodworth’s formula gives \mathrm{ITD}(\theta) = \frac{a}{c}\, (\theta + \sin\theta), \qquad 0 \le \theta \le \pi / 2, with c \approx 343 m/s.

With a = 8.75 cm the ITD reaches 0.66 ms at 90°. The ITD dominates below about 1.5 kHz, and the ILD, caused by head shadowing, above it (the duplex theory). Both cues are equal for all directions on a cone of confusion; the spectral filtering of the pinnae resolves front–back and elevation ambiguities.

Definition 6.2 — HRTF and binaural synthesis The head-related transfer function H_{L}(f, \theta, \phi) is the ratio of the sound pressure at the left eardrum (or at the blocked ear canal) to the free-field pressure at the centre of the head with the listener absent, for a source at azimuth \theta and elevation \phi; similarly H_R. Their inverse transforms are head-related impulse responses (HRIRs).

Binaural synthesis renders a mono source s at (\theta, \phi) over headphones by filtering it with the two HRIRs: y_L = h_L^{\theta, \phi} * s, \qquad y_R = h_R^{\theta, \phi} * s .

HRTFs are measured on a grid of directions, on dummy heads such as KEMAR (Gardner and Martin, 1995) or on people (CIPIC, Algazi et al., 2001). Non-individual HRTFs cause front–back confusions and in-head localisation; head tracking reduces both.

Transaural reproduction

Transaural rendering plays binaural signals over two loudspeakers. Each ear hears both loudspeakers, so the crosstalk must be cancelled.

Proposition 6.3 — Crosstalk cancellation At frequency f, let \mathbf{G}(f) be the 2 \times 2 matrix of transfer functions from the loudspeakers to the ears, and \mathbf{b} the desired binaural signals. The loudspeaker feeds \mathbf{C}\mathbf{b} give the ear signals \mathbf{G}\mathbf{C}\mathbf{b}.

They equal \mathbf{b} when \mathbf{C} = \mathbf{G}^{-1}. The regularised filter of Kirkeby et al. (1998) limits the loudspeaker gains where \mathbf{G} is ill-conditioned: \mathbf{C}_\beta = (\mathbf{G}^H \mathbf{G} + \beta \mathbf{I})^{-1} \mathbf{G}^H . In the symmetric case, with ipsilateral and contralateral paths G_i and G_c, \mathbf{G}^{-1} = \frac{1}{G_i^2 - G_c^2} \begin{pmatrix} G_i & -G_c \\ -G_c & G_i \end{pmatrix}, which is singular whenever G_c = \pm G_i.

Proof. The regularised filter is the Tikhonov solution: for every \mathbf{b}, the feed \mathbf{u} = \mathbf{C}_\beta \mathbf{b} minimises \|\mathbf{G}\mathbf{u} - \mathbf{b}\|^2 + \beta\, \|\mathbf{u}\|^2 . The inverse of a 2 \times 2 matrix is its adjugate divided by its determinant, here G_i^2 - G_c^2. ∎

In free field, G_c \approx G_i\, e^{-2i\pi f \Delta / c}, where \Delta is the path difference between the far and the near loudspeaker. The inverse then blows up at low frequency and at the multiples of c / 2\Delta. The cancellation also holds only in a small “sweet spot” around the assumed head position.

Wave field synthesis

Wave field synthesis (Berkhout, de Vries and Vogel, 1993) reproduces a sound field inside a region by Huygens’ principle: a wavefront can be re-emitted by secondary sources placed on a surface.

Theorem 6.4 — Kirchhoff–Helmholtz integral Let P satisfy the Helmholtz equation \Delta P + k^2 P = 0 in a bounded region V with smooth boundary \partial V and outward normal \mathbf{n}.

Let G be the free-field Green’s function, with r = \|\mathbf{x} - \mathbf{x}_0\|: G(\mathbf{x} \mid \mathbf{x}_0) = \frac{e^{-ik r}}{4\pi r} . Then for \mathbf{x} \in V, P(\mathbf{x}) = \oint_{\partial V} \Big[ G(\mathbf{x} \mid \mathbf{x}_0)\, \frac{\partial P}{\partial n}(\mathbf{x}_0) - P(\mathbf{x}_0)\, \frac{\partial G}{\partial n}(\mathbf{x} \mid \mathbf{x}_0) \Big]\, dS(\mathbf{x}_0) . The field inside V is thus produced by monopoles (first term) and dipoles (second term) on \partial V, driven by the boundary values of the field.

Proof. G satisfies \Delta G + k^2 G = -\delta_{\mathbf{x}}. Green’s second identity on V gives \int_V (G\, \Delta P - P\, \Delta G)\, dV = \oint_{\partial V} \Big( G\, \frac{\partial P}{\partial n} - P\, \frac{\partial G}{\partial n} \Big)\, dS . On the left, \Delta P = -k^2 P and \Delta G = -k^2 G - \delta_{\mathbf{x}}, so the integrand reduces to P\, \delta_{\mathbf{x}} and the integral to P(\mathbf{x}). ∎

For a plane boundary, choosing a Green’s function with zero normal derivative on the plane removes the dipoles and doubles the monopoles: this is the Rayleigh I integral. A virtual source behind the plane is rendered in the half-space in front by monopoles with driving function -2\, \partial P / \partial n, the normal now pointing into the listening region. WFS samples this layer with a line of loudspeakers.

Proposition 6.5 — Spatial aliasing Loudspeakers spaced \Delta x apart on a line, rendering a plane wave whose direction makes the angle \theta with the normal of the array, reproduce it without spatial aliasing only below

Key result — WFS aliasing frequency f_{\mathrm{al}}(\theta) = \frac{c}{\Delta x\, (1 + |\sin\theta|)}

Over all directions the safe bound is c / 2\Delta x.

Proof. The driving signals vary along the array as e^{-i k x \sin\theta}. Sampling them every \Delta x replicates their spatial spectrum at the wavenumbers k\sin\theta + 2\pi m / \Delta x.

A replica with |k_x| < k is a propagating plane wave in another direction (a grating lobe). The nearest replica, m = \pm 1, propagates when 2\pi / \Delta x - k|\sin\theta| < k, that is when f > f_{\mathrm{al}}(\theta). ∎

With 15 cm between loudspeakers, waves arriving at 45° alias above 1339 Hz.

import numpy as np

c, a = 343.0, 0.0875                                  # speed of sound (m/s), head radius (m)
# 1. Woodworth's interaural time difference
for deg in (0, 30, 60, 90):
    th = np.radians(deg)
    print(f"azimuth {deg:2d} deg: ITD = {1e3 * a / c * (th + np.sin(th)):.3f} ms")

# 2. Crosstalk cancellation, free-field model: loudspeakers at +-30 deg, 2 m; ears at +-a
ears = np.array([[-a, 0.0], [a, 0.0]])
spk = 2.0 * np.array([[-np.sin(np.pi / 6), np.cos(np.pi / 6)], [np.sin(np.pi / 6), np.cos(np.pi / 6)]])
dist = np.linalg.norm(ears[:, None, :] - spk[None, :, :], axis=2)    # ear x loudspeaker
def G(f):                                            # acoustic transfer matrix (point sources)
    k = 2 * np.pi * f / c
    return np.exp(-1j * k * dist) / (4 * np.pi * dist)
delta = dist[0, 1] - dist[0, 0]                       # contralateral minus ipsilateral path
print(f"path difference {100 * delta:.2f} cm: G is singular at multiples of c/(2 delta) = {c / (2 * delta):.0f} Hz")
for f in (100, 1000, 1900, 3000):
    Gf = G(f)
    beta = 1e-3 * np.linalg.norm(Gf, 2) ** 2           # Tikhonov regularisation
    Cf = np.linalg.solve(Gf.conj().T @ Gf + beta * np.eye(2), Gf.conj().T)
    E = Gf @ Cf                                       # ear signals = E @ binaural signals
    sep = 20 * np.log10(np.abs(E[0, 0]) / np.abs(E[1, 0]))
    effort = 20 * np.log10(np.linalg.norm(Cf, 2) * np.linalg.norm(Gf, 2))
    print(f"f = {f:4d} Hz: cond(G) = {np.linalg.cond(Gf):6.1f}, separation {sep:5.1f} dB, "
          f"filter gain {effort:5.1f} dB")

# 3. Wave field synthesis of a plane wave with a line of monopoles (Rayleigh I, 2.5D)
dx = 0.15                                             # loudspeaker spacing (m)
xs = np.arange(-4, 4 + 1e-9, dx)
grid = np.array([(u, v) for u in np.linspace(-0.5, 0.5, 11) for v in np.linspace(1, 2, 11)])
r = np.linalg.norm(grid[:, None, :] - np.c_[xs, 0 * xs][None], axis=2)
for deg in (0, 45):
    th = np.radians(deg)
    print(f"plane wave at {deg} deg: aliasing above c / (dx (1 + sin)) = {c / (dx * (1 + np.sin(th))):.0f} Hz")
    for f in (500, 1000, 2000, 4000):
        k = 2 * np.pi * f / c
        drive = np.exp(-1j * k * xs * np.sin(th))           # delays of the incoming wave
        p = (drive * np.exp(-1j * k * r) / (4 * np.pi * r)).sum(1)
        target = np.exp(-1j * k * (grid[:, 0] * np.sin(th) + grid[:, 1] * np.cos(th)))
        gain = np.vdot(target, p) / np.vdot(target, target)   # best complex scale
        err = np.linalg.norm(p - gain * target) / np.linalg.norm(gain * target)
        print(f"   f = {f:4d} Hz: relative error of the synthesised field {err:.2f}")

The ITDs are 0.26, 0.49 and 0.66 ms at 30°, 60° and 90°. The crosstalk canceller separates the ears by 90 and 80 dB at 1000 and 3000 Hz, but only by 24 and 17 dB at 100 and 1900 Hz, near its singular frequencies, despite 20–23 dB of extra gain.

The array reproduces the frontal wave with a relative error of 0.12–0.18 up to 2000 Hz, and 1.60 at 4000 Hz, beyond its aliasing frequency (2287 Hz). At 45° the error jumps from 0.16 at 1000 Hz to 0.89 at 2000 Hz.

The residual of about 12 % at low frequency is the 2.5D amplitude error, not an effect of the array length. A line of point sources makes the wave decay as 1/\sqrt{r}, by a factor \sqrt2 between 1 and 2 m, and a 128 m array leaves the error at 0.11.

Key takeaways — chapter 6

  • Interaural time and level differences locate sources in azimuth; pinna filtering, captured by HRTFs, adds elevation and front–back cues.
  • Binaural synthesis convolves a source with a pair of HRIRs; transaural rendering adds a crosstalk canceller, ill-conditioned at low frequency and at multiples of c / 2\Delta.
  • The Kirchhoff–Helmholtz integral reproduces a field inside a region from monopoles and dipoles on its boundary; WFS keeps the monopoles (Rayleigh I).
  • A loudspeaker spacing \Delta x limits WFS to frequencies below c / (\Delta x (1 + |\sin\theta|)).

7. Source separation I: linear and convolutive mixtures

Source separation, or demixing, recovers individual sources from recordings of their mixture. This chapter treats mixtures with at least as many microphones as sources, which can be inverted once identified blindly from source statistics.

Mixing models

Definition 7.1 — Mixing models Let J sources s_j be recorded by M microphones x_i.

  • Instantaneous (linear) mixture: \mathbf{x}(n) = \mathbf{A}\, \mathbf{s}(n), with an M \times J mixing matrix \mathbf{A}; studio panning produces such mixtures.
  • Anechoic mixture: x_i(n) = \sum_j a_{ij}\, s_j(n - \delta_{ij}), with gains and delays only.
  • Convolutive mixture: x_i(n) = \sum_j (a_{ij} * s_j)(n), with room impulse responses a_{ij}.

The mixture is determined when M = J, overdetermined when M > J and underdetermined when M < J (ch. 8). The contribution of source j to all microphones is its spatial image.

Proposition 7.2 — Ambiguities For any permutation matrix \mathbf{P} and invertible diagonal matrix \mathbf{D}, the mixing matrix and sources \mathbf{A}' = \mathbf{A}\mathbf{D}^{-1}\mathbf{P}^{-1}, \qquad \mathbf{s}' = \mathbf{P}\mathbf{D}\mathbf{s} produce the same mixture as (\mathbf{A}, \mathbf{s}). Blind separation can therefore recover the sources only up to order and scale.

Independent component analysis

The blind assumption is that the sources are mutually independent. Second-order statistics alone do not suffice.

Proposition 7.3 — Whitening leaves a rotation Let \mathbf{x} = \mathbf{A}\mathbf{s} with \mathbf{A} square invertible and uncorrelated sources of unit variance. Let \mathbf{z} = \mathbf{B}\mathbf{x} be white, \mathbb{E}[\mathbf{z}\mathbf{z}^\top] = \mathbf{I}. Then \mathbf{z} = \mathbf{Q}\mathbf{s} with \mathbf{Q} = \mathbf{B}\mathbf{A} orthogonal.

If the sources are Gaussian, \mathbf{Q}\mathbf{s} has the same distribution for every orthogonal \mathbf{Q}, so no method can identify the rotation.

Proof. Since the sources are uncorrelated with unit variance, \mathbb{E}[\mathbf{z}\mathbf{z}^\top] = \mathbf{Q}\, \mathbb{E}[\mathbf{s}\mathbf{s}^\top]\, \mathbf{Q}^\top = \mathbf{Q}\mathbf{Q}^\top = \mathbf{I} . A standard Gaussian vector is invariant under orthogonal maps. ∎

Theorem 7.4 — Identifiability (Comon, 1994) Let \mathbf{x} = \mathbf{A}\mathbf{s} with \mathbf{A} invertible and independent sources, at most one of them Gaussian. If \mathbf{y} = \mathbf{W}\mathbf{x}, with \mathbf{W} invertible, has independent components, then \mathbf{W}\mathbf{A} = \mathbf{P}\mathbf{D} for a permutation \mathbf{P} and an invertible diagonal \mathbf{D}. The proof rests on the Darmois–Skitovich theorem; see Comon (1994).

Definition 7.5 — Contrasts and FastICA ICA maximises a measure of non-Gaussianity of the outputs, called a contrast: negentropy, or for a unit-variance output the kurtosis \kappa(y) = \mathbb{E}[y^4] - 3. Speech and music are super-Gaussian (\kappa > 0).

On whitened data, FastICA (Hyvärinen and Oja, 2000) iterates, for one unit vector \mathbf{w}, \mathbf{w} \leftarrow \mathbb{E}\big[\mathbf{z}\, (\mathbf{w}^\top \mathbf{z})^3\big] - 3\mathbf{w}, \qquad \mathbf{w} \leftarrow \mathbf{w} / \|\mathbf{w}\|, and extracts further components orthogonally to the previous ones.

Proposition 7.6 — FastICA converges cubically Assume that every source has a non-zero kurtosis. Write \mathbf{q} = \mathbf{Q}^\top \mathbf{w}, the coordinates of \mathbf{w} in the source basis. One iteration of Definition 7.5 maps each coordinate to q_i \mapsto \kappa(s_i)\, q_i^3, before normalisation. From almost every starting point, \mathbf{q} converges to a signed unit vector \pm \mathbf{e}_i, that is, \mathbf{w}^\top \mathbf{z} = \pm s_i, and the convergence is cubic.

Proof. Since \mathbf{z} = \mathbf{Q}\mathbf{s}, the output is \mathbf{q}^\top \mathbf{s} and the update in source coordinates is \mathbf{q} \leftarrow \mathbb{E}\big[\mathbf{s}\, (\mathbf{q}^\top \mathbf{s})^3\big] - 3\mathbf{q} . Expanding the cube, independence, zero means and unit variances give \mathbb{E}\Big[s_i \Big(\sum_j q_j s_j\Big)^3\Big] = q_i^3\, \mathbb{E}[s_i^4] + 3 q_i \sum_{j \ne i} q_j^2 = q_i^3\, (\mathbb{E}[s_i^4] - 3) + 3 q_i\, \|\mathbf{q}\|^2 . With \|\mathbf{q}\| = 1, subtracting 3 q_i leaves \kappa(s_i)\, q_i^3.

Each ratio q_j / q_i is therefore cubed and multiplied by \kappa(s_j) / \kappa(s_i) at every step, normalisation included. The coordinate with the largest |\kappa(s_i)|^{1/2} |q_i| thus dominates, and the other ratios go to zero cubically. ∎

Maximum-likelihood ICA, which updates the whole demixing matrix at once, is presented in ch. 11.

Convolutive mixtures in the frequency domain

Proposition 7.7 — Narrowband approximation If the mixing filters are short compared with the STFT window, the convolutive mixture becomes an instantaneous mixture in each frequency bin: \mathbf{x}(m, k) \approx \mathbf{A}(k)\, \mathbf{s}(m, k), where \mathbf{A}(k) holds the frequency responses of the filters. The relation is exact for circular convolution (Proposition 0.2); for linear convolution the error comes from the samples near the frame edges, a fraction of the frame of the order of the filter length divided by N.

Frequency-domain ICA separates each bin with complex-valued ICA (Smaragdis, 1998). Proposition 7.2 now applies per bin. Each bin returns the sources in its own order (the permutation problem), which is resolved by aligning the bins on the correlation of the source envelopes across frequencies or on the directions of arrival.

Each bin also has its own scale, which the minimal distortion principle fixes: \mathbf{W}(k) \leftarrow \mathrm{diag}\big(\mathbf{W}(k)^{-1}\big)\, \mathbf{W}(k) . Each output is then the spatial image of its source on one microphone.

Measuring separation quality

Definition 7.8 — SDR, SIR and SAR Following Vincent, Gribonval and Févotte (2006), decompose an estimate as \hat s_j = s_{\mathrm{target}} + e_{\mathrm{interf}} + e_{\mathrm{artif}}, where s_{\mathrm{target}} is its orthogonal projection on the true source s_j, s_{\mathrm{target}} + e_{\mathrm{interf}} its projection on the span of all the sources, and e_{\mathrm{artif}} the remainder. Then \mathrm{SDR} = 10 \log_{10} \frac{\|s_{\mathrm{target}}\|^2}{\|e_{\mathrm{interf}} + e_{\mathrm{artif}}\|^2}, \qquad \mathrm{SIR} = 10 \log_{10} \frac{\|s_{\mathrm{target}}\|^2}{\|e_{\mathrm{interf}}\|^2}, and the SAR compares s_{\mathrm{target}} + e_{\mathrm{interf}} with e_{\mathrm{artif}} in the same way, all in decibels.

The code mixes a sawtooth and a modulated Laplacian noise with a fixed 2 \times 2 matrix, compares whitening alone with FastICA, then measures the narrowband error for a 32 ms room-like filter.

import numpy as np
from sklearn.decomposition import FastICA, PCA
from scipy.signal import lfilter

rng = np.random.default_rng(0)
fs = 8000
t = np.arange(2 * fs) / fs
s1 = 2 * ((110 * t) % 1) - 1                                   # sawtooth (sub-Gaussian)
s2 = rng.laplace(size=len(t)) * (0.6 + 0.4 * np.sin(2 * np.pi * 3 * t))   # speech-like, super-Gaussian
S = np.c_[s1, s2] / np.c_[s1, s2].std(0)
A = np.array([[1.0, 0.6], [0.5, 1.0]])
X = S @ A.T                                                     # instantaneous mixture x = A s

def sir_db(Y, S):
    """Signal-to-interference ratio after resolving permutation and scale."""
    C = np.abs(np.corrcoef(Y.T, S.T)[:2, 2:])                    # |corr(y_i, s_j)|
    perm = [0, 1] if C[0, 0] + C[1, 1] > C[0, 1] + C[1, 0] else [1, 0]
    out = []
    for i, j in enumerate(perm):
        G = np.linalg.lstsq(S, Y[:, i], rcond=None)[0]         # y_i = G_j s_j + G_other s_other
        out.append(20 * np.log10(abs(G[j]) / abs(G[1 - j])))
    return np.round(out, 1)

print("mixtures      SIR (dB):", sir_db(X, S))
print("PCA whitening SIR (dB):", sir_db(PCA(2, whiten=True).fit_transform(X), S))
print("FastICA       SIR (dB):", sir_db(FastICA(2, whiten="unit-variance", random_state=0).fit_transform(X), S))

# Narrowband approximation of a convolutive mixture: X(m,k) ~ A(k) S(m,k)?
h = rng.standard_normal(256) * np.exp(-np.arange(256) / 40)   # a 32 ms room-like filter
s = rng.standard_normal(4 * fs)
xconv = lfilter(h, [1.0], s)
for N in (256, 1024, 4096):
    w = np.hanning(N)
    fr = lambda z: np.array([np.fft.rfft(z[i:i + N] * w) for i in range(N, len(z) - N, N // 4)])
    Xs, Ss = fr(xconv), fr(s)
    Hk = np.fft.rfft(h, N)
    err = np.linalg.norm(Xs - Hk * Ss) / np.linalg.norm(Xs)
    print(f"window {N:4d} samples: relative error of X = H S per bin: {err:.2f}")

The mixtures have SIRs of 4.4 and 6.0 dB, whitening alone 0.4 dB (the residual rotation of Proposition 7.3), FastICA 42.5 and 44.1 dB. The narrowband error falls from 0.36 to 0.10 and 0.02 for windows of 256, 1024 and 4096 samples.

Key takeaways — chapter 7

  • Mixtures are instantaneous, anechoic or convolutive, and determined, over- or underdetermined; sources are recovered only up to permutation and scale.
  • Whitening leaves an unknown rotation; independence and non-Gaussianity identify it (Comon’s theorem).
  • FastICA maximises kurtosis by a cubically convergent fixed point.
  • Convolutive mixtures become per-bin instantaneous mixtures, at the price of per-bin permutation and scale ambiguities; SDR, SIR and SAR measure the result.

8. Source separation II: underdetermined and sparse models, DUET

With fewer microphones than sources, the mixing matrix has no inverse and independence is not enough. The extra assumption that makes separation possible is sparsity: in the time–frequency plane, few sources are active at each point.

Sparsity in the time–frequency plane

Definition 8.1 — W-disjoint orthogonality Sources are W-disjoint orthogonal (Jourjine, Rickard and Yilmaz, 2000) when, for the STFT with window W, at most one of them is non-zero at each time–frequency point: S_j(m, k)\, S_l(m, k) = 0 \quad \text{for all } j \ne l \text{ and all } (m, k) . Speech approximately satisfies this: harmonics of different voices rarely overlap, and voices pause.

Then each time–frequency point belongs to one source, and separation reduces to classifying points and masking. A softer version of the assumption is a sparse prior: each coefficient follows a heavy-tailed density, such as the Laplacian, whose maximum a posteriori estimate penalises the ℓ1 norm.

Proposition 8.2 — ℓ1 recovery activates at most M sources Let \mathbf{A} be a real M \times J mixing matrix with M < J, known, and \mathbf{x} = \mathbf{A}\mathbf{s} the real coefficients of one time–frequency point. The problem \min_{\mathbf{s}} \|\mathbf{s}\|_1 \quad \text{subject to} \quad \mathbf{A}\mathbf{s} = \mathbf{x} has a solution with at most M non-zero entries. With two microphones, at most two sources are active at each point.

Proof. Write \mathbf{s} = \mathbf{u} - \mathbf{v} with \mathbf{u}, \mathbf{v} \ge 0. The problem becomes the linear programme of minimising \mathbf{1}^\top(\mathbf{u} + \mathbf{v}) under the M equality constraints \mathbf{A}(\mathbf{u} - \mathbf{v}) = \mathbf{x}.

Its objective is bounded below by 0, so an optimum is attained at a vertex of the feasible polyhedron. A vertex is a basic solution, with at most M non-zero variables among the 2J. ∎

For complex STFT coefficients the same problem is a second-order cone programme. In practice \mathbf{A} is unknown and must first be estimated, which is what DUET does from the geometry of anechoic mixtures.

DUET

Proposition 8.3 — Mixing parameters from one time–frequency point Consider two microphones and an anechoic mixture, under the narrowband approximation (Proposition 7.7): X_1(m, k) = \sum_j S_j(m, k), \qquad X_2(m, k) = \sum_j a_j\, e^{-i\omega_k \delta_j}\, S_j(m, k) . At a point where only source j is active, the ratio R = X_2 / X_1 gives its attenuation and its delay, provided |\omega_k \delta_j| < \pi:

Key result — DUET mixing parameters a_j = |R|, \qquad \delta_j = -\frac{\arg R}{\omega_k}

Proof. With a single active source, R = a_j\, e^{-i\omega_k \delta_j} exactly. Its modulus is a_j > 0, and its argument is -\omega_k \delta_j modulo 2\pi.

That argument determines \delta_j uniquely when \omega_k \delta_j lies in (-\pi, \pi). ∎

Algorithm 8.4 — DUET (Yilmaz and Rickard, 2004)

  1. Compute the STFTs X_1, X_2 and, at each point, the ratio R, the symmetric attenuation \alpha = |R| - 1/|R| and the delay \delta = -\arg R / \omega_k.

  2. Build a two-dimensional histogram of (\alpha, \delta) weighted by |X_1 X_2|^p\, \omega_k^q, often with p = 1 and q = 0, and locate its J peaks.

    Peak j gives (\alpha_j, \delta_j), and the attenuation a_j solves a - 1/a = \alpha_j.

  3. Assign each point to the source j that minimises the residual |a_j e^{-i\omega_k \delta_j} X_1 - X_2|^2 / (1 + a_j^2).

  4. On its mask, estimate source j by the least-squares combination of the two channels, \hat S_j = \frac{X_1 + a_j\, e^{i\omega_k \delta_j} X_2}{1 + a_j^2}, set it to zero elsewhere, and invert the STFT.

The symmetric attenuation treats the two microphones alike: swapping them changes the sign of \alpha. Steps 3 and 4 are maximum-likelihood decisions under white Gaussian noise on both channels.

Proposition 8.5 — Microphone spacing The delays are identified without phase wrapping at all frequencies up to the Nyquist frequency if and only if |\delta_j| < 1 sample. For microphones d metres apart, |\delta_j| \le d f_s / c, so the condition holds for every direction when d < \frac{c}{f_s}, which is 2.1 cm at 16 kHz. This follows from Proposition 8.3 with \omega_k up to \pi.

import numpy as np
from scipy.signal import stft, istft
from sklearn.cluster import KMeans

fs, rng = 16000, np.random.default_rng(0)
t = np.arange(3 * fs) / fs

def voice(f0, rate):
    """Harmonic source with vibrato and random syllable-like on/off envelope."""
    f = f0 * (1 + 0.02 * np.sin(2 * np.pi * 5 * t))
    x = sum(np.sin(2 * np.pi * k * np.cumsum(f) / fs) / k for k in range(1, 16) if k * f0 < 7000)
    gates = np.repeat(rng.random(int(3 * rate) + 1) < 0.6, int(fs / rate))[:len(t)]
    env = np.convolve(gates.astype(float), np.hanning(800) / 400, "same")
    return x * env

src = [voice(f0, r) for f0, r in ((110, 4), (175, 5), (260, 6))]
a_true, d_true = (0.6, 1.0, 1.5), (-0.7, 0.0, 0.6)          # attenuations and delays (samples)
omega = 2 * np.pi * np.fft.rfftfreq(len(t))
x1 = sum(src)
x2 = sum(np.fft.irfft(a * np.fft.rfft(s) * np.exp(-1j * omega * d), len(t))
         for s, a, d in zip(src, a_true, d_true))

N = 1024
_, _, X1 = stft(x1, nperseg=N); _, _, X2 = stft(x2, nperseg=N)
w = 2 * np.pi * np.arange(X1.shape[0])[:, None] / N            # rad/sample per bin
keep = (np.abs(X1) > 1e-3 * np.abs(X1).max())
keep[0] = False                                                # DC carries no delay information
R = X2[keep] / X1[keep]
alpha = np.abs(R) - 1 / np.abs(R)                              # symmetric attenuation
delta = -np.angle(R) / np.broadcast_to(w, X1.shape)[keep]
weight = (np.abs(X1[keep] * X2[keep]))                         # DUET weighting, p = 1, q = 0
feats = np.c_[alpha, delta]
km = KMeans(3, n_init=10, random_state=0).fit(feats, sample_weight=weight)
for c in km.cluster_centers_[np.argsort(km.cluster_centers_[:, 1])]:
    a_hat = (c[0] + np.sqrt(c[0] ** 2 + 4)) / 2                # invert alpha = a - 1/a
    print(f"estimated attenuation {a_hat:.2f}, delay {c[1]:+.2f} samples")

centres = km.cluster_centers_
a_est = (centres[:, 0] + np.sqrt(centres[:, 0] ** 2 + 4)) / 2
cost = [np.abs(a_est[j] * np.exp(-1j * w * centres[j, 1]) * X1 - X2) ** 2 / (1 + a_est[j] ** 2)
        for j in range(3)]                                     # residual if only source j were active
label = np.argmin(cost, axis=0)

def sdr(est, ref):
    g = est @ ref / (ref @ ref)
    return 10 * np.log10(np.sum((g * ref) ** 2) / np.sum((est - g * ref) ** 2))
for j in np.argsort(centres[:, 1]):
    S = (X1 + a_est[j] * np.exp(1j * w * centres[j, 1]) * X2) / (1 + a_est[j] ** 2)
    est = istft(np.where(label == j, S, 0), nperseg=N)[1][:len(t)]
    jt = np.argmin([abs(a_est[j] - a) for a in a_true]); ref = src[jt]
    print(f"source {jt + 1}: SDR of the mixture {sdr(x1, ref):5.1f} dB -> after DUET {sdr(est, ref):5.1f} dB")

Three harmonic “voices” (110, 175 and 260 Hz, with vibrato and random pauses) are mixed onto two channels. The weighted clustering, used here instead of histogram peak picking, recovers the attenuations 0.61, 1.02, 1.48 and the delays −0.76, −0.02, +0.63 samples (true: 0.6, 1.0, 1.5 and −0.7, 0, 0.6).

The masks raise the SDRs from −4.6, −3.1 and −1.6 dB in the mixture to 14.7, 10.7 and 14.9 dB.

Soft masks and the Wiener filter

Proposition 8.6 — Wiener filtering Let X = \sum_j S_j at one time–frequency point, with independent, zero-mean, circular complex Gaussian sources of variances v_j. The minimum mean squared error estimate of S_j is \hat S_j = \mathbb{E}[S_j \mid X] = \frac{v_j}{\sum_l v_l}\, X .

Proof. (S_j, X) is jointly Gaussian with zero mean, so \mathbb{E}[S_j \mid X] is linear in X, with coefficient \mathrm{cov}(S_j, X) / \mathrm{var}(X). By independence the covariance is v_j and the variance is \sum_l v_l. ∎

The ratio v_j / \sum_l v_l is a soft mask; when one variance dominates at each point it tends to the binary mask of DUET. The difficulty moves to estimating the variances v_j(m, k). Nonnegative matrix factorisation (ch. 11), the multichannel local Gaussian model (Duong, Vincent and Gribonval, 2010) and neural networks are the main tools.

Key takeaways — chapter 8

  • Underdetermined separation needs sparsity: W-disjoint orthogonality, or a Laplacian prior whose MAP is ℓ1 minimisation, which activates at most M sources per point.
  • In an anechoic two-microphone mixture, the ratio of the STFTs at a point dominated by one source gives its attenuation and delay.
  • DUET clusters these parameters, builds binary masks and combines the two channels; it needs microphones closer than c / f_s.
  • Wiener filtering gives soft masks v_j / \sum_l v_l, optimal for Gaussian sources with known variances.

9. High-resolution analysis I: sinusoidal models beyond Fourier

Many musical sounds are sums of slowly varying sinusoids, and their analysis needs frequency estimates finer than the Fourier resolution of a short frame. This chapter states the model, shows where Fourier analysis fails, and exposes the algebraic structure that high-resolution methods exploit.

Sinusoidal models

Definition 9.1 — Exponential sinusoidal model A frame of N samples follows the exponential sinusoidal model (ESM) of order K when x(n) = \sum_{k=1}^{K} \alpha_k\, z_k^n + w(n), \qquad z_k = e^{\delta_k + i\omega_k}, \qquad \alpha_k = a_k\, e^{i\phi_k}, with frequencies \omega_k, damping factors \delta_k \le 0, amplitudes a_k > 0, phases \phi_k and an additive noise w. A real sinusoid contributes two conjugate terms.

Sinusoidal analysis–synthesis (McAulay and Quatieri, 1986) tracks the peaks of successive short-time spectra as partials; spectral modelling synthesis (Serra and Smith, 1990) adds a stochastic residual. Both rely on accurate per-frame estimates of (\omega_k, \delta_k, a_k, \phi_k), which is what high-resolution methods provide.

What Fourier analysis cannot do

Proposition 9.2 — The periodogram mixes close components For x = \alpha_1 e^{i\omega_1 n} + \alpha_2 e^{i\omega_2 n} windowed by w, with W_j = W(\omega - \omega_j), |X_w(\omega)|^2 = |\alpha_1|^2 |W_1|^2 + |\alpha_2|^2 |W_2|^2 + 2\, \mathrm{Re}\big(\alpha_1 \bar\alpha_2\, W_1 \overline{W_2}\big) . When |\omega_1 - \omega_2| is below the main-lobe half-width, the cross term has the same order as the others. The number and the positions of the peaks then depend on the relative phase of the two components, not only on their frequencies.

Proof. Expand |\alpha_1 W_1 + \alpha_2 W_2|^2 (Proposition 0.4). Inside the main lobes both |W_j| are of order N, so the cross term is comparable to the squared terms. ∎

The limit is one of resolution, not of precision. For a single tone, the precision has a floor set by the noise:

Theorem 9.3 — Cramér–Rao bound for one complex tone Let x(n) = a\, e^{i(\omega_0 n + \phi)} + w(n), 0 \le n < N, with circular white Gaussian noise of variance \sigma^2 and unknown (a, \phi, \omega_0). Every unbiased estimator of \omega_0 satisfies

Key result — Cramér–Rao bound for a frequency \mathrm{var}(\hat\omega_0) \ \ge\ \frac{6\, \sigma^2}{a^2\, N\, (N^2 - 1)}

The proof, a Fisher-information computation (Rife and Boorstyn, 1974), is in ch. 11.

At 10 dB of signal-to-noise ratio and N = 64, the bound on the standard deviation is 2.4 \times 10^{-4} cycles per sample, 65 times smaller than the Fourier resolution 1/N.

Linear prediction and Prony’s method

Proposition 9.4 — A linear recurrence Without noise, the signal of Definition 9.1 satisfies, for every n \ge K, \sum_{p=0}^{K} c_p\, x(n - p) = 0, \qquad \text{where } \sum_{p=0}^{K} c_p\, z^{K - p} = \prod_{k=1}^{K} (z - z_k), \quad c_0 = 1 .

Proof. Substitute x(n - p) = \sum_k \alpha_k z_k^{n - p}. The sum becomes \sum_k \alpha_k z_k^{n - K} \sum_p c_p z_k^{K - p}, and the inner sum is the polynomial evaluated at its root z_k. ∎

Algorithm 9.5 — Prony’s method

  1. Solve the N - K equations of Proposition 9.4 for c_1, \dots, c_K, in the least-squares sense.
  2. Take the roots \hat z_k of the polynomial: \hat\omega_k = \arg \hat z_k and \hat\delta_k = \log |\hat z_k|.
  3. Estimate the \alpha_k by least squares on the Vandermonde system x(n) = \sum_k \alpha_k \hat z_k^n.

Prony’s method is exact without noise, but noise makes the equations inconsistent, and the least-squares coefficients, hence the roots, are biased. The subspace methods of ch. 10 are its robust replacement.

Hankel and covariance matrices

Proposition 9.6 — Hankel factorisation Let N = L + M - 1 and let \mathbf{X} be the L \times M Hankel matrix X_{ij} = x(i + j) of a noiseless frame.

Let \mathbf{V}_L = [z_k^i] be the L \times K Vandermonde matrix of the poles, and \mathbf{V}_M likewise. Then \mathbf{X} = \mathbf{V}_L\, \mathrm{diag}(\alpha_1, \dots, \alpha_K)\, \mathbf{V}_M^\top . If the z_k are distinct, \alpha_k \ne 0 and L, M \ge K, then \mathbf{X} has rank K and its column space is that of \mathbf{V}_L.

Proof. The factorisation is x(i + j) = \sum_k z_k^i\, \alpha_k\, z_k^j. A Vandermonde matrix with K distinct nodes and at least K rows has full column rank, since its top K \times K block has the non-zero determinant \prod_{k < l} (z_l - z_k). Both outer factors thus have rank K, and so does the product. ∎

Proposition 9.7 — Signal and noise subspaces Assume undamped components (|z_k| = 1) with independent phases uniform on [0, 2\pi), and white noise of variance \sigma^2. The covariance of L > K consecutive samples is \mathbf{R} = \mathbf{V}_L\, \mathrm{diag}(a_1^2, \dots, a_K^2)\, \mathbf{V}_L^H + \sigma^2 \mathbf{I} . Its eigenvalues satisfy \lambda_1 \ge \dots \ge \lambda_K > \sigma^2 = \lambda_{K+1} = \dots = \lambda_L . The first K eigenvectors span the signal subspace, the column space of \mathbf{V}_L; the others span its orthogonal complement, the noise subspace.

Proof. The cross terms between components have the factor \mathbb{E}[e^{i(\phi_k - \phi_l)}] = 0 for k \ne l, which gives the formula.

The first term is positive semidefinite of rank K (Proposition 9.6), and adding \sigma^2 \mathbf{I} shifts every eigenvalue by \sigma^2. The eigenvalue \sigma^2 therefore belongs exactly to the kernel of the first term, the orthogonal complement of the column space of \mathbf{V}_L. ∎

import numpy as np

rng = np.random.default_rng(0)
N = 64
n = np.arange(N)
f_true = np.array([0.200, 0.208])                 # cycles/sample, gap 0.008 < 1/N = 0.0156
z = np.exp(2j * np.pi * f_true)
alpha = np.array([1.0, 0.8 * np.exp(1j * np.pi / 3)])
x0 = (alpha[None, :] * z[None, :] ** n[:, None]).sum(1)

# 1. Periodogram (zero-padded): where are its peaks?
X = np.abs(np.fft.fft(x0, 8192)) ** 2
f = np.fft.fftfreq(8192)
band = (f > 0.15) & (f < 0.25)
pk = [i for i in np.where(band)[0] if X[i] > X[i - 1] and X[i] > X[i + 1]]
print("periodogram peaks above half the maximum:", np.round(f[pk][X[pk] > 0.5 * X.max()], 4))

# 2. Prony / linear prediction: x(n) + c1 x(n-1) + c2 x(n-2) = 0
def prony(x, K=2):
    Amat = np.array([x[k - K:k][::-1] for k in range(K, len(x))])
    c = np.linalg.lstsq(Amat, -x[K:], rcond=None)[0]
    return np.sort(np.angle(np.roots(np.r_[1, c])) / (2 * np.pi))   # frequencies of the roots
print("Prony, no noise      :", np.round(prony(x0), 4))
for snr_db in (60, 30):
    sigma = 10 ** (-snr_db / 20)
    x = x0 + sigma * (rng.standard_normal(N) + 1j * rng.standard_normal(N)) / np.sqrt(2)
    print(f"Prony, SNR {snr_db} dB    :", np.round(prony(x), 4))

# 3. Eigenvalues of the empirical covariance (Hankel data matrix, L = 16)
L = 16
x = x0 + 0.1 * (rng.standard_normal(N) + 1j * rng.standard_normal(N)) / np.sqrt(2)
H = np.array([x[i:i + N - L + 1] for i in range(L)])
ev = np.linalg.eigvalsh(H @ H.conj().T / (N - L + 1))[::-1]
print("largest eigenvalues:", np.round(ev[:4], 3), "| median of the others:",
      np.round(np.median(ev[2:]), 4), "| noise power 0.01")

Two tones at 0.200 and 0.208 cycles per sample, half the Fourier resolution apart, give periodogram peaks at 0.1957 and 0.2147, each wrong by more than half the gap (Proposition 9.2).

Prony is exact without noise and nearly so at 60 dB, but returns 0.0233 and 0.2018 at 30 dB. With noise power 0.01, the covariance has two eigenvalues above the noise (9.42 and 0.395) and the others near 0.01 (Proposition 9.7); the second is small because the two Vandermonde vectors are nearly parallel.

Key takeaways — chapter 9

  • The exponential sinusoidal model describes frames as sums of damped complex exponentials plus noise.
  • The periodogram cannot resolve components closer than about 2\pi / N: their cross term moves and merges the peaks. For a single tone, precision is limited only by the Cramér–Rao bound.
  • Noiseless exponentials satisfy a linear recurrence whose characteristic roots are the z_k (Prony), but this is fragile under noise.
  • The Hankel matrix has rank K, and the covariance splits into a signal subspace (range of the Vandermonde matrix) and a noise subspace (eigenvalue \sigma^2).

10. High-resolution analysis II: MUSIC, ESPRIT and model order

The signal subspace of ch. 9 contains the Vandermonde vectors of the poles. MUSIC finds the poles as the Vandermonde vectors orthogonal to the noise subspace; ESPRIT reads them off a shift invariance of the signal subspace. Both need the model order K, which the ESTER criterion estimates.

Estimated subspaces

Definition 10.1 — Estimated signal and noise subspaces From a frame of N samples, form the L \times M Hankel matrix \mathbf{X}, with N = L + M - 1, and its singular value decomposition \mathbf{X} = \mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^H, equivalently the eigendecomposition of \hat{\mathbf{R}} = \mathbf{X}\mathbf{X}^H / M. The first K columns of \mathbf{U} form the estimated signal basis \mathbf{W}; the remaining L - K form the noise basis \mathbf{W}_\perp.

With \mathbf{v}(z) = (1, z, \dots, z^{L-1})^\top the Vandermonde vector of a candidate pole, the two methods follow from Propositions 9.6–9.7.

MUSIC

Theorem 10.2 — MUSIC (Schmidt, 1986) Under the assumptions of Proposition 9.7, with L \ge K + 1 and exact subspaces, a point z of the unit circle satisfies \mathbf{W}_\perp^H\, \mathbf{v}(z) = \mathbf{0} \iff z \in \{z_1, \dots, z_K\} .

Proof. Each \mathbf{v}(z_k) is a column of \mathbf{V}_L, which lies in the signal subspace, orthogonal to the noise subspace.

Conversely, if \mathbf{v}(z) is orthogonal to the noise subspace, it lies in the column space of \mathbf{V}_L, so the matrix [\mathbf{V}_L, \mathbf{v}(z)] has rank K.

If z were distinct from all the poles, this would be a Vandermonde matrix with K + 1 distinct nodes and at least K + 1 rows, hence of rank K + 1: a contradiction. ∎

Definition 10.3 — MUSIC pseudo-spectrum and root-MUSIC With estimated subspaces, the frequencies are the K highest peaks of P_{\mathrm{MU}}(\omega) = \frac{1}{\|\mathbf{W}_\perp^H\, \mathbf{v}(e^{i\omega})\|^2} . Root-MUSIC instead takes the K roots closest to the unit circle of the polynomial Q(z) = \mathbf{v}(1/\bar z)^H\, \mathbf{W}_\perp \mathbf{W}_\perp^H\, \mathbf{v}(z) .

MUSIC was designed for direction-of-arrival estimation with sensor arrays; for time series it assumes undamped poles, since it searches the unit circle.

ESPRIT

For a matrix \mathbf{A} with L rows, write \mathbf{A}_\downarrow for \mathbf{A} without its last row and \mathbf{A}_\uparrow for \mathbf{A} without its first row.

Theorem 10.4 — Rotational invariance (Roy and Kailath, 1989) Let \mathbf{W} = \mathbf{V}_L \mathbf{G}, with \mathbf{G} invertible, be any basis of the signal subspace, with L \ge K + 1 and distinct poles (damped or not). Then

Key result — rotational invariance \mathbf{W}_\uparrow = \mathbf{W}_\downarrow\, \boldsymbol{\Phi}, \qquad \boldsymbol{\Phi} = \mathbf{G}^{-1}\, \mathrm{diag}(z_1, \dots, z_K)\, \mathbf{G}

so the eigenvalues of the matrix \boldsymbol{\Phi}, computable as \mathbf{W}_\downarrow^{+} \mathbf{W}_\uparrow, are the poles z_k.

Proof. Row i + 1 of \mathbf{V}_L is row i multiplied by \mathbf{D} = \mathrm{diag}(z_k), which shifts the rows by one. Hence \mathbf{W}_\uparrow = (\mathbf{V}_L)_\downarrow \mathbf{D}\, \mathbf{G} = \mathbf{W}_\downarrow\, \mathbf{G}^{-1} \mathbf{D}\, \mathbf{G} . (\mathbf{V}_L)_\downarrow is a Vandermonde matrix with L - 1 \ge K rows, of full column rank, and so is \mathbf{W}_\downarrow. The equation therefore determines \boldsymbol{\Phi}, given by the pseudo-inverse, and \boldsymbol{\Phi} is similar to \mathbf{D}. ∎

Algorithm 10.5 — LS-ESPRIT

  1. Form the Hankel matrix with L \approx N / 3 and compute its K dominant left singular vectors \mathbf{W}.
  2. Solve the shift equation of Theorem 10.4 for \boldsymbol{\Phi} by least squares (or total least squares).
  3. Diagonalise \boldsymbol{\Phi}: its eigenvalues give \hat\omega_k = \arg \hat z_k and \hat\delta_k = \log|\hat z_k|.
  4. Estimate the amplitudes and phases by least squares on the Vandermonde system x(n) = \sum_k \alpha_k \hat z_k^n.

The cost is dominated by the SVD; fast subspace tracking (Badeau, David and Richard, 2005) updates \mathbf{W} from frame to frame at a lower cost. Unlike MUSIC, ESPRIT estimates damping factors, which audio partials have.

Choosing the model order

Definition 10.6 — ESTER (Badeau, David and Richard, 2006) For each candidate order p, let \mathbf{W}(p) hold the first p singular vectors, and \boldsymbol{\Phi}(p) = \mathbf{W}_\downarrow(p)^{+}\, \mathbf{W}_\uparrow(p), \qquad J(p) = \frac{1}{\|\mathbf{W}_\uparrow(p) - \mathbf{W}_\downarrow(p)\, \boldsymbol{\Phi}(p)\|_2^2} . The estimated order is the largest p for which J(p) exceeds a threshold.

Proposition 10.7 — ESTER detects the true order Without noise, the invariance error vanishes at p = K, so J(K) = +\infty; this is Theorem 10.4 applied to \mathbf{W}(K). With noise, J(K) stays large while orders above K add noise vectors that break the invariance.

Information criteria such as MDL (Wax and Kailath, 1985) count the eigenvalues above the noise level, which assumes white noise. In practice audio noise is whitened first, and signals are split into subbands that each hold few components.

import numpy as np

rng = np.random.default_rng(0)
N, L = 64, 21                                     # signal length, Hankel rows (about N/3)
n = np.arange(N)
f_true = np.array([0.200, 0.208, 0.300])          # two close tones and a damped one
damp = np.array([0.0, 0.0, -0.02])
alpha = np.array([1.0, 0.8 * np.exp(1j * np.pi / 3), 0.5])
z = np.exp(damp + 2j * np.pi * f_true)
x0 = (alpha * z ** n[:, None]).sum(1)
sigma = 10 ** (-30 / 20)                          # SNR 30 dB for the first tone
x = x0 + sigma * (rng.standard_normal(N) + 1j * rng.standard_normal(N)) / np.sqrt(2)

H = np.array([x[i:i + N - L + 1] for i in range(L)])          # L x (N-L+1) Hankel matrix
U, s, _ = np.linalg.svd(H)

def esprit(K):
    W = U[:, :K]                                             # signal subspace basis
    Phi = np.linalg.lstsq(W[:-1], W[1:], rcond=None)[0]      # W_up = W_down Phi
    zk = np.linalg.eigvals(Phi)
    return zk, np.linalg.norm(W[1:] - W[:-1] @ Phi, 2)

zk, _ = esprit(3)
order = np.argsort(np.angle(zk))
print("ESPRIT frequencies:", np.round(np.angle(zk[order]) / (2 * np.pi), 4),
      "damping:", np.round(np.log(np.abs(zk[order])), 3))

V = zk[None, order] ** n[:, None]                             # amplitudes by least squares
print("amplitudes |alpha|:", np.round(np.abs(np.linalg.lstsq(V, x, rcond=None)[0]), 2))

# ESTER: J(p) = 1 / ||W_up - W_down Phi||^2; keep the largest p with J(p) >= 0.1 max J
J = np.array([1 / esprit(p)[1] ** 2 for p in range(1, 8)])
print("ESTER J(p), p = 1..7:", np.round(J).astype(int), "-> order", 1 + np.max(np.where(J >= 0.1 * J.max())[0]))

# MUSIC pseudo-spectrum on a fine grid
Wn = U[:, 3:]                                                 # noise subspace
grid = np.linspace(0.15, 0.35, 4001)
steer = np.exp(2j * np.pi * np.outer(np.arange(L), grid))
P = 1 / np.linalg.norm(Wn.conj().T @ steer, axis=0) ** 2
pk = [i for i in range(1, len(grid) - 1) if P[i] > P[i - 1] and P[i] > P[i + 1]]
best = sorted(pk, key=lambda i: -P[i])[:3]
print("MUSIC peaks:", np.round(np.sort(grid[best]), 4))

At 30 dB, ESPRIT finds 0.1997, 0.2083 and 0.2999 cycles per sample (true 0.200, 0.208, 0.300), the damping −0.021 (true −0.02), and amplitudes 0.86, 0.84 and 0.51 (true 1.0, 0.8, 0.5); the two close amplitudes are the least accurate.

ESTER gives J = 15277 at p = 3, against 1243 and 93 at p = 1, 2 and at most 32 above, and selects K = 3. MUSIC peaks at 0.1998, 0.2083 and 0.3000.

Key takeaways — chapter 10

  • MUSIC finds the poles on the unit circle as the Vandermonde vectors orthogonal to the noise subspace.
  • ESPRIT uses the shift invariance of the signal subspace; the eigenvalues of the matrix \boldsymbol{\Phi} that maps one shifted basis onto the other are the poles, damped or not.
  • Amplitudes and phases follow by least squares on the Vandermonde system.
  • ESTER selects the order as the largest p with a small invariance error; information criteria need white noise.

11. Complements for self-study

This chapter collects proofs and methods that extend the in-class chapters. Each section names the chapter it complements; none is needed to follow the sessions, and all are useful for the projects.

EM for Gaussian mixtures (complement to ch. 2)

The GMM classifier of Definition 2.2 fits one mixture per class to the training frames of that class.

Proposition 11.1 — EM for Gaussian mixtures Given the current parameters, compute the responsibilities, normalised to sum to one over g: \gamma_{mg} \propto \pi_g\, \mathcal{N}(\mathbf{x}_m; \boldsymbol{\mu}_g, \boldsymbol{\Sigma}_g) . Then update \pi_g = \frac{1}{M} \sum_m \gamma_{mg}, \qquad \boldsymbol{\mu}_g = \frac{\sum_m \gamma_{mg}\, \mathbf{x}_m}{\sum_m \gamma_{mg}}, \qquad \boldsymbol{\Sigma}_g = \frac{\sum_m \gamma_{mg}\, (\mathbf{x}_m - \boldsymbol{\mu}_g)(\mathbf{x}_m - \boldsymbol{\mu}_g)^\top}{\sum_m \gamma_{mg}} . Each iteration does not decrease the log-likelihood of the training frames.

Proof. By Jensen’s inequality, for any distribution q_m over components, \log p(\mathbf{x}_m) \ge \sum_g q_{mg} \log \frac{\pi_g\, \mathcal{N}_g(\mathbf{x}_m)}{q_{mg}}, with equality for q_{mg} = \gamma_{mg}.

The E-step makes the bound tight at the current parameters. The M-step maximises the bound in closed form, which gives the updates above. So the likelihood after the step is at least the bound, which is at least the likelihood before. ∎

In practice the covariances are often diagonal, initialised by k-means, and floored to avoid degenerate components collapsing on single frames.

Feedback delay networks and convolution reverberation (complement to ch. 4)

Proposition 11.2 — Lossless feedback delay networks A feedback delay network (Jot and Chaigne, 1991) has J delay lines whose outputs \mathbf{u}(n) are fed back to their inputs through a matrix \mathbf{Q}, together with the input signal. If \mathbf{Q} is orthogonal, then with zero input the total energy of the samples stored in the delay lines is constant.

Inserting the gain \gamma^{D_j} in line j, with \gamma = 10^{-3 / (T_{60} f_s)}, then makes every circulating sample decay at the same rate: the network reverberates with time T_{60}.

Proof. At each time step, one sample leaves each line and one enters: the entering vector is \mathbf{Q}\mathbf{u}(n), of the same squared norm as the leaving vector \mathbf{u}(n). So the sum of squares stored in the lines does not change.

With the gains, a sample that has circulated for t samples, along any path, has been multiplied by \gamma^{t}, since the delays it crossed add up to t. ∎

Unlike Schroeder’s parallel combs, the network mixes every line into every other one, so the echo density grows quickly and the modes are denser. Frequency-dependent decay is obtained by replacing each gain \gamma^{D_j} by a low-pass filter with that gain at each frequency.

Convolution reverberation convolves the signal with a measured impulse response by FFT blocks (Proposition 0.2), partitioned to keep the latency low (Gardner, 1995).

Decay times are measured on Schroeder’s backward integral of a response h, E(t) = \int_t^\infty h^2(s)\, ds, which averages out the fluctuations of h^2. Its level in dB is close to a straight line, whose slope between −5 and −35 dB, extrapolated to 60 dB, gives T_{60}; the code of ch. 4 does exactly this.

Linear prediction (complement to ch. 5)

Proposition 11.3 — Linear prediction The coefficients \mathbf{a} = (a_1, \dots, a_P) that minimise the mean squared prediction error of x(n) + \sum_{p=1}^{P} a_p\, x(n - p), for a stationary signal with autocorrelation r, solve the Yule–Walker equations \sum_{p=1}^{P} a_p\, r(|j - p|) = -r(j), \qquad j = 1, \dots, P . With A(z) = 1 + \sum_p a_p z^{-p} and the minimal error power G^2, the LPC envelope is G / |A(e^{i\omega})|.

Proof. The error is a quadratic function of \mathbf{a}. Its gradient with respect to a_j is 2\,\mathbb{E}[e(n)\, x(n - j)], and setting it to zero gives the P equations above. The matrix [r(|j - p|)] is a covariance matrix, positive semidefinite, so these stationary points are minima. ∎

The Toeplitz system is solved in O(P^2) operations by the Levinson–Durbin recursion, and the autocorrelation method yields a stable all-pole model. An order of about f_s / 1000 + 2 suits speech.

Inverting a modified STFT (complement to ch. 1 and 5)

Masking (ch. 8) or re-phasing (ch. 5) produces an array Y(m, k) that is usually not the STFT of any signal. Overlap-add still returns the best possible signal in the following sense.

Proposition 11.4 — Least-squares inversion (Griffin and Lim, 1984) Let y_m be the inverse DFT of frame m of Y. Among all signals x, the one that minimises \sum_m \sum_n |y_m(n) - w(n)\, x(n + mR)|^2 is \hat x(n) = \frac{\sum_m w(n - mR)\, y_m(n - mR)}{\sum_m w^2(n - mR)} .

Proof. The criterion separates over the samples x(n): each one appears in the terms |y_m(n - mR) - w(n - mR)\, x(n)|^2. Setting the derivative of this sum of squares to zero gives the formula. ∎

When only the magnitude |Y| is known, the Griffin–Lim algorithm alternates two steps: give |Y| the phases of the current estimate’s STFT, then invert by Proposition 11.4. Griffin and Lim (1984) show that the distance between the magnitude constraint and the set of consistent STFTs does not increase along the iterations.

Amplitude panning and Ambisonics (complement to ch. 6)

Between the perceptual rendering of binaural signals and the physical rendering of WFS, two loudspeaker techniques are widely used.

Proposition 11.5 — Tangent law and VBAP Two loudspeakers at azimuths \pm\theta_0 fed with gains g_1, g_2 \ge 0 create a phantom source at the azimuth \theta given by \frac{g_1 - g_2}{g_1 + g_2} = \frac{\tan\theta}{\tan\theta_0} . Vector base amplitude panning (Pulkki, 1997) chooses the gains by writing the source direction \mathbf{p} as g_1 \mathbf{l}_1 + g_2 \mathbf{l}_2 in the base of the loudspeaker directions, then normalising the gains to unit energy.

Proof. With \mathbf{p} = (\cos\theta, \sin\theta) and \mathbf{l}_{1,2} = (\cos\theta_0, \pm\sin\theta_0), the two coordinates of the decomposition give g_1 + g_2 = \cos\theta / \cos\theta_0 and g_1 - g_2 = \sin\theta / \sin\theta_0. Their ratio is the tangent law; normalising both gains by the same factor keeps the ratio. ∎

First-order Ambisonics (Gerzon, 1973) encodes a plane wave s from azimuth \theta and elevation \phi into four channels that do not depend on the loudspeaker layout: W = \frac{s}{\sqrt{2}}, \qquad X = s \cos\theta \cos\phi, \qquad Y = s \sin\theta \cos\phi, \qquad Z = s \sin\phi . These are the first spherical harmonics of the sound field at the listening point. A decoder computes loudspeaker feeds whose re-encoding matches these channels, for example by a pseudo-inverse. Higher orders sharpen the spatial resolution (Zotter and Frank, 2019).

Maximum-likelihood ICA (complement to ch. 7)

Maximum-likelihood ICA, equivalent to Infomax (Bell and Sejnowski, 1995), updates the whole demixing matrix by the natural gradient, where \phi is the score function of the assumed source density: \mathbf{W} \leftarrow \mathbf{W} + \mu \big(\mathbf{I} - \mathbb{E}[\phi(\mathbf{y})\, \mathbf{y}^\top]\big) \mathbf{W} .

It follows from the log-likelihood of one sample, \log |\det \mathbf{W}| + \sum_i \log p_i(y_i), whose gradient with respect to \mathbf{W}, multiplied on the right by \mathbf{W}^\top \mathbf{W} (the relative or natural gradient), gives the update. With \phi = \tanh it suits super-Gaussian sources such as speech.

Nonnegative matrix factorisation (complement to ch. 8)

The Wiener masks of Proposition 8.6 need the source variances v_j(m, k). Nonnegative matrix factorisation (NMF) models a power spectrogram as a sum of a few spectral templates with time-varying gains.

Definition 11.6 — NMF with the Kullback–Leibler divergence Given a nonnegative F \times T matrix \mathbf{V}, find nonnegative \mathbf{W} (F \times R) and \mathbf{H} (R \times T) that minimise D(\mathbf{V} \mid \mathbf{W}\mathbf{H}) = \sum_{f, t} \Big( V_{ft} \log \frac{V_{ft}}{(\mathbf{W}\mathbf{H})_{ft}} - V_{ft} + (\mathbf{W}\mathbf{H})_{ft} \Big) . The columns of \mathbf{W} are spectral templates (a note, a drum stroke) and the rows of \mathbf{H} their activations.

Proposition 11.7 — Multiplicative updates (Lee and Seung, 2001) With \oslash the entrywise division, the updates \mathbf{H} \leftarrow \mathbf{H} \odot \frac{\mathbf{W}^\top (\mathbf{V} \oslash \mathbf{W}\mathbf{H})}{\mathbf{W}^\top \mathbf{1}}, \qquad \mathbf{W} \leftarrow \mathbf{W} \odot \frac{(\mathbf{V} \oslash \mathbf{W}\mathbf{H})\, \mathbf{H}^\top}{\mathbf{1}\, \mathbf{H}^\top} keep the factors nonnegative and never increase the divergence.

Proof. For the update of \mathbf{H} with \mathbf{W} fixed, the concavity of the logarithm (Jensen’s inequality with weights proportional to W_{fr} H_{rt}) bounds the term -V_{ft} \log (\mathbf{W}\mathbf{H})_{ft} from above by a function separable in the entries of \mathbf{H}.

This auxiliary function equals the divergence at the current \mathbf{H}. Its minimiser, found in closed form, is the update; so the divergence after the step is at most the auxiliary function there, which is at most the divergence before. The update of \mathbf{W} is symmetric. ∎

For separation, templates are learned per source (supervised NMF) or grouped after learning. Then v_j = \mathbf{W}_j \mathbf{H}_j feeds the Wiener masks. The Itakura–Saito divergence, which is scale-invariant and corresponds to the Gaussian model of Proposition 8.6, suits audio better (Févotte, Bertin and Durrieu, 2009), and multichannel NMF extends the model to convolutive mixtures (Ozerov and Févotte, 2010).

The code factorises a synthetic spectrogram made of two harmonic “notes” with sparse activations.

import numpy as np

rng = np.random.default_rng(0)
F, T, K = 64, 100, 2
W0 = np.zeros((F, K)); W0[[5, 10, 15, 20], 0] = 1; W0[[7, 14, 21, 28], 1] = 1   # two 'notes'
H0 = (rng.random((K, T)) < 0.3) * rng.random((K, T))                         # sparse activations
V = W0 @ H0 + 1e-3                                                            # power spectrogram
W, H = rng.random((F, K)) + 0.1, rng.random((K, T)) + 0.1
kl = lambda V, Vh: np.sum(V * np.log(V / Vh) - V + Vh)
hist = []
for it in range(300):                                  # Lee-Seung multiplicative updates (KL)
    H *= (W.T @ (V / (W @ H))) / W.sum(0)[:, None]
    W *= ((V / (W @ H)) @ H.T) / H.sum(1)[None, :]
    hist.append(kl(V, W @ H))
print("KL divergence at iterations 1, 10, 100, 300:", np.round([hist[0], hist[9], hist[99], hist[-1]], 3))
print("monotone decrease:", bool(np.all(np.diff(hist) <= 1e-9)))
print("partials of each learned template (4 largest bins):",
      [sorted(int(i) for i in np.argsort(W[:, k])[-4:]) for k in range(K)])

The divergence falls from 68.9 to 9.32 in 10 iterations and then stabilises at 9.319, decreasing at every step. The two learned templates recover the partials of the two notes (bins 5, 10, 15, 20 and 7, 14, 21, 28). The remaining divergence comes from the constant floor added to the spectrogram.

Harmonic–percussive separation (complement to ch. 8)

In a spectrogram, sustained harmonic sounds form horizontal lines and percussive sounds vertical lines. FitzGerald (2010) median-filters the spectrogram along time, which keeps the horizontal structures, and along frequency, which keeps the vertical ones. The two filtered spectrograms define soft or binary masks, a fast and useful front end for the rhythm analysis of ch. 3 and the pitch analysis of ch. 9.

The Cramér–Rao bound for a tone (complement to ch. 9)

Proof. Proof of Theorem 9.3. The mean of the observation is \mu_n = a\, e^{i(\omega_0 n + \phi)}. For circular white Gaussian noise of variance \sigma^2, the Fisher information of the parameters \theta is I_{jl} = \frac{2}{\sigma^2}\, \mathrm{Re} \sum_{n} \overline{\frac{\partial \mu_n}{\partial \theta_j}}\, \frac{\partial \mu_n}{\partial \theta_l} .

  • The derivatives are \partial_a \mu_n = \mu_n / a, \partial_\phi \mu_n = i \mu_n and \partial_{\omega_0} \mu_n = i n \mu_n.
  • The amplitude decouples: I_{a\phi} = I_{a\omega_0} = 0, because the products are purely imaginary.
  • The phase–frequency block is 2a^2 / \sigma^2 times the matrix with rows (N, S_1) and (S_1, S_2), where S_1 = \sum_n n = \frac{N(N-1)}{2}, \qquad S_2 = \sum_n n^2 = \frac{N(N-1)(2N-1)}{6} .
  • Its determinant involves N S_2 - S_1^2 = N^2 (N^2 - 1) / 12.

The bound is the (\omega_0, \omega_0) entry of the inverse: \frac{\sigma^2}{2a^2} \cdot \frac{N}{N S_2 - S_1^2} = \frac{6\, \sigma^2}{a^2 N (N^2 - 1)} . ∎

For one tone, the maximum of the periodogram is the maximum-likelihood estimator of the frequency, and it reaches the bound above a threshold SNR; the high-resolution methods matter when several components are close. The code compares ESPRIT and the zero-padded periodogram peak with the bound, over 300 noise draws.

import numpy as np

rng = np.random.default_rng(0)
N, f0, trials = 64, 0.1234, 300
n = np.arange(N)
for snr_db in (0, 10, 20):
    s2 = 10 ** (-snr_db / 10)                                    # noise variance, |alpha| = 1
    crb = 6 * s2 / (N * (N ** 2 - 1)) / (2 * np.pi) ** 2         # in (cycles/sample)^2
    e_esp, e_per = [], []
    for _ in range(trials):
        x = np.exp(2j * np.pi * f0 * n + 1j * rng.uniform(0, 2 * np.pi)) \
            + np.sqrt(s2 / 2) * (rng.standard_normal(N) + 1j * rng.standard_normal(N))
        L = N // 3
        Hm = np.array([x[i:i + N - L + 1] for i in range(L)])
        u = np.linalg.svd(Hm)[0][:, :1]                          # ESPRIT with K = 1
        zhat = (np.linalg.pinv(u[:-1]) @ u[1:])[0, 0]
        e_esp.append(np.angle(zhat) / (2 * np.pi) - f0)
        Xf = np.abs(np.fft.fft(x, 64 * N))                      # grid step 1/(64 N)
        e_per.append(np.argmax(Xf) / (64 * N) - f0)
    print(f"SNR {snr_db:2d} dB: RMSE/sqrt(CRB) ESPRIT {np.sqrt(np.mean(np.square(e_esp)) / crb):.2f}, "
          f"periodogram peak {np.sqrt(np.mean(np.square(e_per)) / crb):.2f}")

The ratio of the root mean squared error to the square root of the bound is 1.16, 1.01 and 1.06 for ESPRIT at 0, 10 and 20 dB. For the periodogram peak it is 1.04 and 0.98 at 0 and 10 dB (the bound reached within Monte Carlo error), and 1.60 at 20 dB, where the frequency grid of step 1/(64N) becomes the limit.

Pisarenko’s method (1973), the ancestor of the subspace methods, takes L = K + 1: the noise subspace of Proposition 9.7 is then a single vector, and the roots of the polynomial whose coefficients are its entries are the poles. MUSIC and ESPRIT use larger L, which averages the noise over more dimensions.

Neural networks for indexing and separation (complement to ch. 2, 3 and 8)

Since the mid-2010s, convolutional networks applied to log-mel spectrograms have replaced hand-made features in large-scale audio classification (Hershey et al., 2017; Kong et al., 2020). Recurrent and convolutional networks estimate beat and downbeat activations, decoded by the dynamic programmes and hidden Markov models of ch. 3 (Böck, Krebs and Widmer, 2016).

In separation, networks estimate the masks of ch. 8 from the mixture spectrogram, or work directly on the waveform with a learned encoder (Luo and Mesgarani, 2019; Défossez et al., 2019). The evaluation pitfalls of Proposition 2.7 apply to them unchanged.

Key takeaways — chapter 11

  • EM, linear prediction, lossless feedback delay networks and least-squares STFT inversion each rest on one short optimisation or energy argument.
  • Amplitude panning obeys the tangent law; Ambisonics encodes the field in spherical harmonics independently of the loudspeakers.
  • NMF models spectrograms as nonnegative sums of templates and supplies the variances of Wiener masks; median filtering splits harmonic and percussive parts.
  • For one tone, the periodogram peak and ESPRIT both come within about 15 % of the Cramér–Rao bound 6\sigma^2 / (a^2 N (N^2 - 1)) at moderate SNR.

12. Research directions and open problems

This chapter is for self-study. It maps active questions that start from chapters 2–10, with pointers to papers listed in the references. Each item says what the question is and where to start reading.

Learned representations for machine listening

Separation without isolated sources

Signal processing inside learning

Super-resolution beyond subspace methods

Rhythm, meter and structure

Spatial audio

Questions to explore

  1. Can DUET be extended to reverberant rooms by replacing the single delay per source with a distribution of interchannel phase differences learned from data?
  2. At which frequency separation, as a function of N and SNR, does ESPRIT stop resolving two equal-amplitude tones, and how does this compare with the Cramér–Rao bound for two tones?
  3. Does a classifier trained on music features keep its accuracy when evaluated with strict artist filters on a new data set?
  4. Can a phase vocoder with learned phase propagation remove phasiness without introducing transient smearing?

Key takeaways — chapter 12

  • Pretrained and self-supervised representations are replacing hand-made features, and evaluation without leakage remains essential.
  • Separation research aims at universal, label-free and perceptually evaluated systems.
  • Differentiable signal processing and off-the-grid super-resolution connect the models of this course to modern learning and optimisation.

Exercises

Levels: ★ apply the course, ★★ combine results or prove a short statement, ★★★ open-ended or research-flavoured. Exercises 16, 17 and 18 are computational; exercise 19 is open-ended.

  1. ★ Resolution and leakage. Two tones at 440 and 446 Hz are sampled at 8 kHz. (a) How many samples must a rectangular frame have for the gap to reach the Rayleigh limit? (b) And a Hann frame, judged by its main-lobe half-width? (c) Why does zero-padding the frame not help?

    Solution: (a) the limit is f_s / N \le 6 Hz, so N \ge 1334 samples (0.17 s). (b) The Hann main lobe is twice as wide, so N \ge 2667 samples (0.33 s).

    1. Zero-padding samples the same DTFT more densely; the width of the main lobe is set by the number of signal samples (Proposition 0.4).
  2. ★ STFT parameters and overlap-add. At 44.1 kHz, take a periodic Hann window of N = 2048 samples and a hop R = 512. (a) Give the frame duration, the bin spacing and the number of frames per second. (b) Show that the shifted windows sum to 2 and their squares to 3/2. (c) Which synthesis window reconstructs exactly?

    Solution: (a) 46.4 ms, 21.5 Hz and 86.1 frames per second.

    1. w(n) = \tfrac12 - \tfrac12 \cos(2\pi n / N). Shifting by N/4 rotates the phase of the cosine by \pi/2, so the four shifted cosines cancel and the sum is 4 \times \tfrac12 = 2. Similarly w^2 = \tfrac38 - \tfrac12 \cos(2\pi n/N) + \tfrac18 \cos(4\pi n/N), and both cosines cancel over four shifts: the sum is 4 \times \tfrac38 = \tfrac32.

    2. By Proposition 1.2, w_s = \tfrac23 w.

  3. ★ A mel filterbank by hand. (a) Compute the mel values of 1000, 4000 and 8000 Hz. (b) For 40 filters between 0 and 8000 Hz, find the centres of the first and last filters, and the widths between consecutive centres there. (c) Why is c_0 often discarded from the MFCCs?

    Solution: (a) 1000, 2146 and 2840 mel. (b) The 42 edges are 69.27 mel apart. The first centre is at 69.27 mel, that is 44.4 Hz, and the last at 2770.8 mel, that is 7481 Hz. Consecutive centres are 47 Hz apart at the bottom and 488 Hz apart at the top.

    1. c_0 is the sum of the log energies, which depends on the recording level rather than on timbre.
  4. ★ Tempo from an autocorrelation lag. An onset function sampled at 100 frames per second has its weighted autocorrelation maximum at lag 47. (a) Give the tempo and the tempi of lags 46 and 48. (b) The unweighted autocorrelation also peaks at lag 94: which tempo does it suggest, and how does the prior of Definition 3.2 decide?

    Solution: (a) 127.7 BPM; lags 46 and 48 give 130.4 and 125.0 BPM, so the lag grid has a resolution of about 2.7 BPM here. Parabolic interpolation of the peak refines it.

    1. Lag 94 gives 63.8 BPM, the half tempo (Proposition 3.3). The log-Gaussian prior centred on 120 BPM weights lag 47 more, which selects 127.7 BPM.
  5. ★ Flanger notches. A flanger at 44.1 kHz uses g = 0.7 and a delay swept between 1 and 5 ms. (a) Between which frequencies does the first notch move? (b) Give the depth of the notches and the height of the peaks in dB. (c) How many notches lie below 5 kHz when D = 5 ms?

    Solution: (a) the first notch is at f_s / 2D = 1 / (2 \times \text{delay}): from 500 Hz (1 ms) down to 100 Hz (5 ms).

    1. 20 \log_{10}(1 - g) = -10.5 dB and 20 \log_{10}(1 + g) = +4.6 dB (Proposition 4.2).

    2. Notches at 100, 300, 500, … Hz, odd multiples of 100 Hz, so 25 below 5 kHz.

  6. ★ Tuning a Schroeder reverberator. At 44.1 kHz, compute the comb gains for T_{60} = 2 s and the delays 1557, 1617, 1491 and 1422 samples. Which mean absorption coefficient gives the same T_{60} in the room of ch. 4 (320 m³, 304 m² of walls)?

    Solution: by Proposition 4.9, g = 10^{-3D / (2 \times 44100)}, that is 0.885, 0.881, 0.890 and 0.895: longer delays need smaller gains.

    Sabine’s formula gives A = 0.161 \times 320 / 2 = 25.8 m², hence a mean absorption coefficient of \bar\alpha = 25.8 / 304 = 0.085 .

  7. ★ Interaural time differences. With a = 8.75 cm and c = 343 m/s, compute the ITD at 45° in milliseconds and in samples at 48 kHz. Above which frequency does the interaural phase become ambiguous for a source at 90°?

    Solution: Definition 6.1 gives \mathrm{ITD}(45^\circ) = \frac{0.0875}{343} \Big(\frac{\pi}{4} + \frac{\sqrt2}{2}\Big) = 0.381 \text{ ms}, that is 18.3 samples. At 90° the ITD is 0.656 ms; the phase difference exceeds \pi when half a period is shorter than the ITD, above 1 / (2 \times 0.656 \text{ ms}) = 762 Hz. This is one reason why the ITD is used at low frequencies.

  8. ★ Spacing a WFS array. (a) Which loudspeaker spacing avoids spatial aliasing up to 1500 Hz for every direction? (b) For frontal plane waves only? (c) How many loudspeakers does a 4 m array need in case (a)?

    Solution: by Proposition 6.5, (a) \Delta x \le c / (2 \times 1500) = 11.4 cm; (b) \Delta x \le c / 1500 = 22.9 cm. (c) 4 / 0.114 = 35 intervals, so 36 loudspeakers.

  9. ★★ The Bayes rule over a texture window. (a) Show that summing frame log-likelihoods (Definition 2.2) is the Bayes rule when frames are independent given the class. (b) Two equiprobable classes, 100 frames, mean log-likelihood ratio 0.05 per frame: compute the posterior. (c) If the frames are in fact 25 independent groups of 4 identical frames, what is the correct posterior? Comment.

    Solution: (a) Under conditional independence the likelihood of the window is the product of the frame likelihoods p(\mathbf{x}_m \mid c); take the logarithm and add \log p(c).

    1. The log-odds are 100 \times 0.05 = 5, so the posterior is e^5 / (1 + e^5) = 0.993. (c) Only 25 independent observations: log-odds 1.25 and posterior 0.78.

    The decision is the same, but treating overlapping frames as independent makes the classifier overconfident, which matters when posteriors are combined or thresholded.

  10. ★★ Distortion, harmonics and aliasing. (a) Show that f(x) = x + x^2 / 2 adds a DC offset and a second harmonic to A\cos\theta. (b) A 9 kHz tone passes through x \mapsto x^3 at 44.1 kHz: where does its third harmonic appear? (c) Which smallest integer oversampling factor guarantees that, for every input tone below 20 kHz, the alias of the third harmonic lands above 20 kHz, where the decimation filter removes it?

    Solution: (a) The square term gives \tfrac12 A^2 \cos^2\theta = \tfrac14 A^2 + \tfrac14 A^2 \cos 2\theta, a DC offset and a second harmonic: the even part of a nonlinearity produces even harmonics, consistent with Proposition 4.7.

    1. At 27 kHz, which aliases to 44.1 - 27 = 17.1 kHz, an inharmonic component (1.9 times the fundamental).

    2. At rate M \times 44.1 kHz, a third harmonic of at most 60 kHz aliases to 44.1 M - 60 kHz. This is at least 20 kHz when M \ge 1.81, so M = 2 suffices.

  11. ★★ The phase vocoder hop. With a Hann window of N = 2048 samples, (a) give the largest analysis hop allowed by Proposition 5.4. (b) With R_a = 1024, a sinusoid lies 1.5 bins above the centre of bin k. What frequency does the phase vocoder estimate for bin k?

    Solution: (a) R_a \le N / 4 = 512.

    1. The phase offset is 1.5 \times (2\pi / 2048) \times 1024 = 1.5\pi, which \operatorname{princarg} maps to -0.5\pi. The estimate is therefore \omega_k - 0.5\pi / 1024, that is 0.5 bin below the centre instead of 1.5 bins above: an error of 2 bins, 43 Hz at 44.1 kHz.
  12. ★★ Whitening and kurtosis. (a) Prove that \mathbf{Q} = \mathbf{B}\mathbf{A} of Proposition 7.3 is orthogonal using \mathbf{R}_x = \mathbf{A}\mathbf{A}^\top. (b) Compute the kurtosis of a uniform variable on [-\sqrt3, \sqrt3] and of a Laplace variable of unit variance. (c) Which sign of kurtosis do speech and a sinusoid with random phase have?

    Solution: (a) Whiteness of \mathbf{z} means \mathbf{B}\mathbf{R}_x\mathbf{B}^\top = \mathbf{I}, that is \mathbf{Q}\mathbf{Q}^\top = \mathbf{I}.

    1. Uniform: \mathbb{E}[y^4] = 9/5, so \kappa = -1.2. Laplace with unit variance: \mathbb{E}[y^4] = 6, so \kappa = 3.

    2. Speech is super-Gaussian (\kappa > 0). A sinusoid \sqrt2 \cos\Theta has \mathbb{E}[y^4] = 3/2, so \kappa = -1.5: sub-Gaussian. FastICA handles both signs (Proposition 7.6).

  13. ★★ DUET and microphone spacing. Two microphones 5 cm apart record at 16 kHz. (a) What is the largest delay in samples? (b) Above which frequency can delays wrap? (c) Compute the symmetric attenuation for a = 2 and for a = 1/2, and explain why DUET uses it.

    Solution: (a) d f_s / c = 0.05 \times 16000 / 343 = 2.33 samples, more than the bound of Proposition 8.5.

    1. The phase \omega\delta exceeds \pi above c / (2d) = 3430 Hz. Estimate delays below that frequency only, or use microphones less than 2.1 cm apart.

    2. \alpha = 2 - 1/2 = 1.5 and \alpha = 1/2 - 2 = -1.5. Exchanging the microphones changes a into 1/a and only flips the sign of \alpha, so the histogram treats both channels symmetrically.

  14. ★★ Crosstalk cancellation in free field. Model the contralateral path as G_c = \rho\, G_i\, e^{-i\omega\tau} with 0 < \rho < 1. (a) Compute \det \mathbf{G} and the frequencies where its modulus is minimal. (b) For \rho = 0.95, by how much must the inverse filter amplify the signal there?

    Solution: (a) \det \mathbf{G} = G_i^2 (1 - \rho^2 e^{-2i\omega\tau}). Its modulus is minimal, equal to |G_i|^2 (1 - \rho^2), when 2\omega\tau is a multiple of 2\pi, that is at f = m / (2\tau), including f = 0.

    1. At those frequencies the matrix has the eigenvalues G_i (1 \pm \rho): \mathbf{G} = G_i \begin{pmatrix} 1 & \pm\rho \\ \pm\rho & 1 \end{pmatrix} .

    The inverse therefore amplifies some binaural signals by 1 / ((1 - \rho)|G_i|). That is 1 / (1 - \rho) = 20 times, or 26 dB, more than the gain 1 / |G_i| needed without crosstalk. The determinant alone contributes the factor 1 / (1 - \rho^2) = 10.3, about 20 dB.

    The code of ch. 6 (\rho \approx 0.96) finds only 20–23 dB of extra gain at 100 and 1900 Hz, because its Tikhonov regularisation caps the gain.

  15. ★★ ESPRIT by hand. Let x(n) = \cos(\pi n / 2) for n = 0, \dots, 4. Build the 3 \times 3 Hankel matrix, an orthonormal basis of its column space, the matrix \boldsymbol{\Phi} of Theorem 10.4 and its eigenvalues; then recover the amplitudes.

    Solution: x = (1, 0, -1, 0, 1), and the Hankel matrix has rows (1, 0, -1), (0, -1, 0) and (-1, 0, 1), of rank 2. Its column space has the orthonormal basis (1, 0, -1)/\sqrt2 and (0, 1, 0).

    Removing the last row, then the first, gives \mathbf{W}_\downarrow = \begin{pmatrix} 1/\sqrt2 & 0 \\ 0 & 1 \end{pmatrix}, \quad \mathbf{W}_\uparrow = \begin{pmatrix} 0 & 1 \\ -1/\sqrt2 & 0 \end{pmatrix}, \quad \boldsymbol{\Phi} = \mathbf{W}_\downarrow^{-1} \mathbf{W}_\uparrow = \begin{pmatrix} 0 & \sqrt2 \\ -1/\sqrt2 & 0 \end{pmatrix} . Its characteristic polynomial is \lambda^2 + 1, so the poles are \pm i = e^{\pm i\pi/2}. From x(0) = \alpha_1 + \alpha_2 = 1 and x(1) = i(\alpha_1 - \alpha_2) = 0, both amplitudes are 1/2.

  16. ★★★ Beat tracking through a tempo change (Python). Modify the code of ch. 3 so that the tempo glides linearly from 110 to 140 BPM over 48 beats. Run the global-tempo tracker, then estimate the beat period on 4 s windows every second and let \tau in Proposition 3.5 depend on the frame.

    Hints and expected result: the global autocorrelation is smeared by the glide and the prior then picks the eighth-note level, 240 BPM, at the edge of the search range. The tracker returns about twice too many beats (96–98 for 48, F-measure about 0.65).

    With the local beat period (lags falling from about 53 to 44 frames), it finds 48–49 beats with an F-measure of about 0.98. The recursion of Proposition 3.5 remains exact with a frame-dependent \tau.

  17. ★★★ The resolution threshold of ESPRIT (Python). For two equal-amplitude complex tones with random phases, N = 64, L = 21, and gaps of 0.25, 0.5, 0.75, 1 and 1.5 times 1/N, estimate over 200 draws how often ESPRIT and the two highest peaks of the zero-padded periodogram place both frequencies within a quarter of the gap. Use SNRs of 20 and 40 dB.

    Hints and expected result: at 20 dB, ESPRIT succeeds in about 95 % of the draws at a gap of 0.5/N, and the periodogram needs about 1.5/N (57 % at 1/N).

    At 40 dB, ESPRIT resolves 0.25/N in about 98 % of the draws, while the periodogram does not improve. Its limit is resolution, not noise (Proposition 9.2); the limit of ESPRIT moves with the SNR.

  18. ★★★ NMF and Wiener masks (Python). Using Definition 11.6 and Proposition 8.6, simulate two sources with complex Gaussian STFT coefficients whose variances are one harmonic template times sparse random activations. Fix the templates, estimate the activations on the mixture by the multiplicative update for \mathbf{H}, apply Wiener masks, and compute the SDR of source 1.

    Take the sizes of the NMF code of ch. 11: 64 bins, 100 frames, templates floored at 10^{-3}, activations non-zero in 30 % of the frames. Compare templates with distinct partials (bins 5, 10, 15, 20 and 7, 14, 21, 28) with an octave (bins 10, 20, 30, 40 for source 2).

    Hints and expected result: with distinct partials, the SDR is about 25 dB; with the octave, about 12 dB, close to the 13 dB obtained with the true activations. Denser activations lower both values (about 22 and 7 dB at 80 %). Shared bins receive a mask between 0 and 1 even when the template gains are perfect, because the Wiener filter can only split their energy in proportion to the variances.

  19. ★★★ DUET in a reverberant room (open). Replace the anechoic mixture of the DUET code by convolutions with two different synthetic room responses per source (for instance Schroeder reverberators from ch. 4 with different delays), for T_{60} from 0 to 0.6 s. Measure how the (\alpha, \delta) clusters and the SDRs degrade, and propose a remedy.

    Hints: as T_{60} grows, the ratios X_2 / X_1 at single-source points no longer have one modulus and one phase slope, so the clusters spread and the masks mix sources. Possible remedies are longer windows (Proposition 7.7), probabilistic models of interchannel phase and level differences fitted by EM (Mandel, Weiss and Ellis, 2010), or the multichannel local Gaussian model of Duong, Vincent and Gribonval (2010). This is a natural extension of the first solo project below.

Projects and assessment

The official assessment, per master-mva.com, is the reading and analysis of research papers, with a written report and an oral presentation; the Université Paris-Saclay course detail classifies it as “Evaluation Continue non Intégrale” (partial continuous assessment). The solo and group subjects below are paper studies sized for that format. The written exam is not part of the official assessment: it is a self-test proposal, and none of these proposals is official material.

Solo projects

  1. [Solo · ≈ 20 h] DUET and W-disjoint orthogonality: a paper study. Reproduce the main experiments of Yilmaz and Rickard (2004).
    • Implement: DUET from Algorithm 8.4, with histogram peak picking, and the approximate W-disjoint orthogonality measures of the paper.
    • Data: anechoic mixtures of 2 to 5 speakers simulated from public speech recordings such as LibriSpeech (Panayotov et al., 2015), with chosen attenuations and sub-sample delays.
    • Success criterion: SDR, SIR and SAR (Definition 7.8) as a function of the number of sources and of the window length, reproducing the paper’s trends.
    • Deliverables: code, a 4–6 page report, a 10-minute talk. Chapters 1, 7, 8.
  2. [Solo · ≈ 20 h] ESPRIT and ESTER on musical notes: a paper study. Study Roy and Kailath (1989) and the ESTER criterion of Badeau, David and Richard (2006).
    • Implement: Algorithm 10.5, ESTER and an MDL baseline; a Monte Carlo study against the Cramér–Rao bound (Theorem 9.3).
    • Data: synthetic damped sinusoids, then isolated acoustic keyboard notes from the public NSynth data set (Engel et al., 2017); for piano notes the partial frequencies follow f_k = k f_0 \sqrt{1 + B k^2}.
    • Success criterion: correct order in at least 90 % of synthetic draws at 20 dB, frequency RMSE within a factor 1.5 of the bound, and a fitted inharmonicity coefficient B for several piano notes.
    • Deliverables: code, report, talk. Chapters 9, 10, 11.
  3. [Solo · ≈ 15 h] Beat tracking by dynamic programming: a paper study. Reimplement Ellis (2007) and evaluate it.
    • Data: the public Ballroom data set of the tempo comparison of Gouyon et al. (2006), with the beat annotations released by Krebs, Böck and Widmer (2013).
    • Work: the onset function, tempo estimation with and without the prior, and the effect of the tightness \alpha; F-measures computed with mir_eval (Raffel et al., 2014).
    • Success criterion: a table of F-measures per dance style, with and without the tempo prior; a higher mean F-measure with the prior; and an error analysis that separates metrical-level errors (half or double tempo) from phase errors (off-beat tracking).
    • Deliverables: code, report, talk. Chapter 3.

Group projects

  1. [Group of 2–3 · ≈ 30 h each] Instrument recognition with an honest evaluation. Build and compare instrument-family classifiers on the public NSynth data set (Engel et al., 2017).
    • Work split: one member writes the features of ch. 1 (MFCC statistics, descriptors of Definition 2.6) and the GMM and SVM baselines; one trains a small convolutional network on log-mel spectrograms; one builds the evaluation, with splits that keep each instrument on one side (Proposition 2.7), confusion matrices and error bars.
    • Success criterion: the accuracy gap between random and instrument-disjoint splits, measured for every model, and a model that beats the baselines on the disjoint split.
    • Deliverables: code, a 6-page report, a 15-minute talk. Chapters 1, 2, 11.
  2. [Group of 2–3 · ≈ 30 h each] A binaural and transaural renderer. Render moving virtual sources from the public CIPIC HRTF database (Algazi et al., 2001).
    • Work split: binaural synthesis with interpolation between measured directions; a crosstalk canceller with the regularisation of Kirkeby et al. (1998), studied against \beta and head displacement; a listening test with at least five listeners.
    • Success criterion: simulated channel separation of at least 20 dB between 200 Hz and 6 kHz at the sweet spot, and a localisation-error table from the listening test.
    • Deliverables: code, report, demo, talk. Chapters 6, 11.
  3. [Group of 2–3 · ≈ 30 h each] An effects and reverberation toolkit: a paper study. Reproduce the Schroeder reverberator (Schroeder, 1962) and a feedback delay network (Jot and Chaigne, 1991), and add the effects of ch. 4–5.
    • Work split: flanger, phaser and an oversampled distortion with measured aliasing; an FDN reverberator with frequency-dependent decay; a phase vocoder with the phase locking of Laroche and Dolson (1999).
    • Success criterion: reverberation times within 5 % of the target in octave bands; aliasing products below −60 dB with oversampling; a blind listening comparison.
    • Deliverables: code, report, sound examples, talk. Chapters 4, 5, 11.

Written exam (proposal)

Format: 2 hours, one handwritten A4 sheet allowed, no electronic device; four independent exercises.

  1. Course question (4 points). Define the STFT. State and prove the overlap-add reconstruction condition, and give a window and a hop that satisfy it.

    Expected: Definition 1.1; Proposition 1.2 with its proof (each frame contributes x(n)\, w\, w_s at time n); the periodic Hann window with R = N/4, whose shifted squares sum to 3/2, so w_s = \tfrac23 w.

  2. Computation (6 points). (a) A feedforward comb at 48 kHz has g = 0.8 and a delay of 2.5 ms: give its notch frequencies, notch depth and peak height. (b) Which gain gives a feedback comb of 1500 samples a reverberation time of 1.2 s? (c) Which loudspeaker spacing makes WFS alias-free up to 1 kHz in every direction?

    Expected: (a) notches at 200, 600, 1000, … Hz, depth −14.0 dB, peaks +5.1 dB (Proposition 4.2). (b) g = 10^{-3 \times 1500 / (1.2 \times 48000)} = 0.835 (Proposition 4.9). (c) c / (2 \times 1000) = 17.2 cm (Proposition 6.5).

  3. Short proof (5 points). Let \mathbf{W} be a basis of the signal subspace of a noiseless sum of K distinct complex exponentials, with L \ge K + 1 rows. Prove that the eigenvalues of the matrix \boldsymbol{\Phi} solving the shift equation are the poles.

    Expected: Theorem 10.4: the shift invariance of the Vandermonde matrix, \mathbf{W} = \mathbf{V}_L \mathbf{G}, the full column rank of the truncated Vandermonde matrix, and the similarity of \boldsymbol{\Phi} with the diagonal matrix of the poles.

  4. Problem (5 points). In an anechoic two-microphone mixture, at a point where \omega_k = \pi/4 rad per sample, the STFT ratio is X_2 / X_1 = 0.6\, e^{-i\pi/8}. (a) Assuming one active source, give its attenuation, delay and symmetric attenuation. (b) Can this delay wrap below the Nyquist frequency? (c) If two Gaussian sources of variances 3 and 1 are active instead, give the MMSE estimate of the first.

    Expected: (a) a = 0.6, \delta = (\pi/8) / (\pi/4) = 0.5 sample, \alpha = 0.6 - 1/0.6 = -1.07 (Proposition 8.3). (b) No: |\omega\delta| \le \pi/2 up to Nyquist (Proposition 8.5). (c) The Wiener estimate \tfrac34 X_1 (Proposition 8.6).

Grading rubric (proposal)

For the paper studies, which are the official assessment format:

Criterion Weight What earns the marks
Understanding of the paper 25 % The problem, the model and the key result are restated correctly, with the assumptions and the link to the course chapters
Implementation 25 % Code written from the equations, tested on synthetic cases with a known answer, seeds fixed, runs end to end
Experiments 20 % The paper’s main figure or table reproduced, with error bars, and at least one experiment the paper does not run
Critical analysis 15 % Limits identified (assumptions that fail on real audio, evaluation pitfalls), negative results explained
Report and oral presentation 15 % A clear report within the page limit, sound examples where relevant, a talk that fits its time and answers questions

References

Official references (master-mva.com)

Textbooks

Features and indexing (ch. 1–2)

Rhythm (ch. 3)

Effects and modifications (ch. 4–5)

Spatial audio (ch. 6)

Source separation (ch. 7–8)

High-resolution spectral analysis (ch. 9–10)

Complements (ch. 11)

Research directions (ch. 12) and data sets