声音设计:为已完成视频添加真实音效
目标:让影片听起来如同一位经验丰富的剪辑师使用优秀音效库完成的作品。每一个声音都来自 EditAtlas 的真实文件,放置在经你检视的帧上,其电平可以用数字证明其合理性。
整个过程中有两件事始终成立,请据此规划:
- 你无法听到声音。 你需要根据音效的描述和实测参数(
sounds.py info)来选择音效,通过check.py检查放置位置和电平,最终交给用户一份简短的片段列表供其试听。永远不要说一个音效“听起来不错”;只说明测量了什么,以及哪些还需要人耳判断。 - 严禁凭空编造。 只处理用户给你的视频。如果没有视频,就索要它。如果某个瞬间需要音效而库中没有,就保持静音并在报告中如实说明。
所有脚本在 scripts/ 目录下(Python 3.9+,需要 numpy 和 Pillow 用于生成帧图片,以及 PATH 中的 FFmpeg 和 ffprobe)。在你自己工作目录(work/、result/)中使用技能文件夹路径运行它们;切勿写入用户的项目或此技能文件夹。
python SKILL/scripts/moments.py FILM.mp4 --out work/moments # 生成 moments.json, sheet.png, overview.png
python SKILL/scripts/moments.py FILM.mp4 --at 10.4 --out work/at # 生成某个时间点前后0.1秒的帧序列
python SKILL/scripts/sounds.py search "玻璃杯碰撞" --max-dur 2 # 从公共索引搜索音效ID
python SKILL/scripts/sounds.py info sfx-ID sfx-ID # 下载一次,校验SHA-256,查看测量参数
python SKILL/scripts/sounds.py sheet sfx-ID sfx-ID --out work/c.png # 生成候选音效的波形和频谱图
python SKILL/scripts/mix.py work/cues.json --out result/FILM_sfx.mp4 # 生成 MP4 + _track.wav + _resolved.json
python SKILL/scripts/check.py result/FILM_sfx_resolved.json --moments work/moments/moments.json --listen-out result/listen.wav
音效源自 https://raw.githubusercontent.com/EditAtlas/sfx/main/ 并缓存至 ~/.cache/editatlas-sfx(可通过 EDITATLAS_SFX_CACHE 环境变量修改)。如果拥有 EditAtlas/sfx 的本地克隆,请在 sounds.py 的子命令前传递 --mirror PATH 参数,此时不会进行任何下载。
1. 检视影片及其声音
运行 moments.py。它会报告现有的音频信息(如 has_audio、LUFS 值、静音占比),并通过像素差异找到三种瞬间:cut(场景切换)、move(运动开始或达到顶峰)、land(运动停止:物体安定下来)。然后使用读取工具打开 overview.png 和 sheet.png:数值可能会遗漏微弱动画(例如在静止人脸上缩放的徽章不会产生切场),也可能会过度报告摄像机抖动。在关键处,使用 --at T 参数绘制某个时间点附近的帧,找到物体出现、着陆或转向的确切帧。
根据数值和画面观察,决定如何处理影片的原始音频:
| 在数值和画面中观察到的内容 | 提示表设置 |
|---|---|
无音频,或 silent_share 接近 1 | "keep_audio": false:由音效承载整部影片,最终响度约调至 -16 LUFS |
| 仅有音乐 | "keep_audio": true:音效电平比音乐低约 3 LU;尽量让重音落在节拍上 |
| 有人在说话(字幕、人脸、领夹麦克风) | "keep_audio": true, "under_voice": true:音效电平比人声低约 8 LU;使用更少、更轻柔的音效 |
| 合成哔哔声已混入最终音频 | 询问用户:替换它们需要独立音轨;在现有音效上叠加真实音效会使两者同时存在 |
如果不确定是否保留影片的原始音频,请询问用户。
2. 根据观察编写事件列表
每个值得添加音效的瞬间对应一行:时间,发生了什么,需要什么类型的音效。像剪辑师一样思考:
- 某物出现时(徽章、芯片、按钮、字幕卡):使用一个短促的爆裂声、滴答声或柔和的叮当声,
anchor: start。 - 某物横穿屏幕或转场时:使用一个呼啸声,其最响点落在到达时刻,
anchor: peak。 - 某物有重量地着陆(标志、产品、印章):使用一个撞击声或重击声,落在其停止的那一帧,
anchor: peak。 - 屏幕上出现真实物体(玻璃杯、冰块、纸张、钥匙、饮料):使用匹配的拟音(foley),而不是 UI 音效。
- 成功/错误状态:使用叮当声代表成功,短促的蜂鸣或警报代表失败。每部影片使用同一系列的界面音效。
- 某种积累过程:使用一个上升音,其结束点落在高潮时刻,
anchor: end。
并非每个动作都需要音效。节奏和品味的数值规则在 references/taste.md 中;在制作第一份 cue 清单前请先阅读它。
3. 选择音效:阅读、测量、比较
- 搜索。如果 EditAtlas MCP 已连接,
search_sfx的排序效果更好(它也理解越南语);否则使用sounds.py search。音效标题有意避开了其源文件的词语(例如“照相机快门”被命名为“镜头光圈滴答声”),因此请根据声音的实际内容搜索,并尝试同义词和分类筛选。 - 对 2-4 个候选音效运行
sounds.py info。阅读以下参数:audible_s(实际听到的时长,文件可能更长)、attack_s(0.0x 表示瞬时爆发,0.3+ 表示逐渐增强)、peak_t_s、centroid_hz(约 1500 Hz 以下为低沉暗淡,6000 Hz 以上为明亮锐利)、mono_loss_db(低于 -6 dB 表示声道间在手机上播放时会抵消;mix.py随后会只播放较响的声道)。 - 当两个候选音效的参数接近时,使用
sounds.py sheet:尖锐的竖线是咔嗒声,模糊的涂抹效果是呼啸声,底部的能量代表重量。 - 根据物体的动作和材质选择,其次考虑时长:一个 0.3 秒的芯片爆裂声不应使用一个 1.8 秒的卡通爆裂声。使用
max_len参数截取较长的文件,并添加淡出。 - 同一类型的重复瞬间(例如三个芯片爆裂声)应使用同一系列的不同版本(例如 Tiny Plop 05, 06, Empty Plop 06),而不是重复使用同一个文件三次。
库在某些类别中资源较少(2026年11月7日测量结果):缺少液体倾倒或嘶嘶声、环境音、盖章声,水滴滴落声和重击声也不多。选择最接近的真实音效,并在报告中说明缺口,而不是强行使用一个不合适的音效。
4. 编写 cue 清单并渲染
{
"video": "work/film.mp4",
"keep_audio": false,
"under_voice": false,
"cues": [
{"t": 0.30, "id": "sfx-988dafbd36", "role": "whoosh", "label": "标题着陆"},
{"t": 0.62, "id": "sfx-mi630472", "role": "foley", "anchor": "start", "max_len": 0.9, "gain_db": -2, "label": "冰块进杯"},
{"t": 8.30, "id": "sfx-fs339114", "role": "hit", "label": "瓶子着陆"},
{"t": 0.00, "id": "sfx-c7d271e90f", "role": "ambience", "bed": true}
]
}
t是以秒为单位的瞬间所在帧。role设置电平基准和默认锚点(详见references/taste.md)。anchor:start将音效的可听起点对齐到t,peak将对齐到最响点,end将对齐到可听终点。- 每个 cue 可使用的参数:
gain_db(相对于角色电平的增益偏移)、max_len、fade_in、fade_out、offset_in、pan(-1 到 1)。 "bed": true:一个贯穿全片的长而稳定的环境音,电平为 -54 dBFS(几乎听不见)。仅适用于影片只有音效而没有任何其他音频(人声或音乐)的情况。如果影片长度超过该音效时长,它会自动交叉淡入到自身。
运行 mix.py。它会打印每个音效的放置时间和峰值电平,并提示某个瞬间非常靠前导致音效不得不从其文件内部开始播放的情况。
5. 检查、修复、再次检查
每次渲染后都运行 check.py;如果退出码为 1,则表示它标记了问题。它读取 mix.py 存储在 _resolved.json 旁边的 WAV 轨道,因此复制结果时请保持这些文件在一起。check.py 通过波形在渲染后的轨道中找到每个音效,因此 sync 是真实的:任何偏移超过一帧的情况都表明 cue 清单中存在错误。它还测量每 10 秒的手势数量、最长静音空隙、强撞击音效、重复情况、数字静音、母带响度和真实峰值、单声道折叠质量,以及有多少强画面瞬间获得了音效。
对于每个标记项,要么修复它(向静音空隙添加音效、替换重复项、移动 cue),要么判断它正确并在报告中说明原因(例如“7.8 秒的静音空隙是演讲段落,由人声承载”)。关于慢攻击的注释是提示:如果该瞬间是音效的峰值,请将该 cue 的 anchor 切换为 peak。两到三轮的检查修复是正常的。
6. 交付成果
向用户提供:
FILM_sfx.mp4和FILM_sfx_track.wav(仅包含音效的完整长度 WAV 文件,供用户在其自己的剪辑下叠加使用)。- 一张简短表格:时间、瞬间描述、音效名称和 ID、选择该音效的原因。
check.py输出的数值(节奏、最长静音空隙、LUFS、真实峰值)以及每个剩余标记项的含义。- 试听清单(
listen.wav将这些瞬间剪辑成一个文件):“请用耳机听一遍,再用手机听一遍”。 - 缺口:未被添加音效的瞬间以及库中缺少的音效。
使用用户的母语撰写报告。不要声称你听过这些音效。
可选:real-sfx 引擎
Clipwing 的 real-sfx 技能(MIT 脚本,作者 Alexander Korbanov)使用更强大的引擎完成相同的工作:类型化 cue 清单、合成音层移除、节拍网格、9 轴评估。它可以使用整个 EditAtlas 库作为其主要音色包。适配器和验证详情请参见 references/real-sfx.md。