您的位置:首頁>正文

Unity3d在Window上使用SAPI進行語音辨識

前言

在之前《Unity利用Sapi進行windows語音開發》中, 本計畫不準備繼續做語音辨識。 因為在unity3d中已經提供了語音辨識的相關方法, 詳見unity3d的官方文檔:https://docs.unity3d.com/ScriptReference/Windows.Speech.KeywordRecognizer.html。 但是有一點是這個只支持win10。 對於win7用戶來說, 如果不使用百度語音或者科大訊飛語音的話, 那麼使用SAPI就是最好的方式了。 同樣的, 由於Unity中無法直接使用SAPI, 所以只能按照原來的思路, 把它寫到一個exe工具中, 然後再由unity3d來調用。

工程變更和重構

還是繼續之前的工程, 但是為了規範一些, 我把工程名稱從SpeechTest改為了Speech。 並且重構了Socket通信結構, 將原本的SocketExtra分為了SocketBase, SocketServer和SocketClient。 這樣做的目的就是簡單化,

並且增加SocketServer發送資訊到SocketClient的功能。

這是工程的最終結構圖

通信資料結構

由於speech加入了語音辨識功能, 所以為了區別之前的通信資訊, 重新整理定義了新的通信資料結構。 通信資料結構定為二進位資料, 前4位是一個int32型的命令碼, 這些命令碼有不同的含義和內容:

1:表示初始化, 2:表示文字轉語音, 後面緊跟著一個string3:表示語音辨識, 後面是一個int32型, 0表示結束識別, 1表示開始識別

當speech收到1時, 進行初始化。 收到2的資訊時, 讀取之後的文本資料, 然後交由Speecher來發音。 收到3時, 讀取後面的資料, 如果是1, 則開始進行錄音識別, 如果是0則停止錄音識別。

Speech代碼NetServer.cs

public bool NetReciveMsg(byte[] recivebuffer, int netID) { var arg = new ByteOutArg(recivebuffer); var cmd = arg.ReadInt32; switch ((EmCmd)cmd) { case EmCmd.Init: Init; break; case EmCmd.Speak: var str = arg.ReadString; Console.WriteLine(str); m_speecher.Speak(str); return true; case EmCmd.Recognize: var scmd = arg.ReadInt32; if (scmd == 1) m_recognizer.BeginRec; if (scmd == 0) m_recognizer.EndRec; return true; default: throw new ArgumentOutOfRangeException; } return false; }

在unity發送的代碼。 (ByteInArg是一個簡單地寫如byte[]資料的類)

/***測試代碼, 可刪除Start***/ public void OnGUI { if (GUILayout.Button("Connect")) { StartCoroutine(Connect); } if (GUILayout.Button("InitServer")) { StartCoroutine(InitServer); } if (GUILayout.Button("Speak")) { Speak("hello world"); } if (GUILayout.Button("Recognize Start")) { Recognize(true); } if (GUILayout.Button("Recognize End")) { Recognize(false); } } /***測試代碼, 可刪除End***/ private void Recognize(bool tf) { var arg = new ByteInArg; arg.Write(3); arg.Write(tf ? 1 : 0); NetSendMsg(arg.GetBuffer); } public IEnumerator Connect { m_socket = new SocketClient(this); m_socket.Connect("127.0.0.1", 9903); while (!m_socket.Connected) { yield return 1; } } public IEnumerator InitServer { var arg = new ByteInArg; arg.Write(1); NetSendMsg(arg.GetBuffer); yield return 1; } public void Speech(string str) { if (m_socket.Connected) { var arg = new ByteInArg; arg.Write(2); arg.Write(str); //var bytes = Encoding.Default.GetBytes(str); NetSendMsg(arg.GetBuffer); } }

封裝SAPI語音辨識模組

封裝SAPI的語音辨識模組這方面的代碼很多, 也比較簡單。 這裡創建的Recognizer類, 代碼更改自http://kevin19900306.iteye.com/blog/1206534, 其中的含義可以查閱SAPI的相關文檔。 Recognizer類有構造函數, 兩個介面, 一個回檔向外提供。 這兩個介面為開始識別BeginRec和停止識別EndRec, 當識別完成時, 使用回檔, 將識別的文字傳出。

在speech的NetServer.cs中, 回檔相關的代碼如下

public void Init { m_speecher = new Speecher; m_recognizer = new Recognizer { OnRecognized = OnRecognized }; Console.WriteLine("初始化完成"); } private void OnRecognized(string text) { var arg = new ByteInArg; arg.Write(text); NetSendMsg(arg.GetBuffer); }

測試

運行unity3d, 畫面中出現5個按鈕, 分別為Connect, InitServer, Speak, Recognize Start, Recognize End。 依次點擊Connect, InitServer。 然後點擊Speak, 聽到“hello world”語音。 點擊Recognize Start, 對麥克風說任何中文, 可以看到debug輸出對應的文字。 點擊Recognize End停止識別。

Github原始程式碼

轉載聲明

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示