This repository has been archived on 2026-08-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Cyrene/scripts/voice/batch_convert.py
T
AskaEth 41f653b672 refactor: QQ → OBv11 重命名 + 平台格式统一抽象
- 所有对外称呼从 QQ 改为 OBv11(注释/提示词/日志/配置项)
- 新增 PlatformFormat 结构体,统一管理平台消息标记格式
- defaultPlatformFormats() 注册表替代硬编码 qqTargetRe
- extractProactiveMessage 改为 Thinker 方法,遍历格式注册表匹配
- 配置项重命名: QQ_BOT_PORT → OBV11_BOT_PORT, QQBotPort → OBv11BotPort
- 标记格式: 【QQ群聊】→【OBv11群聊】、【QQ私聊】→【OBv11私聊】

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-22 20:48:07 +08:00

104 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
批量 WEM → WAV 转换,使用 vgmstream-cli + ffmpeg 标准化。
输出: 22050Hz, mono, 16-bit PCM WAV
"""
import os
import subprocess
import sys
from pathlib import Path
VGMSTREAM = r"D:\Project\Code\Uni\Cyrene\scripts\voice\tools\vgmstream\vgmstream-cli.exe"
RAW_DIR = r"D:\Project\Code\Uni\Cyrene-Voice-Model\data\raw"
CLEANED_DIR = r"D:\Project\Code\Uni\Cyrene-Voice-Model\data\cleaned"
# 只转换 3.4-3.7 剧情(昔涟出场版本)
TARGETS = sorted([
d for d in os.listdir(RAW_DIR)
if d.startswith("External_del_3.") and any(
d.startswith(f"External_del_3.{v}") for v in ["4", "5", "6", "7"]
)
])
def convert_wem_to_wav(wem_path: str, wav_path: str) -> bool:
"""vgmstream WEM→临时WAV, ffmpeg 标准化 → 最终WAV (22050Hz mono s16)"""
os.makedirs(os.path.dirname(wav_path), exist_ok=True)
# 跳过已存在且非空的文件
if os.path.exists(wav_path) and os.path.getsize(wav_path) > 100:
return True
tmp_path = wav_path + ".tmp.wav"
try:
# Step 1: vgmstream → temp WAV
result = subprocess.run(
[VGMSTREAM, "-o", tmp_path, wem_path],
capture_output=True, timeout=30,
)
if result.returncode != 0 or not os.path.exists(tmp_path):
return False
# Step 2: ffmpeg → 标准化 22050Hz mono s16
result = subprocess.run(
["ffmpeg", "-y", "-i", tmp_path,
"-ar", "22050", "-ac", "1", "-sample_fmt", "s16",
wav_path],
capture_output=True, timeout=30,
)
if result.returncode != 0:
return False
return os.path.exists(wav_path) and os.path.getsize(wav_path) > 100
except Exception as e:
print(f" FAIL [{os.path.basename(wem_path)}]: {e}")
return False
finally:
# 清理临时文件
if os.path.exists(tmp_path):
os.remove(tmp_path)
def main():
print("=== 批量 WEM → WAV 转换 (VoBanks) ===\n")
total = 0
ok = 0
fail = 0
for target in TARGETS:
src_dir = os.path.join(RAW_DIR, target)
dst_dir = os.path.join(CLEANED_DIR, target)
if not os.path.isdir(src_dir):
print(f"SKIP: {target} (not found)")
continue
wem_files = sorted(Path(src_dir).glob("*.wem"))
if not wem_files:
print(f"SKIP: {target} (empty)")
continue
print(f"[{target}] {len(wem_files)} files...")
for i, wem in enumerate(wem_files):
wav = os.path.join(dst_dir, wem.stem + ".wav")
if convert_wem_to_wav(str(wem), wav):
ok += 1
else:
fail += 1
total += 1
if (i + 1) % 50 == 0:
print(f" {i+1}/{len(wem_files)} (ok:{ok} fail:{fail})")
print(f" Done: {len(wem_files)} files\n")
print(f"=== 转换完成: {ok} ok, {fail} fail, {total} total ===")
if __name__ == "__main__":
main()