|
class tts_zhtw { |
|
constructor(){ |
|
console.log("tts constructor"); |
|
window.speechSynthesis.cancel(); //強制中斷之前的語音 |
|
this.synth = window.speechSynthesis; |
|
|
|
this.u = null; |
|
this.u = new SpeechSynthesisUtterance(); |
|
|
|
if (localStorage.getItem("ls_rate") === null) { |
|
this.u.rate = 1.2; // 語速 0.1~10 |
|
}else{ |
|
this.u.rate = Number(localStorage.getItem("ls_rate")); |
|
} |
|
|
|
if (localStorage.getItem("ls_volume") === null) { |
|
this.u.volume = 0.5; //音量 0~1 |
|
}else{ |
|
this.u.volume = Number(localStorage.getItem("ls_volume")); |
|
} |
|
|
|
if (localStorage.getItem("ls_pitch") === null) { |
|
this.u.pitch = 1; //語調 0.1~2 |
|
}else{ |
|
this.u.pitch = Number(localStorage.getItem("ls_pitch")); |
|
} |
|
|
|
|
|
this.u.onend = function(event){ |
|
//console.log(event); |
|
console.log("tts.onend"); |
|
}; |
|
|
|
this.u.onerror = function(event){ |
|
//console.log(event); |
|
console.log("tts.onerror", event); |
|
this.cancel2(); |
|
}; |
|
} |
|
|
|
speak2(textToSpeak){ |
|
//console.log(document.getElementById("ttsCheck").checked == true ? "[語音開啟]" : "[語音關閉]"); |
|
|
|
this.voices = this.synth.getVoices(); |
|
for(let index = 0; index < this.voices.length; index++) { |
|
/* |
|
"Google US English" |
|
"Google 日本語" |
|
"Google 普通话(中国大陆)" |
|
"Google 粤語(香港)" |
|
"Google 國語(臺灣)" |
|
*/ |
|
|
|
//console.log(this.voices[index].name); |
|
if(this.voices[index].name == "Google 國語(臺灣)"){ |
|
//console.log("Y"); |
|
//this.u.lang = 'zh-TW'; |
|
this.u.voice = this.voices[index]; |
|
break; |
|
}else{ |
|
//console.log("N"); |
|
this.u.lang = 'zh-TW'; |
|
} |
|
} |
|
|
|
//console.log("test"); |
|
|
|
this.u.text = this._textFilter(textToSpeak); |
|
|
|
this.u.onstart = function(event){ |
|
//console.log(event); |
|
console.log("tts.onstart", textToSpeak); |
|
}; |
|
|
|
if( (this.u.text.length > 0) || (this.u.text != null) ){ |
|
this.synth.speak(this.u); |
|
} |
|
|
|
return this; |
|
} |
|
|
|
cancel2(){ |
|
console.log("tts cancel"); |
|
window.speechSynthesis.cancel(); |
|
} |
|
|
|
volume(volume_val){ |
|
let volume = Number(volume_val); |
|
if(volume >= 0 && volume <= 1){ |
|
tts.u.volume = volume; |
|
localStorage.setItem("ls_volume", volume); |
|
console.log(`音量調整為: ${tts.u.volume}`); |
|
}else{ |
|
console.log(`超出範圍`); |
|
} |
|
} |
|
rate(rate_val){ |
|
let rate = Number(rate_val); |
|
if(rate >= 0.5 && rate <= 2){ |
|
tts.u.rate = rate; |
|
localStorage.setItem("ls_rate", rate); |
|
console.log(`語速調整為: ${tts.u.rate}`); |
|
}else{ |
|
console.log(`超出範圍`); |
|
} |
|
} |
|
pitch(pitch_val){ |
|
let pitch = Number(pitch_val); |
|
if(pitch >= 0.1 && pitch <= 2){ |
|
tts.u.pitch = pitch; |
|
localStorage.setItem("ls_pitch", pitch); |
|
console.log(`語調調整為: ${tts.u.pitch}`); |
|
}else{ |
|
console.log(`超出範圍`); |
|
} |
|
} |
|
reset(){ |
|
//localStorage.clear(); |
|
localStorage.removeItem("ls_volume"); |
|
localStorage.removeItem("ls_rate"); |
|
localStorage.removeItem("ls_pitch"); |
|
} |
|
|
|
_textFilter(msg){ |
|
msg = msg.replace(/^(1){4,}$/g, "一一一"); |
|
msg = msg.replace(/^(2){4,}$/g, "二二二"); |
|
msg = msg.replace(/^(3){4,}$/g, "三三三"); |
|
msg = msg.replace(/^(4){4,}$/g, "四四四"); |
|
msg = msg.replace(/^(5){4,}$/g, "五五五"); |
|
msg = msg.replace(/^(6){4,}$/g, "六六六"); |
|
msg = msg.replace(/^(7){4,}$/g, "七七七"); |
|
msg = msg.replace(/^(8){4,}$/g, "八八八"); |
|
msg = msg.replace(/^(9){4,}$/g, "九九九"); |
|
|
|
msg = msg.replace(/^(w){4,}$/gi, "哇拉"); |
|
msg = msg.replace(/^(~){3,}$/g, "~~~"); |
|
msg = msg.replace(/^(\.){3,}$/g, "..."); |
|
|
|
msg = msg.replace(/^484$/gi, "四八四"); |
|
msg = msg.replace(/^87$/g, "八七"); |
|
msg = msg.replace(/^94$/g, "九四"); |
|
msg = msg.replace(/^9487$/g, "九四八七"); |
|
|
|
//過濾emoji(最多3個,超過就刪除) |
|
msg = msg.replace(/(\ud83d[\ude00-\ude4f]){4,}/g, ""); |
|
|
|
return msg; |
|
} |
|
} |
|
|
|
|
|
// example |
|
|
|
var tts = new tts_zhtw(); |
|
tts.speak2("中文語音測試"); |
|
tts.speak2("第二句"); |
|
tts.speak2("第三句"); |
|
|
|
// or |
|
tts.speak2("中文語音測試").speak2("第二句").speak2("第三句"); |