Add
[pause:Nms]text-level pause control to the official IndexTTS 2.5 webui: after generation, a waveform post-processor adjusts the actual pause at each mark to exactly N ms. Minimal patch (+7 lines), no changes to any official generation logic.
在官方原版 IndexTTS 2.5 webui 上增加 [pause:Nms] 文本标记级停顿控制:
生成完成后对输出 wav 做波形级后处理,把指定位置的实际停顿时长精确调整为 N 毫秒。
支持中文与英文文本(lang='zh'/'en')。
- 文本中写
他推开门[pause:800ms],屋里一片漆黑。,生成后该处停顿即被调整为 800ms(回归实测平均偏差 13ms 以内)。 - 双模式执行(自动判定):
- 没停 → 在插入点直接插入 N ms 静音;
- 停了但不够(原停顿 X ms < N)→ 在原停顿段中心增量补差 N−X ms,停顿边界不动;
- 已达到目标(X ≥ N 或差值 < 50ms)→ 不动。只延长,不缩短。
- 不改官方任何生成逻辑:补丁只在
gen_single的tts.infer()之后挂一个后处理钩子,文本里没有[pause:时零开销跳过。 - 中英双语:中文按字 token 双锚 + pypinyin 同音 fallback;英文按词 token 双锚(词形归一化匹配,无同音 fallback)。
[pause:Nms] → 标记替换成逗号生成 wav(模型最熟悉的标点)
→ whisper(base,逐词时间戳;zh 加简体引导 initial_prompt,
condition_on_previous_text=False)
→ 双锚定位:前锚 = 标记前最近定位单元(zh 字 / en 词)token end,
后锚 = 标记后最近定位单元 token start
(zh 精确匹配失败时 pypinyin 无声调同音匹配 fallback)
→ 双锚区间内能量谷 = 插入点(窗口中心 ±150ms)
→ 停没停判定:whisper 间隙 ≥ 50ms 视为停了(可选码级检测器预检交叉)
→ 增量插入 / 直接插入(多标记从后往前执行,防坐标漂移)
为什么用波形后处理而不是文本标点或 token 级注入:
- IndexTTS 2.5 的标点停顿短且不稳定(实测逗号 70~300ms 波动,句号停顿主要是段间硬插 200ms,模型自然停顿接近 0),文本侧没有"标点→时长"旋钮;
- token 级(语义码)路线经大样本验证定位无解(停顿段与语音段的码分布不可分),故生产采用波形级方案。完整研究记录见 RESEARCH.md。
| 文件 | 说明 |
|---|---|
install_cpu.py / install_gpu.py |
一键安装脚本(CPU 版 / GPU 版),见下方"安装" |
patch_webui_pause.diff |
官方 webui.py 最小补丁(+7 行,LF 行尾,基线:官方 commit a371df7 2026-08-12) |
pause_control25.py |
停顿控制核心模块(解析/定位/执行/一站式 process(),中英双语) |
detector_pause25.py |
(可选)码级停顿检测器,供 use_detector=True 预检交叉;不需要时无需部署 |
models/ |
检测器权重:pause_detector_lr.pkl + pause_detector_lstm.pt(仅检测器预检需要) |
training/ |
检测器训练/扫描脚本(prod_loader25.py / train_full25.py / scan_ensemble25.py),见 TRAINING.md |
| RESEARCH.md | 停顿控制研究记录:token 级(语义码注入)路线为何走不通的完整证据链,以及码级检测器的由来(中英摘要见文末) |
LICENSE / LICENSE.bilibili.txt / LICENSE.bilibili.zh.txt / THIRD_PARTY_NOTICES.md |
本项目 MIT 许可、bilibili 官方模型协议(中英)、第三方声明 |
使用第三方整合包(yzy/rainfall 等)?整合包改过 webui.py,补丁可能打不上——见 INSTALL_GUIDE.md 第 8 节(手动插 7 行 / 脚本后处理)。
详见 INSTALL_GUIDE.md(中文)/ INSTALL_GUIDE_EN.md(English)。简要版:
一键安装(推荐):解压本仓库后运行 python install_cpu.py(CPU 版,零显存)或 python install_gpu.py(GPU 版,加速但约 +1GB 显存)——自动装依赖/复制模块/生成启动脚本/打补丁/自检,详见 INSTALL_GUIDE 第 0 节。
手动版:1. 把 pause_control25.py 放到官方 webui.py 同目录;2. pip install openai-whisper pypinyin librosa soundfile(whisper base 首次运行自动下载约 140MB;GPU 加速后处理设 PAUSE_DEVICE=cuda,额外显存约 1GB);3. 在官方仓库根目录打补丁:
git apply patch_webui_pause.diff # 首选(保持行尾,git apply -R 可还原)
# 或:patch -p1 < patch_webui_pause.diff # 兜底(可能把行尾统一为 LF,不影响运行)
WebUI:文本里直接写 [pause:Nms](N 为毫秒),正常点生成即可。
代码调用:
import pause_control25 as pc
clean_text, marks, locs, ops = pc.process(
text='他推开门[pause:800ms],屋里一片漆黑。',
wav_path='outputs/spk_xxx.wav', # 已生成的 wav(标记替换为逗号的文本合成)
out_path='outputs/spk_xxx_paused.wav',
)
# 英文:pc.process('He paused[pause:800ms], then left.', wav, out, lang='en')
# locs: 每标记定位详情(插入点/停没停/原停顿X/双锚/谷点)
# ops: 执行记录(extend/insert/skip/failed)批量复用(避免重复加载 whisper):
locator = pc.PauseLocator()
for text, wav in jobs:
pc.process(text, wav, wav.replace('.wav', '_paused.wav'), locator=locator)可选检测器预检(需要生成侧 dump 的 codes npz,权重在 models/):
pc.process(text, wav, out, use_detector=True, codes_npz='xxx.prod.npz')- 只延长不缩短:模型自然停顿比目标长时不做裁剪(保护语音边界)。
- 停顿调整是静音插入,停顿内部为纯静音;长停顿后模型可能自带换气音(换气非静音,本工具不检测也不修改)。
- 插入点依赖 whisper 逐词时间戳;中文个别字识别失败时走同音匹配 fallback,极端情况(前锚完全定位失败)且无检测器预检时,该标记跳过(ops 记
failed)。 parse_pause_marks统一把标记替换为全角逗号,(中文场景定案);英文文本生成时若偏好半角逗号,可在调用前自行把,换成,,不影响定位。- 检测器预检(
use_detector=True)为可选项,需要在推理侧额外保存注意力/logits 特征 npz;不打这个补丁的普通部署用不到。
集中在 pause_control25.py 顶部常量区:能量谷窗口 ±150ms(VALLEY_WINDOW_MS)、
停没停间隙阈值 50ms(GAP_THRESHOLD_MS)、静音能量阈值(SIL_RMS_THRESHOLD)、
同音匹配 = 无声调拼音相等(_py)。
- 本项目代码(
pause_control25.py/detector_pause25.py/ 安装脚本 / 补丁 / 文档):MIT License(见 LICENSE)。 - 部署的官方 IndexTTS 2.5(模型权重与官方代码):受 bilibili 模型使用许可协议约束(见 LICENSE.bilibili.txt / LICENSE.bilibili.zh.txt 与 THIRD_PARTY_NOTICES.md)。