Skip to content

Latest commit

 

History

History
203 lines (172 loc) · 11.7 KB

File metadata and controls

203 lines (172 loc) · 11.7 KB

MVP Progress — multidj

Stack: Python 3.9+, SQLite (stdlib only for core), librosa + mutagen (analysis), torch + allin1 (cue detection), CLAP + UMAP + HDBSCAN (embeddings/clustering) Entry point: multidj (primary), mixxx-tool (legacy alias) DB default: ~/.multidj/library.sqlite Last verified: 2026-05-28


Completed Features

Infrastructure

  • Package structure (pyproject.toml, __init__.py, __main__.py)
  • db.pyconnect() (read-only URI + read-write), resolve_db_path(), ensure_not_empty(), migration runner
  • backup.py — timestamped .sqlite copies to ~/.multidj/backups/ before every write
  • models.pyLibrarySummary dataclass
  • utils.pyemit() for JSON / human-readable output
  • constants.py — genres, crate prefixes, regex patterns, CAMELOT_KEY_MAP, KNOWN_ADAPTERS
  • config.pyload_config(), save_config(), get_music_dir(), get_llm_config(); ~/.multidj/config.toml
  • cli.py — argparse with global --json / --db flag hoisting; all subcommands wired
  • adapters/base.pySyncAdapter ABC (import_all, push_track, full_sync)
  • adapters/mixxx.pyMixxxAdapter: import + sync + crate sync + hot cue sync
  • adapters/directory.pyDirectoryAdapter: import tracks from filesystem paths
  • pipeline.pyrun_pipeline(): chains all 13 steps, one backup at start, step isolation, --skip-* flags
  • Migrations: 001_initial.sql, 002_cue_points.sql, 003_crates_add_type.sql, 004_cue_points_add_confidence_source.sql, 005_embeddings.sql

Commands

  • import mixxx — one-time pull from ~/.mixxx/mixxxdb.sqlite; dry-run + apply
  • import directory PATH — scan a directory for audio files and import; --apply, --no-backup
  • sync mixxx — push dirty tracks + crates + hot cues back to Mixxx; dry-run + apply
  • scan — active track counts (genre, BPM, key, rating), crate count
  • backup — manual backup with optional --backup-dir
  • audit genres — genre distribution, case collisions, emoji/uninformative detection
  • audit metadata — field coverage percentages across active tracks
  • audit mismatches — detect artist/title swap mismatches vs filenames
  • clean genres — case normalization, uninformative → NULL, whitespace; --apply, --limit
  • clean text — whitespace strip/collapse + trailing garbage cleanup in title/artist/album; --apply
  • parse — extract artist/title/remixer from filenames; confidence tiers; --apply, --force, --min-confidence, --limit
  • enrich language — detect Hebrew tracks by Unicode range; read-only report
  • analyze bpm — librosa beat tracking (start/mid/end windows); reports variable-BPM; --apply, --force, --limit
  • analyze key — Krumhansl-Schmuckler key detection via librosa/chroma; --apply, --write-tags, --force, --limit
  • analyze energy — librosa RMS × spectral centroid, normalized 0–1; --apply, --force, --limit
  • analyze embed — CLAP 512-dim audio embeddings (3-window sampling, mean-pooled); --apply, --force, --limit
  • analyze cues — structural segmentation via allin1 (neural) + librosa cross-validation; detects intro/verse/chorus/drop/outro; high-confidence cues synced to Mixxx; --apply, --force, --limit
  • cluster vibe — UMAP (512d→10d) + HDBSCAN → Vibe/ crates; LLM naming via OpenAI-compatible API; --apply
  • similar <track> — KNN cosine distance in embedding space; --top N
  • cues clear — remove all auto-detected cues and reset intro_end/outro_start; --apply
  • crates audit — three-tier classification (catch-all / auto / hand-curated), threshold report
  • crates hide/show/delete — bulk crate management; --apply, --min-tracks
  • crates rebuild — delete all auto-crates, recreate from DB; config-driven: Genre:/Lang:/BPM:/Key:/Energy:/Vibe:; --apply
  • dedupe — artist+title and filesize+duration matching; --apply, --by
  • triage — mpv-based keyboard audition: KP0=soft-delete, Shift+KP0=hard-delete (rm file), KP1–5=rating, n=skip, ←/→=±30s; --crate, --limit
  • report dashboard — standalone interactive HTML dashboard; --output
  • pipeline — chains all 13 steps: import→fix_mismatches→parse→dedupe→bpm→key→energy→cues→embed→cluster→genres→clean_text→crates→sync→report; --apply, --skip-<step>, --music-dir, --limit
  • config set-db / set-music-dir / show — persistent config management

Phase 13 — Automatic Cue Detection (2026-05-28)

  • multidj/migrations/004_cue_points_add_confidence_source.sql — adds confidence ('high'/'low') + source ('auto'/'manual') to cue_points
  • multidj/cues.pydetect_cues(), analyze_cues(), clear_cues()
    • allin1 (primary): transformer model → labeled segments + bar grid (downbeats)
    • librosa (secondary): RMS energy + spectral flux + chroma novelty → transition timestamps
    • Cross-validation: both agree within ±1 bar → confidence='high'; allin1 only → confidence='low'
    • Bar-snapping: all positions snapped to nearest allin1 downbeat
    • Derived drop cue from first chorus/instrumental segment
    • source='auto' on all machine cues; source='manual' never overwritten
  • Mixxx hot cue sync: intro=slot 0 (blue), drop=slot 1 (red), outro=slot 2 (green); high-confidence only; slots 0/1/2 wiped and repopulated each sync
  • Escape hatch: multidj cues clear --apply wipes all auto cues + NULLs intro_end/outro_start
  • Pipeline step 8 (after energy, before embed); --skip-cues flag; requires uv sync --extra embeddings

Phase 16 — Triage Player (2026-05-28)

  • multidj/triage.pybuild_triage_queue(), write_m3u(), launch_session(), tag_track()
  • multidj/assets/triage.lua — mpv Lua script: KP0=soft-delete, Shift+KP0=hard-delete, KP1–5=rating, n=skip, ←/→=±30s seek; calls multidj triage tag on each decision
  • multidj triage [--crate NAME] [--limit N] — launches mpv with M3U playlist
  • multidj triage tag — internal write subcommand called by Lua script

Phase 12 — Semantic Embeddings + Clustering (2026-05-27)

  • multidj/migrations/005_embeddings.sqlembeddings table: (track_id PK, model_name, vector BLOB, created_at)
  • multidj/embed.pyanalyze_embed(), find_similar(), load_clap_model(), store_embedding(), load_embeddings_from_db()
    • Model: laion/larger_clap_music (512-dim float32 vectors)
    • 3-window sampling: start / mid / end × 30s, mean-pooled
  • multidj/cluster.pycluster_embeddings(), cluster_vibe(), name_cluster()
    • UMAP: 512d→10d (cosine metric); HDBSCAN: automatic cluster count; noise → Vibe/Unclassified
    • LLM naming via [llm] config; fallback to Vibe/Cluster-NN
  • PoC verified (2026-05-27): 35 tracks encoded, 3 clusters found, 4 Vibe/ crates written

Test Suite

  • 271 tests passing (0 failures)
  • Fixture: 10-track canonical dataset covering duplicates, Hebrew, case collisions, missing metadata
  • Tests: test_import, test_import_directory, test_sync, test_scan, test_audit, test_enrich, test_parse, test_clean, test_crates, test_dedupe, test_analyze, test_analyze_energy, test_config, test_mixxx_crate_sync, test_pipeline, test_embed, test_cluster, test_llm_config, test_triage, test_analyze_cues, test_mixxx_cue_sync, test_migrations, test_report, test_session_changes

Safety Model

  • All commands dry-run by default; nothing written without --apply
  • Auto backup before every write (skip with --no-backup)
  • Soft-delete (deleted=1) everywhere — all destructive operations are recoverable
  • Per-track error isolation in all analyze commands
  • deleted = 0 filter applied in all stats and operations
  • Wrong-DB guard: clear error if pointed at Mixxx DB instead of MultiDJ DB

Roadmap Phase Status

Phase Description Status
0 Package rename mixxx_toolmultidj Done
1 DB layer, migration runner, schema v1 Done
2 import mixxx — one-time pull from Mixxx Done
3 Port all commands to MultiDJ schema Done
4 sync mixxx — push dirty tracks back to Mixxx Done
5 Remove mixxx-tool alias Deferred
6 Standalone ingestion — import directory, analyze bpm/energy, config-driven crates Done
7 Mixxx crate sync Done
8 Fingerprint enrichment — pyacoustid → AcoustID for unknown tracks Planned
9 Cue point detection Done (as Phase 13)
10 Mixxx cue sync Done (as Phase 13)
11 MCP server — expose commands as agent-callable tools Planned
12 Semantic embeddings — CLAP → UMAP+HDBSCAN → Vibe/ crates Done
12b Similarity queries — multidj similar KNN search Done
13 Automatic cue detection — allin1 + librosa → intro/drop/outro → Mixxx hot cues Done
14 MCP embedding/playlist tools Planned
15 Natural language DJ — LLM → playlist Vision
16 Triage player — multidj triage mpv + Lua keyboard-driven audition Done

BPM Range Definitions

Crate Name BPM Range
BPM:<90 0 – 89
BPM:90-105 90 – 104
BPM:105-115 105 – 114
BPM:115-125 115 – 124
BPM:125-130 125 – 129
BPM:128-135 128 – 134
BPM:135-160 135 – 159
BPM:160-175 160 – 174
BPM:175+ 175+

Note: 125–130 and 128–135 intentionally overlap — tracks at 128–130 BPM appear in both Tech House and Techno crates.


Known Issues / Open Items

Priority Item
Medium Fingerprint enrichment (Phase 8) not yet built — unknown tracks have no AcoustID lookup
Medium MCP server (Phase 11) not yet built — commands not agent-callable
Low mixxx-tool legacy alias still active
Low Crates created directly in Mixxx are overwritten on next sync mixxx --apply
Low Energy normalization is library-relative: single-track batch gets energy=0.5

Installation

python3 -m venv .venv
.venv/bin/pip install -e .
.venv/bin/pip install -r requirements-dev.txt
source .venv/bin/activate

# Optional extras
uv sync --extra analysis     # librosa — BPM, key, energy analysis
uv sync --extra embeddings   # torch, torchaudio, transformers, librosa, umap-learn, hdbscan, openai, allin1 — embeddings, clustering, cue detection

Usage Quick-Reference

# One-time bootstrap
multidj import mixxx --apply               # from Mixxx
multidj import directory ~/Music --apply   # from raw files

# Daily workflow (all 13 steps)
multidj pipeline --apply
multidj pipeline --apply --skip-embed --skip-cluster --skip-cues  # skip slow ML steps

# Analysis
multidj analyze bpm --apply
multidj analyze key --apply
multidj analyze energy --apply
multidj analyze cues --apply               # auto-detect intro/drop/outro (requires embeddings extra)
multidj analyze embed --apply              # CLAP embeddings (requires embeddings extra)
multidj cluster vibe --apply              # Vibe/ crates from embeddings

# DJ tools
multidj similar "Artist - Track.mp3"      # find sonically similar tracks
multidj triage --crate "New Tracks"       # keyboard audition via mpv
multidj cues clear --apply               # wipe all auto-detected cues

# Library maintenance
multidj scan
multidj audit genres
multidj clean genres --apply
multidj crates rebuild --apply
multidj sync mixxx --apply
multidj dedupe --apply

# Testing
.venv/bin/pytest tests/ -v   # 271 tests