Skip to content

lexicone42/setbreak

Repository files navigation

setbreak

Built with Claude Code Rust

A CLI tool for analyzing jam-band music libraries. Scans audio files, extracts 180+ spectral/temporal/harmonic features via DSP, computes jam-quality scores, and stores everything in SQLite for exploration.

Built for Grateful Dead tape collections, but works with any jam-band library (Phish, Widespread Panic, Goose, Billy Strings, etc.).

What it does

Scan your music library to catalog tracks, parsing band names, show dates, disc/track numbers, and venues from filenames and tags:

setbreak scan ~/music/grateful_dead/ ~/music/phish/
# Scan complete: 10573 scanned, 10573 new, 0 updated, 0 skipped, 0 errors

# Or configure music_dirs in ~/.config/setbreak/config.toml and just:
setbreak scan

Analyze audio files to extract 180+ features using DSP (FFT, STFT, pitch detection, beat tracking, onset detection, chord estimation, harmonic-percussive separation):

setbreak analyze          # auto-detects worker count from config (cores/2)
setbreak analyze -j4      # or specify explicitly
# Analysis complete: 10573 analyzed, 3 failed

Look up song titles from archive.org metadata, matching directory names to archive identifiers:

setbreak setlist --dry-run
# Found 5200 tracks missing titles across 260 directories
# Setlist lookup complete: 255 dirs fetched, 4688 titles updated, 5 errors

Explore your top tracks by any jam score:

setbreak top --sort transcendence -n 10
setbreak top --sort groove --song "Dark Star" -n 5

Find segue chains — multi-song jam suites connected by -> markers, ranked by jam scores:

setbreak chains --sort transcendence -n 10
# Dark Star -> St. Stephen -> The Eleven     1969-02-27   3  44.5    82   63   71   79
# Help > Slip > Franklin's                   1977-05-08   3  32.1    78   58   65   72

Compare versions of a song across shows:

setbreak compare "Dark Star"
# Shows every Dark Star in your library with side-by-side scores

Find similar tracks based on feature-vector cosine distance:

setbreak similar "Dark Star" --date 1972-04-14 -n 10

Discover missing shows from archive.org, comparing your local library against the full collection:

setbreak discover --band gd --year 1977
# Collection: GratefulDead (7700 total shows in archive)
# Local shows: 42 dates | Missing: 38 dates

Classify recordings as live, studio, or live album:

setbreak classify
# Classified: 10233 live, 240 studio, 4 live_album, 96 unknown

Calibrate scores to remove recording quality bias (louder tapes scoring higher):

setbreak calibrate --dry-run   # see regression coefficients
setbreak calibrate             # apply LUFS-based correction

Rescore all tracks when scoring formulas evolve, without re-analyzing audio:

setbreak rescore
# Rescore complete: 10573 tracks updated

Jam scores

Every analyzed track gets 10 scores (0-100), each computed from multiple audio features:

Score Measures High example
Energy RMS + LUFS + sub-band bass + spectral brightness Fire on the Mountain
Intensity Spectral flux variance + dynamic range + loudness range Not Fade Away
Groove Onset rate sweet spot + flux consistency + bass steadiness + pattern repetition China Cat Sunflower
Improvisation Non-repetition + timbral variety + structural density + tonal ambiguity Dark Star
Tightness Tempo stability + coherence + spectral smoothness + beat strength Scarlet Begonias
Build Quality Energy arc detection + tension build/release + energy variance + transitions Dark Star (20+ min)
Exploratory Spectral flatness variety + pitch ambiguity + mode ambiguity + harmonic complexity Space
Transcendence Peak energy + sustained intensity + peak tension + groove-energy synergy Drums > Space
Valence Brightness + tempo + mode + simplicity Sugar Magnolia
Arousal RMS + flux + onset rate + spectral bandwidth Truckin'

Scores are designed to differentiate — a 20-minute Dark Star should score very differently from a 3-minute China Cat Sunflower, and they do. After analysis, calibrate removes recording-quality bias via per-show LUFS regression so a pristine 1977 SBD doesn't automatically outscore a muddy 1969 AUD.

For a detailed breakdown of all 185 extracted features, see ANALYZER.md.

Audio format support

All decoding is native Rust — no external dependencies required:

Format Decoder Notes
MP3 symphonia MPEG Layer III
FLAC claxon Lossless
SHN (Shorten) shorten-rs Common in tape trading
APE (Monkey's Audio) ape-rs All compression levels
WAV symphonia PCM
AIFF symphonia
OGG Vorbis symphonia
M4A/AAC symphonia
Opus symphonia
WavPack ffmpeg fallback Pure Rust decoder in progress
DSF/DFF (DSD) ffmpeg fallback Niche format

DTS-encoded tracks (bitstream masquerading as PCM) are automatically detected and flagged as garbage quality to prevent corrupted analysis results.

Building

Requires Rust 1.85+ (2024 edition). Optional: ffmpeg for WavPack and DSD files only.

# Always build in release mode — debug builds are 10-30x slower for DSP
cargo build --release

Configuration

Optional TOML config at ~/.config/setbreak/config.toml. Everything works without it — the file is purely for overrides.

music_dirs = ["/home/you/music/grateful_dead", "/home/you/music/phish"]
# db_path = "/custom/path/setbreak.db"
workers = 0  # 0 = auto (cores / 2)

[archive]
cache_ttl_days = 30
rate_limit_ms = 500

# Custom bands (merged with 23 built-in bands)
# [[bands]]
# name = "Lettuce"
# codes = ["let", "lettuce"]
# search = ["lettuce"]
# archive = { type = "creator", value = "Lettuce" }

Override priority: CLI argument > config file > built-in default.

The DSP engine is a fork of ferrous-waves (originally by willibrandon) with optimizations for batch analysis — duplicate STFT elimination, configurable feature skipping, and extended spectral/temporal feature extraction. It's pulled automatically as a git dependency.

Architecture

src/
  main.rs              CLI (clap derive) — 15 subcommands
  lib.rs               Public module exports
  bands.rs             Unified band registry (23 bands, 37 codes, OnceLock global)
  config.rs            TOML config loading + XDG paths
  calibrate.rs         LUFS-based score calibration (OLS regression)
  scanner/
    mod.rs             walkdir traversal + lofty tag reading
    filename.rs        Regex-based filename parser (uses BandRegistry)
    metadata.rs        Tag extraction
    classify.rs        Recording type classification (live/studio/live_album)
  analyzer/
    mod.rs             Parallel analysis (rayon + tokio)
    decode.rs          Native audio decoding (symphonia, claxon, shorten-rs, ape-rs)
    features.rs        Feature extraction from AnalysisResult → 185 DB columns
    jam_metrics.rs     Score computation (10 scores)
  db/
    mod.rs             SQLite setup + versioned migrations (v1-v14)
    models.rs          Structs for DB rows
    queries.rs         All SQL (insert, update, query)
  setlist/
    mod.rs             archive.org metadata lookups
  chains.rs            Segue chain detection (multi-song jam suites)
  discovery.rs         archive.org collection discovery (missing shows)
  similarity.rs        Track similarity (cosine distance on feature vectors)

Storage: SQLite with WAL mode. 8 tables, 185 feature columns on analysis_results, plus relational detail tables (chords, segments, tension points, transitions), similarity cache, and archive show cache.

Processing: Rayon thread pool for parallelism, thread-local tokio runtimes for the async analysis engine, chunked processing for crash recovery.

Database

The database lives at ~/.local/share/setbreak/setbreak.db (XDG data dir). Schema uses PRAGMA user_version for migrations (currently v14 — migrations run automatically on startup).

Query examples with sqlite3:

-- Top 10 highest-improvisation tracks
SELECT t.parsed_title, t.parsed_date,
       ROUND(a.improvisation_score, 1) as improv,
       ROUND(a.duration/60.0, 1) as minutes
FROM analysis_results a
JOIN tracks t ON t.id = a.track_id
WHERE t.data_quality != 'garbage'
ORDER BY a.improvisation_score DESC
LIMIT 10;

-- Score comparison across versions of a song
SELECT t.parsed_date,
       ROUND(a.groove_score,1) as groove,
       ROUND(a.improvisation_score,1) as improv,
       ROUND(a.transcendence_score,1) as transcend,
       ROUND(a.duration/60.0,1) as min
FROM analysis_results a
JOIN tracks t ON t.id = a.track_id
WHERE t.parsed_title = 'Dark Star'
  AND t.data_quality != 'garbage'
ORDER BY a.duration DESC;

-- Which shows have the highest average transcendence?
SELECT t.parsed_date,
       COUNT(*) as tracks,
       ROUND(AVG(a.transcendence_score),1) as avg_transcend,
       ROUND(SUM(a.duration)/60.0,0) as total_min
FROM analysis_results a
JOIN tracks t ON t.id = a.track_id
WHERE t.data_quality != 'garbage'
GROUP BY t.parsed_date
HAVING tracks >= 8
ORDER BY avg_transcend DESC
LIMIT 10;

License

Apache-2.0

About

CLI tool for analyzing jam-band music libraries — spectral analysis, jam scoring, segue chain detection, and archive.org integration. Built for Grateful Dead and Phish tape collections.

Topics

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors