In [1]:
%matplotlib inline
import seaborn
import numpy, scipy, matplotlib.pyplot as plt, IPython.display as ipd
import librosa, librosa.display
plt.rcParams['figure.figsize'] = (13, 5)

Constant-Q Transform and Chroma

Constant-Q Transform

Unlike the Fourier transform, but similar to the mel scale, the constant-Q transform (Wikipedia) uses a logarithmically spaced frequency axis. For more information, read the original paper:

Let's load a file:

In [2]:
x, sr = librosa.load('audio/simple_piano.wav')
ipd.Audio(x, rate=sr)
Out[2]:

To compute a constant-Q spectrogram, will use librosa.cqt:

In [3]:
fmin = librosa.midi_to_hz(36)
hop_length = 512
C = librosa.cqt(x, sr=sr, fmin=fmin, n_bins=72, hop_length=hop_length)

Display:

In [4]:
logC = librosa.amplitude_to_db(numpy.abs(C))
librosa.display.specshow(logC, sr=sr, x_axis='time', y_axis='cqt_note', fmin=fmin, cmap='coolwarm')
Out[4]:
<matplotlib.axes._subplots.AxesSubplot at 0x1c12a0ab70>

Note how each frequency bin corresponds to one MIDI pitch number.

Chroma

A chroma vector (Wikipedia) (FMP, p. 123) is a typically a 12-element feature vector indicating how much energy of each pitch class, {C, C#, D, D#, E, ..., B}, is present in the signal.

In [6]:
chromagram = librosa.feature.chroma_stft(x, sr=sr, hop_length=hop_length)
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length)
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x1c1b324e10>
In [7]:
chromagram = librosa.feature.chroma_cqt(x, sr=sr, hop_length=hop_length)
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length)
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x1c127c7ba8>

Chroma energy normalized statistics (CENS) (FMP, p. 375). The main idea of CENS features is that taking statistics over large windows smooths local deviations in tempo, articulation, and musical ornaments such as trills and arpeggiated chords. CENS are best used for tasks such as audio matching and similarity.

In [8]:
chromagram = librosa.feature.chroma_cens(x, sr=sr, hop_length=hop_length)
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length)
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x1c128d2400>