Bake'n Deck (baken) is a Rekordbox to CDJ prep toolkit, the successor to headroom (renamed at v3.0.0).
The headroom subcommand analyzes audio files for loudness (LUFS) and True Peak headroom, then applies lossless gain adjustment. It supports MP3, AAC/M4A, FLAC, AIFF, and WAV files, with batch processing, lossless MP3/AAC gain via mp3rgain, and a scriptable non-interactive CLI mode.
The rbsort subcommand sorts a Rekordbox collection.xml export by Camelot Key and BPM for harmonic mixing prep - no audio touched, no ffmpeg required.
The cdjsafe subcommand (new in v3.0.0) converts every track in a playlist to 320 kbps CBR MP3 at 44.1 kHz for pre-NXS2 CDJs, emitting an updated XML in which converted tracks inherit beatgrids and cue points verbatim.
README
Bake'n Deck (baken)
Built for the Rekordbox → CDJ workflow.
Rekordbox's Auto Gain doesn't survive USB export, and Rekordbox has never offered compound Key+BPM sort (Serato had it for years — but never exported to CDJs). Bake'n Deck bakes both into the files themselves, so what you prep is what plays on the deck.
> [!NOTE]
> headroom is now Bake'n Deck 3.0. As announced in #60, the binary, crate, Homebrew formula, and repository were renamed from headroom to baken at v3.0.0, and the site moved to baken.ravers.workers.dev. This was a hard cut — the old headroom install channels (brew/winget/cargo/AUR) no longer receive updates; reinstall via the baken packages below. The loudness analyzer now lives under the baken headroom subcommand.
What is this?
Bake'n Deck is a CLI toolkit with three subcommands:
baken headroom simulates the behavior of Rekordbox's Auto Gain feature, but with a key difference: it identifies files with available headroom (True Peak below the target ceiling) and applies gain adjustment without using a limiter. Designed for DJs and producers who want to maximize loudness while preserving dynamics, ensuring tracks hit the optimal True Peak ceiling without clipping.
baken rbsort sorts a Rekordbox playlist by Camelot Key (1A→12B) then BPM ascending, and appends the result as a new playlist to your collection.xml. Useful for harmonic mixing prep when the Rekordbox UI does not expose multi-column sort. See Rekordbox Playlist Sorter.
baken cdjsafe(new in v3.0) transcodes every track in a Rekordbox playlist to CDJ-safe MP3s (320 kbps CBR @ 44.1 kHz) and emits an updated XML in which the new tracks inherit the originals' cue points and beatgrid — for gigs on pre-NXS2 CDJs that won't play FLAC/ALAC/AIFF/AAC. See CDJ-safe Transcoder.
Key Features
Single binary: mp3rgain is built-in as a library — only ffmpeg required as external dependency
Uniform True Peak ceiling: -0.5 dBTP for every file by default — the most aggressive, AES TD1008–blessed delivery target — fully overridable via
Multiple processing methods: ffmpeg for lossless formats, built-in mp3rgain for lossless MP3/AAC gain, ffmpeg re-encode for precise gain
Non-destructive workflow: Original files are backed up before processing
Metadata preservation: Audio tags (ID3v2, Vorbis comment, BWF) are preserved during processing, and files are overwritten in place so Rekordbox cue points and other external metadata remain linked
No limiter: Pure gain adjustment only — dynamics are preserved
Interactive CLI: Guided step-by-step process with two-stage confirmation
Scriptable CLI: Non-interactive mode for pipelines and CI (paths, globs, and flags)
Rekordbox playlist sorter: baken rbsort produces a new playlist sorted by Camelot Key then BPM
CDJ-safe transcoder(v3.0+): baken cdjsafe normalizes a gig playlist to 320 kbps CBR MP3 with cues and beatgrid carried over via XML
Installation
baken requires ffmpeg. Package managers install it automatically.
Platform
Command
macOS (Homebrew)
brew install M-Igashi/tap/baken
Windows (winget)
winget install M-Igashi.baken
Arch Linux (AUR)
yay -S baken-bin
Cargo
cargo install baken (ffmpeg must be installed separately)
Pre-built binaries are available on the Releases page (ffmpeg must be installed separately).
Build from Source
git clone https://github.com/M-Igashi/baken.git
cd baken
cargo build --release
Applied automatically (no user confirmation needed)
Re-encode — headroom exists but <1.5 dB to ceiling
Uses ffmpeg for arbitrary precision gain
MP3: libmp3lame with -q:a 0 / AAC: libfdk_aac (falls back to built-in aac)
Preserves original bitrate; requires explicit user confirmation
Skip — no headroom available
True Peak Ceiling
Default — uniform delivery target
Every file targets -0.5 dBTP by default. This is the maximum-aggression value that AES TD1008 §7B describes for high-rate codec inputs ("may work satisfactorily with as little as -0.5 dBTP for the limiting threshold").
File class
Ceiling
Native lossless requires
Lossless (FLAC, AIFF, WAV)
-0.5 dBTP
—
MP3 (any bitrate)
-0.5 dBTP
TP ≤ -2.0 dBTP
AAC/M4A (any bitrate)
-0.5 dBTP
TP ≤ -2.0 dBTP
Why a single ceiling — pre-encode vs delivery
TD1008 has two related but distinct numbers:
Generic delivery recommendation (§4) — "Maximum True Peak level not exceed -1 dBTP at the codec input of lossy-encoded streams." This is the pre-encode limiter threshold.
High-rate codec relaxation (§7B) — "High-rate (e.g., 256 kbps) coders may work satisfactorily with as little as -0.5 dBTP" — also a codec-input threshold; "the limiting threshold may need to be reduced below the recommended -1.0 dBTP" for lower bit rates.
Both bullets describe the limiter that sits in front of the encoder. baken operates in the opposite position: on already-encoded delivery files. There is no further codec stage downstream to absorb additional overshoot, so the bitrate-dependent slack TD1008 grants the pre-encode limiter does not transfer to the end product. A single, codec-agnostic delivery ceiling is the correct interpretation. -0.5 dBTP is chosen because it is the most aggressive value TD1008 sanctions for any limiter in the chain; lossless and high-rate lossy files were already at -0.5, and low-rate files now stop giving up an unnecessary 0.5 dB of loudness.
Match Spotify / Apple Music / YouTube delivery max
--tp-target -1.0
-1.0 dBTP for all files
Conservative master with extra player headroom
--tp-target -2.0
-2.0 dBTP for all files
Mirror TD1008's pre-encode interpretation
--tp-split-bitrate
-0.5 dBTP ≥256 kbps, -1.0 dBTP <256 kbps
--tp-target and --tp-split-bitrate are mutually exclusive. --tp-split-bitrate reproduces the pre-1.10 default exactly.
The native-lossless threshold scales with the chosen ceiling: it is always target − 1.5 dB (e.g. -0.5 → TP ≤ -2.0; -1.0 → TP ≤ -2.5; -2.0 → TP ≤ -3.5).
Output
CSV Report
Filename
Format
Bitrate (kbps)
LUFS
True Peak (dBTP)
Target (dBTP)
Headroom (dB)
Method
Effective Gain (dB)
track01.flac
Lossless
-
-13.3
-3.2
-0.5
+2.7
ffmpeg
+2.7
track04.mp3
MP3
320
-14.0
-5.5
-0.5
+5.0
mp3rgain
+4.5
track06.mp3
MP3
320
-12.0
-1.5
-0.5
+1.0
re-encode
+1.0
track08.m4a
AAC
256
-13.0
-4.0
-0.5
+3.5
native
+3.0
track10.m4a
AAC
256
-12.5
-1.8
-0.5
+0.7
re-encode
+0.7
Backup Structure
./
├── track01.flac ← Modified
├── track04.mp3 ← Modified
├── track08.m4a ← Modified
├── subfolder/
│ └── track06.mp3 ← Modified
└── backup/ ← Created by baken
├── track01.flac ← Original
├── track04.mp3 ← Original
├── track08.m4a ← Original
└── subfolder/
└── track06.mp3 ← Original
Notes & Technical Details
Files are overwritten in place after backup — Rekordbox metadata remains linked
Only files with positive effective gain are shown and processed
MP3/AAC native lossless requires at least 1.5dB headroom to be processed
MP3/AAC re-encoding is opt-in and requires explicit confirmation
macOS resource fork files (._*) are automatically ignored
Why 1.5dB Steps?
Both MP3 and AAC store a "global_gain" value as an integer. Each ±1 increment changes the gain by 2^(1/4) = ±1.5 dB. This is a format-level constraint, not a tool limitation.
baken uses the built-in mp3rgain library to directly modify this field — no decoding or re-encoding involved.
Native Lossless Threshold
Since native lossless gain only works in 1.5 dB steps, at least 1.5 dB of headroom to the configured target ceiling is required. The threshold scales automatically:
At ≥256kbps, re-encoding introduces quantization noise below -90dB — far below audible threshold. Only gain is applied (no EQ, compression, or dynamics processing), and original bitrate is preserved.
Rekordbox Playlist Sorter (baken rbsort)
Rekordbox does not expose a "sort by Key AND BPM" option in its UI. baken rbsort reads your collection.xml, sorts each target playlist by Camelot Key (1A → 12B) ascending then BPM ascending, and emits the sorted copies into a new Sorted (Key+BPM)/ folder appended to the same XML. Originals are left untouched. The layout mirrors the analyzer's backup/ directory: one container folder, each item inside keeps its source name.
This is the same idea as baken headroom applied to playlist order: Rekordbox's software-only features (Auto Gain, multi-column sort) don't follow your tracks to the CDJ. rbsort bakes Key+BPM order into the playlist itself — so when you export to USB in Rekordbox's EXPORT mode, the CDJ plays the set in that exact order with no on-deck reordering.
Workflow
Set key display to Alphanumeric (1A..12B notation) in Rekordbox: Preferences > View > Key display format > Alphanumeric.
Export: File > Export Collection in xml format → e.g. ~/Music/rekordbox/collection.xml.
Run rbsort:
# Sort every TrackID-referenced playlist in the XML
baken rbsort --xml ~/Music/rekordbox/collection.xml
# Or target one playlist (top-level: just the name)
baken rbsort \
--xml ~/Music/rekordbox/collection.xml \
--playlist "Happy House and Trance"
# Or target one nested under a folder
baken rbsort \
--xml ~/Music/rekordbox/collection.xml \
--playlist "Sets/Friday"
Output defaults to collection-out.xml next to the input. Pass --output to override.
Point Rekordbox at the output XML: Preferences > Advanced > Database > rekordbox xml > Imported Library → select collection-out.xml, then restart Rekordbox (Rekordbox only re-reads the XML on startup).
Open the rekordbox xml tree in the left sidebar. It is a separate tree from your main library — switch to it from the sidebar icon column on the far left (the icon labeled rekordbox xml). Inside you'll find a new folder Sorted (Key+BPM)/ containing each sorted playlist under its original name.
Verify the sort by clicking any playlist inside Sorted (Key+BPM)/ — tracks should run 1A (lowest BPM) → 1B → 2A → … → 12B (highest BPM).
Drag the playlists you want from Sorted (Key+BPM)/ into your main Playlists collection. Your original playlists (still in Playlists) are unchanged.
Export to USB for CDJ: switch Rekordbox to EXPORT mode (top-left dropdown), plug in your USB / SD, then right-click the playlist → Export Playlist. CDJs read tracks in playlist order by default — your Key+BPM sort plays back on the deck in that exact order.
> The sorted results live only inside the rekordbox xml > Sorted (Key+BPM)/ folder, not in your main Playlists. If you only see the originals, you're looking at the local library — switch sidebar trees.
Flags
Flag
Description
--xml
Path to collection.xml (required)
--playlist
Source playlist under the Rekordbox Playlists root. Optional — if omitted, every TrackID-referenced playlist in the XML is sorted. Top-level playlists: just the name (e.g. "Happy House and Trance"). Nested: /-separate folder/playlist names (e.g. "Folder/SubFolder/MyPlaylist")
--output (-o)
Output XML path. Optional — defaults to -out. next to the input
--name
Override the sorted playlist's name. Only valid with --playlist. When sorting all playlists, each sorted copy reuses its source name
Tracks with no Camelot key sort after all known keys; within a key group, tracks with BPM 0 / unanalyzed sort last
See docs/rbsort-sort-comparison.md for a 6-track walk-through showing how this compound sort differs from Rekordbox / CDJ's single-column Sort by Key and Sort by BPM.
Notes
Requires the Tonality field to be exported as 1A..12B (Rekordbox's "Alphanumeric" key display format). Non-matching values (e.g. Am, C#) are silently sorted last.
Only KeyType="0" (TrackID-referenced) playlists are supported. In all-playlists mode, non-KeyType=0 playlists are silently skipped; for a single target, rbsort errors out.
baken rbsort does not require ffmpeg — only the headroom and cdjsafe subcommands do.
A single Sorted (Key+BPM)/ folder is appended inside the `` ROOT NODE, regardless of how many playlists were processed. The ROOT Count is bumped by 1.
Pre-NXS2 CDJs (CDJ-2000NXS, CDJ-2000, CDJ-900NXS, CDJ-850, …) have inconsistent or absent support for anything that isn't MP3: FLAC needs an NXS2 (2016+), and ALAC/AIFF/WAV/AAC fail on specific firmware combinations — sometimes mid-set. baken cdjsafe is the emergency-backup path: it takes a gig playlist and produces a USB-ready set of files that will play on any CDJ, with your cues and beatgrid intact.
Reads the target playlist from your exported collection.xml.
Converts every track to the CDJ-safe profile — 320 kbps CBR MP3 @ 44.1 kHz, ID3v2.3 tags, artwork kept (JPEG, capped at 500×500):
Source
Action
FLAC, WAV, AIFF, ALAC
Re-encode
AAC/M4A (any bitrate)
Re-encode
MP3 not exactly 320 kbps CBR @ 44.1 kHz
Re-encode (lossy→lossy, reported)
MP3 already 320 kbps CBR @ 44.1 kHz
Byte-identical copy (no generation loss, LAME header untouched)
Emits an updated XML (default: -out.xml) where each converted track is a new entry with a fresh TrackID that inherits the source's beatgrid (TEMPO) and hot/memory cues (POSITION_MARK) verbatim, grouped in a CDJ-safe (MP3)/ folder. New entries get a [cdjsafe] marker appended to their Comments so they're distinguishable after import.
Reports every lossy→lossy re-encode so you can refresh those tracks from lossless masters before the next gig.
If any track fails to convert, no XML is written — a partial USB defeats the point.
Importing back into Rekordbox
Preferences > Advanced > Database > rekordbox xml > Imported Library → select the output XML, restart Rekordbox.
Open the rekordbox xml sidebar tree → CDJ-safe (MP3)/.
Right-click the imported tracks → Import to Collection. Cues and beatgrid come with them — no re-analysis needed.
Export the playlist to USB in EXPORT mode as usual.
Flags
Flag
Description
--xml
Path to collection.xml (required)
--playlist
Playlist to convert (required). Top-level: just the name; nested: Folder/Playlist
--out-dir
Directory for the MP3 files (required; created if missing)
--output (-o)
Output XML path. Defaults to -out. next to the input
Notes
The output profile is locked (320 kbps CBR / 44.1 kHz / ID3v2.3) — it's the only combination that plays reliably across the whole CDJ fleet, and CBR sidesteps Rekordbox's VBR cue-offset problem.
ffmpeg writes a valid Xing/LAME header, so Rekordbox compensates the LAME encoder delay and cues stay sample-aligned.
Filenames are FAT32/exFAT-sanitized; collisions get a numeric suffix.
Requires ffmpeg (with libmp3lame; soxr resampling is used when available).