feat(assets): SA3 音效补齐 radio 11+1 与 dungeon 13源+15pan(token 走 hf-mirror 实测可用)

- 模型 17/17 文件经镜像全量缓存(gated+token,直连本机不通;sfx.md/setup.md/asset-pipeline.md 镜像结论同步更新)
- 修复迁移遗留:stable_audio_3/models/ 源码子包被 .gitignore models/ 规则误伤丢失,从上游恢复并加白名单
- radio:arg_muffled/brake_screech 等叙事件落地(接线原有 L111/L154 零改动)+ phone_ring SYN→SA3 升级;dungeon 13 源 A/B 对齐(RMS 偏差 ≤0.3dB)全量同名替换,SYN 原版备份 tools/asset_fix_backup/sa3_ab_20260902/
- 关键玩法语义达标:echo 距离档 0.83<1.43<2.18<2.98s 严格递增;one-shot 真峰值全 ≤-3dBFS(解码回读法)
- check_all_assets 8 游戏全绿(radio 254/254、dungeon 303/303);playtest radio 221/dungeon 1610 全绿
This commit is contained in:
xsl
2026-09-02 19:35:38 +08:00
parent d870a75a26
commit 24c526af68
181 changed files with 5324 additions and 12 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ flock .gpu.lock .venv-tts/bin/python app/src/escape/gen/gen_voice.py
### 2a. Stable Audio 3 small-sfx(主力,AI 生成)
```bash
source env.d/sfx.sh # HF_TOKEN(gated 模型,直连官方端点,不走 hf-mirror)
source env.d/sfx.sh # HF_TOKEN(gated 模型;本机直连不通,实测 gated+token 走 hf-mirror 可用,2026-09-02)
cd tools/stable-audio-3
uv run stable-audio --model small-sfx \
-p "footsteps on gravel, slow walking" --duration 3 \
+4 -4
View File
@@ -96,16 +96,16 @@
- voice 双性别版(male/ 与 female/ 各 103 条):**HOST 主播** 29 条(male=Uncle_Fu「低沉温和的中年男声,深夜电台主播,沉稳亲切,有磁性」/ female=Serena「温暖清晰的年轻女声,深夜电台主播,沉稳亲切,不甜腻」:开场 `b_open b_rain`、主播句 `z1_* l1_* k1_* w1_* h1_*` 主播行、心结 `d9_face d9_avoid`、结局 `e1–e4_a/b`)+ **PROD 导播/系统/向导** 74 条(male=Dylan / female=Vivian,instruct「贴近耳机的低语男/女声,年轻电台导播,冷静克制」:`gd_* sys_* prog_c1–5 rep_*`、导播行、抉择提示 `p1–p9`、尾声 `ep_*`)。同性别双 speaker 逐句覆盖见 `tools/gen_voice_dual.py` 的 `VOICE_SPK["radio"]`(同场景高频对话的两者永不同 speaker)。
- voice NPC 平铺(29 条,落 `voice/` 根,引擎平铺回退;**转码带通**见下):老周 7 条(z1_*,Uncle_Fu·苍老沙哑)、小鹿 4 条(l1_*,Serena·哭腔倔强)、糖糖 6 条(k1_*,Vivian·稚嫩童声)、陈姐 7 条(w1_*,Vivian·疲惫沙哑中年)、老韩 5 条(h1_*,Eric·沙哑粗犷司机)。
- **通话滤波(资产侧,15-radio.md §6.2)**:convert 转码时按来电者逐档 ffmpeg 带通+轻压缩(老周 500-2800 / 小鹿 400-3400 / 糖糖 450-3000 / 陈姐 420-3100 / 老韩 300-3400 Hz,均 `acompressor threshold=-20dB ratio=3`);参数在 `tools/gen_voice_dual.py` 的 `NPC_BANDPASS`,未滤波原声保留在 staging `tools/gen_voice_dual_wav/radio/npc/` 可重滤/回退。HOST/PROD 不滤波。**待人工试听**:滤波句可读性抽检,不可读句按「宁窄勿脏」回退未滤波原声(staging 重转即可)。
- sfx(2,SYN 程序合成):`ui_confirm ui_menu`(`web/radio/gen/gen_sfx.py`,全局 storyline 先例同款双音/软音)。**缺失 13 件 SA3**(HF token 未配置,本轮跳过):`onair_sting phone_ring line_connect line_drop amb_studio amb_rain_city amb_station amb_kid_room arg_muffled amb_street_rain amb_cab brake_screech tape_static`。
- sfx(15):`ui_confirm ui_menu`(SYN 程序合成兜底)+ **SA3 12 件**(`web/radio/gen/gen_sfx_sa3.py`,2026-09-02 补产,token 走 hf-mirror):`onair_sting line_connect line_drop arg_muffled brake_screech tape_static amb_rain_city amb_station amb_kid_room amb_street_rain amb_cab amb_studio` + `phone_ring`(**SYN→SA3 真铃声替换**,循环周期 5.2s 烘进文件、游戏侧 loop 接口零改动;原 SYN 备份 `tools/asset_fix_backup/sa3_ab_20260902/`)。`amb_studio` 文档 §5.2 有、game.js 未接线(直播间底噪由 bgm/onair 承担),产出备用。
- bgm(4,Mureka $0.12):`onair bridge ending`(-20 LUFS)+ `menu`(menu pad,-24 LUFS,10 文档 §1.2);90.00s 无缝循环;后处理脚本 `web/radio/gen/gen_bgm.sh`。
- 合计 241 ogg + 241 m4a(每游戏音频 = 235 voice + 2 sfx + 4 bgm);台词/生成/终检走 `tools/gen_voice_dual.py --game radio` 与 `tools/check_all_assets.py`。
- 合计 254 ogg + 254 m4a(每游戏音频 = 235 voice + 15 sfx + 4 bgm);台词/生成/终检走 `tools/gen_voice_dual.py --game radio` 与 `tools/check_all_assets.py`。
### dungeon《回声地窟》(批次 1 新游戏,Roguelike 模式,台词依据 `docs/design/16-dungeon-voice-ids.md`)
- voice 双性别版(male/ 与 female/ 各 125 条,无 NPC——怪物不说话):male=Uncle_Fu「低沉醇厚的男声,像探窟向导,沉稳有力」/ female=Serena「平静清晰的女声,像探窟向导,沉稳可信」,两常量全表统一。分组:序章/标题 4、教学 DRILL 19、系统/菜单/状态 35、探索事件 9、战斗 30、卡关/看门狗/纠错 14、结算/元进度 14。
- sfx(19 文件,全 SYN 程序合成,`web/dungeon/gen/gen_sfx.py`):`pulse`(声波脉冲)、材质尾音 `mat_stone/door/stair/water`、**预 pan 立体声** `side_wall_l/r side_open_l/r`(mono 源 + ffmpeg pan 派生,能量只在单声道,极性脚本断言)、移动 `step_own step_turn bump`、拾取 `coin potion gear`、战斗 `atk_swing parry hurt`、`levelup`(D 小调五声上行钟声琶音)。**缺失 24 文件 SA3**(HF token 未配置,本轮跳过):`echo_1–4 stairs_down mob_step_{small,bug,heavy}_l/c/r tel_{small,bug,heavy}(_l/r 派生) atk_hit enemy_die`(SA3 单声道源 + pan 派生工艺见 16-dungeon.md §9.2)。
- sfx(49 文件):批次 1 SYN 21 文件(`web/dungeon/gen/gen_sfx.py`:`pulse`、材质尾音 `mat_stone/door/stair/water`、**预 pan 立体声** `side_wall_l/r side_open_l/r`(mono 源 + ffmpeg pan 派生,能量只在单声道,极性脚本断言)、移动 `step_own step_turn bump`、拾取 `coin potion gear`、战斗 `atk_swing parry hurt`、`levelup`(D 小调五声上行钟声琶音)+ R2 新增 `amb_cave turn_tick`);批次 2 SYN 兜底 28 文件(`gen_sfx2.py`:`echo_1–4 stairs_down atk_hit enemy_die mob_step_{small,bug,heavy}(_l/_c/_r) tel_{small,bug,heavy}(_l/_r)`)已于 **2026-09-02 全部由 SA3 版同名替换**(`web/dungeon/gen/gen_sfx_sa3.py`,A-B 响度/时长对齐后晋级,echo 距离档 0.83<1.43<2.18<2.98s 递增保持;SYN 原版备份 `tools/asset_fix_backup/sa3_ab_20260902/dungeon/`)。
- bgm(4,Mureka $0.12):`menu explore battle boss`(全部 -20 LUFS,16-dungeon.md §9.1);90.00s 无缝循环;battle/boss 的 bpm 仅为 prompt 特征词、无节拍网格玩法,未跑 bpm_precise;后处理脚本 `web/dungeon/gen/gen_bgm.sh`。
- 合计 273 ogg + 273 m4a(250 voice + 19 sfx + 4 bgm);台词/生成/终检走 `tools/gen_voice_dual.py --game dungeon` 与 `tools/check_all_assets.py`。
- 合计 303 ogg + 303 m4a(250 voice + 49 sfx + 4 bgm;批次 1 表述 273 未计 R2 amb_cave/turn_tick 与批次 2 的 28 文件,本行已按实盘点修正);台词/生成/终检走 `tools/gen_voice_dual.py --game dungeon` 与 `tools/check_all_assets.py`。
### 批次 1 资产账(2026-09-01)
+7
View File
@@ -442,6 +442,11 @@ ENDING: e*_a → e*_b(按 rep×knot 四选一)→ ep_lead → ep_<caller>×5
### 资产生产缺口(列遗留,本轮不修)
> **→ 已闭环(2026-09-02 晚)**:12 件 SA3 条目全部补产(onair_sting / phone_ring / line_connect /
> line_drop / amb_rain_city / amb_station / amb_kid_room / arg_muffled / amb_street_rain / amb_cab /
> brake_screech / tape_static;amb_studio 文档有、未接线,产出备用),`check_all_assets` radio 254+254
> 全过、playtest 221 断言全绿。详见 `research/new8/batch1-assets-report.md` §8。
- §5.2 SFX 15 件中 **12 件 Stable Audio 3 条目未产出**(`gen/gen_sfx.py` 头注:HF token 未配置跳过):
onair_sting / phone_ring / line_connect / line_drop / amb_rain_city / amb_station / amb_kid_room /
arg_muffled / amb_street_rain / amb_cab / brake_screech / tape_static。缺失走引擎 console.error
@@ -466,6 +471,8 @@ ENDING: e*_a → e*_b(按 rep×knot 四选一)→ ep_lead → ep_<caller>×5
| V2 | 复核结论:菜单逻辑无缺失(三项循环 + 回绕正确),按裁定补全项循环断言关案。注:菜单为 3 项(sys_menu + sys_menu_resume/restart/lobby,15-radio.md §实现核对「菜单单击循环顺序」口径)——任务书所写「4 项/sys_menu_save」对应菜单标题句 + 3 菜单项;「保存并回大厅」确认句即 `sys_menu_lobby`(无 sys_menu_save 资产) | ✅ 单击循环两个整周期逐项可达(resume→restart→lobby→resume→restart→lobby,第三项不再缺席)、6 次回绕模 3 无漂移;✅ 双击确认「保存并回大厅」→ sys_menu_lobby 播出 + leaving 置位 + 存档落盘 |
V3(arg_muffled/brake_screech 等 11 件 SA3 资产)维持「等待 HF token」,接线代码已备,不在本轮。
**→ 已闭环(2026-09-02 晚)**:SA3 12 件补产落地(含 phone_ring 真铃声替换),接线复核零代码改动,
详见 `research/new8/batch1-assets-report.md` §8。
### 遗留(R2 收尾时需协同)
+9 -6
View File
@@ -174,13 +174,16 @@ uv sync --extra ui # Python 3.10 venv,PyPI 走阿里云镜像(sfx.sh
### 坑:hf-mirror 对 gated 模型的 308 重定向
**gated 模型不能走 hf-mirror**:镜像会把带 token 的请求 308 重定向回
huggingface.co,本机直连官方又不可达时会直接失败。因此 `env.d/sfx.sh` 里
**故意不设 `HF_ENDPOINT`**(直连官方端点,当前实测 huggingface.co 对该域名
可达)。如果以后直连失效且只下公开模型,可临时取消脚本里的镜像注释。
**更新(2026-09-02)**:实测 gated+token **走 hf-mirror 可用**——
`stabilityai/stable-audio-3-small-sfx` 17 文件全量经镜像下载成功(`HF_ENDPOINT=https://hf-mirror.com`
+ read token,即 `env.d/sfx.sh` 现行配置)。下文「308 重定向必须直连」的旧结论在本机不再成立;
直连官方端点在本机不可达。模型已入缓存后可加 `HF_HUB_OFFLINE=1` 完全离线跑 CLI。
Qwen3-TTS(公开)走镜像、Stable Audio 3(gated)走直连——这就是
`tts.sh` 与 `sfx.sh` 的 `HF_ENDPOINT` 配置相反的原因。两个环境不要同时 source。
<details><summary>旧记录(2026-08-29,已被上条实测推翻)</summary>
镜像曾把带 token 的请求 308 重定向回 huggingface.co,本机直连官方又不可达时会直接失败,
因此当时 `env.d/sfx.sh` 故意不设 `HF_ENDPOINT`。Qwen3-TTS(公开)与 Stable Audio 3 现均走镜像。
</details>
## 8. Mureka BGM API(可选,需付费 key)