语速可调,比想象中麻烦

拾音 发布于 阅读:89 语音合成

「加个语速滑条」听起来是半小时的活。真做完,前后改了三版。

第一版:直接把 float 透传下去

Android 的 TextToSpeech.setSpeechRate(float) 传进来是个浮点,1.0 是标准。第一版我原样交给引擎,结果 0.7 以下声音开始发闷,1.6 以上辅音糊成一团——底层做的不变速变调,而引擎内部其实只认几个离散档位,中间值是被插值出来的。

第二版:分段映射 + 边界保护

把用户可选范围收到 0.75~1.5,按档位映射,并在两端留一点余量:

fun mapRate(ui: Float): Float = when {
    ui < 0.9f -> 0.8f
    ui < 1.1f -> 1.0f
    ui < 1.3f -> 1.2f
    else       -> 1.5f
}

听感上,档位之间有一点跳,但每一档都是干净的。朗读场景里,用户其实记不住 1.13 和 1.17 的区别,能记住的是「稍慢」「正常」「稍快」。

第三版:不给用户裸滑条

最后 UI 改成四个预设加一个高级里的连续滑条。原因不是技术,是使用场景:听小说时人在走路、做饭、开车,没人会停下来精细调 0.05 倍。预设一按就走,滑条留给少数真的想调的人。

还有两个细节:切换语速要作用在「下一句」而不是当前正在播的这一句,否则会听到一声明显的拼接;以及语速设置要跟着引擎一起持久化,阅读 App 每次新建 TextToSpeech 实例时并不会替你记住上次的值。

可调语速的价值不在「能调」,在「调完之后仍然像在听人念书」。

语音合成 语速