Music is a complex layered signal. To classify it, we must extract features that describe the instruments, the melody, and the underlying beat.
1The Harmonic DNA
Chroma Features (or Chromagrams) are a powerful tool for musical analysis. They project the entire spectrum onto 12 bins representing the 12 semi-tones of the musical octave (C, C#, D, etc.). Because it discards octave information, Chroma is incredibly robust for identifying Chord Progressions and Melodic Patterns, regardless of the instrument's pitch. This makes it a key feature for identifying genres like 'Blues' or 'Jazz', where specific harmonic structures are dominant.
import librosa
# Extract Chroma features (12 pitch classes)
chroma = librosa.feature.chroma_stft(y=y, sr=sr)
print(f"Chroma shape: {chroma.shape}")2The Heartbeat of Music
Temporal features like Tempo and Beat Tracking are essential for distinguishing between genres with similar spectral profiles. For example, 'Reggae' and 'Pop' might use similar instruments, but the placement of the beat and the BPM (Beats Per Minute) are fundamentally different. Librosa's beat tracking algorithms look at the 'Onsets' (sudden energy increases) to estimate the periodic rhythm that humans naturally tap their feet to.
# Calculate BPM and exact beat frames
tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
print(f"Estimated Tempo: {tempo[0]:.2f} BPM")3Timbre & Brightness
Beyond notes and beats, we use Spectral Descriptors to capture the 'Feel' of the music. Spectral Centroid measures where the 'Center of Mass' of the spectrum is—high for bright genres like Metal, low for warm genres like Classical. Spectral Rolloff measures the 'Shape' of the high frequencies, and Spectral Flux measures how quickly the spectrum is changing from frame to frame, capturing the 'Aggression' or 'Smoothness' of a track.
# Calculate Spectral Descriptors
centroid = librosa.feature.spectral_centroid(y=y, sr=sr)
rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)
# Average to get a single number for the track
mean_centroid = centroid.mean()