Skip to content

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 18 May 11:07

headroom 2.0.0 — rbsort ships

This is the first major-version bump since the project began. headroom is no longer just a loudness analyzer: it now has a CLI subcommand surface, and the inaugural subcommand rbsort ships in this release.

All v1.x loudness behaviour is 100% backward-compatibleheadroom <paths> and bare-invocation interactive mode are unchanged.


Headliner: rbsort — Rekordbox playlist sorter for harmonic mixing

A pure XML-in / XML-out workflow. Takes a Rekordbox collection.xml export and produces a key/tempo-sorted copy ready to re-import. No audio is touched, no database is written, ffmpeg is not required.

What it does

Sorts a target playlist — or every TrackID-referenced playlist in the XML — by:

  1. Camelot Key ascending (1A1B2A → … → 12B)
  2. BPM ascending within each key group

Sorted copies are written into a brand-new Sorted (Key+BPM)/ folder appended to the ROOT node, each playlist keeping its source name. Mirrors the analyzer's existing backup/ directory pattern.

Tracks with no Camelot key sort after all known keys; within a key group, tracks with no/0 BPM sort last.

Usage

# Sort *every* TrackID-referenced playlist in one pass (recommended)
headroom rbsort --xml /path/to/collection.xml

# Sort a single playlist with a custom name
headroom rbsort \
  --xml /path/to/collection.xml \
  --playlist "Folder/MyPlaylist" \
  --output sorted.xml \
  --name "MyPlaylist (Camelot+BPM)"

Defaults:

Flag Behaviour when omitted
--output <input-stem>-out.<ext> next to the input (e.g. coll.xmlcoll-out.xml)
--playlist Sort every TrackID-referenced (KeyType="0") playlist in the XML

Rekordbox workflow

  1. Preferences > View > Key display format → Alphanumeric so Tonality exports as Camelot (1A..12B). Non-Camelot tonalities silently sort last.
  2. File > Export Collection in xml formatcollection.xml.
  3. Run headroom rbsort --xml collection.xml.
  4. Preferences > Advanced > Database > rekordbox xml → Imported Library points at the output XML; restart Rekordbox.
  5. Open the rekordbox xml tree in the left sidebar; drag the sorted playlist into your real Playlists tree, or right-click → Export Playlist for CDJ EXPORT mode.

Implementation highlights

  • New module src/rbsort/ (mod, camelot, xml) on top of quick-xml 0.40.
  • Two-pass design: scan COLLECTION + target playlists, then stream-rewrite with the sorted folder injected inside <PLAYLISTS> before the ROOT </NODE> closes. ROOT Count is bumped by 1.
  • Robust against real Rekordbox exports — <TRACK> elements with nested <TEMPO> / <POSITION_MARK> children are handled correctly (the original Event::Empty-only path produced an empty collection map and a no-op sort).
  • Subcommand dispatch short-circuits before the audio pipeline, the banner, ffmpeg check, and the update check — rbsort runs in milliseconds and has zero audio-stack dependencies.
  • Verified end-to-end on a real 5,255-track / 24-playlist Rekordbox export — sorted in under a second with zero ordering violations.

Why a major version?

Until now, headroom only did one thing: audio loudness analysis and gain adjustment. v2.0.0 introduces a subcommand surface to the CLI, and rbsort is the first to land there. Future non-audio DJ-prep workflows (set planning, transition analysis, etc.) will be added as subcommands too.

Existing flows are untouched:

  • headroom → interactive loudness analyzer (unchanged)
  • headroom <paths> [flags] → scriptable loudness analyzer (unchanged)
  • headroom rbsort ...new Rekordbox playlist sorter

Internal

  • XML scanner/rewriter switched to byte-level element-name comparison and single-pass attribute extraction — fewer allocations on large exports.
  • Option<T> "None-last" ordering extracted into a reusable helper.
  • processor.rs internal helpers tightened from pub to private; dead AnalysisSummary::total() removed.
  • default_output_path simplified to use Path::with_file_name.
  • 19 unit tests, including full XML round-trip with multi-playlist nested folders.

Migration

None. The audio side is wire-compatible with v1.x. rbsort is purely additive.