Day23 Speech Synthesis

Demo

在這個單元中,我們要將輸入的文字轉為聲音,做出我們自己的 google 小姐。

SpeechSynthesisUtterance

可以想像是一個語音資訊的物件,包含內容、語言、音調、聲音、速率等。
我們可以透過定義一個變數來呼叫他:

1
2
const msg = new SpeechSynthesisUtterance();
console.log(msg)

SpeechSynthesisUtterance 屬性

透過console.log(msg)我們可以看到他的屬性有:

屬性

  • SpeechSynthesisUtterance.lang:語言。
  • SpeechSynthesisUtterance.pitch:音調。
  • SpeechSynthesisUtterance.rate:速度。
  • SpeechSynthesisUtterance.text:文字內容。
  • SpeechSynthesisUtterance.voice:不同語言的聲音。
  • SpeechSynthesisUtterance.volume:音量。

MDN更多介紹

SpeechSynthesis

有了SpeechSynthesisUtterance物件(資料)後,我們要有一個像是控制器的東西
用來播放或暫停等功能。

方法

  • SpeechSynthesis.getVoices():取得一陣列,其中包含目前所有可用語言。
  • SpeechSynthesis.pause():暫停。(搭配resume)
  • SpeechSynthesis.resume():取消暫停。
  • SpeechSynthesis.cancel():移除所有的音訊。(停止播放)
  • SpeechSynthesis.speak():將一段發音加入發音庫,當前面的發音皆播放完成後,就會播放此發音。
    資料參考

更多屬性和方法:MDN更多介紹

進入範例

1
2
3
4
5
6
7
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');

const msg = new SpeechSynthesisUtterance();
let voices = [];

一開始範例已經幫我們建立好對象和SpeechSynthesisUtterance

取得語言

我們先將 speechSynthesis 這個控制器加上唯一的監聽事件 voiceschanged

1
2
3
4
5
6
7
8
function populateVoices() {
voices = this.getVoices()
let lanlist = voices.map((lan) => {
return `<option value="${lan.name}">${lan.name} (${lan.lang})</option>`
})
voicesDropdown.innerHTML = lanlist.join('')
}
speechSynthesis.addEventListener('voiceschanged', populateVoices)

透過getVoices()方法取得語言資料,可以console.log看看

並將資料渲染到html上

設定語言

當我們選擇語言時,也就是onchange時,
我們要將語言設定到msg物件的voice值裡面,
我們可以console.log(msg)看看SpeechSynthesisUtterance長什麼樣子:

裡面有很多值我們要設定進去。

1
2
3
4
5
6
7
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
console.log(msg)
//speechSynthesis.cancel();
//speechSynthesis.speak(msg);
}
voicesDropdown.addEventListener('change', setVoice);

注意:這邊的voice不能直接給他名稱msg.voice = this.value
this.value是字串,正確的msg.voice格式是:

這樣一整筆的傳進去給msg

設定其他值

跟設定聲音一樣

1
2
3
4
5
6
7
8
function setOption() {
msg[this.name] = this.value;
speechSynthesis.cancel();
speechSynthesis.speak(msg);
};
options.forEach(function (option) {
option.addEventListener('change', setOption);
});

當我們改變這些值的時候,看看msg變化:

越來越多資料進去了!

控制播放和暫停

所以我們要操控speechSynthesis的方法

1
2
3
4
5
6
7
8
function speak() {
speechSynthesis.speak(msg);
};
function pause() {
speechSynthesis.cancel();
};
speakButton.addEventListener('click', speak);
stopButton.addEventListener('click', pause);

我們也可以在選擇語言後就自動播放,修改一下前面的setVoice涵式

1
2
3
4
5
6
7
function setVoice(e) {
msg.voice = voices.find(voice => voice.name === this.value);
console.log(msg)
speechSynthesis.cancel(); //先暫停
speechSynthesis.speak(msg); //再播放
}
voicesDropdown.addEventListener('change', setVoice);

類似前面操作audio,先暫停再播放的概念。

注意

當畫面載入後,msg物件其實還未收到任何資料(未觸發任何change事件),
所以他不知道要講甚麼話,用甚麼語言,一開始的msg物件很多值都還是空的
避免這個問題我們可以預設先讓msg抓到text.value

1
msg.text = document.querySelector('[name="text"]').value;

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');

msg.text = document.querySelector('[name="text"]').value;

function populateVoices(e) {
voices = this.getVoices()
let lanlist = voices.map((lan) => {
return `<option value="${lan.name}">${lan.name} (${lan.lang})</option>`
})
voicesDropdown.innerHTML = lanlist.join('')
}
function setVoice(e) {
msg.voice = voices.find(voice => voice.name === this.value);

console.log(msg)
speechSynthesis.cancel();
speechSynthesis.speak(msg);
}

function setOption() {
msg[this.name] = this.value;
speechSynthesis.cancel();
speechSynthesis.speak(msg);
};

function speak() {
speechSynthesis.speak(msg);
};
function pause() {
speechSynthesis.cancel();
};

speechSynthesis.addEventListener('voiceschanged', populateVoices)
voicesDropdown.addEventListener('change', setVoice);

options.forEach(function (option) {
option.addEventListener('change', setOption);
});

speakButton.addEventListener('click', speak);
stopButton.addEventListener('click', pause);

day23day20結合,說不定就可以做一個模仿說話的機器人了!

0%