M-Igashi/headroom

GitHub: M-Igashi/headroom

headroom 是一个音频响度分析和增益调整工具,专为Rekordbox到CDJ的工作流程设计,解决自动增益不保留和播放列表排序限制的问题。

Stars: 29 | Forks: 3

# 净空 **为 Rekordbox → CDJ 工作流程而生。** Rekordbox 的自动增益功能无法随 USB 导出保留,且 Rekordbox 从未提供复合键位+BPM 排序(Serato 早已具备该功能,但从未支持导出至 CDJs)。headroom 将这两项功能直接嵌入文件本身,确保您准备的内容在播放器上的表现一致。 ## 这是什么? **headroom** 模拟了 Rekordbox 的自动增益功能,但有一个关键区别:它会识别具有可用余量(真实峰值低于目标上限)的文件,并在**不使用限幅器**的情况下应用增益调整。 此工具专为希望在最大化响度的同时保留动态范围、确保音轨达到最优真实峰值上限且不发生削波的 DJ 和制作人设计。 **v2.0.0 新增功能** — 配套的 `rbsort` 子命令可将 Rekordbox 播放列表按 **Camelot 键位 (1A→12B) 再按 BPM 升序** 排序,并将结果作为新播放列表追加到您的 `collection.xml` 文件中。当 Rekordbox 界面不支持多列排序时,此功能对和声混音准备工作非常有用。请参阅 [Rekordbox 播放列表排序器](#rekordbox-playlist-sorter-rbsort)。 ## 主要功能 - **单一二进制文件**:mp3rgain 作为库内建 — 仅需 ffmpeg 作为外部依赖 - **统一真实峰值上限**:默认所有文件均设为 **-0.5 dBTP** — 最激进的、符合 AES TD1008 标准的交付目标 — 可通过 `--tp-target` 完全覆盖 - **多种处理方法**:ffmpeg 处理无损格式,内建 mp3rgain 用于无损 MP3/AAC 增益,ffmpeg 重编码用于精确增益 - **非破坏性工作流**:处理前备份原始文件 - **元数据保留**:处理过程中保留音频标签(ID3v2、Vorbis 注释、BWF),文件就地覆盖以确保 Rekordbox 提示点及其他外部元数据链接保持不变 - **无限制器**:仅进行纯增益调整 — 保留动态范围 - **交互式命令行界面**:带两阶段确认的引导式分步流程 - **可脚本化命令行界面**:用于流水线和 CI 的非交互模式(支持路径、通配符和标志) - **Rekordbox 播放列表排序器** *(v2.0+)*:`headroom rbsort` 可生成按 Camelot 键位再按 BPM 排序的新播放列表 ## 安装说明 headroom 需要 ffmpeg。软件包管理器会自动安装它。 | 平台 | 命令 | |----------|---------| | **macOS (Homebrew)** | `brew install M-Igashi/tap/headroom` | | **Windows (winget)** | `winget install M-Igashi.headroom` | | **Arch Linux (AUR)** | `yay -S headroom-bin` | | **Cargo** | `cargo install headroom` (ffmpeg 需单独安装) | 预编译二进制文件可在 [发布页面](https://github.com/M-Igashi/headroom/releases) 获取(ffmpeg 需单独安装)。 ### 从源码构建 ``` git clone https://github.com/M-Igashi/headroom.git cd headroom cargo build --release ``` ## 响度归一化器 ### 工作原理 1. 扫描当前目录中的音频文件(FLAC、AIFF、WAV、MP3、AAC/M4A) 2. 使用 ffmpeg 测量 LUFS(整合响度)和真实峰值 3. 按处理方法对文件分类: - **绿色**:无损文件(ffmpeg) - **黄色**:MP3/AAC 文件,具有足够余量可进行原生无损增益 - **品红色**:MP3/AAC 文件,需要重编码 4. 显示分类报告 5. 两阶段确认: - 首先:“应用无损增益调整?”(无损 + 原生 MP3/AAC) - 其次:“是否同时处理需要重编码的文件?”(需重编码的 MP3/AAC) 6. 创建备份并处理文件 #### 示例 ``` $ cd ~/Music/DJ-Tracks $ headroom ╭─────────────────────────────────────╮ │ headroom v2.0.0 │ │ Audio Loudness Analyzer & Gain │ ╰─────────────────────────────────────╯ ▸ 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: ./headroom_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) ``` ### 用法 #### 交互模式 不带参数运行以使用当前目录中的引导式工作流: ``` cd ~/Music/DJ-Tracks headroom ``` 工具将引导您完成: 1. 扫描并分析所有音频文件 2. 查看分类报告 3. 确认无损处理 4. 可选启用 MP3/AAC 重编码 5. 创建备份(推荐) #### 可脚本化模式 传递路径、通配符或标志以非交互方式运行(适用于流水线和脚本): ``` # 分析目录而不修改任何内容 headroom --analyze-only ~/Music/DJ-Tracks # 仅应用无损增益,并备份,将报告保存到指定路径 headroom --lossless --backup ./bak --report results.csv ./album/ # 同时启用重新编码 headroom --lossless --reencode --backup ./bak ./album/ # 对特定文件进行操作 headroom --lossless track1.mp3 track2.flac # Glob 模式 headroom --lossless --no-report "./music/**/*.mp3" # 为流媒体平台提供更严格的上限(Spotify / Apple / YouTube 最大值) headroom --lossless --tp-target -1.0 ./album/ # 恢复传统的比特率相关分割(v1.10之前的行为) headroom --lossless --tp-split-bitrate ./album/ ``` **非交互式默认设置**(当提供任何标志或路径时): - `--lossless` 默认 **开启**,除非指定 `--no-lossless` - `--reencode` 默认 **关闭**,除非显式传递 `--reencode` - `--backup` 默认 **关闭**,除非提供;单独使用 `--backup` 时默认使用 `/backup` 路径 - 默认写入 CSV 报告,除非指定 `--no-report`;`--report PATH` 可设置自定义位置 - `--analyze-only` 仅运行分析和报告,跳过处理 运行 `headroom --help` 获取完整的标志参考。 ### 处理方法 headroom 根据文件格式和余量为每个文件选择最佳方法: | 格式 | 方法 | 精度 | 质量损失 | |--------|--------|-----------|--------------| | FLAC、AIFF、WAV | ffmpeg | 任意精度 | 无 | | MP3、AAC/M4A | mp3rgain(内建) | 1.5dB 步进 | **无**(global_gain 修改) | | MP3、AAC/M4A | ffmpeg 重编码 | 任意精度 | ≥256kbps 时不可闻 | #### 有损格式(MP3/AAC)的三级处理方法 每个 MP3 和 AAC/M4A 文件被归入以下三级之一: 1. **原生无损** — 距配置上限有 ≥1.5 dB 余量 - 真正的无损 global_gain 头部修改,步进为 1.5dB - 使用内建的 [mp3rgain](https://github.com/M-Igashi/mp3rgain) 库 - 自动应用(无需用户确认) 2. **重编码** — 有余量但距上限 <1.5 dB - 使用 ffmpeg 进行任意精度增益调整 - MP3:`libmp3lame`,使用 `-q:a 0`;AAC:`libfdk_aac`(回退到内建 `aac`) - 保留原始比特率;需要用户明确确认 3. **跳过** — 无可用余量 ### 真实峰值上限 #### 默认设置 — 统一交付目标 每个文件默认目标为 **-0.5 dBTP**。这是 [AES TD1008](https://www.aes.org/technical/documentDownloads.cfm?docID=731) §7B 为高速率编码器输入描述的最大激进值(“对于限幅阈值,低至 -0.5 dBTP 也可能令人满意地工作”)。 | 文件类型 | 上限 | 原生无损要求 | |---|---|---| | 无损 (FLAC, AIFF, WAV) | **-0.5 dBTP** | — | | MP3 (任意比特率) | **-0.5 dBTP** | TP ≤ -2.0 dBTP | | AAC/M4A (任意比特率) | **-0.5 dBTP** | TP ≤ -2.0 dBTP | #### 为什么使用单一上限 — 预编码 vs 交付 TD1008 有两个相关但不同的数值: 1. **通用交付建议 (§4)** — “在有损编码流的编码器输入端,最大真实峰值电平不应超过 -1 dBTP。” 这是*预编码*限幅器的阈值。 2. **高速率编码器放宽条件 (§7B)** — “高速率(例如 256 kbps)编码器在低至 -0.5 dBTP 时也可能令人满意地工作” — 同样是一个*编码器输入*阈值;“对于较低比特率,限幅阈值可能需要降至建议的 -1.0 dBTP 以下”。 这两点描述的都是位于编码器*前端*的限幅器。headroom 的操作位置恰恰相反:作用于**已编码的交付文件**。下游没有进一步的编码阶段来吸收额外的过冲,因此 TD1008 授予预编码限幅器的、依赖比特率的宽松余量不会转移到最终产品。单一的、与编码器无关的交付上限是正确的解释。选择 -0.5 dBTP 是因为它是 TD1008 对链路中任何限幅器所允许的最激进值;无损和高速率有损文件原本就设定在 -0.5,低比特率文件现在也无需再放弃不必要的 0.5 dB 响度。 更详细的解释及引用请参见 [docs/true-peak-ceiling.md](docs/true-peak-ceiling.md)。 #### 调整上限 | 目标 | 标志 | 结果上限 | |---|---|---| | 默认(最大激进交付) | *(无)* | 所有文件均为 -0.5 dBTP | | 匹配 Spotify / Apple Music / YouTube 的最大交付值 | `--tp-target -1.0` | 所有文件均为 -1.0 dBTP | | 为播放器提供额外余量的保守母带 | `--tp-target -2.0` | 所有文件均为 -2.0 dBTP | | 复现 TD1008 的预编码解释 | `--tp-split-bitrate` | ≥256 kbps 为 -0.5 dBTP,<256 kbps 为 -1.0 dBTP | `--tp-target` 和 `--tp-split-bitrate` 互斥。`--tp-split-bitrate` 精确复现了 headroom 在 1.10 版本之前的默认行为。 原生无损阈值随所选上限自动缩放:始终为 `target − 1.5 dB`(例如 `-0.5` → TP ≤ -2.0;`-1.0` → TP ≤ -2.5;`-2.0` → TP ≤ -3.5)。 ### 输出 #### CSV 报告 | 文件名 | 格式 | 比特率 (kbps) | LUFS | 真实峰值 (dBTP) | 目标 (dBTP) | 余量 (dB) | 方法 | 有效增益 (dB) | |----------|--------|----------------|------|------------------|---------------|---------------|--------|---------------------| | track01.flac | 无损 | - | -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 | 重编码 | +1.0 | | track08.m4a | AAC | 256 | -13.0 | -4.0 | -0.5 | +3.5 | 原生 | +3.0 | | track10.m4a | AAC | 256 | -12.5 | -1.8 | -0.5 | +0.7 | 重编码 | +0.7 | #### 备份结构 ``` ./ ├── track01.flac ← Modified ├── track04.mp3 ← Modified ├── track08.m4a ← Modified ├── subfolder/ │ └── track06.mp3 ← Modified └── backup/ ← Created by headroom ├── track01.flac ← Original ├── track04.mp3 ← Original ├── track08.m4a ← Original └── subfolder/ └── track06.mp3 ← Original ``` ### 备注与技术细节 - 备份后**文件就地覆盖** — Rekordbox 元数据链接保持不变 - 仅显示和处理具有**正有效增益**的文件 - MP3/AAC 原生无损要求至少 **1.5dB 余量**才能处理 - MP3/AAC 重编码为**可选项**,需要用户明确确认 - macOS 资源派生文件 (`._*`) 会被自动忽略 #### 为什么是 1.5dB 步进? MP3 和 AAC 都将 "global_gain" 值存储为整数。每次 ±1 增减都会改变增益 `2^(1/4)` = **±1.5 dB**。这是格式级别的限制,并非工具限制。 headroom 使用内建的 [mp3rgain](https://github.com/M-Igashi/mp3rgain) 库直接修改此字段 — 不涉及解码或重编码。 #### 原生无损阈值 由于原生无损增益仅能以 1.5 dB 步进工作,因此需要至少 1.5 dB 的余量才能达到配置的目标上限。阈值会自动缩放: | 目标 | 要求 TP ≤ | |---|---| | -0.5 dBTP(默认) | -2.0 dBTP | | -1.0 dBTP (`--tp-target -1.0`) | -2.5 dBTP | | -2.0 dBTP (`--tp-target -2.0`) | -3.5 dBTP | 示例:320 kbps 文件位于 -3.5 dBTP,默认目标 → 2 步 (+3.0 dB) → -0.5 dBTP(最优)。 #### 重编码质量 在 ≥256kbps 时,重编码引入的量化噪声低于 -90dB — 远低于可听阈值。仅应用增益(不进行 EQ、压缩或动态处理),并保留原始比特率。 ## Rekordbox 播放列表排序器 (`rbsort`) *于 v2.0.0 版本添加。* Rekordbox 在其界面中未提供“按键位和 BPM 排序”的选项。`headroom rbsort` 读取您的 `collection.xml`,按 **Camelot 键位 (1A → 12B) 升序** 再按 **BPM 升序** 对每个目标播放列表进行排序,并将排序后的副本输出到追加到同一 XML 的新 `Sorted (Key+BPM)/` 文件夹中。原始播放列表保持不变。布局与 headroom 的 `backup/` 目录相同:一个容器文件夹,内部每个项目保留其源名称。 这与 headroom 的分析器应用于播放列表排序的理念相同:Rekordbox 的纯软件功能(自动增益、多列排序)不会跟随您的音轨到 CDJ。`rbsort` 将键位+BPM 顺序烘焙到播放列表本身中 — 因此当您在 Rekordbox 的导出模式下导出到 USB 时,CDJ 会以完全相同的顺序播放该列表集,无需在播放器上重新排序。 ### 工作流程 1. **在 Rekordbox 中将键位显示设置为字母数字格式 (1A..12B 记法)**:*首选项 > 视图 > 键位显示格式 > 字母数字*。 2. **导出**:*文件 > 以 xml 格式导出曲库* → 例如 `~/Music/rekordbox/collection.xml`。 3. **运行 rbsort**: ```bash # 对 XML 中所有引用 TrackID 的播放列表进行排序 headroom rbsort --xml ~/Music/rekordbox/collection.xml # 或指定一个播放列表(顶层:仅名称) headroom rbsort \ --xml ~/Music/rekordbox/collection.xml \ --playlist "Happy House and Trance" # 或指定一个嵌套在文件夹下的播放列表 headroom rbsort \ --xml ~/Music/rekordbox/collection.xml \ --playlist "Sets/Friday" ``` 输出默认保存为与输入文件同目录下的 `collection-out.xml`。使用 `--output ` 可覆盖此设置。 4. **在 Rekordbox 中指向输出的 XML**:*首选项 > 高级 > 数据库 > rekordbox xml > 导入的曲库* → 选择 `collection-out.xml`,然后**重启 Rekordbox**(Rekordbox 仅在启动时重新读取 XML)。 5. **在左侧边栏中打开 `rekordbox xml` 树**。这是一个与您的主曲库*分开*的树 — 从最左侧的**边栏图标列**切换到它(标有 `rekordbox xml` 的图标)。在其中您会找到一个新文件夹 `Sorted (Key+BPM)/`,里面包含按原始名称命名的每个排序后的播放列表。 6. **通过点击 `Sorted (Key+BPM)/` 中的任何播放列表来验证排序** — 曲目应按 `1A`(最低 BPM)→ `1B` → `2A` → … → `12B`(最高 BPM)的顺序运行。 7. **将您想要的播放列表从 `Sorted (Key+BPM)/` 拖放到您的主 `播放列表` 曲库中**。您原始的播放列表(仍在 `播放列表` 中)保持不变。 8. **导出到 USB 用于 CDJ**:将 Rekordbox 切换到 *EXPORT* 模式(左上角下拉菜单),插入您的 USB / SD 卡,然后**右键单击播放列表 → 导出播放列表**。CDJ 默认按播放列表顺序读取曲目 — 您的键位+BPM 排序将以完全相同的顺序在播放器上回放。 ### 标志 | 标志 | 描述 | |------|-------------| | `--xml ` | 指向 `collection.xml` 的路径(必需) | | `--playlist ` | Rekordbox `播放列表` 根目录下的源播放列表。**可选** — 如果省略,XML 中所有引用 TrackID 的播放列表都会被排序。顶层播放列表:仅名称(例如 `"Happy House and Trance"`)。嵌套的:使用 `/` 分隔文件夹/播放列表名称(例如 `"Folder/SubFolder/MyPlaylist"`) | | `--output ` (`-o`) | 输出 XML 路径。可选 — 默认为与输入文件同目录下的 `-out.` | | `--name ` | 覆盖排序后播放列表的名称。仅与 `--playlist` 一起使用有效。当对所有播放列表排序时,每个排序后的副本会重用其源名称 | ### 排序规则 - **主要**:Camelot 键位升序 — `1A → 1B → 2A → 2B → … → 12A → 12B` - **次要**:在每个键位分组内按 BPM 升序 - 没有 Camelot 键位的曲目排在所有已知键位**之后**;在键位分组内,BPM 为 0 / 未分析的曲目排在最后 有关此复合排序与 Rekordbox / CDJ 的单列*按键位排序*和*按 BPM 排序*有何不同的 6 音轨详细说明,请参阅 [docs/rbsort-sort-comparison.md](docs/rbsort-sort-comparison.md)。 ### 备注 - 要求 `Tonality` 字段导出为 1A..12B 格式(Rekordbox 的“字母数字”键位显示格式)。不匹配的值(例如 `Am`、`C#`)会被静默地排到最后。 - 仅支持 `KeyType="0"`(引用 TrackID)的播放列表。在全部播放列表模式下,非 `KeyType=0` 的播放列表会被静默跳过;对于单个目标,`rbsort` 会报错退出。 - `rbsort` **不需要** ffmpeg — 仅分析器子命令需要。 - 无论处理了多少播放列表,都会在 `` 根节点内追加一个 `Sorted (Key+BPM)/` 文件夹。根节点的 `Count` 计数会增加 1。 ## 许可证 MIT
标签:CDJ兼容, DJ工具, ffmpeg依赖, Rekordbox集成, True Peak调整, 元数据保留, 动态范围保护, 可视化界面, 响度分析, 增益调整, 播放列表排序, 文件处理, 文档结构分析, 母带处理, 混音准备, 通知系统, 非破坏性工作流, 音乐制作, 音频处理, 音频标准化