real-sfx: 為動態影片提供真實音效
目標:讓影片聽起來就像是由一位擁有良好音效庫的專業人士剪輯出來的。所以:
- 音效絕不合成。 來源:使用者的音效庫(
config.json)和 uisfx(一個現成的 CC0 介面音效包,本身是合成的:唯一的例外,僅用於介面時刻;「無合成」選項可將其關閉:--ui library)。沒有合適的音效:該時刻保持靜音,並會記錄在報告中。這會覆蓋 motion-standards 中的「無音軌:合成」規則。 - 你無法「聽見」。 聲音是以數字、文字和圖片的形式讀取(
references/listening.md)。請不要將選擇描述為「聽過」:請說明是透過眼睛和測量檢查了哪些部分,以及使用者應該聽哪些部分。 - 保留音樂和人聲,當它們主導影片時。最終結果總是包含一個新的 MP4 和一個獨立的 WAV 音軌。
- 不要重複。 已合成到影片渲染音訊中的音效,會被真實音效取代,而不是疊加在它們之上(第一步)。批評分析會將此量化為一個數值(
doubling軸)。 - 不要修改專案或技能資料夾。 將所有工作檔案放在你自己的資料夾中(
work/,result/)。
在 Video Director 內部
(在 Video Director 的副本中新增;原始 Clipwing 版本沒有。UPSTREAM.md 列出了所有變更。) 此副本位於 Video Director 技能內部,並由其聲音階段執行:../references/sound-stage.md,「聲音工程」。這些步驟會決定哪些時刻需要音效,只將這些時刻傳遞給此技能(build/audio/sfx/events.json),固定使用者選擇的錄音(sound_handoff.py pins),以 --ui library、--no-loudnorm 且不包含紋理層或基底的方式執行,並只取回效果音軌和已解析的提示(sound_handoff.py collect)。請遵循這些步驟,並僅針對它們未涵蓋的選項閱讀此檔案。將 REAL_SFX_CONFIG, REAL_SFX_INDEX, REAL_SFX_TASTE, REAL_SFX_RATINGS, REAL_SFX_STEADY 和 REAL_SFX_STYLES 設定為 ~/.config/real-sfx/ 下的路徑(該插件每次安裝新版本都會放在新資料夾中,因此此處寫入的任何內容在下次更新時都會遺留),並且不要使用 --remember,因為它會寫入此資料夾(learn_style.py 也是如此:將學習到的樣式複製到 ~/.config/real-sfx/styles/)。
快速路徑
首先執行 python scripts/setup.py check(ffmpeg、主要/額外音效庫、索引、uisfx)和 python scripts/look.py FILM.mp4 --out work/look(包含時間和原始聲音的影格)。然後,根據你擁有的資料:
# 1. 專案有事件清單(docs/cues.json, scripts/cues.json)或合成其聲音的腳本(audio.cjs)
python scripts/from_cues.py PROJECT_FOLDER|docs/cues.json --video RENDER.mp4 --out work/cues.json
# 2. 沒有清單的螢幕錄影:ui_events.py ...(references/screencast.md),然後 from_cues.py work/ui/events.json
# 3. 僅有影片: find_moments.py FILM.mp4 --out work/moments; suggest_cues.py work/moments/moments.json --out work/cues.json
# 3b. 沒有清單的柔和彩色動畫(UI 預覽、插圖、動態圖形):自動化會看到 40 個動作中的 5-6 個。
# 步驟 2,「沒有清單的無聲動畫」:find_moments.py FILM --out work/moments --fine; look.py FILM --at T --span 2.4
# --step 0.1 --out work/at.png; 根據影格自行建立事件清單(references/typed-cues.md)-> from_cues.py - --ui library
python scripts/mix.py work/cues.json --out result/film_sfx.mp4 --plan # 查看每個音效的位置;然後不加 --plan 執行
python scripts/critique.py result/film_sfx_resolved_cues.json result/film_sfx_sfx_track.wav
python scripts/levels.py result/film_sfx_resolved_cues.json result/film_sfx_sfx_track.wav --json work/edits.json
# 一個聲音只有 SFX(沒有自己的音樂或人聲)的影片:在間隙中放置細小聲音,然後再次執行 mix.py(步驟 4,「細小聲音層」)
python scripts/texture.py work/cues.json --moments work/moments/moments.json
# 同一個影片:一個基底(一個在整個影片下方的長段昏暗真實錄音;步驟 4,「基底」),然後再次執行 mix.py
python scripts/bed.py work/cues.json [--list]
# 與九個完成的 SFX 卷軸進行比較(步驟 6,「對照參考」):沒有分數,不影響最終判斷
python scripts/critique.py RESOLVED.json WAV --style clean-sfx-refs
# 讓人工聆聽變得簡單(步驟 6):一個包含批評問題和單擊判斷的頁面;遮罩模型
python scripts/listen_page.py build work/listen --moments result/film_sfx.mp4 --critique RESOLVED.json WAV
python scripts/listen_page.py serve work/listen [--lan] # 然後:listen_page.py results work/listen --log
python scripts/mix.py work/cues.json --out result/film_sfx.mp4 --masking # 其餘聲音隱藏哪些部分(需要虛擬環境)
專案資料夾會找到自己的事件清單(docs/, scripts/, assets/);合成器腳本只在沒有清單時讀取。在編輯工作表之前選擇所有 from_cues.py 標誌:再次執行它會清除手動編輯(然後使用 sheet.py apply)。
影片中有人聲:mix.py ... --voice-safe(深度 normal;當有許多安靜紋理時使用 --voice-depth light,deep 僅用於暫停中的稀有聲音:它會完全將介面從混音中移除)。音樂主導影片:--duck。
響度:預設情況下,重建的基底會匹配原始響度;你自己的設定:--target-lufs NUMBER。
沒有索引,或音效庫已移動:python scripts/build_index.py,然後 python scripts/listen.py tag-index。
沒有 uisfx:setup.py init --uisfx。
另一台機器:setup.py scan FOLDER,setup.py add-library NAME PATH [--tier main|extra] --index。
從技能資料夾執行腳本;引用包含空格或非拉丁字元的路徑;在 Windows 上使用含非拉丁路徑的自訂 Python:PYTHONUTF8=1。在 PowerShell 中,引號會破壞 JSON 引數:將它們放入檔案中。
聲音的來源
| 需要的聲音類型 | 來源 |
|---|---|
| 基礎:呼嘯聲、撞擊聲、上升音效、爆裂聲、鈴聲、按鍵聲、紙張聲、擬音、環境音 | 主音效庫(tier: main,路徑在 config.json 中)。一個包含 catalog.json / catalog.csv 的分類包,為每個聲音提供類型和來源錄音,這比根據檔案名稱猜測要好 |
| 主音效庫缺少的:低沉掉落聲、硬幣聲、短促雜訊 | 備用音效庫(tier: extra,在結果中標記為 ~):僅在主音效庫少於三個合適聲音時使用 |
| 具有特定角色的設計包 | 角色 granular, atmosphere, power, music_transition, voice 從不透過自動選取請求:請明確使用它們(--role, "pick": {"role": ...}) |
| 介面時刻:點擊聲、滴答聲、視窗聲、通知聲 | uisfx(--ui auto),當清單本身命名了介面類型(click, chime...)時:from_cues 會說明原因和位置(routes: key -> library:click, pop -> uisfx:select) |
| 打字聲 | 始終使用音效庫的真實鍵盤,即使使用 --ui auto 也是如此;from_cues 會自動將連續 8 個以上、間隔 35-170 毫秒的 click 事件識別為打字(--no-typing-detect) |
| 物理接觸:球、腳步、珠子、物體 | 始終使用音效庫:地板上的球是沉悶的重擊聲,而不是 select 聲音(配方見下文) |
如果還沒有音效庫:僅使用 setup.py init --uisfx 即可獲得 78 個 CC0 UI 提示。值得檢查的免費真實錄音來源(請閱讀每個授權):Freesound(CC0 篩選器)、Sonniss GDC 包、Mixkit、Pixabay 音效。
「從我的音效庫」、「無合成」或「聲音聽起來很合成」:--ui library。在帶有 uisfx 介面聲音的專案中,為標誌加上重音或「cha-ching」聲:--from-library pop,bell(清單中的種類名稱);對於單個聲音:sheet.py set --at T --label bell id=65。
在調性音樂下:
- uisfx 重複音調和音效庫調性聲音(chime, pop, glass, coin)的音高步進在專案有樂譜時會自動關閉(
--ui-pitch off|cycle); - 真實聲音的音高會被調整以配合音樂的樂音:
mix.py會使用工作表的music_ref(無效果的基底,或音樂音軌)或--music-ref FILE,並將調性聲音最多移調 2 個半音,再加上將其置於某個音符上的音分(總共 2.5 音分),前提是這樣能讓它落在一個音符上;噪音則保持不變(--no-tonal-fit;scripts/tonal.py SOUND --music FILE --at T會顯示音符); - 作者原始頻率的間隔(
tick(t, 1800 * 2 ** (4 * i / 12)))會成為替換音效的音高步進(melody:)。
工作流程
1. 聲音中已有的內容
look.py 顯示原始聲音的頻譜圖(人聲是片語的頻帶,音樂是帶有節拍的地毯,寂靜是黑色);listen.py voice FILM.mp4 給出語音和音樂的比例。三種情況:
- 作者的音樂或人聲:它們保留下來,SFX 疊加在上面(
--duck/--voice-safe)。 例外情況(真實影片上的人的答覆,2026-10-19):該影片被發送來「進行聲音設計」,其原始聲音只有音樂(listen.py voice:語音 0%),且此人希望不帶音樂的版本,就像他們自己的乾淨 SFX 卷軸一樣。製作一個無音樂的版本(from_cues.py ... --ui library --drop-original,然後使用喜愛的氛圍執行bed.py --id ... --level -46),如果需要的話也製作一個有音樂的版本,並說明兩者的區別。在三個選項(原始 / 音樂上的效果 / 僅效果)的盲測中,此人毫無疑問地選擇了最後一個。from_cues在這樣的影片上會印出BAKED:,儘管沒有烘烤的合成(語音 0%,音樂 84%,攻擊點與事件不匹配:7% 對比隨機的 9%):這是誤報。 - 合成音效已烘烤到音軌中(專案是為合成配樂編寫的):在其上疊加真實音效會造成重複。
from_cues.py會自行檢查這一點(BAKED:,unbake:)並從基底中移除合成音效,而不影響音樂和人聲;具體方法,以及如果腳本失敗或合成音效位於音樂音軌內部時該怎麼做(--extra-synth):請參閱references/project-audio.md(當輸出包含BAKED,WARN stems,unbake: not possible,或專案使用腳本合成其聲音時,請立即閱讀)。建置後,critique.py會列印doubling軸:該圖層與原始和新影片的相關性(應接近 0)。 - 螢幕錄影視窗內播放剪輯的聲音:原始聲音保留下來;這些視窗內的被捨棄。
2. 找到時刻(從最佳來源到最差來源)
- 專案的事件清單或合成器腳本 →
from_cues.py(見下文)。詳細資訊:references/typed-cues.md。 - 螢幕錄影 →
references/screencast.md(ui_events.py區域、將按鍵與字元匹配、剪輯聲音)。 - 帶有
data-start的 HyperFrames 且無清單:from_hyperframes.py PROJECT --out work/moments.json。 「1 個時刻」包含 18 個元素,表示動作不遵循data-start:尋找合成器腳本。 - 僅有影片:
find_moments.py FILM --out work/moments [--roi x,y,w,h] [--from A --to B] [--fine];種類cut,burst,onset,settle(settle也會在空影格或靜止迴圈上觸發:請查看影格);look.py --moments ...繪製時刻的影格。骨架:suggest_cues.py(references/recipes.md);草稿是起點,不是答案。--fine用於柔和彩色動畫(漸層、發光、改變顏色而非亮度的柔和形狀):它也會讀取色度變化,時刻會獲得src=chroma|luma;在三部此類影片上,它找到了代理從影格中記錄的事件的 33–69%(在 80 毫秒內),而僅使用亮度只有 13–25%;候選項多 3–4 倍(每 10 秒 15–25 個)。這些是候選項:由影格決定。 - 在音樂下:
beats.py FILM --out work/beats.json --plot work/beats.png;使用usable: true,mix.py --snap-beats(±50 毫秒)。該格線會根據大鼓進行檢查(低頻帶 < 125 Hz 單獨處理):它會列印有多少節拍在 40 毫秒內落在大鼓上。落在大鼓旁邊的格線(跟蹤器位於鈸上,「偏移 0.22 秒」)會被移動到其上;落在無聲處的格線會得到usable: false,而--snap-beats會忽略它。--plot繪製頻帶、大鼓(綠色標記)和格線(紅色線條):標記應位於線條上,否則不要信任格線。如果音樂是你的且可以配合畫面:beats.py FILM --suggest-offset work/moments.json會建議將音樂偏移多少,以便剪輯和撞擊聲落在節拍上(僅供建議;音樂本身不會被修改)。
from_cues.py:python scripts/from_cues.py LIST|PROJECT_FOLDER|SCRIPT.cjs|- --video RENDER.mp4 --out work/cues.json(- 從標準輸入讀取清單;來自 PowerShell 的 BOM 也能理解)。它會自行執行並說明:
- 這是否是正確的渲染:清單與畫面不符(
VERDICT);一個設計時期的清單與一個根據人聲計時渲染的檔案:使用來自專案錨點的 time map(帶有a的timing.json)