Sound design 是 whaleyxbt/claude-motion 中的一个程序化音效模块,用于给 AI 生成的动态图形配上声音。多数 AI 制作的动态图形是静音的,而声音能让作品更像成品。
【用途】 sfx/ 引擎用纯 Python 标准库合成每一个声音:不使用采样、不需要授权、无需额外安装,每次运行输出相同。它读取与画面相同的时间线 JSON,因此声音不会与画面失去同步。
【主要构成】 文件与角色如下:
- sfx/synth.py:生成器,每个返回 48 kHz 单声道采样。
- sfx/mix.py:Mix,把声音放到时间轴上、按响度目标做母带处理、写出 WAV。
- sfx/loudness.py:BS.1770 集成响度(与 ffmpeg 的 ebur128 一致)。
- sfx/cues/<video>.py:提示表,即一个视频的声音设计。
【使用方式】 列出生成器及其用途: python3 -m sfx --list 渲染为母带 WAV: python3 -m sfx sfx/cues/<video>.py
为新视频编写提示表:新建 sfx/cues/<video>.py,从 sfx.synth 导入 click、pop、whoosh、chime、riser、impact 等生成器,指定 TIMELINE(与合成读取同一文件)、OUT、可选的 TARGET_LUFS(默认 -14.0),并定义 score(mix, tl) 函数。mix.put(t, samples, gain, pan) 中的 t 始终来自 tl,不要手写数字;允许使用相对节拍的偏移,例如 s1["exit"] + 0.05。mix.typing(start, end, chars) 每个字符产生一次拟人化击键。mix.put_stereo(t, left, right, gain) 用于 pad() 之类的立体声源。
母带处理是自动的:引擎做软削波并设置增益以达到 TARGET_LUFS,仅在需要时提高驱动量,以保持真峰值 ≤ −2 dBFS(为 AAC 过冲留出余量,使 MP4 保持在 −1 dBTP 以下)。如果一段混音大部分是短促的敲击、之间是静音,则无法在不压碎的情况下达到 −14;此时引擎会输出更安静的结果并说明这一点。应通过持续声音(pad、更长的尾音)解决,而不是强行拉高。
可在 package.json 中添加指向新提示表的 "sfx" 脚本,或直接运行。sfx/cues/effort.py 是一个完整真实的示例:128 个声音外加一层 pad 铺底。
【视觉事件到声音的对应】
- 打字:mix.typing(),抖动 ±4–6 ms,随机增益。
- 单词/行显现:whoosh() + 落点上的 blip(),短而通透。
- 徽章、标签、标注弹入:pop(),在一段序列中提高音高。
- 控件咔哒到某一步:click() + 同调内的 blip()。
- 草图/绘制:scratch()。
- 蓄势:riser(),精确结束在强拍上;每个视频只用一次大 riser。
- 成功/到达:chime(),同调和弦。
- 主转场:进入时 whoosh(),强拍上 impact();每个视频只用一次 impact。
- 整体铺底:pad() 配 envelope(),在主转场下做闪避。
要点是强调而不是解说:不是每个运动都需要声音,持续运动(漂移、颗粒、旋转)保持静音。
【电平与空间】
- 主强拍:增益 0.25–0.35。辅助声音:0.08–0.2。Pad:约 0.03,在主转场下闪避约 65%。
- 声像跟随屏幕位置(−1 左 … +1 右)。序列在立体声场中扫过。
- 选定一个调性并让所有有音高的声音都保持在该调内;音高随进度上升,并在回报点解决。(在 effort 示例中,pad 和滑块音是 D 大调,但场景 3 的 pop 和 chime 仍在 C 大调。不要照抄这一点。)
【添加生成器】 在 sfx/synth.py 中写一个函数,返回 SR 下的浮点数列表。把用途写在第一行文档字符串中,--list 会显示它。噪声使用模块级 random,以保证渲染可复现。任何通透的声音都基于 bandnoise() 构建。
【验证】 npm run sfx # 或 python3 -m sfx sfx/cues/<video>.py npm run wave # out/wave.png + WAV 的响度 npm run build node scripts/wave.mjs out/effort.mp4 # 你实际要发布的文件的响度
在 out/wave.png 中,每条珊瑚色线是一个时间线节拍。每个瞬态应落在一条线上或稍后一点。落在两线之间的敲击意味着硬编码时间或过期的 WAV。对于有自己时间线文件的视频,传 --timeline。
【可选:生成音频】 对于无法合成的旁白或声音,ElevenLabs MCP(见 .mcp.json.example)可以生成文件到 public/。用 <Audio src={staticFile(...)} /> 放在 <Sequence from={beat * FPS}> 内来放置它们。