chore: 环境迁移至本机(/home/ubuntu→/home/xsl 共28文件55处)+ tools/node、tools/bin 符号链接接入 + setup.md 补 torch cu128 钉版本踩坑(cu130 轮子驱动不兼容)+ tts_smoke_test 自建输出目录 + .gitignore 补 .venv-asr/tools-chrome

This commit is contained in:
xsl
2026-09-02 18:52:17 +08:00
parent 06d86d04e9
commit 3537610130
29 changed files with 77 additions and 57 deletions
+6
View File
@@ -11,6 +11,8 @@ local.properties
models/
# Qwen3-TTS Python 虚拟环境
.venv-tts/
.venv-asr/
tools/chrome/
# Stable Audio 3 虚拟环境
tools/stable-audio-3/.venv/
# ffmpeg/ffprobe 静态二进制
@@ -49,3 +51,7 @@ tools/gen_voice_dual_wav/
tools/gen_amb_wav/
tools/gen_inst_wav/
tools/gen_rpg_sfx_wav/
# 批次 1(radio/dungeon)资产中间产物(可由 gen 脚本复现,不入库)
web/radio/gen/staging/
web/dungeon/gen/staging/
tools/bgm_post_wav/
+1 -1
View File
@@ -5,7 +5,7 @@
通过 instruct 区分情绪(旁白/提示/如释重负)。
用法(必须 flock 串行,共享 GPU):
flock /home/ubuntu/SoundGame/.gpu.lock .venv-tts/bin/python app/src/escape/gen/gen_voice.py
flock /home/xsl/SoundGame/.gpu.lock .venv-tts/bin/python app/src/escape/gen/gen_voice.py
输出 wav 到 app/src/escape/gen/wav/voice/,随后由 convert_audio.sh 转 ogg。
每个文件 assert 时长 > 0.3s 且峰值 > 0.05。
+1 -1
View File
@@ -1,6 +1,6 @@
"""wav -> ogg 转换 + 对白首尾静音修剪/峰值归一,输出到 flavor assets 目录。
用法:/home/ubuntu/SoundGame/.venv-tts/bin/python convert_audio.py
用法:/home/xsl/SoundGame/.venv-tts/bin/python convert_audio.py
依赖 PATH 里的 ffmpeg(source env.d/android.sh)。
"""
import os
+1 -1
View File
@@ -1,5 +1,5 @@
import os
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np, soundfile as sf, torch
from qwen_tts import Qwen3TTSModel
+2 -2
View File
@@ -6,13 +6,13 @@
- 数字 0-9(报分用,逐位朗读):Uncle_Fu,语气平稳清晰
运行(必须 flock 串行,共享 GPU):
flock /home/ubuntu/SoundGame/.gpu.lock /home/ubuntu/SoundGame/.venv-tts/bin/python gen_voice.py
flock /home/xsl/SoundGame/.gpu.lock /home/xsl/SoundGame/.venv-tts/bin/python gen_voice.py
输出 wav 到 ./wav_voice/,随后由 convert_audio.sh 统一转 ogg。
"""
import os
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np
+1 -1
View File
@@ -2,7 +2,7 @@
# 《声命线》wav -> ogg 转码,按 docs 约定放入 assets/audio/{bgm,voice,sfx}/
# 用法: bash app/src/storyline/gen/convert.sh
set -euo pipefail
cd /home/ubuntu/SoundGame
cd /home/xsl/SoundGame
WAV=/tmp/slg/wav
AST=app/src/storyline/assets/audio
+2 -2
View File
@@ -1,7 +1,7 @@
"""《声命线》全部对白批量生成(Qwen3-TTS CustomVoice)。
用法(必须 flock 串行,共享 GPU):
flock /home/ubuntu/SoundGame/.gpu.lock .venv-tts/bin/python app/src/storyline/gen/gen_voice.py
flock /home/xsl/SoundGame/.gpu.lock .venv-tts/bin/python app/src/storyline/gen/gen_voice.py
音色分配:
- 旁白 Narrator : Uncle_Fu 低沉醇厚中年男声,冷静苍凉
@@ -15,7 +15,7 @@ import os
import sys
import time
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np
+1 -1
View File
@@ -81,6 +81,6 @@ ctext(H - 420, "左滑 / 右滑 做出抉择", font(46, 400), (200, 205, 214))
ctext(H - 330, "单击 继续剧情 双击 重听", font(46, 400), (200, 205, 214))
ctext(H - 240, "上滑 状态帮助 下滑 菜单", font(46, 400), (200, 205, 214))
out = "/home/ubuntu/SoundGame/app/src/storyline/res/drawable/cover.png"
out = "/home/xsl/SoundGame/app/src/storyline/res/drawable/cover.png"
img.save(out)
print("saved", out)
+13
View File
@@ -108,6 +108,19 @@ cd /home/ubuntu/SoundGame
实测版本:`torch 2.11.0+cu128`、`torchaudio 2.11.0+cu128`、`qwen-tts 0.1.1`、
`transformers 4.57.3`。
**⚠ torch 必须钉版本**(2026-09 踩坑):`uv pip install torch torchaudio` 不带
版本号时,cu128 源会解析到最新版(2.13.0+**cu130**,CUDA 13 轮子),驱动
CUDA 12.8 带不动,报 "NVIDIA driver on your system is too old (found version
12080)"。且 uv 只升 torch 不动 torchaudio 时会出现混搭(torchaudio 链接
libcudart.so.13 加载失败)。正确做法按上面命令钉死 `==2.11.0`;若已装坏:
```bash
~/.local/bin/uv pip install --python .venv-tts/bin/python 'torch==2.11.0' 'torchaudio==2.11.0' \
--index-url https://download.pytorch.org/whl/cu128
~/.local/bin/uv pip install --python .venv-tts/bin/python --reinstall 'torchaudio==2.11.0' \
--index-url https://download.pytorch.org/whl/cu128 # torchaudio 必要时强制重装
```
模型下载(共 3 个仓库,缓存在 `models/hf`,由 `HF_HOME` 指定):
```bash
+4 -4
View File
@@ -1,8 +1,8 @@
# SoundGame Android 开发环境(纯用户态,无 sudo)
# 用法: source /home/ubuntu/SoundGame/env.d/android.sh
# 用法: source /home/xsl/SoundGame/env.d/android.sh
export JAVA_HOME=/home/ubuntu/SoundGame/tools/jdk17
export ANDROID_HOME=/home/ubuntu/SoundGame/tools/android-sdk
export JAVA_HOME=/home/xsl/SoundGame/tools/jdk17
export ANDROID_HOME=/home/xsl/SoundGame/tools/android-sdk
# 兼容旧工具的变量名
export ANDROID_SDK_ROOT="$ANDROID_HOME"
@@ -10,4 +10,4 @@ export PATH="$JAVA_HOME/bin:$PATH"
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"
export PATH="$ANDROID_HOME/platform-tools:$PATH"
# ffmpeg / ffprobe 静态构建
export PATH="/home/ubuntu/SoundGame/tools/bin:$PATH"
export PATH="/home/xsl/SoundGame/tools/bin:$PATH"
+1 -1
View File
@@ -2,7 +2,7 @@
# 用法: cp env.d/sfx.example.sh env.d/sfx.sh,填入真实 HF_TOKEN 后 source env.d/sfx.sh
# 注意: env.d/sfx.sh 含真实 token,已被 .gitignore 忽略,切勿提交
export PATH="$HOME/.local/bin:$PATH"
export HF_HOME=/home/ubuntu/SoundGame/models/hf
export HF_HOME=/home/xsl/SoundGame/models/hf
# 注意: hf-mirror 镜像会把 gated 模型 308 重定向回 huggingface.co 导致下载失败。
# Stable Audio 3 是 gated 模型, 必须直连官方端点。
# 若以后直连失效且只用公开模型, 可临时改回镜像:
+3 -3
View File
@@ -1,7 +1,7 @@
# Qwen3-TTS 环境变量(用法: source /home/ubuntu/SoundGame/env.d/tts.sh)
export HF_HOME=/home/ubuntu/SoundGame/models/hf
# Qwen3-TTS 环境变量(用法: source /home/xsl/SoundGame/env.d/tts.sh)
export HF_HOME=/home/xsl/SoundGame/models/hf
# huggingface.co 本机连不通,使用国内镜像
export HF_ENDPOINT=https://hf-mirror.com
export HF_HUB_ENABLE_HF_TRANSFER=0
# 便捷别名
alias venv-tts='source /home/ubuntu/SoundGame/.venv-tts/bin/activate'
alias venv-tts='source /home/xsl/SoundGame/.venv-tts/bin/activate'
+6 -6
View File
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
"""全项目音频资产终检(R5)。
检查 6 个游戏 web/<game>/audio/:
检查 8 个游戏 web/<game>/audio/:
1. 每个 .ogg 都有同名 .m4a(反之亦然)
2. voice/male 与 voice/female 的 id 集合一致(storyline/rpg 的平铺 NPC/角色句除外)
3. 无 0 字节文件;ogg/m4a 均可被 ffprobe 解码且时长 > 0
@@ -12,10 +12,10 @@ import os
import subprocess
import sys
ROOT = "/home/ubuntu/SoundGame/web"
GAMES = ["storyline", "escape", "simon", "rhythm", "space", "rpg"]
ROOT = "/home/xsl/SoundGame/web"
GAMES = ["storyline", "escape", "simon", "rhythm", "space", "rpg", "radio", "dungeon"]
# 平铺 voice 文件(角色/NPC,单音色,不做性别集合一致性要求)
FLAT_OK = {"storyline", "rpg"}
FLAT_OK = {"storyline", "rpg", "radio"}
def ids(d, ext):
@@ -26,7 +26,7 @@ def ids(d, ext):
def main():
problems = []
print("# 全项目音频资产终检(R5,2026-08-29)\n")
print("# 全项目音频资产终检(R5 建立,批次 1 起含 radio/dungeon,2026-09-01)\n")
print("| 游戏 | ogg | m4a | 0字节 | 解码失败 | voice male/female id 一致 |")
print("|---|---|---|---|---|---|")
for g in GAMES:
@@ -82,7 +82,7 @@ def main():
for p in problems:
print(f"- {p}")
return 1
print("## 结论\n\n全部通过:双格式配对完整、无 0 字节、全部可解码、voice 性别目录 id 集合一致(storyline/rpg 平铺角色句按约定豁免)。")
print("## 结论\n\n全部通过:双格式配对完整、无 0 字节、全部可解码、voice 性别目录 id 集合一致(storyline/rpg/radio 平铺角色句按约定豁免)。")
return 0
+1 -1
View File
@@ -18,7 +18,7 @@ import sys
import numpy as np
import soundfile as sf
ROOT = "/home/ubuntu/SoundGame"
ROOT = "/home/xsl/SoundGame"
WEB = os.path.join(ROOT, "web")
BACKUP = os.path.join(ROOT, "tools", "asset_fix_backup")
FADE_MS = 8
+4 -4
View File
@@ -2,9 +2,9 @@
# R4 RPG《剑与声》SA3 音效批量生成(29 件,SYN 的 5 件不在此列)。
# 用法: bash tools/gen_rpg_sfx.sh (内部 flock 串行 GPU;输出 tools/gen_rpg_sfx_wav/)
set -u
source /home/ubuntu/SoundGame/env.d/sfx.sh
cd /home/ubuntu/SoundGame/tools/stable-audio-3
OUT=/home/ubuntu/SoundGame/tools/gen_rpg_sfx_wav
source /home/xsl/SoundGame/env.d/sfx.sh
cd /home/xsl/SoundGame/tools/stable-audio-3
OUT=/home/xsl/SoundGame/tools/gen_rpg_sfx_wav
mkdir -p "$OUT"
declare -A P D
@@ -45,7 +45,7 @@ P[amb_peak]="mountain peak ambience, strong cold wind, thin air, howling gusts,
ORDER="tel_wolf tel_bandit tel_spider tel_elite tel_boss1 tel_croc tel_shaman tel_puppet tel_boss2 atk_swing atk_hit parry skill_slash enemy_die potion chest drink_water rest door_heavy amb_village amb_path amb_fork amb_chest amb_stream amb_hunter amb_deepwood amb_gate amb_hall amb_swamp amb_peak"
flock /home/ubuntu/SoundGame/.gpu.lock bash -c '
flock /home/xsl/SoundGame/.gpu.lock bash -c '
'"$(declare -p P D OUT)"'
for k in '"$ORDER"'; do
if [ -s "$OUT/$k.wav" ]; then echo "skip $k"; continue; fi
+3 -3
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""Ryan 音色中文发音冒烟测试:决定 simon/rhythm 男声旁白选型。"""
import os
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np
import soundfile as sf
@@ -24,9 +24,9 @@ wavs, sr = model.generate_custom_voice(
speaker=["Ryan"] * len(texts),
instruct=["热情活力的中文游戏解说语气,吐字清晰"] * len(texts),
)
os.makedirs("/home/ubuntu/SoundGame/tools/samples", exist_ok=True)
os.makedirs("/home/xsl/SoundGame/tools/samples", exist_ok=True)
for i, wav in enumerate(wavs):
wav = np.asarray(wav, dtype=np.float32)
sf.write(f"/home/ubuntu/SoundGame/tools/samples/ryan_zh_{i}.wav", wav, sr)
sf.write(f"/home/xsl/SoundGame/tools/samples/ryan_zh_{i}.wav", wav, sr)
print(f"ryan_zh_{i}: {len(wav)/sr:.2f}s peak={np.max(np.abs(wav)):.3f}")
print("done")
+1 -1
View File
@@ -15,7 +15,7 @@ import sys
import numpy as np
import soundfile as sf
ROOT = "/home/ubuntu/SoundGame/web"
ROOT = "/home/xsl/SoundGame/web"
GAMES = ["storyline", "escape", "simon", "rhythm", "space", "rpg"]
EDGE_MS = 5
DC_THRESH = 0.001
+3 -2
View File
@@ -2,7 +2,7 @@
import os
import time
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import torch
@@ -27,7 +27,8 @@ wavs, sr = model.generate_custom_voice(
instruct="用惊恐、急促的语气大声喊出来",
)
out = "/home/ubuntu/SoundGame/tools/samples/tts_test.wav"
out = "/home/xsl/SoundGame/tools/samples/tts_test.wav"
os.makedirs(os.path.dirname(out), exist_ok=True)
sf.write(out, wavs[0], sr)
dur = len(wavs[0]) / sr
print(f"saved: {out} sr={sr} duration={dur:.2f}s samples={len(wavs[0])}")
+1 -1
View File
@@ -2,7 +2,7 @@
"""资产引用校验:game.js 引用的每个音频 id 都必须有 .ogg 和 .m4a 文件。"""
import re, sys, pathlib
root = pathlib.Path('/home/ubuntu/SoundGame/web/escape')
root = pathlib.Path('/home/xsl/SoundGame/web/escape')
src = (root / 'game.js').read_text(encoding='utf-8')
ids = set()
+1 -1
View File
@@ -5,7 +5,7 @@ import os
from PIL import Image, ImageDraw, ImageFont
W, H = 1080, 1920
ROOT = "/home/ubuntu/SoundGame/web/rhythm"
ROOT = "/home/xsl/SoundGame/web/rhythm"
FONT = os.path.join(ROOT, "gen", "NotoSansSC-Bold.ttf")
img = Image.new("RGB", (W, H), (10, 12, 24))
+1 -1
View File
@@ -21,7 +21,7 @@ import numpy as np
import soundfile as sf
SR = 44100
OUT = "/home/ubuntu/SoundGame/web/rhythm/audio/sfx"
OUT = "/home/xsl/SoundGame/web/rhythm/audio/sfx"
os.makedirs(OUT, exist_ok=True)
+4 -4
View File
@@ -1,14 +1,14 @@
"""节拍行者 — 语音对白生成(Qwen3-TTS CustomVoice)。
用法(必须 flock,GPU 与其他 agent 共享):
flock /home/ubuntu/SoundGame/.gpu.lock \
/home/ubuntu/SoundGame/.venv-tts/bin/python gen_voice.py
flock /home/xsl/SoundGame/.gpu.lock \
/home/xsl/SoundGame/.venv-tts/bin/python gen_voice.py
产出 web/rhythm/audio/voice/*.wav(24kHz),随后由 gen_convert.sh 转 ogg/m4a。
"""
import os
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np
@@ -16,7 +16,7 @@ import soundfile as sf
import torch
from qwen_tts import Qwen3TTSModel
OUT = "/home/ubuntu/SoundGame/web/rhythm/audio/voice"
OUT = "/home/xsl/SoundGame/web/rhythm/audio/voice"
os.makedirs(OUT, exist_ok=True)
# (id, 文本, 情感指令)
+1 -1
View File
@@ -22,7 +22,7 @@ import subprocess
import numpy as np
import soundfile as sf
ROOT = "/home/ubuntu/SoundGame"
ROOT = "/home/xsl/SoundGame"
STAGING = os.path.join(ROOT, "web", "rpg", "gen", "staging", "sfx")
OUT = os.path.join(ROOT, "web", "rpg", "audio", "sfx")
FFMPEG = os.path.join(ROOT, "tools", "bin", "ffmpeg")
+4 -4
View File
@@ -2,12 +2,12 @@
# R6 缺口 sfx:victory(Stable Audio 3,英文 prompt 照录 docs/design/11 §5)。
# 用法: bash web/rpg/gen/gen_gap_sfx.sh (内部 flock 串行 GPU;输出 staging)
set -u
source /home/ubuntu/SoundGame/env.d/sfx.sh
cd /home/ubuntu/SoundGame/tools/stable-audio-3
OUT=/home/ubuntu/SoundGame/web/rpg/gen/staging/sfx
source /home/xsl/SoundGame/env.d/sfx.sh
cd /home/xsl/SoundGame/tools/stable-audio-3
OUT=/home/xsl/SoundGame/web/rpg/gen/staging/sfx
mkdir -p "$OUT"
flock /home/ubuntu/SoundGame/.gpu.lock bash -c '
flock /home/xsl/SoundGame/.gpu.lock bash -c '
if [ -s "'"$OUT"'/victory.wav" ]; then echo "skip victory"; else
uv run stable-audio --model small-sfx \
-p "triumphant short brass fanfare, 3 rising notes, wuxia style, under 1.5 seconds" \
+2 -2
View File
@@ -19,10 +19,10 @@ import os
import subprocess
import sys
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
ROOT = "/home/ubuntu/SoundGame"
ROOT = "/home/xsl/SoundGame"
sys.path.insert(0, os.path.join(ROOT, "tools"))
from gen_voice_dual import split_text, valid_wav, PEAK_NORM, GAP_SEC # noqa: E402 只读复用主管线
+1 -1
View File
@@ -6,7 +6,7 @@ import random
from PIL import Image, ImageDraw, ImageFilter, ImageFont
W, H = 1080, 1920
FONT = "/home/ubuntu/SoundGame/app/src/reflex/gen/NotoSansSC-Bold.ttf"
FONT = "/home/xsl/SoundGame/app/src/reflex/gen/NotoSansSC-Bold.ttf"
OUT = os.path.join(os.path.dirname(__file__), "..", "cover.png")
img = Image.new("RGB", (W, H), (10, 12, 26))
+2 -2
View File
@@ -5,8 +5,8 @@ import random
from PIL import Image, ImageDraw, ImageFilter, ImageFont
W, H = 1080, 1920
FONT = "/home/ubuntu/SoundGame/app/src/reflex/gen/NotoSansSC-Bold.ttf"
OUT = "/home/ubuntu/SoundGame/web/space/cover.png"
FONT = "/home/xsl/SoundGame/app/src/reflex/gen/NotoSansSC-Bold.ttf"
OUT = "/home/xsl/SoundGame/web/space/cover.png"
random.seed(42)
+3 -3
View File
@@ -1,9 +1,9 @@
#!/bin/bash
# 盲航 SFX 批量生成(Stable Audio 3 small-sfx),单 flock 会话内串行跑完
set -e
source /home/ubuntu/SoundGame/env.d/sfx.sh
cd /home/ubuntu/SoundGame/tools/stable-audio-3
OUT=/home/ubuntu/SoundGame/web/space/audio/build
source /home/xsl/SoundGame/env.d/sfx.sh
cd /home/xsl/SoundGame/tools/stable-audio-3
OUT=/home/xsl/SoundGame/web/space/audio/build
mkdir -p "$OUT"
gen() { # $1=name $2=duration $3=prompt
+3 -3
View File
@@ -1,11 +1,11 @@
"""盲航(space)TTS 对白批量生成:教学旁白 + 游戏内提示 + 数字播报。
用法:flock /home/ubuntu/SoundGame/.gpu.lock .venv-tts/bin/python gen_voice.py
用法:flock /home/xsl/SoundGame/.gpu.lock .venv-tts/bin/python gen_voice.py
输出 24kHz wav 到 web/space/audio/build/voice/,随后由 ffmpeg 转 ogg/m4a。
"""
import os
os.environ.setdefault("HF_HOME", "/home/ubuntu/SoundGame/models/hf")
os.environ.setdefault("HF_HOME", "/home/xsl/SoundGame/models/hf")
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
import numpy as np
@@ -13,7 +13,7 @@ import soundfile as sf
import torch
from qwen_tts import Qwen3TTSModel
OUT = "/home/ubuntu/SoundGame/web/space/audio/build/voice"
OUT = "/home/xsl/SoundGame/web/space/audio/build/voice"
os.makedirs(OUT, exist_ok=True)
CALM = "冷静、沉稳的飞船导航合成语音,吐字清晰"