CQT

Constant-Q transform: geometrically spaced bins with a constant frequency-to-bandwidth ratio [brown1991], computed by recursive octave decimation [schorkhuber2010]. The log-frequency axis matches musical pitch (an exponential chirp renders as a straight line), which is why it is the front end of choice for music analysis. The VQT generalizes it with a bandwidth offset; Chroma folds its bins onto pitch classes.
specux.cqt(x, *, sr, hop_length=512, fmin=None, n_bins=84, bins_per_octave=12, filter_scale=1.0, sparsity=0.01, tuning=0.0, output="magnitude", eps=1e-10, backend="auto")import numpy as np
import specux
x = np.random.randn(8, 4 * 22050).astype(np.float32)C = specux.cqt(x, sr=22050, n_bins=84)C.shape # (8, 84, 173) = (..., n_bins, n_frames)import torch
import specux
xt = torch.randn(8, 4 * 22050, device="cuda", requires_grad=True)C = specux.cqt(xt, sr=22050, n_bins=84)C.sum().backward() # differentiable, on the GPU end to endimport cupy
import specux
xc = cupy.random.standard_normal((8, 4 * 22050), dtype=cupy.float32)C = specux.cqt(xc, sr=22050, n_bins=84)C.shape # (8, 84, 173), stays on the GPU, no torchBin k is centered on fmin * 2**(k / bins_per_octave) Hz; frame t is
centered on t * hop_length. Leading dimensions pass through.
How it computes
The signal pyramid halves per octave (a zero-phase half-band FIR), so every
octave runs at its natural rate: one boxcar complex STFT per octave, reduced
by that octave’s frequency-domain wavelet basis
[brown1992]. The analysis window lives inside the
basis, each wavelet is L1-normalized, and the per-bin 1/sqrt(length)
scaling is folded into the basis rows, so a unit sinusoid at a bin center
responds with 1/(2*sqrt(length)) at every octave.
Parameters
sr: sample rate in Hz (required; bin frequencies are absolute).hop_length: frame advance at the full rate. Must be divisible by2**(n_octaves - 1)so every pyramid level advances by an integer; anything else raises with the nearest valid value.fmin: lowest bin frequency;Nonemeans C1 (32.70 Hz).n_bins,bins_per_octave: bin count and density. Any values that fit under Nyquist work, including hundreds of bins per octave.filter_scale: Q scaling; below 1 trades frequency resolution for time resolution.sparsity: fraction of each basis row’s magnitude trimmed from the tails (0keeps the full rows).tuning: bin offset in fractions of a bin.output:"magnitude"(the CQT convention, default),"complex","power", or"db".backend:"auto","cuda","cpu", or"metal"for the per-octave transforms.
The configured form
t = specux.CQT(sr=22050, n_bins=84)C = t(x) # (..., n_bins, n_frames)assert specux.CQT(**t.to_dict()) == tThe torch Module for training pipelines is specux.transforms.CQT.
References
- [brown1991]: the constant-Q spectral transform.
- [brown1992]: frequency-domain kernels.
- [schorkhuber2010]: recursive multirate computation.