Artrajz / vits-simple-api

A simple VITS HTTP API, developed by extending Moegoe with additional features.
GNU Affero General Public License v3.0
807 stars 119 forks source link

支持 SSML 的 duration 属性 #103

Open ZhangTianrong opened 11 months ago

ZhangTianrong commented 11 months ago

运行环境

问题描述

能否支持 SSML 的 duration attribute? 像是字幕之类的文件翻译成 SSML 后会带有 duration, 并只依靠 duration 和 break 来完成时间上的对齐。生成完一句话之后才能测量时长并修改 break 的时间重新对其。

问题复现步骤

N/A

Artrajz commented 11 months ago

个人对这个功能还是比较感兴趣的,但是最近比较忙,新功能需要等到大概12月底才有空写,而且用duration来控制语音合成出来的长度我目前也不知道如何实现,得等之后再去研究了。

如果有人有思路的话也可以提供下,非常感谢~

ZhangTianrong commented 11 months ago

个人对这个功能还是比较感兴趣的,但是最近比较忙,新功能需要等到大概12月底才有空写,而且用duration来控制语音合成出来的长度我目前也不知道如何实现,得等之后再去研究了。

如果有人有思路的话也可以提供下,非常感谢~

我设想的其实比较简单,只是单纯为了对齐每句话的起始位置,用来给有翻译的音声配一个 shadow 的翻译,免得一个闭目用的东西非得睁着眼睛看字幕(有点像许多播放器的 text to speech 功能,但是语音生硬,音量还不好调整),所以并不考虑改动每句话的语速来完全 match duration (毕竟 SRT 转 SSML 其实 duration 也并不准确,话说完了字幕并不会清空),只是给每个带有 duration attribute 的 voice element 后补一个 time 为 -1 的 break element, 每次遇到这种 break 时通过上一个 voice 的 duration 和 audio 的长度确定当前 break 长度,如果是负的就暂时直接把上一个 audio 尾部多出来的部分删除。不过如果要边生成变 trial and error length 似乎也没有多困难,在 duration 外设置一个 tolerance, 控制最长和最短时长,然后继续通过 -1 break 元素对齐时间(我是有这个需求才开始了解 VITS 的,可能有其他可以调的方式活着需要注意的参数,只是我不知道)。其实我这个需求最好直接生成每个句子的起始锚点,然后新增的 audio 直接插入对应位置就好了,但是考虑到 SSML 好像是一个比较通行的表达方式,而它似乎用的是 duration 所以才打算还是绕一下路来实现,设置左 tolerance 为 0 倍 duration, 右 tolerance 为 1 倍即可。

Edit: 简单在这里尝试修改一下,测试还有点问题,有空我再看看。

Edit: 结果发现好像没什么问题,只是单纯 test_api.py 中的 "蓊蓊" 两个字是 <UNK> 然后无法 handle 了……我以为这个 test 本来肯定是可以过的啊。

Edit: 目前的效果就是每个 <voice> 元素可以有 duration, duration_min, duration_max 3 个 attribute:

<voice> 元素本身就含有 <break> 时,只能所有部分共用上述 attributes, 如果总长度超过了 duration, 将会直接从末尾截断。如果一定要用这种格式,那只能人为给这句话分配一个较小的 duration_max, 比如分了 3 段,然后给一个 0.33 之类的 duration_max.

暂时用上去好像没啥问题,我有空再完善一下,比如重试多少次无法达成要求的持续时间区间就退出啊之类的,然后看看能不能 PR 吧。