Communitygithub.com

BlackAngel242/sound-design

使用 sfx 引擎进行程序化声音设计——编写与视频时间线对齐的提示表,将声音与视觉事件匹配,控制增益层次、声像、音乐调性,自动母带至 -14 LUFS,添加新发生器并验证同步。在需要为仓库中的视频添加、修改或检查音频、音效、背景音乐或响度时使用。

sound-design 是什么?

这个技能旨在解决 AI 生成动态图形大多无声的问题,通过纯 Python 程序化合成声音,无需音频样本、许可证或额外安装,且输出可复现。它使用与画面相同的时间线 JSON 文件,确保声音与画面精确同步,不会出现漂移。该技能支持多种 AI 编码平台(如 Claude Code、Cursor、Codex),通过编写提示表(cue sheet)定义视觉事件对应的声音,例如打字声、滑音、打击音、升调音效等,并通过自动母带处理达到 -14 LUFS 的响度目标,同时保持真峰值不超过 -2 dBFS。用户可以利用内置的发生器库快速创建声音设计,也可以新增自定义发生器,并通过命令行渲染 WAV 文件并验证响度和同步准确性。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/BlackAngel242/skill-market/tree/HEAD/skills/claude-motion/sound-design

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

声音设计

大多数 AI 生成的动态图形都是无声的。声音才能让作品显得精致。

sfx/ 引擎使用纯 Python 标准库合成所有声音:无需样本、无需许可证、无需安装,每次运行输出相同。它读取与画面相同的时间线 JSON,因此声音不会不同步。

各部分如何协同工作

文件角色
sfx/synth.py发生器:每个返回 48 kHz 的单声道采样
sfx/mix.pyMix:在时间轴上放置声音,母带处理至目标响度,写入 WAV
sfx/loudness.pyBS.1770 集成响度(与 ffmpeg 的 ebur128 一致)
sfx/cues/<video>.py提示表:一个视频的声音设计
python3 -m sfx --list                   # 列出发生器及其用途
python3 -m sfx sfx/cues/<video>.py      # 渲染 → 母带后的 WAV

为新的视频编写提示表

创建 sfx/cues/<video>.py:

from sfx.synth import click, pop, whoosh, chime, riser, impact

TIMELINE = "timeline.json"      # 与合成读取的同一文件
OUT = "public/sfx.wav"
TARGET_LUFS = -14.0             # 可选,此为默认值

def score(mix, tl):
    s1 = tl["s1"]
    mix.put(s1["title"], whoosh(0.4, 500, 2400, peak=0.45), 0.12)
    for i, t in enumerate(s1["items"]):
        mix.put(t, pop(900 + i * 150, 400), 0.3, pan=-0.4 + i * 0.3)
  • 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;引擎会以较低音量输出并提示。修复方法是用持续的声音(如铺垫、较长的尾音),而不是强制提高增益。
  • 在 package.json 中添加指向新提示表的 "sfx" 脚本,或直接运行。

sfx/cues/effort.py 是一个完整且真实的示例:包含 128 种声音和一个铺垫音床。

视觉事件 → 声音

屏幕上的内容发生器备注
打字mix.typing()抖动 ±4–6 毫秒,随机增益
文字/行揭示whoosh() + blip()(在落地时)短促、空灵
徽章、芯片、标注弹出pop()在序列中逐渐提高音高
控件跳到某个步骤click() + blip()(在调内)
草图/手绘效果scratch()
蓄势riser()精确结束在击中点;每个视频一个大的升调音效
成功/到达chime()调内和弦
主角转场whoosh()(进入时),impact()(在击中点)每个视频一个冲击音效
所有内容下方pad() 配合 envelope()在主角转场时将其压低

强调,而非叙述:并非每个动作都需要声音。连续动作(漂移、颗粒、旋转)保持静音。

电平与空间

  • 主角击中:增益 0.25–0.35。辅助声音:0.08–0.2。铺垫:约 0.03,在主角转场下压低约 65%。
  • 声像跟随屏幕位置(−1 左 … +1 右)。序列扫过立体声场。
  • 选择一个调性,保持所有有调性的声音都在该调内;音高随进度上升,并在高潮处解决。(在 effort 示例中,铺垫和滑条音符是 D 大调,但场景 3 的弹出和铃声仍然是 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}> 内部。

相关技能