André van Schaik
International Centre for Neuromorphic Systems
The University of Manchester
June 2026
with Claude Code Opus 4.8
A from-scratch, fully invertible Constant-Q Transform (CQT) developed step by step in a
single Jupyter notebook (hybrid_cqt.ipynb). It is written to be didactic: every stage —
the analysis kernels, the efficient multi-rate algorithm, the matching inverse, and a set of
test signals — is explained in the markdown alongside the code.
Music is logarithmic in pitch, so a transform should space its bins geometrically (per octave) and give each bin a bandwidth proportional to its centre frequency — a constant-Q filter bank. This is also, roughly, how the cochlea analyses sound. A naïve CQT is expensive, though: the lowest bin needs a very long window, which would set the size of one huge FFT run at every hop.
- Multi-rate. Halving the sample rate and the frequency leaves the required window length
unchanged, so each octave is analysed at its own decimated rate. Every octave then shares
one small
N_fftand one set of kernels. - Per octave. Frame the (decimated) signal, take a single batch FFT, and matrix-multiply
by pre-computed frequency-domain kernels. Cost is
O(M · B · N log N): many small FFTs instead of one large one. - Invertible. The kernels are normalised so their squared responses sum to 1, making the
filter bank a Parseval (tight) frame. Its inverse is then just the adjoint
Kᴴ(a transpose — no pseudoinverse or SVD), followed by overlap-add and upsampling.
HybridCQT(forward) andHybridICQT(inverse), sharing the same kernel matrix.- A visualisation of the filter bank: kernel overlap and the flat (tight-frame) coverage.
- Six worked examples — pure sine, chord, log chirp, major scale, inharmonic bell, and band-limited noise — each with audio and a spectrogram, chosen to probe a different property.
- Round-trip reconstruction with SNR, and forward / round-trip performance benchmarks.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtOpen hybrid_cqt.ipynb in Jupyter or VS Code and run the cells in order, top to bottom.
| Parameter | Value | Description |
|---|---|---|
FS |
44100 | Sample rate (Hz) |
F_MIN |
65.41 | Lowest bin centre — C2 |
N_OCTAVES |
7 | C2 → C9 (≈ 8.4 kHz) |
BINS_PER_OCTAVE |
24 | Quarter-tone resolution (2 bins per semitone) |
HOP_LENGTH |
64 | ≈ 1.45 ms; gives the top octave an 8× overlap |
The small hop is chosen for the inverse (the overlap-add needs generous overlap). For
analysis-only use it can be enlarged toward N_fft/2 for faster processing at coarser time
resolution — see section 2.5 of the notebook.