Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Authored by Souvik Mandal, Ph.D.

Project Leader & Instructor, Computational Behavioral Sciences, LS100, FAS, Harvard University | Linkedin ID: souvik-mandal-phd


Last updated: 2026-07-02

Open in Colab Open in GitHub Codespaces

This notebook extracts a rich set of musical features from audio tracks and produces:

  • Timestamped annotations (beats/BPM, rhythm structure, chords, melody F0, loudness, instrument probabilities, etc.).

  • Per-track JSON metadata written to ./outputs/metadata/.

  • Embeddings & tabular features written to ./outputs/features/.

  • Clustering & 2D visualization of track similarity (UMAP + HDBSCAN, with a K-Means fallback).

Folder structure: place your audio files under ./audio/ (e.g., WAV/MP3).
Recommended formats: 44.1 kHz or 48 kHz, mono or stereo.

Install dependencies

Uncomment the pip install line(s) if you need to install any package listed. You can remove the name of the packages that are already installed in your virtual environment. If you are running this notebook on cloud notebooks (e.g., Colab, Codespaces, etc.), you will most probably need to install all the packages. I deliberately did not pin the versions to keep compatibility broad for teaching (and to give you a taste of troubleshooting, in case a trouble occurs due to version conflict).

Helper utilities for time indexing and statistics

This cell defines small utility functions used throughout the notebook.

  • load_audio_mono(...) loads an audio file at a fixed sample rate and converts it to mono so downstream analyses use consistent input.

  • frame_times(...) converts frame indices to timestamps, which aligns feature arrays with real time in seconds.

  • summarize_series(...) computes robust summary statistics (mean, std, min, max, median) for numeric feature vectors.

Together, these helpers reduce repeated code and standardize how values are loaded, aligned, and summarized.

Rhythm and tempo analysis functions

This cell extracts beat-level rhythm features from each track.

  • compute_beats(...) estimates global tempo (BPM), beat timestamps, and instantaneous tempo from inter-beat intervals.

  • compute_tempogram(...) builds an onset-strength tempogram and derives a local tempo curve over time.

  • compute_downbeats_optional(...) tries to detect bar-level downbeats using madmom if installed, and safely falls back to an empty result if unavailable.

These functions provide both global and time-varying rhythm descriptors for metadata and later feature aggregation.

Chord template construction and segmentation

This cell builds a lightweight chord-recognition pipeline based on chroma features.

  • It first creates 12 major and 12 minor triad templates over pitch classes.

  • chord_segments(...) computes chroma, synchronizes it to beat boundaries, and matches each segment to the best-scoring chord template.

  • It then merges consecutive identical chord labels to produce cleaner harmonic segments with start/end times and confidence values.

The approach is interpretable and robust for teaching harmonic structure extraction.

Melody pitch tracking with CREPE

This cell defines melody extraction from raw waveform audio.

  • estimate_melody_f0(...) calls CREPE to estimate frame-wise fundamental frequency (f0) and confidence.

  • It returns synchronized arrays of timestamps, frequency values (Hz), and confidence scores.

This gives a melody contour that can be analyzed for pitch movement, register, and confidence-weighted quality.

Loudness and timbre feature extraction

This cell computes energy and spectral descriptors that characterize sound texture.

  • loudness_rms(...) calculates frame-wise RMS energy from the STFT and summarizes the distribution.

  • timbre_features(...) computes MFCCs and spectral descriptors (centroid, bandwidth, rolloff, ZCR, tonnetz), then summarizes or averages them.

These descriptors capture intensity, brightness, noisiness, and harmonic color of each track.

Instrument probability tagging over time

This cell estimates likely instruments present throughout a track using pretrained music tagging.

  • instrument_taggram(...) runs the musicnn tagger to obtain a frame-by-frame tag probability matrix.

  • It maps broad instrument names (for example, guitar, piano, drums) to matching model tags.

  • For each time frame, it stores probabilities and marks instruments as present when probability exceeds a threshold.

The output includes a time-resolved taggram and a compact list of detected instruments.

Deep audio embeddings with OpenL3

This cell converts audio into dense vector embeddings suitable for similarity analysis.

  • compute_openl3_embeddings(...) computes frame-wise OpenL3 embeddings from waveform input.

  • It also computes a mean embedding per track, which becomes a compact fixed-length representation.

These embeddings capture high-level audio characteristics and are later combined with handcrafted features.

End-to-end processing for one track

This cell defines the main per-track pipeline that orchestrates all earlier feature functions.

  • process_track(...) loads audio and computes tempo, rhythm, chords, melody, loudness, timbre, instrument tags, and embeddings.

  • It packages results into a structured metadata dictionary with both scalar summaries and time-series annotations.

  • To keep metadata JSON manageable, it stores only the mean OpenL3 embedding (not full frame embeddings).

This function centralizes the workflow so batch processing can call one consistent interface.

Batch processing and feature table export

This cell runs the full pipeline over all audio files in the input folder and writes outputs to disk.

  • It finds supported audio files under ./audio/ and processes each with process_track(...).

  • For each track, it saves rich per-track metadata as JSON in ./outputs/metadata/.

  • It builds a flattened, model-ready track-level feature vector (timbre stats, instrument indicators, OpenL3 mean embedding).

  • Finally, it exports the tabular dataset to both Parquet and CSV in ./outputs/features/.

This produces the main dataset used for downstream clustering and visualization.

Dimensionality reduction, clustering, and 2D plotting

This cell transforms the feature table into a low-dimensional representation and groups similar tracks.

  • It reloads feature data, separates identifier columns, and standardizes numeric features.

  • It applies PCA for compactness, then UMAP for 2D embedding suitable for visualization.

  • It clusters tracks using HDBSCAN when available, otherwise falls back to K-Means.

  • It saves clustering results and produces a labeled UMAP scatter plot image.

This step turns high-dimensional descriptors into interpretable structure for exploratory analysis.

Quick metadata inspection for validation

This final cell performs a sanity check by loading one generated metadata JSON file and printing selected sections.

  • It looks for files in ./outputs/metadata/ and opens the first available JSON.

  • It prints a compact preview of key fields (track, tempo, rhythm, chords) for quick verification.

  • If no files exist yet, it reminds you to run the batch processing cell first.

Use this as a lightweight quality-control step to confirm that extraction outputs are being generated as expected.