如何在语音合成中改变声音?

时间:2017-03-09 11:46:39

标签: javascript text-to-speech speech-synthesis

我正在尝试使用Speechsynthesis的简单示例。

<script>

voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);

</script>

但这会产生错误,声音未定义。我发现getVoices()是异步加载的。我看到this回答并更新了我的代码,如下所示使用回调。

<script>
window.speechSynthesis.onvoiceschanged = function() {
voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);
};
</script>

但是由于一些奇怪的原因,文本被说了三次而不是一次。我该如何修复此代码?

3 个答案:

答案 0 :(得分:3)

我无法复制您的问题,但尝试添加一个事件监听器,以便在加载语音后运行您的函数。

let voices, utterance;

function speakVoice() {
voices = this.getVoices();
utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[1];
speechSynthesis.speak(utterance);
};

speechSynthesis.addEventListener('voiceschanged', speakVoice);

答案 1 :(得分:3)

这可以在许多JS Bin类型的演示中看到。例如:

http://jsbin.com/sazuca/1/edit?html,css,js,output

https://codepen.io/matt-west/pen/wGzuJ

在使用非本地语音时,Chrome会使用voiceschanged事件。另一个影响是声音列表通常是三重的。

W3C规范说:

  

voiceschanged event

     

当内容被解雇时   将返回getVoices方法将返回的SpeechSynthesisVoiceList   改变。示例包括:列表所在的服务器端综合   异步确定,或客户端声音时   安装/卸载

...所以我认为当Chrome获得声音时会触发一次事件,而当使用第一个非本地声音时则会触发两次。

鉴于似乎没有办法区分哪个更改正在触发事件,我一直在使用这个丑陋的代码:

    // Add voices to dropdown list
    loadVoices();
    // For browsers that use voiceschanged event
    speechSynthesis.onvoiceschanged = function(e) {
        // Load the voices into the dropdown
        loadVoices();
        // Don't add more options when voiceschanged again
        speechSynthesis.onvoiceschanged = null;
    }

其中loadVoices()是将声音添加到选择选项的功能。它并不理想,但它适用于所有浏览器(使用语音合成),无论是否使用onvoices。

答案 2 :(得分:-1)

您可以简单地添加此代码并在项目中使用SpeechSynthesis,它适用于我。

var su;

su = new SpeechSynthesisUtterance();

su.text = "Hello World";

speechSynthesis.speak(su);

speechSynthesis.cancel();