An FFT at 44,100 Hz sample rate with a 4096-point window gives you bins that are about 10.8 Hz wide, spaced linearly from 0 to 22,050 Hz. A2 and Bb2 (110 Hz and 116 Hz) are separated by barely 0.6 bins: two adjacent semitones land in the same bucket and are unresolvable. A4 and Bb4 (440 Hz and 466 Hz) are separated by about 2.4 bins: barely distinct. Two octaves higher, A6 and Bb6 (1760 Hz and 1865 Hz) are nearly 10 bins apart: comfortably resolved.
Same interval. Completely different resolution depending on register. The FFT knows nothing about octaves or semitones. It divides frequency into equal slices in Hz, and music does not live in equal Hz slices.
The Constant-Q Transform (CQT) solves this by making bandwidth proportional to center frequency instead of fixed. Every bin covers the same musical interval, regardless of where it sits in the spectrum.
The Q Factor
Q is not exclusive to audio. Electrical engineers use it to describe resonant circuits: Q = f_center / bandwidth, where bandwidth is the 3 dB rolloff width. A high-Q resonator has a narrow bandwidth relative to its center frequency. A tuning fork has a Q in the thousands. A guitar string has a Q in the hundreds.
In signal processing, every analysis window functions as a bandpass filter. The FFT uses a rectangular or Hann window of fixed length, which gives every bin the same bandwidth in Hz. That means Q varies: low-frequency bins have high Q (narrow bandwidth relative to center frequency), and high-frequency bins have low Q (wide bandwidth relative to center frequency). For music analysis, this is backwards.
The CQT fixes Q at a constant value across all bins. Bandwidth scales with center frequency, which is exactly how the musical interval system works: a semitone is always a 6% frequency ratio, not a fixed 10 Hz gap.
The Math
For a CQT with B bins per octave, the required Q value is:
Q = 1 / (2^(1/B) - 1)
For B = 12 (one bin per semitone), this gives Q ≈ 16.8. For B = 24 (quarter-tone resolution), Q ≈ 34.1.
The center frequency of bin k (counting from bin 1 at the minimum frequency f_min) is:
f_k = f_min * 2^((k-1)/B)
Each bin k requires an analysis window of size N_k samples:
N_k = round(Q * fs / f_k)
Where fs is the sample rate. Because f_k doubles with each octave, N_k halves. A low-frequency bin needs a long window to resolve the narrow frequency difference between adjacent notes. A high-frequency bin needs a short window, and the notes are farther apart in Hz anyway, so that works out.
This connection to Judith C. Brown's 1991 paper "Calculation of a constant Q spectral transform" (JASA, vol. 89, no. 1, pp. 425-434) is direct: she was the first to formalize this relationship and show that a computationally practical transform with constant Q could be built from a bank of time-domain basis functions.
The Time-Frequency Tradeoff
There is no free lunch here. The Heisenberg-Gabor uncertainty principle for signal analysis states that you cannot simultaneously have high frequency resolution and high time resolution. A long analysis window resolves frequency precisely but smears time. A short window pinpoints time but blurs frequency.
The CQT navigates this tradeoff in a musically sensible way:
- Low-frequency bins use long windows (hundreds to thousands of samples) and resolve pitch precisely but lag in time.
- High-frequency bins use short windows (tens of samples) and respond quickly but cannot separate closely spaced harmonics.
For music, this is the right compromise. In the bass register, tempo is slow and harmonic relationships matter most. In the treble, transient timing matters and harmonic density is high. An FFT with a single window size forces you to choose one tradeoff for everything. The CQT gives the right tradeoff for each register automatically.
Computing the CQT
The naive implementation is expensive. Computing each bin separately with its own DFT would cost O(N_k) per bin, and the low-frequency bins have very large N_k. The total computational cost is proportional to N_1 * number_of_bins, which is impractical in real time.
The efficient approach treats the CQT as a sparse matrix multiplication. The basis functions a_k(n) are windowed complex sinusoids. Their DFTs are sparse: most of the energy is concentrated around the center frequency, and values far from that peak are near zero. Truncating those near-zero values and computing only the nonzero region turns the full DFT into a short inner product. Brown and Puckette introduced this sparse approach in a 1992 follow-up paper (JASA, vol. 92, no. 5).
In practice, the CQT is often computed by:
- Computing a standard FFT of the input frame
- Multiplying by the complex-valued spectral kernels for each bin (each kernel being a short, localized region of the FFT output)
- Summing to get the CQT coefficient for that bin and time frame
This keeps the cost proportional to the number of nonzero kernel samples, which scales reasonably with frequency and bin count.
From CQT to Chromagram
A chromagram collapses pitch across octaves. It maps all CQT bins to their pitch class: A is A regardless of octave, C# is C# regardless of register. The result is a 12-dimensional vector per time frame describing the relative strength of each of the 12 pitch classes.
To compute it, you sum the CQT magnitudes for all bins that correspond to the same pitch class across all octaves:
chroma[p] = sum of |CQT[k]| for all k where (k mod B) == p
Chromagrams are the backbone of most chord recognition and key detection systems. The chord "C major" has strong energy in pitch classes C, E, and G. A chromagram makes that pattern visible regardless of which octave the instrument is playing in.
Because the CQT bins align to semitones, the pitch class assignment is exact. An FFT-based chromagram requires interpolation to map non-aligned bins to pitch classes, introducing inaccuracies that become audible in chord detection at the borders between keys.
Practical Applications
Tuner plugins: A tuner computing pitch from an FFT is limited by bin resolution. At A4, a 4096-point FFT at 44,100 Hz gives roughly 10.8 Hz per bin. The deviation between A (440.0 Hz) and one cent flat (439.75 Hz) is 0.25 Hz, smaller than one bin. Accurate tuner software uses either zero-padding (expensive), phase derivatives, or a CQT-like approach where the analysis window is adapted to the frequency being measured.
Chord detection: Libraries like Essentia, Librosa, and madmom all use CQT-derived chromagrams as the primary feature for chord recognition. Training machine learning models on raw FFT features requires the network to learn the octave equivalence relationship. CQT features provide that equivalence for free.
Audio visualization: Spectrum analyzers that display by musical octaves rather than linear Hz are using CQT (or a variant called the constant-Q spectrogram). DAW spectrum displays that look "wrong" with heavily bass-boosted signals are often using linear FFT, where the bass registers occupy a tiny fraction of the display width.
Music transcription: Automatic transcription systems that convert audio to MIDI use CQT representations because note onset and pitch are aligned to the feature dimensions that the model must classify.
Implementation in JUCE
A practical CQT in a JUCE plugin can be built by precomputing the spectral kernels in the constructor and applying them to each FFT output buffer. The kernel for bin k is a Hann-windowed complex sinusoid of length N_k, zero-padded to match the FFT size. At runtime, the cost is a set of dot products between the FFT output and each kernel's nonzero region.
// Precompute kernels (simplified sketch)
for (int k = 0; k < numBins; ++k)
{
double fk = fMin * std::pow(2.0, k / binsPerOctave);
int Nk = (int)std::round(Q * sampleRate / fk);
kernels[k] = computeHannKernel(Nk, fk, sampleRate);
}
// At runtime
auto fftOutput = computeFFT(inputBuffer);
for (int k = 0; k < numBins; ++k)
cqtOutput[k] = applyKernel(fftOutput, kernels[k]);
For real-time use, the kernel application step dominates. Precomputing and caching kernel positions, and skipping bins where the signal is below threshold, keeps the per-block cost predictable.
When to Use CQT Instead of STFT
Use the CQT when:
- Frequency resolution needs to align with musical intervals (tuners, chord detection, transcription)
- Your feature space should be invariant to octave transposition (machine learning models on chords or keys)
- You are building a spectrum display that should feel like a piano keyboard
Stick with the STFT when:
- You need uniform time resolution across all frequencies (onset detection, attack characterization)
- Latency budget is tight and the CQT's variable window introduces too much delay in the bass
- Spectral editing requires a reversible transform (inverse CQT exists but adds complexity)
The FFT is not wrong. It is the right tool for signals where frequency is a linear quantity. Music just is not one of those signals.