前言
在之前《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:表示文字轉語音,后面緊跟着一個string
- 3:表示語音識別,后面是一個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源代碼
源代碼下載https://github.com/CodeGize/UnitySapi/
轉載聲明
轉載請保留