Skip to content

Releases: M-Igashi/baken

v3.0.1

Choose a tag to compare

@github-actions github-actions released this 15 Jul 23:18

Bake'n Deck 3.0.1 — faster lossless gain via mp3rgain 2.10

Highlights

  • Updated built-in mp3rgain library from 2.9.6 to 2.10.0. The gain-apply pipeline now reads each file once instead of twice, roughly halving I/O on large batches, and APE tag-only updates rewrite just the file tail. Output stays bit-identical — this is a pure performance update, no behavior changes.

Other Changes

  • Deduplicated the shared interactive/scriptable pipeline in cli.rs
  • Codebase simplification: deduplicated XML helpers, fixed a potential panic on non-ASCII paths, misc cleanups
  • Added homepage to crate metadata (now live on crates.io)
  • Excluded web/ from the crates.io package

Full Changelog: v3.0.0...v3.0.1

v3.0.0

Choose a tag to compare

@github-actions github-actions released this 08 Jul 08:06
50441bc

Bake'n Deck 3.0.0 — headroom is now baken

headroom is now Bake'n Deck (issue #60). The binary, crate, Homebrew formula, and repository are renamed to baken, the CLI moves to a subcommand layout, and a third subcommand — cdjsafe — completes the Rekordbox → CDJ prep toolkit: loudness gain, Key+BPM playlist sort, and CDJ-safe MP3 transcode, all baked into the files so they survive USB export.


Highlights

  • Rebrand: headroom → Bake'n Deck (baken) (#60). New install channels: brew install M-Igashi/tap/baken, winget install M-Igashi.baken, cargo install baken, yay -S baken-bin. Website moves to baken.ravers.workers.dev. This is a hard cut — the old headroom channels stop receiving updates (pre-announced in #61).
  • Subcommand CLI. The loudness analyzer now lives under baken headroom; the playlist sorter stays at baken rbsort. Bare baken prints help. All analyzer flags and both interactive/scriptable modes are unchanged, just one level deeper.
  • New: baken cdjsafe (#40). Emergency-backup USB prep for pre-NXS2 CDJs: converts every track in a Rekordbox playlist to 320 kbps CBR MP3 @ 44.1 kHz (ID3v2.3, artwork kept) and emits an updated XML in which each new track inherits the source's beatgrid and hot/memory cues verbatim — import, "Import to Collection", export to USB, no re-analysis. Sources already at the safe profile are copied byte-identically; lossy→lossy re-encodes are listed in the run report.

Other changes

  • CSV report default filename is now baken_report_<timestamp>.csv.
  • Update-check opt-out env var renamed: HEADROOM_NO_UPDATE_CHECKBAKEN_NO_UPDATE_CHECK.
  • Backup directories are marked with .baken-backup; directories with the legacy .headroom-backup marker are still skipped, so existing v2 backups are never re-processed.
  • Cargo metadata refreshed: description and keywords now reflect the DJ/Rekordbox/CDJ scope.
  • Docs and release workflow rebranded; the Homebrew formula published by CI is now Formula/baken.rb.

Migration

Reinstall via the new baken packages — the old headroom install channels no longer receive updates:

Old New
brew install M-Igashi/tap/headroom brew install M-Igashi/tap/baken
winget install M-Igashi.headroom winget install M-Igashi.baken
cargo install headroom cargo install baken
yay -S headroom-bin yay -S baken-bin
headroom [paths] [flags] baken headroom [paths] [flags]
headroom rbsort ... baken rbsort ...
HEADROOM_NO_UPDATE_CHECK BAKEN_NO_UPDATE_CHECK

Scripts calling the old bare headroom command must switch to baken headroom; flags are unchanged.


v2.1.1

Choose a tag to compare

@github-actions github-actions released this 03 Jul 14:02

headroom 2.1.1 — rbsort performance & maintenance

A small maintenance release. rbsort XML parsing is faster, and the dependency and CI toolchains are refreshed. No new flags, no behavior changes: output is byte-identical to 2.1.0.


Performance

  • Faster rbsort XML parsing (#56). Both the scan and rewrite passes now read events directly from the in-memory XML slice (quick-xml's zero-copy slice reader) instead of copying each event through an intermediate buffer, and the rewrite pass writes borrowed events instead of deep-copying them. The collection map is also pre-sized from the COLLECTION Entries attribute. ~10% faster on a 50k-track (32 MB) collection export, with byte-identical output.

Other changes

  • Dependencies: quick-xml 0.40 → 0.41, mp3rgain 2.8.0 → 2.9.4, plus routine rust-minor-patch group updates (serde, serde_json, chrono, clap, …).
  • CI: actions/checkout v6 → v7, dtolnay/rust-toolchain refreshed, softprops/action-gh-release 3.0.0 → 3.0.1.

Migration

None. Fully backward-compatible with v2.1.0.


v2.1.0

Choose a tag to compare

@github-actions github-actions released this 12 Jun 16:53

headroom 2.1.0 — AI-assisted hardening & performance

A reliability and performance release. The codebase was systematically audited with Claude (Fable 5), which uncovered several latent bugs — including one that could silently modify your backups — all fixed here, alongside a round of performance work. No new flags, no breaking changes: existing commands behave the same, just safer and faster.


Latent bugs found & fixed (Claude Fable 5 audit)

  • Backups are no longer re-processed (#45). The default backup directory <target>/backup lives inside the scan root, so a second run would pick the backup copies up and gain-adjust them too — defeating the purpose of a backup. Backup directories created by headroom now contain a .headroom-backup marker file and are skipped during recursive scans. Explicitly pointing headroom at a backup directory still works. Note: backups created by older versions are unmarked; re-running with --backup marks the default location going forward.
  • Silent audio no longer saturates the gain math. ffmpeg's loudnorm reports -inf for silent files, which previously overflowed into i32::MAX gain steps. Non-finite measurements are now rejected with a clear per-file error.
  • Backup path edge case. With mixed-root inputs, strip_prefix could yield an absolute or empty relative path, making the backup copy target the source file itself. Now guarded with a bare-filename fallback.
  • Report column alignment. Columns are padded before ANSI styles are applied, fixing misaligned analysis tables.

Performance

  • Parallel gain processing. File processing now runs in parallel via rayon (analysis already did), cutting wall-clock time on multi-file batches.
  • One less process per lossy file (#47). The bitrate is parsed from the loudnorm run's existing ffmpeg output instead of spawning a separate ffprobe for every MP3/AAC file; ffprobe remains as a fallback.
  • Startup is never blocked by the update check (#46). The version check runs on a background thread with a 3-second timeout, and the upgrade hint now prints after the run — where you'll actually see it.

Other changes

  • Refactor: per-format gain wrappers merged into a single LossyFormat enum
  • Docs: rbsort sort-comparison write-up (docs/rbsort-sort-comparison.md), README updates
  • Dependencies: mp3rgain 2.7.0 → 2.8.0, chrono 0.4.45, serde_json bump
  • CI: actions/checkout pinned to v6.0.3

Migration

None. Fully backward-compatible with v2.0.x.


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.

v1.10.1

Choose a tag to compare

@M-Igashi M-Igashi released this 15 May 13:45

Highlights

  • mp3rgain 2.6.1: Upgrade to the stable symphonia 0.6.0 release (previously 0.6.0-alpha.2). No public API changes; lossless MP3/AAC gain behavior is identical.

Other Changes

  • ci: bump actions/dependency-review-action from 4.9.0 to 5.0.0 (#36)

Highlights

  • Uniform True Peak ceiling at -0.5 dBTP, with full per-run tuning. AES TD1008's bitrate-dependent ceiling describes the limiter threshold prior to lossy encoding (§7B Sources of Peak Overshoot — Codecs). headroom processes already-encoded delivery files, where there is no further codec stage downstream to absorb additional overshoot, so the same -0.5 dBTP ceiling — the most aggressive value TD1008 sanctions for any limiter in the chain — is now applied uniformly to every file. Low-bitrate lossy files gain +0.5 dB of loudness for free; lossless and ≥256 kbps lossy behaviour is unchanged. Resolves #34.
  • New --tp-target <DB> flag. Override the uniform target with any custom value, e.g. --tp-target -1.0 for the Spotify / Apple Music / YouTube delivery max, or --tp-target -2.0 for a conservative master that leaves headroom for player-side SRC / Hilbert downmix.
  • New --tp-split-bitrate flag. Opt back into the legacy bitrate-dependent split (-0.5 dBTP for ≥256 kbps, -1.0 dBTP for <256 kbps). Mirrors TD1008's pre-encode interpretation for users who prefer it.
  • Native-lossless threshold scales with the chosen target. The True Peak below which an MP3/AAC file qualifies for in-place global_gain modification is now target − 1.5 dB rather than the hardcoded -2.0 / -2.5 dBTP used through v1.9.x.
  • mp3rgain bumped to v2.5.0. Brings a fix for temp-file collisions when applying gain in parallel (mp3rgain@4e9b0b3) — relevant because headroom applies gain across files in parallel via rayon. Also picks up faster AAC apply / ReplayGain analysis pipelines.

Documentation

  • New docs/true-peak-ceiling.md walks through the TD1008 reading with §-level citations, explains the pre-encode vs delivery distinction, and lists preset flag combinations for common targets (Spotify / R128 / TD1008 §4 / TD1008 §7B).
  • README §True Peak Ceiling rewritten end-to-end with the new flag table and migration note.

Migration

Users who relied on the v1.9.x bitrate-dependent split can restore it exactly with --tp-split-bitrate. Users who want to match streaming-platform delivery max can use --tp-target -1.0.

v1.10.0

Choose a tag to compare

@github-actions github-actions released this 07 May 23:43

Highlights

  • Uniform True Peak ceiling at -0.5 dBTP, with full per-run tuning. AES TD1008's bitrate-dependent ceiling describes the limiter threshold prior to lossy encoding (§7B Sources of Peak Overshoot — Codecs). headroom processes already-encoded delivery files, where there is no further codec stage downstream to absorb additional overshoot, so the same -0.5 dBTP ceiling — the most aggressive value TD1008 sanctions for any limiter in the chain — is now applied uniformly to every file. Low-bitrate lossy files gain +0.5 dB of loudness for free; lossless and ≥256 kbps lossy behaviour is unchanged. Resolves #34.
  • New --tp-target <DB> flag. Override the uniform target with any custom value, e.g. --tp-target -1.0 for the Spotify / Apple Music / YouTube delivery max, or --tp-target -2.0 for a conservative master that leaves headroom for player-side SRC / Hilbert downmix.
  • New --tp-split-bitrate flag. Opt back into the legacy bitrate-dependent split (-0.5 dBTP for ≥256 kbps, -1.0 dBTP for <256 kbps). Mirrors TD1008's pre-encode interpretation for users who prefer it.
  • Native-lossless threshold scales with the chosen target. The True Peak below which an MP3/AAC file qualifies for in-place global_gain modification is now target − 1.5 dB rather than the hardcoded -2.0 / -2.5 dBTP used through v1.9.x.
  • mp3rgain bumped to v2.5.0. Brings a fix for temp-file collisions when applying gain in parallel (mp3rgain@4e9b0b3) — relevant because headroom applies gain across files in parallel via rayon. Also picks up faster AAC apply / ReplayGain analysis pipelines.

Documentation

  • New docs/true-peak-ceiling.md walks through the TD1008 reading with §-level citations, explains the pre-encode vs delivery distinction, and lists preset flag combinations for common targets (Spotify / R128 / TD1008 §4 / TD1008 §7B).
  • README §True Peak Ceiling rewritten end-to-end with the new flag table and migration note.

Migration

Users who relied on the v1.9.x bitrate-dependent split can restore it exactly with --tp-split-bitrate. Users who want to match streaming-platform delivery max can use --tp-target -1.0.

v1.9.0

Choose a tag to compare

@github-actions github-actions released this 29 Apr 06:04

Highlights

  • Update notification on startup. headroom now checks GitHub Releases once per 24 hours and prints the appropriate upgrade command (Homebrew / winget / cargo) when a newer version is available. Disable with --no-update-check or HEADROOM_NO_UPDATE_CHECK=1.
  • Reliable AAC/M4A gain via mp3rgain v2.3.0. Picks up mp3rgain#120 which fixes a short-window spectral parser bug that previously caused some processed .m4a files to fail in ffmpeg with invalid band type / Number of bands exceeds limit. Also benefits from mp3rgain#121 — AAC analysis is now 4-6× faster.

Other Changes

  • deps: bump rayon and the rust-minor-patch group (#33)

v1.8.0

Choose a tag to compare

@github-actions github-actions released this 17 Apr 20:00

Installation

Platform Command
macOS (Homebrew) brew install M-Igashi/tap/headroom
Windows (winget) winget install M-Igashi.headroom
Cargo cargo install headroom (ffmpeg must be installed separately)

Package managers (Homebrew, winget) install ffmpeg automatically. mp3rgain is built-in — no separate installation needed.

Checksums

See headroom-v1.8.0-checksums.txt for SHA256 checksums of all binaries.

What's Changed

  • ci: bump softprops/action-gh-release from 2.6.1 to 3.0.0 by @dependabot[bot] in #30
  • ci: bump actions/upload-artifact from 7.0.0 to 7.0.1 by @dependabot[bot] in #31
  • feat: add CLI flags for scriptable, non-interactive usage (#29) by @M-Igashi in #32

Full Changelog: v1.7.3...v1.8.0

v1.7.3

Choose a tag to compare

@M-Igashi M-Igashi released this 08 Apr 15:00

Installation

Platform Command
macOS (Homebrew) brew install M-Igashi/tap/headroom
Windows (winget) winget install M-Igashi.headroom
Cargo cargo install headroom (ffmpeg must be installed separately)

Package managers (Homebrew, winget) install ffmpeg automatically. mp3rgain is built-in — no separate installation needed.

Checksums

See headroom-v1.7.3-checksums.txt for SHA256 checksums of all binaries.

What's Changed

  • chore(ci): add dependency review and fix context injection in run blocks by @M-Igashi in #27
  • ci: bump dtolnay/rust-toolchain from efa25f7f19611383d5b0ccf2d1c8914531636bf9 to 3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 by @dependabot[bot] in #28

Full Changelog: v1.7.2...v1.7.3