sound(完整版)
給影片配聲音的完整工具鏈,三條能力線:
- 音效選材 —— 多源搜索、按人類反饋信號篩選、下載、測量。
- BGM(背景音樂) —— 兩條路線:離線合成可無縫循環的音樂,或從素材庫檢索長音頻鋪底。
- 人聲與混音 —— 降噪/EQ/去齒音/壓縮、側鏈閃避(duck)、靜態混合、兩遍響度歸一。
環境只要 Python 3 + FFmpeg(ffmpeg / ffprobe 在 PATH 裡)。純標準庫,無第三方包、無 API key、無需登錄。
本 skill 的全部能力均在本倉庫開源實現(MIT 許可):所有命令、規則、參數都在下面的文檔和 references/ 裡,可自由修改與分發。
安裝後按實際位置設變量,下面統一用項目內安裝的寫法:
S=.claude/skills/sound/scripts/sfx.py # 檢索 / 下載 / 分析
V=.claude/skills/sound/scripts/vocal.py # 人聲 / 混音
C=.claude/skills/sound/scripts/compose.py # 離線合成 BGM
全局安裝時把 .claude/skills/sound/ 換成 ~/.claude/skills/sound/。
一、音效選材
工作流
- 把畫面動作轉成英文關鍵詞("卡片飛入" →
short whoosh,"開關切換" →soft click)。 all跨源搜候選,必要時單源補搜;--urls給用戶試聽鏈接。- 先判斷是否貼合畫面,再看熱度;給出候選與推薦依據,別把數字當成"我聽過"。
- 按用途定許可,下載,用
analyze核對時長與能量分佈。 - 交付時保留來源 URL、作者、許可證;非 CC0 的補齊署名。
python3 $S all "short whoosh" --license cc0 -n 10 --urls
python3 $S freesound "paper slide" --license by -n 5 --sort short
python3 $S commons "bell" -n 5 --json
python3 $S mixkit "whoosh" -n 5
python3 $S kenney "impact" -n 5
python3 $S get sfx/ fs:167563 wm:131079817 mk:1489
python3 $S analyze sfx/*.mp3 --loudness --silence --json
選材規則(沿用人類反饋信號)
- 評分人數 > 平均分:
★4.4(380)是比★4.9(6)更強的證據。 - 上傳者描述最接近試聽:出現 "built-in mic" / "made with my mouth" 意味著低保真;點名錄音機(Zoom、Sound Devices)和明確聲源("cork from a wine bottle")說明可控。描述裡的聲源與畫面不符,再熱門也棄用。
- 熱度不代表貼合:下載量最高的 "thud" 可能是 3 秒的電影低頻轟鳴。必須看時長,用
analyze看能量落在哪裡、尾巴多長,再決定是否裁切。 - 先給候選再下載:用戶要試聽時加
--urls,不要直接替他定。 - 可用信號按源不同:Freesound 有下載量與評分人數;Commons 有真實時長和許可;Mixkit 有時長但無熱度;Kenney 是整包素材。別把缺失字段當成 0 分。
許可規則(嚴格分級,不要放寬)
| 參數 | 放行 | 典型用途 |
|---|---|---|
--license cc0 | 僅 CC0 / PDM | 商用、不想管署名 |
--license by | CC0 / PDM / BY / BY-SA | 可接受署名(已排除 BY-NC、BY-NC-SA、BY-ND) |
--license any | 全部,但結果仍標註許可 | 只想先看候選 |
- BY-NC 一律不用於商用,腳本在
cc0/by下已排除;any下要自己判斷。 - Mixkit 用的是自有 "Mixkit Free License"(實際可商用免署名),但不屬於 CC0/BY 標籤體系,因此
cc0/by下會被排除,需要它時顯式--license any並在交付物裡註明許可名。 - 非 CC0 素材
get會打印作者與許可提示;這只是線索,交付時要保留來源與許可原文。 - Kenney 全部 CC0,但下載的是整包 zip,不是單個音效,需要自行解壓挑文件。
音源分工
| 源 | 強項 | 局限 |
|---|---|---|
| Freesound | 唯一有下載量/評分人數 | 只下得到預覽 MP3,不是原始文件;單連接約 80 KB/s |
| Wikimedia Commons | 真實時長 + 許可字段齊全,環境錄音/鐘聲/長音頻 | 按文件描述匹配,關鍵詞怪會搜不到;無熱度 |
| Mixkit | 商用免署名,界面音效質量穩 | 頁面結構解析;無熱度;時長是整秒標註 |
| Kenney | CC0 遊戲/界面音效包 | 整包 zip,無單條時長 |
詳細抓取方式與許可標籤映射見 references/sources.md。
二、BGM:合成 or 鋪底
先判斷用戶要的是"有音樂"還是"配一首符合情緒的曲子":
| 場景 | 路線 | 命令 |
|---|---|---|
| 要可循環、零依賴、可控情緒、無版權風險 | 離線合成 | compose.py |
| 要真實樂器/人聲/環境氛圍 | 檢索鋪底 | sfx.py music |
| 已有短 BGM 想鋪滿畫面 | 循環/裁剪 | vocal.py loop / trim |
離線合成(首選,真正對應"BGM 合成")
python3 $C bgm.wav --style ambient --duration 30 --bpm 90 --key Am
python3 $C bgm.wav --style lofi --duration 30 --bpm 85 --key C
python3 $C bgm.wav --style upbeat --duration 30 --bpm 120 --key G
ambient:緩慢 pad(鋪底和弦),無鼓,適合解說/產品演示;lofi:失諧 chorus + 鬆弛 kick/hat + 磁帶底噪;upbeat:明亮短和弦 + 四踩底鼓 + bass line(低音線)。- 輸出 44.1 kHz / 16-bit / 立體聲 WAV,首尾相位對齊 + 和弦環形交叉淡化,可無縫循環。
- 時長會就近對齊整小節(如 30s @ 90 BPM 實際 29.333s);要精確秒數用能被 4 拍整除的 BPM(如 120)。
- 腳本會打印可直接粘貼的
--bgm-gain建議值(單位 dB),與vocal.py參數一致,直接拿去用。 --seed保證同參數輸出完全一致,便於版本管理。
檢索鋪底
python3 $S music "ambient" --duration long --max-seconds 600 -n 8 --urls --json
python3 $S get bgm/ wm:123456
python3 $V trim bgm/xxx.ogg bed.wav --start 0 --end 30
music走 Commons 的filetype:audio檢索,--duration long默認 ≥30 秒、未知時長默認排除(要放行加--allow-unknown)。- Commons 常返回小時級現場錄音/有聲書,鋪底時務必加
--max-seconds 600,否則會下載幾百 MB。 - 長音頻下載後一般要
trim出一段,或loop把短段鋪滿畫面長度。
三、人聲清理與混音
標準鏈路
# 1. 人聲:降噪 → 高通 → (去齒音) → 壓縮 → 兩遍響度歸一 → 淡入淡出
python3 $V clean voice.wav clean.wav --deesser
# 默認目標 -16 LUFS;不要歸一時加 --no-loudnorm
# 2. BGM 對齊畫面長度(二選一)
python3 $V loop bgm.wav bed.wav --duration 30 # 短素材鋪滿,接縫真交叉淡化
python3 $V trim bgm.wav bed.wav --start 0 --end 30
# 3. 混合:有人說話時自動壓低 BGM(側鏈閃避)
python3 $V duck clean.wav bed.wav mixed.wav --bgm-gain -12 --threshold -30 --ratio 8
# 無人聲/純氛圍時改靜態混合
python3 $V mix bed.wav clean.wav mixed.wav --bgm-gain -18
# 4. 成片響度復核 / 歸一
python3 $V report mixed.wav
python3 $V loudnorm mixed.wav final.wav --target-lufs -16
參數規則
| 參數 | 默認 | 何時調整 |
|---|---|---|
--bgm-gain | duck -12 / mix -18 dB | 用 compose.py 打印的建議值;BGM 蓋過人聲就再降 3~6 dB |
--threshold | -30 dB | 側鏈門限是電平門限,不是語音檢測;人聲很輕時調到 -36,BGM 很響時調高 |
--ratio | 8 | 閃避太明顯/呼吸感強就降到 4 |
--target-lufs | -16 LUFS | 口播/視頻用 -16;純音樂流媒體用 -14;播客可到 -16 |
--true-peak | -1.5 dBTP | 平台有明確上限時按平台改 |
--fade | duck 0.3 / clean 0.05 秒 | 片頭片尾、循環接縫 |
- 量綱別混:
I是 LUFS(集成響度)、TP是 dBTP(真峰值)、LRA是 LU(響度範圍);mean_volume是 dBFS 平均電平,report裡會明確標註,不能拿它當 LUFS。 duck/mix兩路都補apad(靜音補齊)並用duration=longest,BGM 比人聲短也不會被截斷;--duration可指定成品長度。clean的兩遍 loudnorm 測量跑在整條前級鏈之後,且測量遍的 I/TP/LRA 與第二遍完全一致;淡入淡出放在 loudnorm 之前,保證測量信號與歸一輸入是同一個,否則measured_*對不上。loudnorm內部測量口徑與ebur128可能差約 1 LU,腳本會在成片後閉環復核並補一次增益,摘要裡打印「閉環復核 ±X.X dB」;這是精確達標的必要步驟,不要刪。- 極短/近靜音素材測不出有效 LUFS 時會自動降級單遍 loudnorm,並在輸出裡明寫「單遍」;此時閉環自動跳過,不會對著靜音狂加增益。
濾鏡鏈原文、兩遍 loudnorm 原理與調參表見 references/mixing.md。
四、常用配方
A. 30 秒產品演示(全離線、零素材)
python3 $C bgm.wav --style ambient --duration 30 --bpm 120 --key Am
python3 $V clean voice.wav clean.wav --deesser
python3 $V duck clean.wav bgm.wav mixed.wav --bgm-gain -13
python3 $V loudnorm mixed.wav final.wav --target-lufs -16
python3 $S all "soft whoosh" --license cc0 -n 6 --urls
B. 給已有配音配真實氛圍鋪底
python3 $S music "rain ambience" --duration long --max-seconds 600 --license by -n 6 --urls
python3 $S get bgm/ wm:xxx
python3 $V trim bgm/xxx bed.wav --start 10 --end 40
python3 $V clean voice.wav clean.wav
python3 $V duck clean.wav bed.wav mixed.wav --bgm-gain -18
C. 只要一個轉場音,且要能商用
python3 $S all "paper slide" --license cc0 -n 8 --sort short --urls
python3 $S get sfx/ fs:xxx
python3 $S analyze sfx/*.mp3 --loudness --silence --json
D. 跟著畫面走的音量包絡(Remotion 渲染)
成片母帶用上面的 FFmpeg 鏈路;逐幀淡入淡出/卡點音量改在 Remotion 渲染期做,見 references/remotion-audio.md。