前篇文章用 Balabolka 搞定自製英文單字朗讀 MP3,但老讀者們都猜到接下來會發生什麼事... 是的,C# 整合 SAPI 讓電腦講話的練習來了!

原本以為要裝什麼 SDK 或套件,沒想到 .NET 已內建,專案只需參照 System.Speech 就好。

開始前先看一下你的 Windows 裝了哪些語音以及其支援語系:

static void ListInstalledVoices()
{
    var voice = new System.Speech.Synthesis.SpeechSynthesizer();
    voice.GetInstalledVoices()
        .ToList().ForEach((v) =>
        {
            Console.WriteLine(
                v.VoiceInfo.Name + " " +
                v.VoiceInfo.Culture.DisplayName);
        });
    Console.Read();
}

在我的 Windows 10 繁體中文專業版執行結果如下:

Microsoft Hanhan Desktop 中文 (繁體,台灣)
Microsoft Zira Desktop 英文 (美國)
Microsoft Tracy Desktop 中文 (繁體,香港特別行政區)
Microsoft David Desktop 英文 (美國)

依據文件,Windows 10 2018 4 月更新有增加其他語音選項,國語部分加入了 Zhiwei(志偉?) 跟 Yating (雅婷?)。

來個最基本的應用示範,其中包含前篇文章提到的某段文字用不同語音朗讀。要加入 <voice> 標籤有兩種做法,第一種是自己組 SSML 再呼叫 SpeakSsml(),但得自己處理 XML namespace 比較繁瑣,另一種做法是使用 PromptBuilder,透過 AppendText() 加入純文字,用 AppendSsmlMarkup() 加入包含 <voice> 等標籤的 SSML 片段,最後將 PromptBuilder 當成參數交給 Speak() 執行,比拼湊 XML 省事也易讀一些。

static void SayHi()
{
    var voice = new System.Speech.Synthesis.SpeechSynthesizer();
    //美語 男聲
    voice.SelectVoice("Microsoft David Desktop");
    voice.Speak("Hi there, I am darkthread.");
    //美語 女聲
    voice.SelectVoice("Microsoft Zira Desktop");
    voice.Speak("Hi there, I am darkthread.");
    //國語
    var pb = new PromptBuilder();
    pb.StartVoice("Microsoft Hanhan Desktop");
    pb.AppendText("大家好,我是黑暗執行緒");
    //https://msdn.microsoft.com/zh-tw/library/hh378418(v=office.14).aspx
    pb.AppendSsmlMarkup("<voice name=\"Microsoft David Desktop\">darkthread</voice>");
    pb.EndVoice();
    voice.Speak(pb);
    //廣東話
    voice.SelectVoice("Microsoft Tracy Desktop");
    voice.Speak("大家好,我是黑暗執行緒");
}

PromptBuilder 除了加入 SSML 標籤,還有其他好用的控制選項,例如:

  • AppendAudio()
    插入外部聲音檔(WMA)
  • AppendBreak()
    插入停頓
  • StartParagraph()/EndParagraph()/StartSentence()/EndSentence()
    形成段落跟句子,模擬自然說話的停頓效果,使語音更逼真
  • StartVoice()/EndVoice()
    指定語音名稱,或指定語系、性別、年齡,由 SAPI 挑選適用的語音

除了前面介紹過的 <voice>,SSML 還有一些有用標籤,可做到精細調控:
(參考:Speech Synthesis Markup Language Reference)

  • emphasis
    強調,加重語氣
  • p、s
    標註段落跟句子,讓說話效果更自然逼真
  • phoneme
    可使用特殊音標指定特定字語的發音,例如指定 Zhou 要唸成「趙」
    His name is Mike <phoneme alphabet=""x-microsoft-ups"" ph=""JH AU"">Zhou</phoneme>
    參考:發音標示符號表 Phonetic Alphabet Reference
  • prosody
    指定範圍內文字的音調(pitch)、速度(rate)、音量(volume)
    Your order for <prosody pitch=""+1st"" rate=""-10%"" volume=""50""> eight books </prosody>
  • voice
    指定範圍內文字使用不同語音

想將語音輸出轉成 WAV 檔也很簡單,在 voice.Speak() 之前先加上 voice.SetOutputToWaveFile("x:\\filename.wav"),一行搞定! 如果要轉成 MP3,則需要整合第三方程式庫或直接用 lame.exe 將 .wav 檔轉 .mp3,lame.exe x:\filename.mav x:\filename.mp3,一樣一行搞定最省事。

又到了久違的呼口號時間:

SAPI 真酷! .NET 好威呀!

Inspired by Balabolka, I tried to write several lines of code to call SAPI to create my custom English vocabularies learning MP3.


Comments

# by not

您好,我想要把產生的語音檔放在iis上,讓使用者下載或是播放,不過把您的範例code放在後端程式呼叫時總是會出現 "非同步作業目前無法開始。" 的錯誤訊息 https://i.imgur.com/TitLzay.png 我想如果要把檔案存成wav後才要顯示網頁,應該是同步程式比較符合我的需求才對,可是連第一步GetInstalledVoices想看裝了哪些語音都過不去... 可以問問要如何在網頁的環境執行嗎?

# by Jeffrey

to not, 可參考Stackoverflow的這則範例,https://stackoverflow.com/a/47300962/288936

# by 阿強

網頁版這個會不會比較方便,我是沒用過。 https://responsivevoice.org/

# by Jeffrey

to 阿強,挺方便的。經實測「 948794 狂」,Chinese Female 語音的效果跟卡提諾狂新聞旁白一木一樣啊 XD 感謝分享

# by Brad

請問有甚麼辦法可以選到Yating 和Zhiwei呢? 因為我已經安裝這兩個聲音,Edge和朗讀程式都可以使用 但是GetInstalledVoices沒有出現, SelectVoice也會失敗

# by Jeffrey

to Brad, Edge跟朗讀程式可用但.NET程式找不到,會跟x64/x86有關嗎? 切換.NET平台目標試看看是否結果不同。

# by Oaww

我分享一下這幾天的心得 1.在Server 找不到語音,一般建議都改用Mircosoft.speech (其實我也不知道為什麼Orz) 2.在發行到Server 的時候IIS的application pool的辨識要改為localService,IIS才有權利執行 3.改成Microsoft.speech的時候有幾個東西要灌,請參考下面網址 https://blog.patw.me/archives/619/c-net-use-text-to-speech-in-microsoft-speech-sdk-11lai-function/ 4.在執行的時候有發現缺DLL,請參考下面網址 https://stackoverflow.com/questions/45101353/microsoft-speech-synthesis-chinese-speak-error-zh-cn-huihui 這幾個步驟讓我可以解決我的問題,希望也可以解決你的問題: D

# by 阿詹

你好,我仿照你的code執行,但只要放進voice.Speak(pb)這一句,語音會出來,但網頁就一直轉。我debug 後端程式,他的確都有跑完,但畫面就出不來,請問可能是什麼原因嗎?

Post a comment