Skip to content

Instantly share code, notes, and snippets.

@mouyong
Forked from Eotones/README.md
Created October 9, 2020 04:51
Show Gist options
  • Save mouyong/3e4fa6f2361594f78463d3af266fdc79 to your computer and use it in GitHub Desktop.
Save mouyong/3e4fa6f2361594f78463d3af266fdc79 to your computer and use it in GitHub Desktop.

Revisions

  1. @Eotones Eotones revised this gist Aug 1, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -20,6 +20,7 @@ speak("你要讀出的中文內容2");
    但是這種寫法在系統有支援多種語音的情況下只會選擇系統預設語音

    * win7繁中 - 無支援中文語音
    * 2020/8月補充: 現在win7繁中版可以去載Chromium版的Edge來使用微軟中文語音
    * win7簡中 - 有支援微軟中文語音(系統預設)
    * win10 - 簡繁中都有支援微軟中文語音(系統預設)

  2. @Eotones Eotones revised this gist Jun 28, 2020. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -68,11 +68,12 @@ class tts2 {

    //console.log("test");

    u.text = this._textFilter(textToSpeak);
    let filter_text = this._textFilter(textToSpeak);
    u.text = filter_text;

    u.onstart = function(event){
    u.onstart = (event) => {
    //console.log(event);
    console.log("tts.onstart", textToSpeak);
    console.log("tts.onstart", filter_text);
    };

    if( (u.text.length > 0) || (u.text != null) ){
  3. @Eotones Eotones revised this gist Jun 28, 2020. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -32,12 +32,12 @@ class tts2 {
    u.volume = this.u_volume;
    u.pitch = this.u_pitch;

    u.onend = function(event){
    u.onend = (event) => {
    //console.log(event);
    console.log("tts.onend");
    };

    u.onerror = function(event){
    u.onerror = (event) => {
    //console.log(event);
    console.log("tts.onerror", event);
    this.cancel2();
    @@ -132,6 +132,9 @@ class tts2 {
    }

    _textFilter(msg){
    //網址不唸
    msg = msg.replace(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g, "網址");

    msg = msg.replace(/^(1){4,}$/g, "一一一");
    msg = msg.replace(/^(2){4,}$/g, "二二二");
    msg = msg.replace(/^(3){4,}$/g, "三三三");
  4. @Eotones Eotones revised this gist May 21, 2020. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -97,6 +97,7 @@ class tts2 {
    console.log(`超出範圍`);
    }
    }

    rate(rate_val){
    let rate = Number(rate_val);
    if(rate >= 0.5 && rate <= 2){
    @@ -107,6 +108,7 @@ class tts2 {
    console.log(`超出範圍`);
    }
    }

    pitch(pitch_val){
    let pitch = Number(pitch_val);
    if(pitch >= 0.1 && pitch <= 2){
    @@ -117,6 +119,7 @@ class tts2 {
    console.log(`超出範圍`);
    }
    }

    reset(){
    //localStorage.clear();
    localStorage.removeItem("ls_volume");
    @@ -157,8 +160,7 @@ class tts2 {

    //

    var tts = new tts2();
    //tts2.init();
    const tts = new tts2();
    /*
    tts
    .speak2("大家看到我,就知道我是誰了,我就是歐付寶終結者RRRRRRRRRRRRRRRRRRRRR")
  5. @Eotones Eotones revised this gist May 21, 2020. 2 changed files with 58 additions and 47 deletions.
    104 changes: 58 additions & 46 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -5,11 +5,17 @@
    像是這樣就能切換成中文語音:

    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
    u.lang = 'zh-TW';
    u.text = "你要讀出的中文內容";
    synth.speak(u);
    const synth = window.speechSynthesis;

    const speak = (msg) => {
    let u = new SpeechSynthesisUtterance();
    u.lang = 'zh-TW';
    u.text = msg;
    synth.speak(u);
    };

    speak("你要讀出的中文內容1");
    speak("你要讀出的中文內容2");
    ```
    但是這種寫法在系統有支援多種語音的情況下只會選擇系統預設語音

    @@ -22,49 +28,55 @@ synth.speak(u);
    就要另外再寫

    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
    //u.lang = 'zh-TW'; //這句絕對不要用
    u.text = "你要讀出的中文內容";

    // 用 synth.getVoices() 取得支援的語音列表
    // 要注意網頁開啟後首次執行 window.speechSynthesis 後才會把語音功能載入
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測
    // (這個事件在載入過程會被觸發多次,很難用,他是偵測changed不是偵測完全載入完成,
    // 但這是window.speechSynthesis裡唯一的一個事件偵測,沒其他選擇)
    // var voices;
    // window.speechSynthesis.onvoiceschanged = function() {
    // voices = synth.getVoices();
    // // 注意 speak() 不要直接寫在這裡,不然會被重覆觸發多次
    // };
    var voices = synth.getVoices();

    for(let index = 0; index < voices.length; index++) {
    /*
    "Google US English"
    "Google 日本語"
    "Google 普通话(中国大陆)"
    "Google 粤語(香港)"
    "Google 國語(臺灣)"
    */

    //console.log(this.voices[index].name);
    if(voices[index].name == "Google 國語(臺灣)"){
    //u.lang = 'zh-TW'; //這句絕對不要用
    //要使用Google中文語音的話請不要再用u.lang指定語言
    //不然可能又會被切回系統預設的中文語音
    u.voice = voices[index];
    break;
    }else{
    //如果沒有則使用預設中文語音
    u.lang = 'zh-TW';
    const synth = window.speechSynthesis;

    const speak = (msg) => {
    let u = new SpeechSynthesisUtterance();
    //u.lang = 'zh-TW'; //這句絕對不要用
    u.text = msg;

    // 用 synth.getVoices() 取得支援的語音列表
    // 要注意網頁開啟後首次執行 window.speechSynthesis 後才會把語音功能載入
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測
    // (這個事件在載入過程會被觸發多次,很難用,他是偵測changed不是偵測完全載入完成,
    // 但這是window.speechSynthesis裡唯一的一個事件偵測,沒其他選擇)
    // var voices;
    // window.speechSynthesis.onvoiceschanged = function() {
    // voices = synth.getVoices();
    // // 注意 speak() 不要直接寫在這裡,不然會被重覆觸發多次
    // };
    let voices = synth.getVoices();

    for(let index = 0; index < voices.length; index++) {
    /*
    "Google US English"
    "Google 日本語"
    "Google 普通话(中国大陆)"
    "Google 粤語(香港)"
    "Google 國語(臺灣)"
    */

    //console.log(this.voices[index].name);
    if(voices[index].name == "Google 國語(臺灣)"){
    //u.lang = 'zh-TW'; //這句絕對不要用
    //要使用Google中文語音的話請不要再用u.lang指定語言
    //不然可能又會被切回系統預設的中文語音
    u.voice = voices[index];
    break;
    }else{
    //如果沒有則使用預設中文語音
    u.lang = 'zh-TW';
    }
    }
    }

    synth.speak(u);
    synth.speak(u);
    };

    speak("你要讀出的中文內容1");
    speak("你要讀出的中文內容2");
    ```

    ## 參考資料
    1 change: 0 additions & 1 deletion tts.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,6 @@ class tts2 {
    console.log("tts constructor");
    window.speechSynthesis.cancel(); //強制中斷之前的語音
    this.synth = window.speechSynthesis;
    this.v_index = 0;

    //

  6. @Eotones Eotones revised this gist May 21, 2020. 1 changed file with 54 additions and 43 deletions.
    97 changes: 54 additions & 43 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -1,48 +1,52 @@
    class tts_zhtw {
    class tts2 {
    constructor(){
    console.log("tts constructor");
    window.speechSynthesis.cancel(); //強制中斷之前的語音
    this.synth = window.speechSynthesis;

    this.u = null;
    this.u = new SpeechSynthesisUtterance();
    this.v_index = 0;

    //

    if (localStorage.getItem("ls_rate") === null) {
    this.u.rate = 1.2; // 語速 0.1~10
    this.u_rate = 1.2; // 語速 0.1~10
    }else{
    this.u.rate = Number(localStorage.getItem("ls_rate"));
    this.u_rate = Number(localStorage.getItem("ls_rate"));
    }

    if (localStorage.getItem("ls_volume") === null) {
    this.u.volume = 0.5; //音量 0~1
    this.u_volume = 0.5; //音量 0~1
    }else{
    this.u.volume = Number(localStorage.getItem("ls_volume"));
    this.u_volume = Number(localStorage.getItem("ls_volume"));
    }

    if (localStorage.getItem("ls_pitch") === null) {
    this.u.pitch = 1; //語調 0.1~2
    this.u_pitch = 1; //語調 0.1~2
    }else{
    this.u.pitch = Number(localStorage.getItem("ls_pitch"));
    this.u_pitch = Number(localStorage.getItem("ls_pitch"));
    }
    }

    speak2(textToSpeak){
    let u = new SpeechSynthesisUtterance();

    u.rate = this.u_rate;
    u.volume = this.u_volume;
    u.pitch = this.u_pitch;

    this.u.onend = function(event){
    u.onend = function(event){
    //console.log(event);
    console.log("tts.onend");
    };

    this.u.onerror = function(event){
    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++) {
    //
    let voices = this.synth.getVoices();
    for(let index = 0; index < voices.length; index++) {
    /*
    "Google US English"
    "Google 日本語"
    @@ -51,29 +55,29 @@ class tts_zhtw {
    "Google 國語(臺灣)"
    */

    //console.log(this.voices[index].name);
    if(this.voices[index].name == "Google 國語(臺灣)"){
    //console.log(voices[index].name);
    if(voices[index].name == "Google 國語(臺灣)"){
    //console.log("Y");
    //this.u.lang = 'zh-TW';
    this.u.voice = this.voices[index];
    //u.lang = 'zh-TW';
    u.voice = voices[index];
    break;
    }else{
    //console.log("N");
    this.u.lang = 'zh-TW';
    u.lang = 'zh-TW';
    }
    }

    //console.log("test");

    this.u.text = this._textFilter(textToSpeak);
    u.text = this._textFilter(textToSpeak);

    this.u.onstart = function(event){
    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);
    if( (u.text.length > 0) || (u.text != null) ){
    this.synth.speak(u);
    }

    return this;
    @@ -87,29 +91,29 @@ class tts_zhtw {
    volume(volume_val){
    let volume = Number(volume_val);
    if(volume >= 0 && volume <= 1){
    tts.u.volume = volume;
    this.u_volume = volume;
    localStorage.setItem("ls_volume", volume);
    console.log(`音量調整為: ${tts.u.volume}`);
    console.log(`音量調整為: ${this.u_volume}`);
    }else{
    console.log(`超出範圍`);
    }
    }
    rate(rate_val){
    let rate = Number(rate_val);
    if(rate >= 0.5 && rate <= 2){
    tts.u.rate = rate;
    this.u_rate = rate;
    localStorage.setItem("ls_rate", rate);
    console.log(`語速調整為: ${tts.u.rate}`);
    console.log(`語速調整為: ${this.u_rate}`);
    }else{
    console.log(`超出範圍`);
    }
    }
    pitch(pitch_val){
    let pitch = Number(pitch_val);
    if(pitch >= 0.1 && pitch <= 2){
    tts.u.pitch = pitch;
    this.u_pitch = pitch;
    localStorage.setItem("ls_pitch", pitch);
    console.log(`語調調整為: ${tts.u.pitch}`);
    console.log(`語調調整為: ${this.u_pitch}`);
    }else{
    console.log(`超出範圍`);
    }
    @@ -119,6 +123,10 @@ class tts_zhtw {
    localStorage.removeItem("ls_volume");
    localStorage.removeItem("ls_rate");
    localStorage.removeItem("ls_pitch");

    this.u_rate = 1.2; // 語速 0.1~10
    this.u_volume = 0.5; //音量 0~1
    this.u_pitch = 1; //語調 0.1~2
    }

    _textFilter(msg){
    @@ -148,13 +156,16 @@ class tts_zhtw {
    }
    }


    // example

    var tts = new tts_zhtw();
    tts.speak2("中文語音測試");
    tts.speak2("第二句");
    tts.speak2("第三句");

    // or
    tts.speak2("中文語音測試").speak2("第二句").speak2("第三句");
    //

    var tts = new tts2();
    //tts2.init();
    /*
    tts
    .speak2("大家看到我,就知道我是誰了,我就是歐付寶終結者RRRRRRRRRRRRRRRRRRRRR")
    .speak2("測試1")
    .speak2("測試2")
    .speak2("測試3")
    .speak2("測試4")
    .speak2("測試5");
    */
  7. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -78,4 +78,4 @@ synth.speak(u);
    * window.speechSynthesis.onvoiceschanged
    * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
    * 列出瀏覽器有支援哪些語音和測試語音的小工具
      * [Speech synthesiser](https://mdn.github.io/web-speech-api/speak-easy-synthesis/)
    * [Speech synthesiser](https://mdn.github.io/web-speech-api/speak-easy-synthesis/)
  8. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -76,4 +76,6 @@ synth.speak(u);
    * SpeechSynthesisUtterance
    * [SpeechSynthesisUtterance - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance)
    * window.speechSynthesis.onvoiceschanged
    * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
    * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
    * 列出瀏覽器有支援哪些語音和測試語音的小工具
      * [Speech synthesiser](https://mdn.github.io/web-speech-api/speak-easy-synthesis/)
  9. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -69,7 +69,7 @@ synth.speak(u);

    ## 參考資料

    **SpeechSynthesis**是瀏覽器內原生的語音功能,詳細用法可以看以下MDN的教學文件
    **window.speechSynthesis**是瀏覽器內原生的語音功能,詳細用法可以看以下MDN的教學文件

    * window.speechSynthesis
    * [SpeechSynthesis - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
  10. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -69,7 +69,7 @@ synth.speak(u);

    ## 參考資料

    SpeechSynthesis是瀏覽器內原生的語音功能,詳細用法可以看以下MDN的教學文件
    **SpeechSynthesis**是瀏覽器內原生的語音功能,詳細用法可以看以下MDN的教學文件

    * window.speechSynthesis
    * [SpeechSynthesis - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
  11. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -68,6 +68,9 @@ synth.speak(u);
    ```

    ## 參考資料

    SpeechSynthesis是瀏覽器內原生的語音功能,詳細用法可以看以下MDN的教學文件

    * window.speechSynthesis
    * [SpeechSynthesis - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
    * SpeechSynthesisUtterance
  12. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,9 @@ u.text = "你要讀出的中文內容";
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,很難用)
    // 或是使用下面的事件偵測
    // (這個事件在載入過程會被觸發多次,很難用,他是偵測changed不是偵測完全載入完成,
    // 但這是window.speechSynthesis裡唯一的一個事件偵測,沒其他選擇)
    // var voices;
    // window.speechSynthesis.onvoiceschanged = function() {
    // voices = synth.getVoices();
  13. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    # speechSynthesis強制使用Chrome中的Google小姐中文語音

    網路上的`window.speechSynthesis`教學主要都只有說切換指定語言

    像是這樣就能切換成中文語音:
  14. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -69,4 +69,4 @@ synth.speak(u);
    * SpeechSynthesisUtterance
    * [SpeechSynthesisUtterance - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance)
    * window.speechSynthesis.onvoiceschanged
      * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
    * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
  15. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -63,4 +63,10 @@ for(let index = 0; index < voices.length; index++) {
    synth.speak(u);
    ```

    Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`的討論: https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
    ## 參考資料
    * window.speechSynthesis
    * [SpeechSynthesis - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
    * SpeechSynthesisUtterance
    * [SpeechSynthesisUtterance - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance)
    * window.speechSynthesis.onvoiceschanged
      * Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`[討論](https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
  16. @Eotones Eotones revised this gist Apr 27, 2018. No changes.
  17. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion tts.js
    Original file line number Diff line number Diff line change
    @@ -154,4 +154,7 @@ class tts_zhtw {
    var tts = new tts_zhtw();
    tts.speak2("中文語音測試");
    tts.speak2("第二句");
    tts.speak2("第三句");
    tts.speak2("第三句");

    // or
    tts.speak2("中文語音測試").speak2("第二句").speak2("第三句");
  18. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -61,4 +61,6 @@ for(let index = 0; index < voices.length; index++) {
    }

    synth.speak(u);
    ```
    ```

    Stack Overflow上關於`window.speechSynthesis.onvoiceschanged`的討論: https://stackoverflow.com/questions/21513706/getting-the-list-of-voices-in-speechsynthesis-of-chrome-web-speech-api?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
  19. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -34,6 +34,7 @@ u.text = "你要讀出的中文內容";
    // var voices;
    // window.speechSynthesis.onvoiceschanged = function() {
    // voices = synth.getVoices();
    // // 注意 speak() 不要直接寫在這裡,不然會被重覆觸發多次
    // };
    var voices = synth.getVoices();

  20. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -30,9 +30,10 @@ u.text = "你要讀出的中文內容";
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,不太好用)
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,很難用)
    // var voices;
    // window.speechSynthesis.onvoiceschanged = function() {
    // window.speechSynthesis.getVoices();
    // voices = synth.getVoices();
    // };
    var voices = synth.getVoices();

  21. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -30,8 +30,10 @@ u.text = "你要讀出的中文內容";
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,不好用)
    // window.speechSynthesis.onvoiceschanged
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,不太好用)
    // window.speechSynthesis.onvoiceschanged = function() {
    // window.speechSynthesis.getVoices();
    // };
    var voices = synth.getVoices();

    for(let index = 0; index < voices.length; index++) {
  22. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ u.text = "你要讀出的中文內容";
    // 用 synth.getVoices() 取得支援的語音列表
    // 要注意網頁開啟後首次執行 window.speechSynthesis 後才會把語音功能載入
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要延遲 synth.getVoices(); 的執行時間
    // 所以要想辦法延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,不好用)
    // window.speechSynthesis.onvoiceschanged
  23. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ synth.speak(u);
    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
    u.lang = 'zh-TW';
    //u.lang = 'zh-TW'; //這句絕對不要用
    u.text = "你要讀出的中文內容";

    // 用 synth.getVoices() 取得支援的語音列表
  24. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    網路上的`window.speechSynthesis`教學主要都只有說切換指定語言
    像是這樣就能切換成中文語音

    像是這樣就能切換成中文語音:

    ```javascript
    var synth = window.speechSynthesis;
    @@ -15,7 +16,9 @@ synth.speak(u);
    * win10 - 簡繁中都有支援微軟中文語音(系統預設)

    如果想要切換成其他語音(例如Chrome才有的Google中文語音)

    就要另外再寫

    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
  25. @Eotones Eotones revised this gist Apr 27, 2018. 2 changed files with 60 additions and 1 deletion.
    57 changes: 57 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    網路上的`window.speechSynthesis`教學主要都只有說切換指定語言
    像是這樣就能切換成中文語音

    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
    u.lang = 'zh-TW';
    u.text = "你要讀出的中文內容";
    synth.speak(u);
    ```
    但是這種寫法在系統有支援多種語音的情況下只會選擇系統預設語音

    * win7繁中 - 無支援中文語音
    * win7簡中 - 有支援微軟中文語音(系統預設)
    * win10 - 簡繁中都有支援微軟中文語音(系統預設)

    如果想要切換成其他語音(例如Chrome才有的Google中文語音)
    就要另外再寫
    ```javascript
    var synth = window.speechSynthesis;
    var u = new SpeechSynthesisUtterance();
    u.lang = 'zh-TW';
    u.text = "你要讀出的中文內容";

    // 用 synth.getVoices() 取得支援的語音列表
    // 要注意網頁開啟後首次執行 window.speechSynthesis 後才會把語音功能載入
    // 大概要花幾秒鐘的時間才能完全載入,再來才能正確取得語音列表
    // 所以要延遲 synth.getVoices(); 的執行時間
    //
    // 或是使用下面的事件偵測(這個事件在載入過程會被觸發多次,不好用)
    // window.speechSynthesis.onvoiceschanged
    var voices = synth.getVoices();

    for(let index = 0; index < voices.length; index++) {
    /*
    "Google US English"
    "Google 日本語"
    "Google 普通话(中国大陆)"
    "Google 粤語(香港)"
    "Google 國語(臺灣)"
    */

    //console.log(this.voices[index].name);
    if(voices[index].name == "Google 國語(臺灣)"){
    //u.lang = 'zh-TW'; //這句絕對不要用
    //要使用Google中文語音的話請不要再用u.lang指定語言
    //不然可能又會被切回系統預設的中文語音
    u.voice = voices[index];
    break;
    }else{
    //如果沒有則使用預設中文語音
    u.lang = 'zh-TW';
    }
    }

    synth.speak(u);
    ```
    4 changes: 3 additions & 1 deletion tts.js
    Original file line number Diff line number Diff line change
    @@ -152,4 +152,6 @@ class tts_zhtw {
    // example

    var tts = new tts_zhtw();
    tts.speak2("中文語音測試");
    tts.speak2("中文語音測試");
    tts.speak2("第二句");
    tts.speak2("第三句");
  26. @Eotones Eotones revised this gist Apr 27, 2018. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -40,7 +40,6 @@ class tts_zhtw {

    speak2(textToSpeak){
    //console.log(document.getElementById("ttsCheck").checked == true ? "[語音開啟]" : "[語音關閉]");
    let that = this;

    this.voices = this.synth.getVoices();
    for(let index = 0; index < this.voices.length; index++) {
    @@ -66,14 +65,14 @@ class tts_zhtw {

    //console.log("test");

    this.u.text = that._textFilter(textToSpeak);
    this.u.text = this._textFilter(textToSpeak);

    this.u.onstart = function(event){
    //console.log(event);
    console.log("tts.onstart", textToSpeak);
    };

    if( (that.u.text.length > 0) || (this.u.text != null) ){
    if( (this.u.text.length > 0) || (this.u.text != null) ){
    this.synth.speak(this.u);
    }

  27. @Eotones Eotones created this gist Apr 27, 2018.
    156 changes: 156 additions & 0 deletions tts.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,156 @@
    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 ? "[語音開啟]" : "[語音關閉]");
    let that = this;

    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 = that._textFilter(textToSpeak);

    this.u.onstart = function(event){
    //console.log(event);
    console.log("tts.onstart", textToSpeak);
    };

    if( (that.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("中文語音測試");