音声合成でリアルタイムにしゃべってもらう話は以前しましたね。
simplestar-tech.hatenablog.com
ここで、予告通り今回はオウム返しするシステムを作ります。
マイクでしゃべったことをテキストに変換する話も以前しましたね。
simplestar-tech.hatenablog.com
ここで
これらをつなげるだけで行けました。
結果、マイクに向かってしゃべったことをCeVIOが返してくれました。
誰かと会話しているみたいで、もはや独り言ではなかった。(新感覚)
これを実現したコードを次に示します。
using UnityEngine; using System.Collections; public class RepeatBehaviour : MonoBehaviour { public CeVIOControlBehaviour CeVIOCtrl; public VoiceRecognitionBehaviour VoiceRecognition; private Queue _sentenceQueue = new Queue(); // Use this for initialization void Start () { VoiceRecognition.OnRecData += VoiceRecognition_OnRecData; } // Update is called once per frame void Update () { if (0 < _sentenceQueue.Count) { string sentence = (string)_sentenceQueue.Dequeue(); VoiceRecognition.StopRec(); Debug.Log(sentence); CeVIOCtrl.StartTalk(sentence); VoiceRecognition.StartRec(); } } void VoiceRecognition_OnRecData(string sentence) { _sentenceQueue.Enqueue(sentence); } }
VoiceRecognitionBehaviour
のイベントにハンドラを設定し
認識結果の文字列を受け取ったら、それを
CeVIOControlBehaviour
のTalk関数に渡すというものです。
無限ループに陥らないように、CeVIOがトーク中は音声認識を切っている点が工夫したところですね。
あとは既存記事をたどれば以下のコードの意味も読み解けると思います。
VoiceRecognitionBehaviour
using UnityEngine; using System.Collections; public class VoiceRecognitionBehaviour : MonoBehaviour { #region Inspector Config Vars public enum RecognitionType { Dictation, CommandControl } public RecognitionType mode = RecognitionType.Dictation; public string[] commands; private string cur_deviceName = "VF0800"; //Optional: F200 Device Name #endregion #region SenseInput Vars private PXCMSession _session; private PXCMAudioSource _source; private PXCMSpeechRecognition _sr; private PXCMSpeechRecognition.Handler _handler; private pxcmStatus _sts; #endregion #region Public Events To Subscribe public delegate void OnRecDataDelegate(string sentence); public event OnRecDataDelegate OnRecData; public delegate void OnAlertDelegate(string alertlabel); public event OnAlertDelegate OnAlertData; public delegate void OnShutDownDelegate(); public event OnShutDownDelegate OnShutdown; #endregion internal void StopRec() { _sr.StopRec(); } internal void StartRec() { _sr.StartRec(_source, _handler); } private void OnRecognition(PXCMSpeechRecognition.RecognitionData data) { if (mode == RecognitionType.CommandControl) { if (data.scores[0].confidence > 50) if (OnRecData != null) OnRecData(data.scores[0].sentence); } else { if (OnRecData != null) OnRecData(data.scores[0].sentence); } } private void OnAlert(PXCMSpeechRecognition.AlertData data) { if (OnAlertData != null) OnAlertData(data.label.ToString()); } // Use this for initialization void Start() { _SetupRecognition(); _sts = _sr.StartRec(_source, _handler); // for default device: source = null if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to Start Recognition: " + _sts); } private void _SetupRecognition() { _session = PXCMSession.CreateInstance(); if (_session == null) Debug.LogError("Failed to create a session"); _source = _session.CreateAudioSource(); _SetInputDevice(); _sts = _session.CreateImpl<PXCMSpeechRecognition>(out _sr); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to create a Speech Recognition Instance: " + _sts); _SetLanguage(); /* Set handler: OnRecognition & OnAlert */ _handler = new PXCMSpeechRecognition.Handler(); _handler.onRecognition = OnRecognition; _handler.onAlert = OnAlert; _SetRecognitionMode(); } private void _SetRecognitionMode() { switch (mode) { case RecognitionType.Dictation: _sts = _sr.SetDictation(); // Set Dictation Mode if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to set Dictation Mode: " + _sts); break; case RecognitionType.CommandControl: if (commands.Length == 0) { Debug.LogError("Grammar list is Empty"); // return; } _sts = _sr.BuildGrammarFromStringList(1, commands, null); // Build the grammar if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to Build Grammar from list: " + _sts); _sts = _sr.SetGrammar(1); // Set active grammar if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to set Grammar: " + _sts); break; } } private void _SetLanguage() { PXCMSpeechRecognition.ProfileInfo pinfo; _sts = _sr.QueryProfile(out pinfo); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to retrieve a Speech Recognition Profile: " + _sts); pinfo.language = PXCMSpeechRecognition.LanguageType.LANGUAGE_JP_JAPANESE; _sr.SetProfile(pinfo); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to set language Profile: " + _sts); } private void _SetInputDevice() { _source.ScanDevices(); bool isDeviceSet = false; PXCMAudioSource.DeviceInfo dinfo = null; int deviceNum = _source.QueryDeviceNum(); Debug.Log("Found " + deviceNum + " input devices."); for (int d = 0; d < deviceNum; d++) { _sts = _source.QueryDeviceInfo(d, out dinfo); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) continue; if (dinfo.name.Contains(cur_deviceName)) { _sts = _source.SetDevice(dinfo); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) { Debug.LogError("Failed to Set Device: " + _sts); } else { isDeviceSet = true; Debug.Log("Selected F200 Input: " + dinfo.name); } break; } } /* If F200 not found select last found Input device */ if (!isDeviceSet) { _sts = _source.SetDevice(dinfo); if (_sts < pxcmStatus.PXCM_STATUS_NO_ERROR) Debug.LogError("Failed to Set Device: " + _sts); else Debug.Log("Selected: " + dinfo.name); } } // Use this for Cleap Up void OnDisable() { /* Inform Subscribers */ if (OnShutdown != null) OnShutdown(); /* Stop the session */ if (_sr != null) { // Stop recognition _sr.StopRec(); // Destroy the Speech Recognition Instance _sr.Dispose(); } /* Destroy the session */ if (_session != null) _session.Dispose(); } }
CeVIOControlBehaviour
using UnityEngine; using System.Collections; using System.Diagnostics; public class CeVIOControlBehaviour : MonoBehaviour { private Process _process; public void StartTalk(string text) { if (null == _process) { _process = new Process(); _process.StartInfo.FileName = Application.dataPath + "/External/CeVIOCtrl.exe"; _process.StartInfo.Arguments = text; // for Redirect { _process.StartInfo.CreateNoWindow = true; _process.StartInfo.UseShellExecute = false; _process.StartInfo.RedirectStandardOutput = true; } // for ExitEvent { _process.EnableRaisingEvents = true; _process.Exited += Process_Exited; } _process.Start(); _process.WaitForExit(); } } public void ExitTalk() { if (null != _process) { if (!_process.HasExited) { _process.CloseMainWindow(); _process.Dispose(); _process = null; } } } // Use this for initialization void Start () { _process = null; } // Update is called once per frame void Update() { } void Process_Exited(object sender, System.EventArgs e) { _process.Dispose(); _process = null; } }
さて、動作を確認するには
CeVIO4.0のインストールと
RealsenseSDK 関連のアセットを取得してUnityにインポートする必要があります。
それ以外のものをアップしておきます。
上記で示したものと同一のサンプルです。
http://file.blenderbluelog.anime-movie.net/Echo.zip