# SoundGame — 资产生产流水线 三类音频资产(对白 voice / 音效 sfx / 音乐 bgm)的完整生成与再生成流程。 所有脚本都在 `app/src//gen/` 下,可随时复现全部资产。 通用约定: - **GPU 任务必须串行**:`flock /home/ubuntu/SoundGame/.gpu.lock <命令>` (TTS 与 Stable Audio 3 共用一块 RTX 3090)。 - 环境脚本:`source env.d/tts.sh`(HF_HOME + hf-mirror 镜像)、 `source env.d/android.sh`(ffmpeg 在 PATH)、`source env.d/sfx.sh`(HF_TOKEN, 含密钥不入库,模板见 `env.d/sfx.example.sh`)。 - 中间产物 wav 输出到各 gen 目录或 `/tmp/slg/`(不入库),最终 ogg 进 `app/src//assets/audio/{bgm,voice,sfx}/`。 ## 1. TTS 对白(Qwen3-TTS CustomVoice) 引擎与用法详见 `env.d/tts.md`(CustomVoice 预置音色 + instruct 情感指令、 VoiceDesign、预置音色表)。流水线层面: ```bash source env.d/tts.sh # 《声命线》:48 条,6 条一批;输出 /tmp/slg/wav/,可传文件名参数只重生指定条目 flock .gpu.lock .venv-tts/bin/python app/src/storyline/gen/gen_voice.py [文件id...] bash app/src/storyline/gen/convert.sh # wav -> ogg 进 assets(含电台带通效果) # 《声东击西》:33 条,逐条生成;输出 gen/wav_voice/ cd app/src/reflex/gen flock /home/ubuntu/SoundGame/.gpu.lock /home/ubuntu/SoundGame/.venv-tts/bin/python gen_voice.py # 《暗室》:41 条,8 条一批,统一峰值归一 0.89;输出 gen/wav/voice/ flock .gpu.lock .venv-tts/bin/python app/src/escape/gen/gen_voice.py ``` - 每条生成后自动校验:**时长 > 0.3s 且峰值 > 0.05**,不达标直接 assert 失败。 - 音色分配见各游戏文档(docs/games/*.md):旁白 Uncle_Fu、林晚 Serena、 猎狗 Dylan、小满/广播 Vivian;escape 全员 Uncle_Fu 靠 instruct 区分语气。 - 已知不稳条目:reflex 的 `num_6`("六"),单独用 `app/src/reflex/gen/fix_num6.py` 重试生成(最多 4 次取时长合格的一条)。 - 改台词只需改 gen_voice.py 里的 `LINES` 表再重跑;文件名即游戏代码引用的 id。 ## 2. 音效(Stable Audio 3 + 程序合成) ### 2a. Stable Audio 3 small-sfx(主力,AI 生成) ```bash 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 \ -o /home/ubuntu/SoundGame/tools/samples/sfx_test.wav ``` - 提示词必须英文;`--duration` ≤ 120s;`--steps` 默认 8;small 模型峰值显存 约 2.4GB。批量:`-p "p1" "p2" --duration 3 5`。 - 首次使用需完成 gated 许可 + token 流程,详见 `env.d/sfx.md` / `docs/setup.md`。 - 生成后用 ffmpeg 转 ogg 进 assets(规格见下文"资产规格")。 ### 2b. 程序合成(保底/已在线方案,numpy + soundfile,纯 CPU 无需 GPU 锁) | 游戏 | 脚本 | 输出 | |---|---|---| | storyline | `app/src/storyline/gen/gen_sfx.py` | `/tmp/slg/wav/sfx/`(24kHz),`convert.sh` 转 ogg | | reflex | `app/src/reflex/gen/gen_sfx_bgm.py` | `gen/wav_sfx/`(44.1kHz),`convert_audio.py` 转 ogg | | escape | `app/src/escape/gen/gen_sfx.py` | `gen/wav/sfx/`(44.1kHz),手动 ffmpeg 转 ogg | 当前线上资产全部为程序合成版;Stable Audio 3 环境已就绪,可按 README 待办逐步替换(替换时保持同名同目录,游戏代码零改动)。 ## 3. BGM ### 3a. Mureka API(storyline / escape) ```bash source env.d/mureka.sh # MUREKA_API_KEY(含密钥不入库,模板 env.d/mureka.example.sh) python3 tools/mureka_gen.py \ --prompt "dark ambient horror game background music, low drone, ..., seamless loop, instrumental" \ --out tools/mureka_out/storyline # 提交→轮询→下载全部候选 flac python3 tools/mureka_gen.py --task-id --out tools/mureka_out/xxx # 只轮询已有任务 ``` 后处理(两条已上线 BGM 相同参数,记录见 `tools/mureka_log.md`): ``` 裁剪前 120s → 首尾 3s acrossfade(tri) 无缝循环化 → loudnorm I=-20/TP=-2/LRA=11 → aresample 44.1kHz 立体声 → libvorbis -q:a 3 ``` 成品 117.00s,保持原文件名(`dark_drone.ogg` / `drone.ogg`)直接替换 assets。 原程序合成版备份在 `tools/bgm_backup/`。 **成本参考**:`POST /v1/instrumental/generate` 每条任务 **$0.03**(一次出 2 个 候选),项目预算上限 $0.50,已用 $0.06(2 条任务均一次成功)。每次调用必须 登记到 `tools/mureka_log.md`。 ### 3b. 程序合成(reflex,有意保留) `app/src/reflex/gen/gen_sfx_bgm.py` 的 `make_pulse_bgm(bpm, bars=8)`: 心跳底鼓 + 低音脉冲音序 + 镲噪声 + 不协和 pad,100/128/152 BPM 三档各 8 小节。 玩法要求 BPM 随波次精确切换,AI 生成曲目 BPM 不精确会破坏机制,**不要用 Mureka 替换 reflex 的 BGM**。 ## 资产规格 | 项 | 标准 | |---|---| | 容器/编码 | ogg vorbis(`-c:a libvorbis`) | | 码率 | voice/sfx `-q:a 4`;bgm `-q:a 3`(控制体积) | | 采样率 | TTS 源 24kHz;程序合成 reflex/escape 44.1kHz;BGM 统一 aresample 44.1kHz | | BGM 响度 | loudnorm **I=-20 LUFS / TP=-2 / LRA=11** | | BGM 循环 | 首尾交叉淡化无缝循环(Mureka 版 3s acrossfade;合成版 2s/4s 等功率交叉) | | 时长校验 | 每条 > 0.3s(数字语音等短条目除外,fix_num6 放宽到 0.3~1.5s 区间判定) | | 峰值校验 | 生成后 assert 峰值 > 0.05(防静音/失败条目混入) | | 峰值归一 | storyline 合成 sfx 0.85;escape voice 0.89 / sfx 0.85(环境音 0.55-0.7);reflex voice 0.6 / sfx 0.7-0.95 | ## 目录约定 ``` app/src// assets/audio/{bgm,voice,sfx}/*.ogg # 最终资产(入库) gen/ # 生成脚本(入库)+ 中间 wav/字体(不入库) tools/ mureka_gen.py / mureka_log.md # Mureka 调用脚本与台账(入库) mureka_out/ bgm_backup/ samples/ # 原始下载/备份/冒烟输出(不入库) stable-audio-3/ # SFX 仓库(代码入库,.venv 不入库) ``` 引擎按 id 前缀(`bgm/` `voice/` `sfx/`)分发到三个播放层,文件名即代码中的 引用 id;新增资产保持"同名替换、新增先改代码引用"的原则。 ## 封面图 - storyline:`gen/make_cover.py`(PIL,字体 /tmp/slg/NotoSansSC.ttf) - escape:`gen/gen_cover.py`(PIL,字体 gen/font.otf,不入库需自备) - reflex:封面无独立生成脚本(骨架渐变图 + 后期替换) - 统一输出 `app/src//res/drawable/cover.png`,1080x1920,文件名固定。