更新林夏设计纲要、执行文档与技术报告,对齐 VoxCPM2 8002 端口、v4/v5 流水线、游戏 184 个 MP3 引用及 13 角色参考音色。 Co-authored-by: Cursor <cursoragent@cursor.com>
236 lines
8.2 KiB
Markdown
236 lines
8.2 KiB
Markdown
# 《林夏》音频制作 — 当前状态说明
|
||
|
||
> 更新日期:2026-05-23
|
||
> 本文档记录 TTS 音色选型、全量生成、游戏部署的**现行状态**,便于下次继续迭代。
|
||
|
||
---
|
||
|
||
## 1. 一句话总结
|
||
|
||
**游戏当前使用的是 v5 克隆音色**:从 Voice Design 试听样本中选定参考音频 → VoxCPM2 Style Control 克隆 → 部署到 `audio/mp3/tts/*_wav_v1.mp3`。
|
||
`audio/mp3/` 已清理,仅保留游戏引用的 **184** 个文件。
|
||
|
||
---
|
||
|
||
## 2. 游戏实际加载哪些音频
|
||
|
||
游戏代码在 `game/js/story.js`、`game/js/engine.js`,根路径:
|
||
|
||
```
|
||
../audio/mp3/
|
||
├── tts/ 对白(169 条,游戏引用)
|
||
├── music/ BGM、铃声
|
||
├── sfx/ 音效
|
||
└── ambience/ 环境音
|
||
```
|
||
|
||
### 命名规则(重要)
|
||
|
||
| 文件名 | 游戏是否使用 |
|
||
|--------|-------------|
|
||
| `*_wav_v1.mp3` | **是** — 全部对白、系统语音都用这种 |
|
||
| `*_mp3_v1.mp3` | **否** — 旧流水线遗留,已全部删除 |
|
||
|
||
后缀里的 `wav` 表示「用 WAV 参考音色生成的 v1 版」,文件格式仍是 MP3。
|
||
|
||
### 示例
|
||
|
||
```
|
||
game/js/story.js → npc('lv11_0015_mom_call_01_wav_v1.mp3')
|
||
实际文件 → audio/mp3/tts/lv11_0015_mom_call_01_wav_v1.mp3
|
||
```
|
||
|
||
**不需要改 `story.js`**,只要更新 `audio/mp3/tts/` 里对应的 `*_wav_v1.mp3` 即可。
|
||
|
||
---
|
||
|
||
## 3. TTS 服务
|
||
|
||
| 项目 | 路径 / 值 |
|
||
|------|-----------|
|
||
| 服务目录 | `/home/xsl/tts-server/` |
|
||
| 启动脚本 | `VOXCPM_PORT=8002 VOXCPM_ENABLE_DENOISER=0 bash /home/xsl/tts-server/start-voxcpm.sh` |
|
||
| 端口 | **8002**(8000 被 head3d 占用) |
|
||
| 健康检查 | `curl http://127.0.0.1:8002/health` |
|
||
| 主要接口 | `POST /v1/voices` 注册参考音频 |
|
||
| | `POST /v1/speech/styled` 合成(`voice_id` + `style` = 克隆;无 `voice_id` = Voice Design) |
|
||
|
||
---
|
||
|
||
## 4. 音色演进(v1 → v5)
|
||
|
||
| 版本 | 目录 | 方式 | 状态 |
|
||
|------|------|------|------|
|
||
| v1 | `audio_1/tts/v1_voxcpm2/` | 旧参考音频直接克隆,无 style | 已被 v5 替代 |
|
||
| v2 | `audio_2/tts/v2_styled/`(已不在磁盘) | 旧参考 + Style Control 表演 | 已废弃 |
|
||
| v3 | `audio_2/tts/v3_voice_design/`(已不在磁盘) | 纯 Voice Design,无参考 | 已废弃 |
|
||
| v4 | `audio_2/tts/v4_voice_samples/` | 每角色 5 条试听,用户挑选 | **保留选定样本** |
|
||
| **v5** | `audio_2/tts/v5_cloned/` | 选定样本克隆 + 表演修饰 | **当前正式版** |
|
||
| 游戏 | `audio/mp3/tts/*_wav_v1.mp3` | v5 自动部署副本 | **游戏正在使用** |
|
||
|
||
---
|
||
|
||
## 5. 各角色选定的参考音色(v4 试听挑选)
|
||
|
||
参考文件位于 `audio_2/tts/v4_voice_samples/{角色}/`,每角色仅保留 1 条 `.wav`:
|
||
|
||
| 角色 | 选定文件 | 性别 |
|
||
|------|----------|------|
|
||
| linxia | `linxia_v05.wav` | 女 |
|
||
| mom | `mom_v01.wav` | 女 |
|
||
| azhe | `azhe_v03.wav` | 男 |
|
||
| xiaomei | `xiaomei_v05.wav` | 女 |
|
||
| xiaomei_drunk | `xiaomei_drunk_v05.wav` | 女 |
|
||
| zhounan | `zhounan_v05.wav` | 男 |
|
||
| hr | `hr_v05.wav` | 女 |
|
||
| anan | `anan_v04.wav` | 女 |
|
||
| dorm_a | `dorm_a_v03.wav` | 女 |
|
||
| dorm_b | `dorm_b_v02.wav` | 女 |
|
||
| dorm_c | `dorm_c_v03.wav` | 女 |
|
||
| delivery | `delivery_v04.wav` | **男** |
|
||
| self_3y | `self_3y_v03.wav` | 女 |
|
||
|
||
副本已同步到 `voice/{角色}/{角色}_ref.wav`(`xiaomei_drunk` → `voice/xiaomei/xiaomei_drunk_ref.wav`,`self_3y` → `voice/linxia/self_3y_ref.wav`)。
|
||
|
||
---
|
||
|
||
## 6. v5 全量生成结果
|
||
|
||
- **177 条** MP3:`audio_2/tts/v5_cloned/*_wav_v5.mp3`
|
||
- **177 条**已部署:`audio/mp3/tts/*_wav_v1.mp3`
|
||
- 生成清单:`audio_2/tts/v5_cloned/clone_manifest.tsv`
|
||
|
||
来源台词表:`audio/batch_tts_voxcpm.py` 中 `LINES`(173 条)+ 脚本内 `EXTRA_LINES`(4 条):
|
||
|
||
| 额外文件 | 角色 | 说明 |
|
||
|----------|------|------|
|
||
| `lv11_0030_self3y_voice_01/02/03` | self_3y | 三年前录音三版 |
|
||
| `lv11_sys_memo_01` | linxia | 系统提示「三年前今天…」 |
|
||
|
||
克隆时**只用表演修饰**(warm/cold/分段等),音色完全由参考 wav 决定。配置见 `audio_2/voice_style_prompts.py` 中 `get_clone_style()`。
|
||
|
||
---
|
||
|
||
## 7. 目录结构速查
|
||
|
||
```
|
||
blind/
|
||
├── game/js/story.js 游戏剧情 + 音频引用
|
||
├── game/js/engine.js 系统语音、结局、BGM
|
||
├── audio/
|
||
│ ├── batch_tts_voxcpm.py 台词表 LINES + 角色语速 ROLES
|
||
│ └── mp3/ 游戏运行时音频(184 文件,已清理)
|
||
│ ├── tts/ 169 条对白(游戏引用)
|
||
│ ├── music/
|
||
│ ├── sfx/
|
||
│ └── ambience/
|
||
├── voice/ 各角色参考音频(含 v5 选定副本)
|
||
└── audio_2/
|
||
├── 项目状态说明.md ← 本文档
|
||
├── 角色语音风格提示词.md Voice Design 说明(历史参考)
|
||
├── voice_style_prompts.py 表演修饰 + Voice Design 提示词
|
||
├── voice_sample_prompts.py v4 试听:5 变体/角色 + 统一试听文本
|
||
├── scripts/
|
||
│ ├── 01_gen_tts_styled.py v2 Style Control(旧)
|
||
│ ├── 02_gen_tts_voice_design.py v3 Voice Design(旧)
|
||
│ ├── 03_gen_voice_samples.py v4 生成试听样本
|
||
│ └── 04_gen_tts_clone.py v5 克隆 + 部署游戏 ★
|
||
└── tts/
|
||
├── v4_voice_samples/ 选定参考音色(每角色 1 wav + mp3)
|
||
└── v5_cloned/ 正式产物 + clone_manifest.tsv
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 常用命令
|
||
|
||
### 启动 TTS
|
||
|
||
```bash
|
||
VOXCPM_PORT=8002 VOXCPM_ENABLE_DENOISER=0 bash /home/xsl/tts-server/start-voxcpm.sh
|
||
curl http://127.0.0.1:8002/health
|
||
```
|
||
|
||
### 重跑全量克隆(改参考音频或提示词后)
|
||
|
||
```bash
|
||
cd /home/xsl/blind
|
||
VOXCPM_PORT=8002 python audio_2/scripts/04_gen_tts_clone.py --force
|
||
```
|
||
|
||
- 输出:`audio_2/tts/v5_cloned/*_wav_v5.mp3`
|
||
- 自动覆盖:`audio/mp3/tts/*_wav_v1.mp3`
|
||
|
||
### 只重跑某角色
|
||
|
||
```bash
|
||
VOXCPM_PORT=8002 python audio_2/scripts/04_gen_tts_clone.py --role mom --force
|
||
```
|
||
|
||
### 重新生成某角色试听(换提示词挑音色)
|
||
|
||
```bash
|
||
VOXCPM_PORT=8002 python audio_2/scripts/03_gen_voice_samples.py --role delivery --force
|
||
```
|
||
|
||
### 预览任务不合成
|
||
|
||
```bash
|
||
python audio_2/scripts/04_gen_tts_clone.py --dry-run
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 其他音频服务(非 TTS)
|
||
|
||
| 用途 | 位置 |
|
||
|------|------|
|
||
| 音乐 / 音效生成 | `/home/xsl/tools/ACE-Step-1.5` |
|
||
| Stable Audio | `/home/xsl/tools/stable-audio-tools` |
|
||
| UI 短音效 | Web Audio(浏览器内合成) |
|
||
|
||
VoxCPM2 **不能**用提示词生成敲门、心跳等 SFX,只能做人声 TTS。
|
||
|
||
---
|
||
|
||
## 10. 已知注意点
|
||
|
||
1. **Voice Design 音色不稳定**:同角色各条可能漂移,因此最终方案是「试听选定 → 克隆锚定」。
|
||
2. **外卖小哥语速**:`delivery` 提示词已调慢,`ROLES["delivery"]["speed"]` 已从 1.20 改为 **1.00**。
|
||
3. **男声角色**:`azhe`、`zhounan`、`delivery`。
|
||
4. **重新清理未使用音频**:扫描 `game/js/*.js` 与 `audio/mp3/` 对比删除;当前已对齐(184 = 184)。
|
||
5. **改游戏引用**:若将来改用 `_wav_v5.mp3` 等新后缀,需批量改 `story.js` / `engine.js`;目前无需改动。
|
||
|
||
---
|
||
|
||
## 11. 下次可继续的事
|
||
|
||
- [ ] 实机/playtest 听一遍各角色,标记需重跑的台词或角色
|
||
- [ ] 若某角色不满意:改 `voice_sample_prompts.py` → 重跑 `03` 挑选 → 替换 `v4_voice_samples/{role}/` → 重跑 `04`
|
||
- [ ] 微调单条表演:改 `voice_style_prompts.py` 中 `_performance` 规则 → `--role xxx --force`
|
||
|
||
---
|
||
|
||
## 12. 快速验证游戏音频是否正常
|
||
|
||
```bash
|
||
# 游戏引用的文件是否都存在
|
||
python3 - <<'PY'
|
||
import re
|
||
from pathlib import Path
|
||
root = Path("/home/xsl/blind")
|
||
text = "".join((root/"game/js/story.js").read_text() + (root/"game/js/engine.js").read_text())
|
||
refs = set()
|
||
for m in re.finditer(r'\$\{(MUS|SFX|AMB|T)\}/([^`\']+\.mp3)', text):
|
||
sub = {'MUS':'music','SFX':'sfx','AMB':'ambience','T':'tts'}[m.group(1)]
|
||
refs.add(root/f"audio/mp3/{sub}/{m.group(2)}")
|
||
for m in re.finditer(r"(?:npc|lx|rx)\('([^']+\.mp3)'\)", text):
|
||
refs.add(root/f"audio/mp3/tts/{m.group(1)}")
|
||
missing = [r for r in refs if not r.exists()]
|
||
print(f"引用 {len(refs)} 缺失 {len(missing)}")
|
||
for p in sorted(missing): print(" MISSING:", p.relative_to(root))
|
||
PY
|
||
```
|
||
|
||
预期输出:`缺失 0`。
|