音频剪辑工具箱(audio-editor-toolbox)
基于 ffmpeg / ffprobe 的纯音频处理命令封装。一句话定位:成品文件公式——给音频素材 + 一句话,直接交付处理好的成品音频文件。
> 与"视频剪辑工具箱"的分工(务必区分)
> | 技能 | 管什么 | 典型问题 |
> |---|---|---|
> | 视频剪辑工具箱(video-editor-toolbox) | 带画面的视频 | "剪掉视频开头 10 秒""两段视频拼起来""视频转 GIF""画面裁剪""视频加背景音乐" |
> | 本技能(audio-editor-toolbox) | 纯音频文件 | "把这段录音剪一下""两首歌接起来""mp3 转 wav""音量调大点""这段音频快进 1.5 倍""加个淡出" |
>
> 本技能只处理音频,不做画面相关操作;需要从视频里抽音轨再剪,请先用 video-toolbox 的 extract-audio 取出音频,再交给本技能。
功能 / 子命令速查
SKILL_DIR="$HOME/.workbuddy/skills/audio-editor-toolbox"
[ -f "$SKILL_DIR/scripts/audio_edit.py" ] || SKILL_DIR="$PWD/.workbuddy/skills/audio-editor-toolbox"
[ -f "$SKILL_DIR/scripts/audio_edit.py" ] || SKILL_DIR="/sandbox/workspace/skills/audio-editor-toolbox"
S="$SKILL_DIR/scripts/audio_edit.py"
python3 $S trim in.mp3 -o clip.mp3 --start 00:01:30 --end 00:03:00 # 截取片段
python3 $S trim in.mp3 -o clip.mp3 --start 90 --duration 30 # 截取片段(按时长)
python3 $S concat a.mp3 b.mp3 -o merged.mp3 # 拼接多个音频
python3 $S convert in.wav -o out.mp3 --bitrate 192k # 格式转换
python3 $S volume in.mp3 -o out.mp3 --gain 6dB # 音量调整(增益)
python3 $S volume in.mp3 -o out.mp3 --factor 1.5 # 音量调整(倍数)
python3 $S normalize in.mp3 -o out.mp3 # 音量标准化(-16 LUFS)
python3 $S speed in.mp3 -o fast.mp3 --rate 1.5 # 变速(保持音高)
python3 $S fade in.mp3 -o out.mp3 --fade-in 3 --fade-out 3 # 淡入淡出
python3 $S --help # 查看全部用法
| 子命令 | 作用 | 关键参数 |
|---|---|---|
trim |
截取片段 | --start(默认 0)、--end 或 --duration(--end 优先);支持 00:01:30 / 90 / 90.5 |
concat |
拼接多个音频 | 位置参数给多个文件(按顺序);编码一致走无损 concat,否则统一转码 |
convert |
格式转换 | --format mp3\|wav\|m4a\|flac\|ogg(不填按 -o 后缀)、--bitrate(默认 192k,仅对 mp3/m4a/aac/ogg/opus 生效) |
volume |
音量调整 | --gain 6dB(纯数字按 dB 处理)或 --factor 1.5,二者其一 |
normalize |
音量标准化 | loudnorm 拉到 -16 LUFS(EBU R128),可选 -i/--tp/--lra |
speed |
变速(保持音高) | --rate 1.5;>2 或 <0.5 自动链式 atempo |
fade |
淡入淡出 | --fade-in 3、--fade-out 3(秒) |
> 所有子命令都支持 -o/--output 指定输出文件,通用参数 --bitrate(有损容器有效)。运行 python3 $S <子命令> --help 可看单个子命令细节。
工作流程
- 确认输入:拿到用户给的音频文件路径(本地文件);确认目标操作 → 选子命令。
- 确定输出:默认输出到用户指定路径;文件已存在会被覆盖(脚本内部
-y)。 - 跑一条命令:脚本会先打印输入的【时长/格式/编码/采样率/声道/大小】,执行后打印输出信息,便于对比。
- 校验结果:看输出行是否符合预期——裁剪后时长≈
end-start;变速后≈原时长 ÷ rate;拼接后≈各段之和;标准化后应接近-16 LUFS。必要时用ffprobe复核(脚本内部即用 ffprobe)。 - 交付:把输出文件的绝对路径给用户;多步操作(如先 trim 再 speed 再 normalize)串联执行。
命令参考(各子命令实现要点)
- trim:
-ss前置输入定位 +-t输出时长 + 按后缀重编码(保证帧级精确与起点准确)。--end与--duration同时给出时以--end为准;截取长度 ≤0 会报错。 - concat:先用
ffprobe比对所有输入的编码/采样率/声道。全部一致且扩展名相同 → concat demuxer +-c copy(无损、秒级);不一致 →filter_complex重编码(每路先aformat统一到 44100Hz 立体声,再concat=n=N:v=0:a=1)。 - convert:
-c:a按目标扩展名映射编码器(mp3→libmp3lame、wav→pcm_s16le、m4a/aac→aac、flac→flac、ogg→libvorbis、opus→libopus),有损容器追加-b:a。--format可独立于-o后缀指定。 - volume:
-af volume=<值>;--gain纯数字自动补dB,也支持-3dB;--factor直接作倍数传入。 - normalize:
-af loudnorm=I=-16:TP=-1.5:LRA=11,单遍 EBU R128 响度标准化。注意 loudnorm 默认会把输出重采样到 48000Hz(属正常行为)。 - speed:
-af atempo=...,单次 atempo 范围0.5~2.0,超出自动链式拆分(如3x → atempo=2.0,atempo=1.5),因此变速同时保持音高不变。 - fade:
afade=t=in:st=0:d=<in>与afade=t=out:st=<时长-淡出>:d=<out>组合(淡出起始点由 ffprobe 实测总时长推算)。
示例对话
例 1|裁剪
> 用户:把这段播客开头和结尾的废话剪掉,只留 01:30 到 03:00。
> 助手:python3 $S trim podcast.mp3 -o clip.mp3 --start 00:01:30 --end 00:03:00
> → 输出 clip.mp3(时长 01:30),返回绝对路径。
例 2|合并
> 用户:把 intro.mp3、main.mp3、outro.mp3 接成一个文件。
> 助手:python3 $S concat intro.mp3 main.mp3 outro.mp3 -o full.mp3
> → 三路参数一致时走无损拼接,输出 full.mp3 时长 = 三段之和。
例 3|格式转换 + 压码率
> 用户:这个 wav 太大了,转成 mp3,128k 就行。
> 助手:python3 $S convert big.wav -o big.mp3 --bitrate 128k
例 4|音量
> 用户:这段录音声音太小,整体调大一点。
> 助手:python3 $S normalize rec.mp3 -o rec_loud.mp3(自动拉到 -16 LUFS);若只想统一 +6dB 则 volume rec.mp3 -o out.mp3 --gain 6dB。
例 5|变速
> 用户:这段口播太慢了,加速到 1.5 倍,别变声。
> 助手:python3 $S speed talk.mp3 -o talk_fast.mp3 --rate 1.5
例 6|淡入淡出
> 用户:给这首歌开头淡入 3 秒、结尾淡出 3 秒。
> 助手:python3 $S fade song.mp3 -o song_fade.mp3 --fade-in 3 --fade-out 3
运行环境
- 脚本:
scripts/audio_edit.py(相对技能根目录) - Python:3.9+
- 外部命令:
ffmpeg、ffprobe
开工前先跑一次自检,缺什么当场补,别等跑到一半报错:
command -v ffmpeg >/dev/null 2>&1 || echo "缺 ffmpeg,请先安装再重试"
command -v ffprobe >/dev/null 2>&1 || echo "缺 ffprobe,请先安装再重试"
> 缺依赖时用中文告诉用户缺什么、装完就能用,不要把 Python 的英文 traceback 原样贴给用户。
注意事项
- 只处理音频:本技能面向纯音频文件(mp3/wav/m4a/aac/flac/ogg/opus 等)。视频画面相关一律交给 video-editor-toolbox。
- 会重编码:除 concat 的"无损 +
-c copy"路径外,其余操作都会重编码音频;有损→有损会有轻微音质损失属正常。 - 覆盖行为:输出文件同名会被直接覆盖(内部
-y),请提示用户或使用不同输出名。 - normalize 会重采样:loudnorm 默认输出 48000Hz,若需保持原采样率请另行转换。
- 变速范围:
atempo单次 0.5~2.0,脚本已自动链式拆分支持任意正数倍率;变速保持音高(不是变调)。 - concat 采样率:走"统一转码"路径时输出统一为 44100Hz 立体声;若想完全保留原始参数,请确保各输入编码/采样率/声道一致。
- 错误处理:文件不存在、缺参、截取长度非法、ffmpeg 执行失败都会打印明确中文错误并以非 0 退出码结束,便于上游判断。
- 时间为秒:
--duration、--fade-in/out单位为秒;--start/--end支持HH:MM:SS、MM:SS、纯秒数三种写法。