承接上篇語音合成,本文完成 SAPI 5.1 另一大核心能力:語音辨識 (Speech Recognition, SR)。透過 SpSharedRecoContext(共享辨識上下文)與 ISpeechRecoGrammar(口語文法),實現中文口述輸入文字,支援啟動/停止、事件驅動結果回呼、UI 執行緒安全更新。
using System;
using System.Windows.Forms;
using SpeechLib;
public class SpeechRecognizer
{
private static SpeechRecognizer _instance;
private SpSharedRecoContextClass _recoContext;
private ISpeechRecoGrammar _grammar;
private Control _displayControl; // 結果顯示目標控制項
private SpeechRecognizer() {
_recoContext = new SpSharedRecoContextClass();
_grammar = _recoContext.CreateGrammar(1); // 文法 ID
// 訂閱辨識事件
_ISpeechRecoContextEvents_RecognitionEventHandler handler =
new _ISpeechRecoContextEvents_RecognitionEventHandler(OnRecognition);
_recoContext.Recognition += handler;
}
public static SpeechRecognizer Instance {
get {
if (_instance == null) _instance = new SpeechRecognizer();
return _instance;
}
}
// 開始聽寫模式
public void StartDictation(Control displayControl) {
_displayControl = displayControl;
_grammar.DictationSetState(SpeechRuleState.SGDSActive);
}
// 停止辨識
public void StopDictation() {
_grammar.DictationSetState(SpeechRuleState.SGDSInactive);
}
// 辨識事件回呼(在 SAPI 工作執行緒觸發)
private void OnRecognition(
int streamNumber,
object streamPosition,
SpeechRecognitionType recognitionType,
ISpeechRecoResult result)
{
string text = result.PhraseInfo.GetText(0, -1, true); // 取得辨識文字
// 跨執行緒更新 UI:使用 Control.Invoke
if (_displayControl != null && _displayControl.InvokeRequired) {
_displayControl.Invoke(new Action(() => {
_displayControl.Text += text + " ";
}));
} else if (_displayControl != null) {
_displayControl.Text += text + " ";
}
}
}
public partial class MainForm : Form {
private SpeechRecognizer _recognizer;
public MainForm() {
InitializeComponent();
_recognizer = SpeechRecognizer.Instance;
}
private void btnStart_Click(object sender, EventArgs e) {
_recognizer.StartDictation(txtResult); // txtResult 為 TextBox
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e) {
_recognizer.StopDictation();
btnStart.Enabled = true;
btnStop.Enabled = false;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
_recognizer.StopDictation();
base.OnFormClosing(e);
}
}
SpSharedRecoContextClass 連接系統共享辨識器(任務列語音列),無需獨佔音訊裝置,適合桌面應用DictationSetState(SGDSActive) 載入系統內建大詞彙統計語言模型,支援自由語句辨識;相對的是命令與控制文法(CFG/GRXML),限定詞彙、準確率高Recognition 事件在 SAPI 內部執行緒觸發 → 必須用 Control.Invoke/BeginInvoke 回 UI 執行緒,否則跨執行緒操作 UI 會拋例外或行為未定義ISpeechRecoResult 包含 PhraseInfo(辨識片語)、Alternates(備選結果)、Audio(原始音訊)等豐富資訊自由聽寫錯誤率較高。若應用場景為固定指令(如「開啟檔案」、「儲存」、「列印」),應使用 XML 文法 (GRXML):
// 定義 commands.grxml
- 開啟檔案
- 儲存檔案
- 列印文件
- 結束程式
// 載入文法
_grammar.CmdLoadFromFile("commands.grxml", SpeechLoadOption.SLOStatic);
_grammar.CmdSetRuleState("commands", 0, SpeechRuleState.SGDSActive);
此模式辨識準確率大幅提升,適合語音控制類應用。
| 現象 | 可能原因 | 對策 |
|---|---|---|
| 無反應/不觸發事件 | 麥克風未設為預設錄音裝置、隱私權限未開啟 | 控制台→聲音→錄音 設定預設;Win10 設定→隱私權→麥克風 允許應用存取 |
| 辨識為亂碼/英文 | 語言模型未安裝或非中文環境 | 確認安裝 Speech SDK 5.1 Language Pack (Chinese Simplified);系統地區語言設為中文 |
| CPU 佔用高 | 共享辨識器持續運作 | 不使用時呼叫 StopDictation();或改用 InProcRecognizer (獨佔模式) 按需啟動 |
| Invoke 例外 | 表單關閉後事件仍觸發 | FormClosing 時 StopDictation() 並取消訂閱事件 |
| 特性 | SAPI 5.1 (COM) | System.Speech (Managed) | Azure Speech SDK |
|---|---|---|---|
| 平台 | Windows Only | Windows Only | 跨平台 (Win/Linux/Mac/iOS/Android) |
| 中文支援 | 需 Language Pack | 內建 (Win7+) | 雲端高精度,支援方言/領域適應 |
| 部署 | 需安裝 SDK | .NET 3.0+ 內建 | NuGet 套件,需網路/金鑰 |
| 離線辨識 | 是 | 是 | 否 (需混合模式) |
| 授權成本 | 免費 | 免費 | 按使用量付費 |
SAPI 5.1 提供了完整的 COM 級語音辨識能力。本文實現的 SpeechRecognizer 類別展示了核心模式:共享上下文 + 聽寫文法 + 事件回呼 + 跨執行緒 UI 更新。理解 文法類型選擇(聽寫 vs 命令控制)、音訊裝置配置、執行緒邊界處理 是落地關鍵。現代新專案建議優先評估 System.Speech.Recognition (Managed Wrapper) 或 Azure Speech SDK,但 SAPI 5.1 互操作技術在維護舊系統、特定嵌入式 Windows 環境仍具不可替代價值。