那天發了十一個版本,沒有一個在改劇本
9 月 4 日《還沒送到的信》在 Larch 市集連發 release 10 到 20,十個跟聲音有關。合成的部分中午前後陸續收完,剩下的時間卡在三件事:播放器不讀卡片上的 bgmVolume、F5 的 speed 調高會吞掉句首、whisper 標了 51 句未達標,複檢後剩 5 句。

9 月 4 日那天,《還沒送到的信》在 Larch 市集連發了十一個版本(release 10 到 20)。repo 裡有 18 個 commit,放劇本的 story/ 一個字都沒動。十一個版本裡,一個是去補專案描述裡的日記站連結,剩下十個都在處理聲音。
《還沒送到的信》是優理(Yori)的獨立短篇視覺小說,跑在 Larch 上。分支松鼠的郵局裡躺著一封蓋了 done 章的信,郵戳卻早於郵局開張日,優理提著終端燈籠連夜去補它缺的東西。一個序、三章、一個尾聲,路上會問兩次要往哪走,收在兩種結局。不用登入就能開:https://larch.ink/play/market/1abe8522-06b6-4527-87ef-ab20eaf9c2af
先說分工。角色正典、任務書、每一個「這樣可以收了嗎」是我定的;劇本文字、合成腳本、混音腳本、QC 腳本都是 AI 寫的。聲音這條線上我做的事,一半是聽,一半是出規格(字速要 4.5 字、台詞不接受被動)。破音字唸錯、音樂蓋過人聲,那天都是聽出來的,檢查器一次都沒叫。
引擎的比較寫在同一天做了三套語音對話迴圈。這篇不談選型,只談引擎把檔案交出來之後的事。
音量欄位填了等於沒填
第一件事是背景音樂太大聲。
上午優理 79 句台詞上線,第一輪聽下來,背景音樂把人聲壓過去了。
第一個修法是調欄位。每張卡片的 bgmVolume 從 0.28 降到 0.14,標題畫面 0.16。commit 裡連算式都寫了:「BGM 母帶 -12 LUFS、語音 -18;0.14 讓語音高過 BGM 約 11 dB」。算對了,聽起來沒變。
原因在播放器。另一部作品《空白也有質地》同一天實測,市集播放器不讀卡片上的 bgmVolume,遊戲裡量到的 volume 固定是 1。兩部作品同一個下午撞上同一件事。
欄位沒用,音量就只能動檔案本身。下午四首 BGM 重新做成 -31 LUFS 上傳,卡片跟標題的 bgmVolume 一律填回 1.0,當作沒有這個欄位,gen/make_loop.sh 的預設也跟著改。
這個數字撐了四十七分鐘。我回報背景音「小到有點聽不到了」,commit 標題上的理由記成三個字:聽不到。四首再做一次,這回 -25。
硬碟上留著的檔案,今天用 ffmpeg loudnorm 重量了一遍:
| 檔案 | 量到的響度(LUFS) |
|---|---|
| Lyria 產的四首 BGM 原檔 | -11.37 到 -12.06 |
| 壓到 -31 那版 | -31.44 到 -31.45 |
| 定案 -25 那版 | -25.43 到 -25.45 |
| 優理 77 個語音檔(中位數) | -16.32 |
| 旁白 64 個語音檔(中位數) | -18.55 |
封面那張圖就是這 153 個檔案的量測值。
repo 的 README 混音那一段寫著「原始 -18 太吵」,跟實測對不上。量出來的 BGM 原檔在 -12 附近,-18 是語音的目標值,寫的時候串行了。
還有一組數字可以對照。同一天,《空白也有質地》的 BGM 定在 -26(今天量到 -26.42 到 -27.43),這部定在 -25。同一套方法、同一雙耳朵、同一天,兩部作品沒有收斂到同一個數字。所以「VN 的 BGM 該壓到 -26」這種現成數字搬不動,換一批素材就得重聽一次。
speed 調的是時長預算,會吞字
第二件事是句首被吃掉。
8 月比較三個引擎的時候,F5-TTS 那一欄註記的是「非自回歸,不吞字」。這句要補一個但書。
F5 的 speed 名字叫語速,實際上動的是時長預算:時長大約是參考音長乘上字數比,再除以 speed。預算調緊,模型不會加快嘴巴,它會整段砍掉開頭那一兩個詞,句尾照樣唸完。
優理的參考音本身偏慢。上午配方定成 speed 1.4 整批重合,中午連旁白 56 句跟 12 段場景過場文一起上線,全劇 141 個語音檔。
這種缺字,whisper(語音轉文字的模型)抓不到。拿 voices.json 裡 12 個字以上的 114 句,每一句砍掉開頭兩個字,再跟原文比一次相似度:中位數還有 0.96,最低的一句 0.909,114 句全部高過 0.85 的收件門檻。分數一片綠,句首少了一個詞。
下午配方改成現在這樣:合成用 speed 1.0 把每個字唸齊,之後用 ffmpeg -af atempo=1.4 保音高變速。變速放到合成之後,句首就沒有東西可以被砍了。
慢版跟成品都還在硬碟上,77 句一對一比對,時長比中位數 1.399。語速從每秒 2.93 個字變成 4.11 個字(只數中文與英數字元,不含標點)。
優理的聲音卡(voice/yori/README.md,記這把聲音怎麼做出來的那份文件)上記著:speed 1.4 之下,77 句有 43 句開頭少字;1.2 也吞掉一半;補參考音靜音、句首加停頓,都救不回來。這個配方從 release 13 用到 release 19。
QC 同時補了一條規則進 synth():原文的第一個字要出現在 whisper 轉錄的前三個字裡,不然這一抽直接判失敗,換 seed 重來。
檢查器叫了 51 次,複檢剩 5 次
第三件事是檢查器本身。
當天早上第一批 79 句跑完,批次腳本內建的 QC 在 51 句後面打了未達標。接著複檢腳本 requalify.py 進 repo,同一批檔案、同一個 whisper 模型,跑出來剩 5 句可疑。
差別只在比對之前有沒有做繁簡歸一。whisper 轉中文吐的是簡體,劇本是繁體,逐字比下去幾乎沒有一個字對得上。這件事可以自己量:把 voices.json 裡的句子拿去跟它自己的簡體版比相似度,中位數只有 0.75,129 句裡有 106 句掉到 0.85 門檻以下。早上那 51 個警告,大部分就是這樣來的。
requalify.py 的判準是:先用 OpenCC 把兩邊都轉成簡體,去掉英數與標點再比(Day 0000 這種本來就不該進相似度),門檻放到 0.80,三個字以內的短句直接跳過,交給耳朵。
那 5 句裡最短的一句是「……真的有寫。」,whisper 轉出來是「真的有血」,相似度 0.75。剩下四句裡有三句,是腳本自己多抽幾次就過了,分數從 0.75 上下推到 0.86 以上。
會叫的檢查器跟叫對的檢查器,中間就差一個正規化步驟。假警報一多,它跟沒有檢查器一樣,因為沒有人會去看第五十一則警告。
破音字唸錯,機器給綠燈
唸錯字這件事,檢查器抓得到一部分,抓不到另一部分。
引擎唸錯的時候,能動的只有送進去的那串字,畫面上顯示的一直都是原文。這部作品收工時的替身表有七條:五條寫在 voice/batch_yori.py 的 SUBS 裡,另外兩條是規則轉換,Day 後面的四位數逐字唸、底線換成空格。七條裡有兩條是檢查器先叫出來的(Day 0000 跟 final_new),其餘幾條是聽出來的。
| 畫面上的字 | 送進引擎的字 | 為什麼要換 |
|---|---|---|
| 數便當盒、數對了 | 鼠便當盒、鼠對了 | 當動詞的「數」被唸成第四聲 |
| 同一本 notebook | 句首加一個「……」停頓的「同一本筆記本」 | 光是換成筆記本,「同一本」還是會掉 |
| notebook | 筆記本 | 英文詞擺在主詞位置,前面的中文會連著消失 |
| 著 | 着 | 不換的話「睡不著」會唸成 zhù |
| Day 0000 | Day 零零零零 | 阿拉伯數字唸不穩,改成逐字 |
| final_new | final new | 底線會把英文詞黏成一團 |
表格是六列,替身是七條,因為第一列那兩個詞組在程式裡是分開的兩條。
七條裡有兩條,檢查器永遠找不到。「數」跟「著」都是破音字,whisper 轉出來的字是對的,錯的是聲調,相似度一路綠燈。「像便當店關門前數便當盒」那一句,直到下午才補進替身表、單獨抓回去重合。那時候含旁白的全劇配音已經上線一個多小時,中間發過四個版本。
notebook 那一條拖到最後。有一句台詞以「同一本 notebook」開頭,換成筆記本之後,那三個字照樣消失。最後是在句首再塞一個「……」的停頓才留住(seed 11),那是 release 20。
聲音卡上另外掛了一份「走過的死路」清單,五條。像是 CosyVoice3 的高起伏參考音會咬字崩、instruct 模式會把情緒指示唸進台詞。還有參考音本身不要重生:同一支音色每次腔調不一樣,是抽籤,ref.wav 是抽到中文腔的那一次。死路寫得比配方細,下一部作品要配優理的時候,不用從頭試一遍。
十九句沒有聲音
最後對一下帳,看還有誰沒配到。
一週後把版子從 agent API 讀回來:35 個節點、38 條邊,147 個位置掛著語音,相異檔案 141 個。差的那六個是重複台詞。檔名是內容雜湊,同一句、同一情緒就是同一個檔,兩條分支共用。
沒有聲音的是三個配角:分支松鼠 8 句、紙堆怪獸 6 句、迴紋針守門員 5 句,合計 19 句。另外還有優理自己的一句,那句只有刪節號,合成腳本會跳過只剩標點的行。
要配他們,就得再開三張聲音卡。一張聲音卡要有一支剪好整平的參考音、一段照實際發音寫的參考文字、一份配方、一張替身表。優理那張從凌晨第一支試合腳本開始做,收工是下午 3 點半。那天的範圍就停在優理跟旁白這兩把聲音。
去聽一遍
配音已經掛上去了,直接開來聽:https://larch.ink/play/market/1abe8522-06b6-4527-87ef-ab20eaf9c2af
優理自己的圖文日記站在這裡:https://yazelin.github.io/yori-growth-log/