產品片 AI 旁白:從「有點怪」到專業解說水準
本技能來自一次真實返工。一部 2 分 43 秒的英文黑客松產品片(11 句旁白、配畫面卡點),用戶反應配音「聽起來還是有點怪」。經 9 個版本、十餘種 TTS 引擎與音色、校準過的評審和大樣本統計,最終採用 MOSS-TTS 一次性連續生成 + 按內容核驗切句 + 只做不傷聲音的經典後期,用戶認可。
評測方法見 references/evaluation.md,聲學處理的取捨見 references/acoustic-polish.md,可複用腳本在 scripts/。
1. 先診斷「怪」在哪:一般不是音質,而是韻律
[!IMPORTANT] 好的 TTS 在音質上早已超過普通錄音。UTMOS / Distill-MOS 打分都高於乾淨的真人人聲朗讀(LibriSpeech),所以「怪」幾乎都來自韻律。以公有領域專業解說(NASA 紀錄片,Demucs 分離人聲)為參照,實測特徵如下:
| 特徵 | 專業解說 | 逐句克隆 TTS(最初版本) |
|---|---|---|
| 音高起伏(F0 標準差,半音) | 4.6 | 2.7(平) |
| 短語句尾下降(半音) | 0.7 | 2.3(句尾往下沉) |
| 語速(音節/秒) | 4.2 | 4.55(偏快) |
| 平均停頓(秒) | 0.39 | 0.54 |
用 scripts/prosody_compare.py、scripts/end_fall.py 和 scripts/take_features.py 把候選和參照放在同一套特徵上比較,用數據說話,不靠印象。
2. 生成:一次讀完整段,不要逐句拼接
- 連續生成優先。逐句生成時,每句的起伏、輕重和氣口都各自從頭開始,拼起來就是「怪」。讓 TTS 一次讀完全部旁白,句子之間用空行分隔,模型能看到上下文,前後句才連得起來。本例採用 MOSS-TTS v1.5 克隆模式,參考音頻是一段約 15 秒、語氣合適的旁白,用 4 個隨機種子各生成一遍,每遍約 2 分 10 秒、整段字錯率 2–6%。
- 候選比較的結果(同一套評測):
- MOSS 一次性連續生成:與專業解說的韻律距離 0.29(最近),缺陷最少;
- Qwen3-TTS VoiceDesign 逐句生成,附表演指示、多抽幾次後按韻律挑選:距離 0.37,自然度與 MOSS 持平;
- OpenAI gpt-audio:距離 0.57;
- 逐句克隆:距離 0.89。
- 已知坑:
- MOSS-VoiceGenerator(用文字描述音色)遇到長文本,約 33 秒就提前停止,不能用於整段生成。
- Gemini TTS 必須使用「AUDIO PROFILE / DIRECTOR'S NOTES / TRANSCRIPT」的分段格式,否則會把指示文字也唸出來;免費層每個模型每天只有 10 次呼叫。
- OpenAI 的音色在評審裡起伏偏小。只要用了商用 AI 聲音,片尾就要註明。
- 選種子看韻律特徵:在字錯率合格的前提下,選與專業參照距離最小的種子。某一句表現差(例如結尾口號沉成氣泡音),可以只把這一句換成同一參考聲音、其他種子的版本。
3. 切句:按內容核驗,不要只信時間戳
連續生成的整段音頻要切回逐句,才能對上畫面。scripts/align_split.py 的做法:
- 用 SenseVoice 拿到詞級時間,按編輯距離與稿子對齊。
- 在每兩句之間的靜音處下刀。
- 再按內容核驗:在切點前後 1.5 秒內的每一段靜音都試切一次,把左右兩段重新辨識,選兩段字錯率之和最低的位置。
只看時間戳會出錯:TTS 常在句子內部停頓(例如「Just | sentences.」),而在兩句之間連讀,詞級時間又比實際起音晚。不加核驗時,「does | it」和「Just | sentences」都被切到了下一句開頭。
4. 後期:只修可量化的問題,不碰音高
| 處理 | 結論 |
|---|---|
按標點規整停頓(pause_fix_en.py:詞組內 0.10 s、逗號 0.25 s、冒號 0.33 s、句末 0.45 s;短口號保留 0.8 s 的一拍) | 保留:只縮短不加長,與專業解說的停頓更接近 |
統一響度(每句 -20 LUFS)、高通 70 Hz、300 Hz 處 -2 dB、輕度去齒音、6% 小房間殘響(vo_post.py) | 保留:音質評分不降 |
| 限制器 | 去掉:Distill-MOS 降約 0.14,改為線性增益控制峰值 |
| 用 WORLD 聲碼器或 Praat PSOLA 抬句尾、整體放大音高起伏 | 放棄:特徵更接近專業了,但嚴格評審打分反而下降(WORLD 修得越狠越差,最強一檔 −0.30,信賴區間 [−0.61, −0.03]) |
原則:句尾和起伏的問題,透過多生成幾次、挑選來解決,不要事後改音高。
5. 混音:音樂不要在句間「泵」
scripts/duck_curve.py:句間停頓短於 2.5 秒時,音樂保持壓低(−11 dB);壓低提前 0.25 秒開始,恢復用 0.9 秒的單極點平滑。原來的 0.3 秒滑動平均會讓音樂在每個停頓裡漲起來,聽眾會覺得「喘」。最終成片 −14 LUFS,峰值不超過 −1 dBFS;混音裡旁白的 ASR 字錯率在 0–6.5%。
6. 畫面時長
- 旁白放不進畫面的部分,動畫段可以整體放慢約 5%,介面錄片段可以延長停留,不要壓縮人聲。
- 密集逗號容易讓 TTS 讀得生硬,可以在不改原意的前提下微調措辭,例如把「Here it is, live, on real footage」改成「running live on real footage」。
7. 放行標準
- 稿子逐句字錯率不超過 0.08,混音內複測同樣合格。
- 逐句單獨請 Gemini 做缺陷檢查(每次只聽一條),沒有剪切聲、吞字、讀錯、氣泡音句尾。
- 對照專業解說的韻律距離,以及嚴格自然度測試(單條、大樣本、bootstrap 信賴區間)不劣於參照,詳見評測文件。
- 最終由使用者試聽確認。AI 評審無法證明「聽起來不怪」,見下一節。
8. 關於「AI 評審」的教訓
- Gemini 兩兩對比不可用:有 86% 的情況選先播放的那條,正反順序給出相反結論。
- 多條一起排名不穩定:同一組素材兩輪排名互相矛盾。
- 沒有參照的打分不可信:業餘真人人聲錄音只得約 5 分,反而低於 TTS 的約 6 分。
- 可用的方法:以專業旁白為參照的單條嚴格測試,配合大樣本和信賴區間。即便如此,「判為真人」這一項仍雜訊很大(同一音頻可能 0/8 也可能 3/8,專業演員也會被判成 AI)。
- AI 評審的意見要核實:例如「混音在泵」這一說法與實測的增益曲線矛盾,應以測量為準。