【问题标题】:Changing the SpeechSynthesis voice not working更改 SpeechSynthesis 语音不起作用
【发布时间】:2020-04-03 17:06:49
【问题描述】:

我已经尝试了在 stackoverflow 上可以找到的所有变体,但我仍然无法在 SpeechSynthesis 上改变声音

下面是独立代码,它用所有可用的声音填充下拉列表,并允许我选择我想要的声音。

不幸的是,这段代码并没有改变声音。此外,在改变声音之前。 msg.voice 为空,即使它已用于列出所有可用的声音。

谁能告诉我代码有什么问题? (console.log(msg.voice); 在被设置之前给出一个空值)

<!doctype html>
<html>
<head>
<SCRIPT>
var msg = new SpeechSynthesisUtterance();
voices = window.speechSynthesis.getVoices();
var numberOfVoices=0;


function Main(){
voiceSelect=document.getElementById("voiceSelect");
setTimeout(getVoicesFunction,2000);
}

function getVoicesFunction(){
msg = new SpeechSynthesisUtterance("hello");
numberOfVoices=0;   
speechSynthesis.getVoices().forEach(function(voice) {
var option = document.createElement('option');
        option.text = option.value = voice.voiceURI;
        voiceSelect.add(option, 0);
        numberOfVoices=numberOfVoices+1;
});
    voiceSelect.onchange = voiceChange;
}

function voiceChange(){
    textToSpeech("this is the old voice");
    var selectedOption = this[this.selectedIndex];
    selectedVoice = selectedOption.text;
    msg = new SpeechSynthesisUtterance();
    voices = window.speechSynthesis.getVoices();
    msg = new SpeechSynthesisUtterance();
    console.log("before change msg.voice");
    console.log(msg.voice);
    for(i = 0; i < numberOfVoices ; i++) {
    if(voices[i].voiceURI === selectedVoice) {
    var temp="changing the voice number to "+i;
    setTimeout(textToSpeech,2000,temp);
    msg.voice = voices[i];
    console.log(msg.voice);
    var tempVoiceNumber=i;
    };
    }
    setTimeout(textToSpeech,4000,"this is the new voice");
}

function textToSpeech(tspeech){
    msg = new SpeechSynthesisUtterance();
    msg.text = tspeech;
    speechSynthesis.speak(msg);
    console.log("speech "+tspeech);
}       
</SCRIPT>
</head>
<body onload= "Main()" id= "mainb">
<div id="container">
<select name="Combobox1" size="1" id="voiceSelect">
</select>
</div>
</body>
</html>

【问题讨论】:

  • 为什么有这么多的setTimeouts?在这里尝试第一个示例:developer.mozilla.org/en-US/docs/Web/API/…
  • 感谢弗雷泽 - 我使用超时,因为根据您的链接的标准方法在没有它们的情况下不起作用。我认为这是 javascript 的异步特性——你会在许多关于语音合成的问题上看到这一点——部分解决方案是延迟时间。我发现 Mozilla 文档 - 或任何其他官方文档都没有提到这一点令人惊讶。例如 voices.length 为零,没有时间延迟。并非其中的所有内容都是必需的,但为了安全起见,我已将它们全部放入,并表明即使有时间延迟,这些费用仍然无法正常工作
  • 在链接的示例中,有一个部分带有 onvoiceschanged。这是在不使用超时的情况下获取声音的方法。超时的答案不值得一读。
  • 谢谢,但那是我开始使用的那段代码。在三台不同的机器和操作系统上,它会将 voices.length 设为零,除非您设置时间延迟。然后它至少给出了正确的声音长度,以及正确的声音列表。不幸的是,它仍然没有真正改变声音。我意识到我可能做错了什么,这就是为什么我用脚本列出了整个 html

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


【解决方案1】:

IanR,我复制了代码,它对我有用。我剪掉了音高和速率控件,让 html 更简单,但基本上是一样的。

如果它对您不起作用,您会收到任何控制台错误吗?

var synth = window.speechSynthesis;

var inputForm = document.querySelector('form');
var inputTxt = document.querySelector('.txt');
var voiceSelect = document.querySelector('select');

/*var pitch = document.querySelector('#pitch');
var pitchValue = document.querySelector('.pitch-value');
var rate = document.querySelector('#rate');
var rateValue = document.querySelector('.rate-value');*/



var voices = [];

function populateVoiceList() {
  voices = synth.getVoices();

  for (i = 0; i < voices.length; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';

    if (voices[i].default) {
      option.textContent += ' -- DEFAULT';
    }

    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    voiceSelect.appendChild(option);
  }
}

populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}

inputForm.onsubmit = function(event) {
  event.preventDefault();

  var utterThis = new SpeechSynthesisUtterance(inputTxt.value);
  var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
  for (i = 0; i < voices.length; i++) {
    if (voices[i].name === selectedOption) {
      utterThis.voice = voices[i];
    }
  }
  //utterThis.pitch = pitch.value;
  //utterThis.rate = rate.value;
  synth.speak(utterThis);

  inputTxt.blur();
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>61016951</title>
  <script src="61016951.js" defer></script>
</head>

<body>
  <div id="div">
    <form>
      <input type="text" class="txt">
      <select></select>
      <button type="submit">Play</button>
    </form>
  </div>
</body>

</html>

【讨论】:

  • 弗雷泽 - 非常抱歉 - 我确实发表了评论感谢你,但我显然按下了错误的按钮,因为它不可见。是的,您是对的,此代码确实适用于 Windows。感谢您花时间展示这一点。我很感激。它确实消除了超时的需要。我的代码不起作用的原因是我使用了一个调用 new SpeechSynthesisUtterance() 的函数。我没有将声音重置为相关声音[voiceNumber]。我现在的问题是,让它在 IOS 上运行。但我现在正在看这个,并在解决后更新这个线程。再次感谢。
  • @IanR 我确定我昨天看到了你的评论,我什至赞成!
  • iOS 和 Android 都对调用 getVoices() 时可用的声音撒谎。 iOS 为您实际使用的每种语言环境提供一个,Android 为每种语言提供一个。您可以从设备设置(并重新启动)中更改为您提供的 Android 设备。使用 iOS,您可以维护一个实际有效的声音列表,而忽略其余部分。更多信息:talkrapp.com/speechSynthesis.html
【解决方案2】:

去除代码中的所有额外位,以下是您需要如何处理 speechSynthesis.getVoices() 上的异步加载;

if (voiceLoaded()) {
  speak();
} else {
  speechSynthesis.addEventListener('voiceschanged', speak);
}

function speak() {
  const utterance = new SpeechSynthesisUtterance('text');
  utterance.voice = getFemaleVoice();
  speechSynthesis.speak(utterance);
}

function getFemaleVoice() {
  const voiceIndex = 4;
  return speechSynthesis.getVoices()[voiceIndex];
}

function voiceLoaded() {
  return speechSynthesis.getVoices().length;
}

如果 voices 数组已经加载,那么它将说出话语,否则此代码将在 voiceschanged 事件上添加事件侦听器,一旦浏览器加载了语音数组,就会触发该事件,然后您的说话回调将运行。

【讨论】:

    猜你喜欢
    • 2019-03-29
    • 2014-06-22
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    相关资源
    最近更新 更多