如何提前计算SpeechSynthesis语音合成utterance的时长?
如何预计算TTS文本转语音的播放时长
你当前通过静音播放获取时长的方法,对长文本确实不够友好。下面是几种不用提前播放、也无需生成完整音频的解决方案:
一、基于统计的估算公式(快速但精度一般)
这是最轻量化的方案,依托语言的平均语速做估算:
- 英文:正常口语语速约为120-160词/分钟,取中间值150词/分钟的话,单词语均时长约0.4秒。可以额外加上标点停顿修正:每个句号/感叹号加0.2秒,逗号加0.1秒。
- 中文:正常语速约为200-250字/分钟,单字时长约0.24-0.3秒,同样可根据标点调整停顿时间。
示例估算代码(英文场景):
function estimateDuration(text) { const wordCount = text.trim().split(/\s+/).length; const punctuationPause = (text.match(/[.,!?]/g) || []).length * 0.15; // 平均每个标点停顿0.15秒 const baseDuration = wordCount * 0.4; // 150词/分钟的单词语长 return baseDuration + punctuationPause; }
二、调用TTS服务商的时长估算API(精度高)
主流云TTS服务都支持在不生成音频的前提下,直接返回文本的语音时长;或者在生成音频的接口中附带时长元数据(无需下载音频文件)。这类接口响应速度快,精度和实际播放完全一致,适合需要准确值的场景。
三、服务器端离线TTS工具(自主部署)
可以在服务器端部署开源TTS引擎(比如eSpeak、Festival),这类工具在处理文本时能直接输出语音时长数据,不需要生成音频文件。你可以封装成内部接口,供前端调用获取时长。
你的基础示例代码(整理后)
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TTS时长演示</title> </head> <body> <textarea rows="20" cols="80"> The rate property of the SpeechSynthesisUtterance interface gets and sets the speed at which the utterance will be spoken at. If unset, a default value of 1 will be used. A float representing the rate value. It can range between 0.1 (lowest) and 10 (highest), with 1 being the default rate for the current platform or voice, which should correspond to a normal speaking rate. Other values act as a percentage relative to this, so for example 2 is twice as fast, 0.5 is half as fast, etc. </textarea><br /> <input type="range" style="width:25vw"><output></output> <p></p> </body> </html>
JavaScript部分
function HHMMSS(s) { let date = new Date(1970, 0, 1); date.setSeconds(s); const result = date.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1"); return result.replace(/^00:/, ""); } async function calc_duration(text) { const utterance = new SpeechSynthesisUtterance(); utterance.text = text; utterance.rate = 1; utterance.volume = 0; window.speechSynthesis.speak(utterance); return new Promise(resolve => { utterance.addEventListener('end', (e) => { resolve(e.elapsedTime); }); }); } const range = document.querySelector('input[type="range"]'); const word = document.querySelector('output'); const time = document.querySelector('p'); const text = document.querySelector('textarea').value; const words = text.split(/\s+/).length; // 先显示估算时长 const estimated = estimateDuration(text); time.textContent = `${HHMMSS(estimated)} (估算值,${words} words)`; // 后台获取准确时长并更新 calc_duration(text).then(total => { range.min = 1; range.max = text.length; const utterance = new SpeechSynthesisUtterance(); utterance.addEventListener('boundary', (e) => { word.textContent = text.slice(e.charIndex, e.charIndex + e.charLength); time.textContent = `${HHMMSS(e.elapsedTime)} / ${HHMMSS(total)} (${words} words)`; range.value = e.charIndex; }); utterance.addEventListener('end', () => { range.value = range.max }); utterance.text = text; utterance.rate = 1; utterance.volume = 1; // utterance.voice = speechSynthesis.getVoices()[0]; window.speechSynthesis.speak(utterance); });
内容的提问来源于stack exchange,提问作者frumbert
相关产品推荐
相关产品推荐

