Files
SoundGame/research/new8/batch1-assets-report.md
T
xsl 24c526af68 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 全绿
2026-09-02 19:35:38 +08:00

166 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 批次 1 资产报告:radio《不眠频率》+ dungeon《回声地窟》
> 音频资产管线 agent 产出 · 2026-09-02 · 覆盖任务书 A(语音)/ B(BGM)/ C(音效)/ D(收尾)。
> 总耗时 ≈ **35 分钟**(00:47–01:21,含 2 轮 GPU TTS 串行、8 个 Mureka 任务、全部 QC 与文档)。
## 1. 语音(TTS,GPU flock 串行)
| 项 | radio | dungeon |
|---|---|---|
| 台词句数 | 132(双性别 103 + NPC 平铺 29) | 125(×2 性别,无 NPC) |
| 生成文件 | 103×2 + 29 = 235 条 ×2 格式 = 470 文件 | 250 条 ×2 格式 = 500 文件 |
| speaker | HOST=Uncle_Fu/Serena,PROD=Dylan/Vivian(VOICE_SPK 逐句覆盖,同性别双音色) | 全表 Uncle_Fu/Serena,单一 instruct 常量 |
| `--check` | ALL OK(无时长离群/短句) | ALL OK |
- 台词表进入 `tools/gen_voice_dual.py`(新增 radio/dungeon),**由一次性提取脚本直接解析两份 voice-ids 设计文档生成**,并做了二次闭环校验(重解析文档 vs 脚本内表格逐字 diff)——台词全文与文档一字不差。
- NPC 平铺按 rpg 先例写入 `NPCS["radio"]`(id, speaker, instruct, 台词),staging 走 `<game>/npc/`,convert 落 `web/radio/audio/voice/<id>.*`。
- `extract_voice_text.py` 已刷新 `web/harness/voice_text.json`:games=8,radio 132 条、dungeon 125 条。
- **文档内矛盾检查**:无重复 id、无超 40 字(汉字口径,与文档自查注记一致;p7/p9 含标点 41/43 字,走章程 §3.4 自动拆句机制,0.12s 句间停顿)。发现一处**文档头部账目笔误**(不影响管线,未改文档):15-radio-voice-ids.md 头注「HOST 21 + PROD 82」与逐行表不符,逐行表实数 HOST 29 + PROD 74(总数 103 一致)。
- **radio 电话音质感(资产侧带通,15-radio.md §6.2)**:convert 转码时按来电者逐档 `highpass+lowpass+轻压缩`(老周 500-2800 / 小鹿 400-3400 / 糖糖 450-3000 / 陈姐 420-3100 / 老韩 300-3400 Hz,均 acompressor threshold=-20dB ratio=3 attack=10 release=150);已验证滤波生效(NPC 高频带能量 ≈ 未滤波 HOST 的 1/4,时长与 staging 完全一致);ogg+m4a 双格式均从同一滤波链转出。未滤波原声保留在 `tools/gen_voice_dual_wav/radio/npc/`(不入库)。
## 2. BGM(Mureka API)
8 首全部一次成功,无重试;**总花费 $0.24(预算 $0.30 内,台账见 `tools/mureka_log.md` 2026-09-01 节,项目累计 $0.87/$2.00)**。
| 曲目 | task id | 选用 choice | 候选时长 | 响度目标 |
|---|---|---|---|---|
| radio onair | 158551062544386 | 158551165370369 | 135.5/201.2s | -20 LUFS |
| radio bridge | 158551207313409 | 158551341465604 | 211.2/225.1s | -20 LUFS |
| radio menu | 158551383277574 | 158551500914690 | 188.6/222.0s | **-24 LUFS**(menu pad,10 文档 §1.2) |
| radio ending | 158551538401281 | 158551630872578 | 202.0/189.2s | -20 LUFS |
| dungeon menu | 158551678976001 | 158551817322499 | 162.8/177.8s | -20 LUFS(16-dungeon.md §9.1) |
| dungeon explore | 158551855333377 | 158551978868739 | 177.0/209.8s | -20 LUFS |
| dungeon battle | 158552010457089 | 158552169709569 | 186.4/225.9s | -20 LUFS |
| dungeon boss | 158552209555457 | 158552331321345 | 149.5/202.3s | -20 LUFS |
- 选用原则:拿不准选时长更接近 90s 的候选(仅 radio ending 选候选 1)。
- 后处理(脚本入库 `web/{radio,dungeon}/gen/gen_bgm.sh`,可复现):首个强 onset(silenceremove -35dB)→ 93s 裁剪 → 首尾 3s acrossfade(tri) 无缝循环 → loudnorm(TP=-2/LRA=11)→ 44.1kHz → ogg q3 + m4a 128k。**成品全部 90.00s**,mean -20.4~-24.7dB,循环接缝差值与在库 BGM 同量级。
- 无节奏关键曲目,未跑 bpm_precise(dungeon battle/boss 的 bpm 仅为 prompt 特征词)。
## 3. 音效(SYN 程序合成;SA3 全部跳过)
- `web/radio/gen/gen_sfx.py`:`ui_confirm ui_menu`(storyline 全局先例同款),2 文件 ×2 格式。
- `web/dungeon/gen/gen_sfx.py`:19 文件 ×2 格式 = 17 id(`pulse`、材质尾音 4、**预 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`)。
- **QC(解码回读法,全部通过)**:逐声道真峰值 ≤ -3dBFS(修复:硬 pan 立体声不能按声道均值测,否则漏检超限;AAC/MDCT 过冲按实测迭代补 volume);|直流| ≤ 0.001(与在库 91 件 sfx 基线一致;修复:源去直流 + 8ms cos² 淡入淡出 + 前后垫 60/120ms 静音 + highpass=f=30 抑制编解码直流再生);无首尾爆豆。最终 42 文件全绿。
- 可复现:两个 gen 脚本入库,一键重出全部 ogg+m4a;staging(`web/<game>/gen/staging/`、`tools/bgm_post_wav/`)已加入 .gitignore 不入库。
## 4. 缺失资产清单(SA3 待 HF token,本轮全部跳过、未尝试生成)
> **已于 2026-09-02 晚全部补产闭环,见本文档 §8**(amb_studio 产出备用未接线;dungeon 28 文件
> 为 A/B 替换而非纯缺失——批次 2 曾以 SYN 兜底,见 `web/dungeon/gen/gen_sfx2.py`)。
**radio(13 件)**:`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`(15-radio.md §5.2;prompt 草稿在表内,token 就绪后按 gen_rpg_sfx.sh 工艺补产)。
**dungeon(24 文件 = 13 个 SA3 源 + 11 个 pan 派生)**:`echo_1 echo_2 echo_3 echo_4 stairs_down atk_hit enemy_die mob_step_small mob_step_bug mob_step_heavy`(+各 l/c/r 三份派生)`tel_small tel_bug tel_heavy`(+各 l/r 派生)(16-dungeon.md §9.2;mono 源 → `stereotools`/`pan` 派生工艺同表注)。
**SA3 缺失影响评估**:radio 的 amb/线索音缺失时游戏层按「资产缺失回退路径」静默降级(设计 §9 断言已有屏蔽资产的兜底断言);dungeon 回声/脚步是核心动词,**开发联调前建议先补产 dungeon 的 SA3 条目**(或临时用 SYN 兜底:side_* 已有 SYN 版,echo/mat 可参考 §9.2 降级条款程序合成)。
## 5. check_all_assets 结果(radio/dungeon 已入 GAMES 列表)
```
| 游戏 | ogg | m4a | 0字节 | 解码失败 | voice male/female id 一致 |
| radio | 241 | 241 | 0 | 0 | ✅ 各 103(平铺 29 个角色/NPC 句,豁免) |
| dungeon | 273 | 273 | 0 | 0 | ✅ 各 125 |
结论:全部通过(8 游戏全绿,exit=0)
```
radio ogg 构成 = 103+103 双性别 + 29 平铺 NPC + 2 sfx + 4 bgm;dungeon = 125+125 + 19 sfx + 4 bgm。
## 6. 遗留问题 / 待办
1. ~~**SA3 token**:环境未配置(env.d/sfx.sh 无有效 HF token),radio 13 + dungeon 24 件 sfx 待补产(清单见 §4,prompt 均已在设计文档定稿)。~~ **已闭环(2026-09-02 §8)**。
2. **人工试听两处**:① radio NPC 带通句可读性抽检(不可读回退未滤波原声,staging 重转即可,管线已支持);② 多音字风险句(15-radio-voice-ids.md 文末注记:h1_dango「嘶」、k1_lullo、d9_face 等;16b:btl_bat「蝠」、unlock_potion「行囊」)。
3. **文档笔误待策划改**:15-radio-voice-ids.md 头注「HOST 21 + PROD 82」应为「HOST 29 + PROD 74」(总数 103 不变,不影响任何资产)。
4. radio 无「大姐/姑娘」自称合规、gd_* 两级不同句等台词侧设计约束均已在表内落实,开发接线时按 §7.2 看门狗表取用即可。
5. 红线遵守:GPU 全程 flock 串行(radio → dungeon 两轮,无并行);Mureka $0.24 ≤ $0.30 且每笔记账;未改 web/engine/、未写任何 game.js/index.html/test;key 未入任何入库文件(mureka.sh 本就被 gitignore)。
## 7. 产出物索引
| 类型 | 路径 |
|---|---|
| 台词表(入库) | `tools/gen_voice_dual.py`(radio/dungeon 表 + SPEAKERS + VOICE_SPK + NPC_BANDPASS) |
| voice 成品 | `web/{radio,dungeon}/audio/voice/{male,female}/`(+ radio 平铺 `voice/<id>.*`) |
| bgm 成品 + 脚本 | `web/{radio,dungeon}/audio/bgm/`;`web/{radio,dungeon}/gen/gen_bgm.sh` |
| sfx 成品 + 脚本 | `web/{radio,dungeon}/audio/sfx/`;`web/{radio,dungeon}/gen/gen_sfx.py` |
| 期望文本映射 | `web/harness/voice_text.json`(games=8) |
| 台账/总账 | `tools/mureka_log.md`(2026-09-01 节);`docs/audio/asset-manifest.md`(radio/dungeon 章节) |
| staging(不入库) | `tools/gen_voice_dual_wav/{radio,dungeon}/`、`web/<game>/gen/staging/`、`tools/bgm_post_wav/`、`tools/mureka_out/` |
## 8. SA3 补产(2026-09-02 晚,HF token 就绪后;§4 缺失清单闭环)
> 总耗时 ≈ **40 分钟**(18:57–19:38,3 轮 GPU flock 串行生成 + 全部 QC/A-B/文档)。
> 模型 `stabilityai/stable-audio-3-small-sfx` 17 文件经 hf-mirror(gated+token)全量下载成功,
> 落 `models/hf/hub/models--stabilityai--stable-audio-3-small-sfx/`。生成参数:`--steps 8 --seed 20260902`,
> 3 轮 CLI 批量(radio 12 + dungeon 13 + amb_studio 1),原始 wav 在 `web/<game>/gen/staging/sfx_sa3/`(不入库)。
**环境修复(重要,机器迁移遗留)**:`tools/stable-audio-3/.gitignore` 的 `models/` 规则误伤了
源码子包 `stable_audio_3/models/`(factory.py 的依赖,初迁时未入库而丢失,import 直接报
ModuleNotFoundError)。已从上游 GitHub(经 ghfast.top 代理,本机直连 GitHub 不通)恢复该子包,
并在 .gitignore 追加 `!stable_audio_3/models/` 防复发。CLI 需 `source env.d/sfx.sh`
(HF_TOKEN/HF_ENDPOINT),模型已在缓存时加 `HF_HUB_OFFLINE=1` 免网络。
**工艺(入库脚本 `web/{radio,dungeon}/gen/gen_sfx_sa3.py`,含 `--emit` 打印生成命令)**:
SA3 输出为定长 latent 床(radio raw 16.16s / dungeon raw 10.59s,与请求时长无关),按实测事件
窗截取(arg_muffled 摔门峰 @5.00s、brake_screech 最强吱咬 @3.91s、tape_static 停带 @3.72s,
窗切点 50ms 缓出);one-shot 去直流 + 8ms cos² 淡化 + 峰值定档;amb 床只去直流不淡化
(游戏层 0.4s 重触发重叠掩接缝),RMS −26dBFS 定档 + 峰值帽 −8(escape amb 床先例);
dungeon 候选按在役 SYN 版解码 RMS 同口径对齐(保混音参数,峰值帽 −4 不变;垫后计算避免稀释偏差;
派生 l/r/c 从对齐后基准复制,与 SYN 派生逐声道振幅一致)。编码 ogg q4 + m4a 128k
(hp30 + 垫 60/120ms),解码回读 QC 全过:逐声道真峰值 ≤ −3dBFS、|直流| ≤ 0.001、
超限降增益 + 首轮重编 18kHz 低通(本轮无一触发补偿);phone_ring 另验循环边界 ≤ −60dBFS。
### 8a. radio(13 件 = 缺失 11 + phone_ring 替换 + amb_studio 备用;11+替换件已接线)
| id | 时长s | ogg峰dBFS | m4a峰dBFS | RMS | 结论 |
|---|---|---|---|---|---|
| onair_sting | 2.14 | −4.10 | −4.14 | −19.0 | 补产落地(台标 sting,k1 前 INTRO 已接线) |
| phone_ring | 5.20 | −4.00 | −3.76 | −30.5 | **替换 SYN**(A/B:真电话铃双击响明显更优;循环周期 5.2s 烘进文件、边界静音 ≤−60dBFS,游戏侧 `_ringSrc` loop 接口零改动,原 SYN 备份在 `tools/asset_fix_backup/sa3_ab_20260902/radio/`) |
| line_connect | 0.78 | −7.30 | −7.11 | −33.6 | 补产落地(接听咔哒,subtle 档 −7) |
| line_drop | 2.23 | −7.27 | −7.51 | −31.1 | 补产落地(挂断+忙音) |
| amb_rain_city | 16.16 | −8.77 | −8.58 | −26.2 | 补产落地(C1 老周侧 amb 床) |
| amb_station | 16.16 | −7.66 | −7.73 | −34.3 | 补产落地(C2 小鹿侧;峰值帽导致偏静,深夜车站符合设计) |
| amb_kid_room | 16.16 | −10.52 | −10.70 | −37.2 | 补产落地(C3 糖糖侧;刻意安静,反衬 arg_muffled 线索) |
| arg_muffled | 4.58 | −8.44 | −8.74 | −33.9 | 补产落地(**C3 埋线索**:k1_b 已接线 ×2 播,事件窗含摔门 @raw 5.0s) |
| amb_street_rain | 16.16 | −8.14 | −7.76 | −27.2 | 补产落地(C4 陈姐侧) |
| amb_cab | 16.16 | −11.31 | −11.20 | −26.4 | 补产落地(C5 老韩侧,引擎+雨刷) |
| brake_screech | 2.38 | −4.75 | −5.01 | −22.9 | 补产落地(**C5 危机拍**:h1_danger 已接线 preMs=2000 前置,最强吱咬事件窗 2.2s) |
| tape_static | 3.53 | −5.70 | −5.40 | −33.4 | 补产落地(p9 直面留言机电流) |
| amb_studio | 10.00 | −14.56 | −14.59 | −27.1 | 备用(文档 §5.2 有、game.js 未接线——直播间底噪由 bgm/onair 承担;不改代码) |
### 8b. dungeon(28 文件 = 13 SA3 源 + 15 pan 派生,全部同名替换在役 SYN 兜底)
| 源 id | SA3 时长s (SYN) | ogg峰 (SYN峰) | SA3 RMS (SYN RMS) | 结论 |
|---|---|---|---|---|
| echo_1 | 0.83 (0.58) | −11.1 (−5.5) | −28.4 (−28.3) | 替换;**距离档递增校验通过** 0.83<1.43<2.18<2.98 |
| echo_2 | 1.43 (1.08) | −4.3 (−4.4) | −29.7 (−27.3) | 替换(峰值型瞬态,RMS 对齐受峰值帽 −1~2dB 内) |
| echo_3 | 2.18 (1.68) | −14.0 (−4.2) | −28.5 (−28.4) | 替换 |
| echo_4 | 2.98 (2.38) | −14.1 (−4.2) | −26.9 (−26.2) | 替换 |
| stairs_down | 3.72 (1.88) | −4.0 (−4.6) | −25.1 (−24.1) | 替换(真实下行金属梯+窟内混响) |
| atk_hit | 0.87 (0.48) | −4.5 (−4.6) | −25.8 (−21.4) | 替换(甲壳钝响峰值对齐,RMS −4.4dB 为峰值帽所致) |
| enemy_die | 1.88 (1.08) | −3.6 (−4.0) | −21.5 (−19.8) | 替换 |
| mob_step_small | 0.63 (0.42) | −7.2 (−4.4) | −27.1 (−27.0) | 替换(+_l/_c/_r 派生 3 文件) |
| mob_step_bug | 0.73 (0.48) | −4.3 (−3.7) | −22.6 (−20.7) | 替换(+派生 3;虫肢咔嗒质感) |
| mob_step_heavy | 0.83 (0.58) | −4.4 (−4.3) | −22.6 (−20.8) | 替换(+派生 3) |
| tel_small | 1.18 (0.78) | −3.5 (−3.6) | −19.5 (−17.6) | 替换(+_l/_r 派生 2) |
| tel_bug | 1.28 (0.78) | −5.3 (−4.7) | −23.1 (−23.0) | 替换(+派生 2) |
| tel_heavy | 1.48 (1.08) | −3.5 (−4.3) | −17.4 (−12.9) | 替换(+派生 2;SYN 低吼 RMS −12.9 受峰值帽只对齐到 −17.4,峰值 −3.5 保留冲击力) |
**A/B 结论(默认「质量明显更好才替换」)**:13 源全部替换。依据:① 真实声源质感(石壁反射/
虫甲/金属梯)对合成正弦+噪声团,听感代差明确,且 16-dungeon.md §9.2 本就以 SA3 为正选、SYN 仅为
无 token 兜底(gen_sfx2.py 头注「日后补产 SA3 版,直接覆盖同名文件」);② 语义可测项全部达标——
echo 距离档时长/暗度严格递增(回声尾长=墙距是核心玩法信息)、脚步/前摇/命中时长落在玩法窗口
(mob_step ≤0.83s、tel 1.18-1.48s、atk_hit 0.87s)、响度按在役 SYN 解码 RMS 对齐(混音零改动)。
SYN 版全部备份于 `tools/asset_fix_backup/sa3_ab_20260902/dungeon/`,可一键回退。
### 8c. 终检与回归
- `tools/check_all_assets.py`:8 游戏全绿——radio **254/254**(235 voice + 15 sfx + 4 bgm)、
dungeon **303/303**(250 voice + 49 sfx + 4 bgm),0 字节/解码失败/配对缺失均为 0。
- `web/radio/test/playtest.mjs`:**221 断言全绿**(未改任何代码;静态审计「sfx 缺失」变 0——
STABLE_AUDIO_PENDING 清单闭环;arg_muffled ×2 / brake_screech 前置 2s 触发断言原本就有)。
- `web/dungeon/test/playtest.mjs`:**1610 断言全绿**(同名替换游戏层零改动)。
- 接线复核:arg_muffled=game.js L111(k1_b `sfx` + `sfxEcho` atMs 6500)、brake_screech=L154
(h1_danger `danger:true, preMs:2000, sfx`),R1 报告属实,本轮零代码改动。
- key/token 未入任何入库文件;GPU 全程 flock 串行(3 轮);未动 web/engine/、web/harness/live/**、
8123/8124/8001 服务。