What you prep in Rekordbox is what plays on the deck.
Rekordbox does three things in software that never survive the trip to a CDJ. Bake'n Deck bakes each one into the files themselves:
| Subcommand | The gap it fills | What it does |
|---|---|---|
baken headroom |
Auto Gain is ignored on USB export | Measures LUFS / True Peak and bakes safe gain into the audio file — no limiter, dynamics preserved, cues stay linked |
baken rbsort |
No compound Key+BPM sort in Rekordbox | Sorts playlists by Camelot Key (1A→12B) then BPM and writes the order into collection.xml — CDJs play it in that exact order |
baken cdjsafe |
Pre-NXS2 CDJs only play MP3 reliably | Transcodes a whole playlist to 320 kbps CBR MP3 with cues and beatgrid carried over — the emergency-backup USB |
🌐 baken.ravers.workers.dev — full docs, workflow guides, and FAQ.
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). To build from source: git clone https://github.com/M-Igashi/baken.git && cd baken && cargo build --release.
baken headroom ~/Music/DJ-Tracks # analyze & bake loudness gain (interactive)
baken rbsort --xml collection.xml # sort every playlist by Key+BPM
baken cdjsafe --xml collection.xml --playlist "Sets/Friday" --out-dir ~/Music/cdjsafeRun baken --help or baken <subcommand> --help for the full reference.
Note
Renamed from headroom at v3.0.0 (#60). The old headroom install channels (brew/winget/cargo/AUR) no longer receive updates — reinstall via the baken packages above. The loudness analyzer now lives under the baken headroom subcommand.
- Single binary — mp3rgain built in; only ffmpeg required (and
rbsortdoesn't even need that) - Truly lossless MP3/AAC gain — global_gain header modification in 1.5 dB steps, no re-encode
- Uniform True Peak ceiling — -0.5 dBTP by default (AES TD1008 §7B), tunable via
--tp-target - Non-destructive — automatic backups;
rbsort/cdjsafenever modify your originalcollection.xml - Metadata preserved — files overwritten in place, so Rekordbox cues, hot cues, and beatgrids stay linked
- Interactive or scriptable — guided two-stage confirmation, or flags/globs for pipelines and CI
- Scans the target directory for audio files (FLAC, AIFF, WAV, MP3, AAC/M4A)
- Measures LUFS (Integrated Loudness) and True Peak using ffmpeg
- Categorizes files by processing method:
- Green: Lossless files (ffmpeg)
- Yellow: MP3/AAC files with enough headroom for native lossless gain
- Magenta: MP3/AAC files requiring re-encode
- Displays categorized report
- Two-stage confirmation:
- First: "Apply lossless gain adjustment?" (lossless + native MP3/AAC)
- Second: "Also process files with re-encoding?" (MP3/AAC requiring re-encode)
- Creates backups and processes files
Full interactive session (28 files analyzed → 10 processed)
$ cd ~/Music/DJ-Tracks
$ baken headroom
╭─────────────────────────────────────╮
│ baken v3.0.1 │
│ Bake'n Deck — CDJ Prep Toolkit │
╰─────────────────────────────────────╯
▸ Target directory: /Users/xxx/Music/DJ-Tracks
✓ Found 28 audio files
✓ Analyzed 28 files
● 3 lossless files (ffmpeg, precise gain)
Filename LUFS True Peak Target Gain
track01.flac -13.3 -3.2 dBTP -0.5 dBTP +2.7 dB
track02.aif -14.1 -4.5 dBTP -0.5 dBTP +4.0 dB
track03.wav -12.5 -2.8 dBTP -0.5 dBTP +2.3 dB
● 2 MP3 files (native lossless, 1.5 dB steps, requires TP ≤ -2.0 dBTP)
Filename LUFS True Peak Target Gain
track04.mp3 -14.0 -5.5 dBTP -0.5 dBTP +4.5 dB
track05.mp3 -13.5 -6.0 dBTP -0.5 dBTP +4.5 dB
● 2 AAC/M4A files (native lossless, 1.5 dB steps, requires TP ≤ -2.0 dBTP)
Filename LUFS True Peak Target Gain
track08.m4a -13.0 -4.0 dBTP -0.5 dBTP +3.0 dB
track09.m4a -12.5 -4.5 dBTP -0.5 dBTP +3.0 dB
● 2 MP3 files (re-encode required for precise gain)
Filename LUFS True Peak Target Gain
track06.mp3 -12.0 -1.5 dBTP -0.5 dBTP +1.0 dB
track07.mp3 -11.5 -1.2 dBTP -0.5 dBTP +0.7 dB
● 1 AAC/M4A files (re-encode required)
Filename LUFS True Peak Target Gain
track10.m4a -12.5 -1.8 dBTP -0.5 dBTP +1.3 dB
▸ TP target: -0.5 dBTP (uniform delivery ceiling, AES TD1008 §7B)
✓ Report saved: ./baken_report_20250109_123456.csv
? Apply lossless gain adjustment to 3 lossless + 2 MP3 (lossless gain) + 2 AAC/M4A (lossless gain) files? [y/N] y
ℹ 2 MP3 + 1 AAC/M4A files have headroom but require re-encoding for precise gain.
• Re-encoding causes minor quality loss (inaudible at 256kbps+)
• Original bitrate will be preserved
? Also process these files with re-encoding? [y/N] y
? Create backup before processing? [Y/n] y
✓ Backup directory: ./backup
✓ Done! 10 files processed.
• 3 lossless files (ffmpeg)
• 2 MP3 files (native, lossless)
• 2 AAC/M4A files (native, lossless)
• 2 MP3 files (re-encoded)
• 1 AAC/M4A files (re-encoded)
Run baken headroom without further arguments to use the guided workflow in the current directory:
cd ~/Music/DJ-Tracks
baken headroomThe tool will guide you through:
- Scanning and analyzing all audio files
- Reviewing the categorized report
- Confirming lossless processing
- Optionally enabling MP3/AAC re-encoding
- Creating backups (recommended)
Pass paths, globs, or flags to run non-interactively (useful for pipelines and scripts):
# Analyze a directory without modifying anything
baken headroom --analyze-only ~/Music/DJ-Tracks
# Apply only lossless gain, with backup, save report to a specific path
baken headroom --lossless --backup ./bak --report results.csv ./album/
# Enable re-encoding as well
baken headroom --lossless --reencode --backup ./bak ./album/
# Operate on specific files
baken headroom --lossless track1.mp3 track2.flac
# Glob patterns
baken headroom --lossless --no-report "./music/**/*.mp3"
# Tighter ceiling for streaming-platform delivery (Spotify / Apple / YouTube max)
baken headroom --lossless --tp-target -1.0 ./album/
# Restore the legacy bitrate-dependent split (pre-v1.10 behaviour)
baken headroom --lossless --tp-split-bitrate ./album/Non-interactive defaults (when any flag or path is provided):
--losslessis on unless--no-lossless--reencodeis off unless--reencodeis explicitly passed--backupis off unless provided; bare--backupuses<target>/backup- CSV report is written unless
--no-report;--report PATHsets a custom location --analyze-onlyruns analysis + report only, skips processing
Run baken headroom --help for the full flag reference.
baken selects the optimal method for each file based on format and headroom:
| Format | Method | Precision | Quality Loss |
|---|---|---|---|
| FLAC, AIFF, WAV | ffmpeg | Arbitrary | None |
| MP3, AAC/M4A | mp3rgain (built-in) | 1.5dB steps | None (global_gain modification) |
| MP3, AAC/M4A | ffmpeg re-encode | Arbitrary | Inaudible at ≥256kbps |
Each MP3 and AAC/M4A file is categorized into one of three tiers:
-
Native Lossless — ≥1.5 dB headroom to the configured ceiling
- Truly lossless global_gain header modification in 1.5dB steps
- Uses built-in mp3rgain library
- Applied automatically (no user confirmation needed)
-
Re-encode — headroom exists but <1.5 dB to ceiling
- Uses ffmpeg for arbitrary precision gain
- MP3:
libmp3lamewith-q:a 0/ AAC:libfdk_aac(falls back to built-inaac) - Preserves original bitrate; requires explicit user confirmation
-
Skip — no headroom available
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 |
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.
See docs/true-peak-ceiling.md for a longer walk-through with citations.
| Goal | Flag | Resulting ceiling |
|---|---|---|
| Default (max-aggressive delivery) | (none) | -0.5 dBTP for all files |
| 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).
| 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 |
./
├── 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
- 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
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.
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:
| Target | Requires TP ≤ |
|---|---|
| -0.5 dBTP (default) | -2.0 dBTP |
-1.0 dBTP (--tp-target -1.0) |
-2.5 dBTP |
-2.0 dBTP (--tp-target -2.0) |
-3.5 dBTP |
Example: 320 kbps file at -3.5 dBTP, default target → 2 steps (+3.0 dB) → -0.5 dBTP (optimal).
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 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.
- 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:
Output defaults to
# 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"
collection-out.xmlnext to the input. Pass--output <PATH>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 xmltree 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 labeledrekordbox xml). Inside you'll find a new folderSorted (Key+BPM)/containing each sorted playlist under its original name. - Verify the sort by clicking any playlist inside
Sorted (Key+BPM)/— tracks should run1A(lowest BPM) →1B→2A→ … →12B(highest BPM). - Drag the playlists you want from
Sorted (Key+BPM)/into your mainPlaylistscollection. Your original playlists (still inPlaylists) 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 mainPlaylists. If you only see the originals, you're looking at the local library — switch sidebar trees.
| Flag | Description |
|---|---|
--xml <PATH> |
Path to collection.xml (required) |
--playlist <PATH> |
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 <PATH> (-o) |
Output XML path. Optional — defaults to <input-stem>-out.<ext> next to the input |
--name <NAME> |
Override the sorted playlist's name. Only valid with --playlist. When sorting all playlists, each sorted copy reuses its source name |
- Primary: Camelot Key ascending —
1A → 1B → 2A → 2B → … → 12A → 12B - Secondary: BPM ascending within each key group
- 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.
- Requires the
Tonalityfield 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=0playlists are silently skipped; for a single target,rbsorterrors out. baken rbsortdoes not require ffmpeg — only theheadroomandcdjsafesubcommands do.- A single
Sorted (Key+BPM)/folder is appended inside the<PLAYLISTS>ROOT NODE, regardless of how many playlists were processed. The ROOTCountis bumped by 1.
Added in v3.0.0. Design discussion: #40.
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.
baken cdjsafe \
--xml ~/Music/rekordbox/collection.xml \
--playlist "Sets/Friday" \
--out-dir ~/Music/cdjsafe-friday-
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:
<input>-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 aCDJ-safe (MP3)/<playlist>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.
- Preferences > Advanced > Database > rekordbox xml > Imported Library → select the output XML, restart Rekordbox.
- Open the
rekordbox xmlsidebar tree →CDJ-safe (MP3)/<playlist>. - 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.
| Flag | Description |
|---|---|
--xml <PATH> |
Path to collection.xml (required) |
--playlist <PATH> |
Playlist to convert (required). Top-level: just the name; nested: Folder/Playlist |
--out-dir <DIR> |
Directory for the MP3 files (required; created if missing) |
--output <PATH> (-o) |
Output XML path. Defaults to <input-stem>-out.<ext> next to the input |
- 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;soxrresampling is used when available).
MIT