.NET 提供兩套語音 API:System.Speech (傳統桌面、SAPI 5.x 封裝) 與 Windows.Media.SpeechSynthesis/SpeechRecognition (UWP/WinUI 3、現代語音平台)。本文涵蓋兩套 API 的語音合成 (TTS)、語音辨識 (SR)、中英文混合處理、SSML 標記、離線/線上模式切換。
using System.Speech.Synthesis;
public class SpeechSynthesizerWrapper : IDisposable
{
private readonly SpeechSynthesizer _synth = new();
public SpeechSynthesizerWrapper()
{
// 列出已安裝語音
foreach (var voice in _synth.GetInstalledVoices())
{
Console.WriteLine($"Voice: {voice.VoiceInfo.Name}, Culture: {voice.VoiceInfo.Culture}, Gender: {voice.VoiceInfo.Gender}");
}
}
public void SetVoice(string cultureName = "zh-TW")
{
_synth.SelectVoiceByHints(VoiceGender.NotSet, VoiceAge.NotSet, 0, new System.Globalization.CultureInfo(cultureName));
}
public void Speak(string text) => _synth.Speak(text); // 同步
public void SpeakAsync(string text) => _synth.SpeakAsync(text); // 非同步
// SSML 輸出 (支援中文標點、停頓、音調)
public void SpeakSsml(string ssml)
{
var prompt = new PromptBuilder();
prompt.AppendSsmlMarkup(ssml);
_synth.Speak(prompt);
}
public void Dispose() => _synth.Dispose();
}
// 使用範例
var tts = new SpeechSynthesizerWrapper();
tts.SetVoice("zh-TW"); // 需安裝 Microsoft Tracy (zh-TW) 或 Hanhan (zh-CN)
tts.Speak("你好,歡迎使用 C# 語音合成。");
// SSML 範例
tts.SpeakSsml(@"
這是 中文測試。
語速較慢、音調較高 。
English: Hello World .
");
using System.Speech.Recognition;
public class SpeechRecognizerWrapper : IDisposable
{
private readonly SpeechRecognitionEngine _recognizer;
public SpeechRecognizerWrapper(string culture = "zh-TW")
{
_recognizer = new SpeechRecognitionEngine(new System.Globalization.CultureInfo(culture));
_recognizer.SetInputToDefaultAudioDevice(); // 使用預設麥克風
// 建立文法:指令模式
var commands = new Choices("開啟", "關閉", "設定", "離開");
var gb = new GrammarBuilder { Culture = _recognizer.RecognizerInfo.Culture };
gb.Append(commands);
var grammar = new Grammar(gb);
_recognizer.LoadGrammar(grammar);
// 也可載入系統口述文法 (免費語音輸入)
// _recognizer.LoadGrammar(new DictationGrammar());
_recognizer.SpeechRecognized += OnSpeechRecognized;
_recognizer.RecognizeCompleted += OnRecognizeCompleted;
}
public void Start() => _recognizer.RecognizeAsync(RecognizeMode.Multiple);
public void Stop() => _recognizer.RecognizeAsyncStop();
private void OnSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result.Confidence > 0.7f)
{
Console.WriteLine($"辨識: {e.Result.Text} (信心度: {e.Result.Confidence:P0})");
ExecuteCommand(e.Result.Text);
}
else
{
Console.WriteLine("辨識信心度過低");
}
}
private void ExecuteCommand(string cmd)
{
switch (cmd)
{
case "開啟": Console.WriteLine("執行開啟..."); break;
case "關閉": Console.WriteLine("執行關閉..."); break;
}
}
private void OnRecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null)
Start(); // 重新啟動持續聆聽
}
public void Dispose() => _recognizer.Dispose();
}
System.Speech 單一語音引擎通常只支援單一語系。混合讀法需:
SelectVoiceByHints 切換 zh-TW / en-US
public class MixedLanguageSpeaker
{
private readonly SpeechSynthesizer _synth = new();
public void SpeakMixed(string text)
{
var segments = SplitByLanguage(text);
foreach (var (segment, culture) in segments)
{
_synth.SelectVoiceByHints(VoiceGender.NotSet, VoiceAge.NotSet, 0, culture);
_synth.Speak(segment); // 同步等待上一段結束
}
}
private List<(string Text, CultureInfo Culture)> SplitByLanguage(string text)
{
var result = new List<(string, CultureInfo)>();
var current = new System.Text.StringBuilder();
CultureInfo currentCulture = null;
foreach (char c in text)
{
var culture = IsChinese(c) ? new CultureInfo("zh-TW") : new CultureInfo("en-US");
if (currentCulture != culture && current.Length > 0)
{
result.Add((current.ToString(), currentCulture));
current.Clear();
}
currentCulture = culture;
current.Append(c);
}
if (current.Length > 0) result.Add((current.ToString(), currentCulture));
return result;
}
private bool IsChinese(char c) => c >= 0x4E00 && c <= 0x9FFF; // 簡易判斷
}
using Windows.Media.SpeechSynthesis;
using Windows.Storage.Streams;
public class ModernSpeechSynthesizer
{
private readonly SpeechSynthesizer _synth = new();
public async Task SynthesizeToStreamAsync(string text, string voiceName = null)
{
if (!string.IsNullOrEmpty(voiceName))
{
var voice = SpeechSynthesizer.AllVoices.FirstOrDefault(v => v.DisplayName.Contains(voiceName));
if (voice != null) _synth.Voice = voice;
}
return await _synth.SynthesizeTextToStreamAsync(text);
}
public async Task SpeakAsync(string text)
{
using var stream = await SynthesizeToStreamAsync(text);
var mediaElement = new MediaElement(); // 需 UI 執行緒
mediaElement.SetSource(stream, stream.ContentType);
mediaElement.Play();
await Task.Delay(TimeSpan.FromSeconds(stream.Size / 16000)); // 估算播放時間
}
// SSML 支援
public async Task SynthesizeSsmlToStreamAsync(string ssml)
{
return await _synth.SynthesizeSsmlToStreamAsync(ssml);
}
}
using Windows.Media.SpeechRecognition;
public class ModernSpeechRecognizer
{
private readonly SpeechRecognizer _recognizer;
public ModernSpeechRecognizer(string language = "zh-TW")
{
_recognizer = new SpeechRecognizer(new Windows.Globalization.Language(language));
// 限制文法:清單模式
var listConstraint = new SpeechRecognitionListConstraint(new[] { "開啟", "關閉", "設定" }, "commands");
_recognizer.Constraints.Add(listConstraint);
// 或主題文法 (網路辨識,需網路)
// _recognizer.Constraints.Add(new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario.Dictation, "dictation"));
_recognizer.ContinuousRecognitionSession.ResultGenerated += OnResultGenerated;
}
public async Task StartAsync()
{
await _recognizer.CompileConstraintsAsync();
await _recognizer.ContinuousRecognitionSession.StartAsync();
}
public async Task StopAsync() => await _recognizer.ContinuousRecognitionSession.StopAsync();
private void OnResultGenerated(SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
if (args.Result.Confidence == SpeechRecognitionConfidence.High || args.Result.Confidence == SpeechRecognitionConfidence.Medium)
{
Console.WriteLine($"辨識: {args.Result.Text}");
}
}
}
// NuGet: Microsoft.CognitiveServices.Speech
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
public class AzureSpeechService
{
private readonly SpeechConfig _config;
public AzureSpeechService(string subscriptionKey, string region)
{
_config = SpeechConfig.FromSubscription(subscriptionKey, region);
_config.SpeechSynthesisLanguage = "zh-TW";
_config.SpeechSynthesisVoiceName = "zh-TW-HsiaoChenNeural"; // 神經網路語音
}
public async Task SpeakAsync(string text)
{
using var synthesizer = new SpeechSynthesizer(_config, AudioConfig.FromDefaultSpeakerOutput());
var result = await synthesizer.SpeakTextAsync(text);
if (result.Reason != ResultReason.SynthesizingAudioCompleted)
throw new Exception($"合成失敗: {result.ErrorDetails}");
}
public async Task RecognizeAsync()
{
using var recognizer = new SpeechRecognizer(_config, AudioConfig.FromDefaultMicrophoneInput());
var result = await recognizer.RecognizeOnceAsync();
if (result.Reason == ResultReason.RecognizedSpeech)
Console.WriteLine($"辨識: {result.Text}");
}
}
| 特性 | System.Speech | Windows.Media | Azure Speech SDK |
|---|---|---|---|
| 平台 | .NET Framework / .NET Core (Windows) | UWP / WinUI 3 / Windows App SDK | 跨平台 (Windows/Linux/macOS/iOS/Android) |
| 語音品質 | 傳統 SAPI 語音 (較機械) | 現代語音 (含神經網路) | 最佳 (神經網路、可自訂語音) |
| 離線辨識 | 支援 (需安裝語言包) | 支援 (裝置端) | 需網路 (或容器部署) |
| 中文支援 | 需安裝 Microsoft 語言包 | 內建 | 完整支援 (多方言、混合) |
| SSML | 支援 (PromptBuilder) | 支援 | 完整支援 (含訊息標記) |
| 授權 | 免費 (Windows 授權) | 免費 | 依用量付費 (免費額度) |
System.Speech,注意安裝正確語言包 (zh-TW 需 Microsoft Tracy,zh-CN 需 Hanhan)Windows.Media.SpeechSynthesis/Recognition,獲得更好語音品質與 API 設計zh-TW-HsiaoChenNeural 可自然讀出英文)