<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jotaro</title>
    <description>The latest articles on DEV Community by Jotaro (@jotaros).</description>
    <link>https://dev.to/jotaros</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F48328%2Fd98e3f66-7268-4eac-9980-4e6f77735910.jpeg</url>
      <title>DEV Community: Jotaro</title>
      <link>https://dev.to/jotaros</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jotaros"/>
    <language>en</language>
    <item>
      <title>Unityで対話型音声認識アプリを作れるフレームワークをつくった</title>
      <dc:creator>Jotaro</dc:creator>
      <pubDate>Mon, 11 Jan 2021 21:52:21 +0000</pubDate>
      <link>https://dev.to/jotaros/unity-495n</link>
      <guid>https://dev.to/jotaros/unity-495n</guid>
      <description>&lt;p&gt;&lt;strong&gt;macOS, Windows両方で動く、Unityで対話型の音声認識アプリがすぐに作れるフレームワークを作りました。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;リポジトリへのリンク：&lt;a href="https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity"&gt;https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity&lt;/a&gt;&lt;br&gt;
Unity Package: &lt;a href="https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity/releases/tag/v1.0"&gt;https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity/releases/tag/v1.0&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  つかいかた
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;SpeechOut/SpeechIn&lt;/code&gt;を宣言し、以下のように書くだけ。&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="n"&gt;SpeechOut&lt;/span&gt; &lt;span class="n"&gt;speechOut&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SpeechOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;SpeechIn&lt;/span&gt;  &lt;span class="n"&gt;speechIn&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SpeechIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnRecognized&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nf"&gt;Dialog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Dialog&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;speechOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;speechIn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hey"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;speechOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"How are you doing?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;speechIn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"I'm fine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Nah"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I'm Sick"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  なぜつくったか
&lt;/h2&gt;

&lt;p&gt;macOS, Windowsを使う学生のために、Unityを扱う授業で音声認識を使った対話型アプリを作るためのフレームワークがあればいいなと思ったので作りました。&lt;br&gt;
主に非同期処理の&lt;code&gt;async/await&lt;/code&gt;ベースで、逐次処理をわかりやすく書けるように、また速度や”間”などのチューニングも簡単にできるようにしました。&lt;/p&gt;

&lt;p&gt;授業ではmac, Windowsそれぞれを使う学生を同様に対応しないといけないのですが、Unityそのものは双方で動作する一方、ネイティブOSの機能を使おうとすると相互にコードを共有できない＝他のチームやグループが作ったアプリを動作させられないことになるので、このようなコードを作りました。&lt;/p&gt;

&lt;p&gt;授業のためとはいえ、一般的に使いやすいツールだと思います。&lt;/p&gt;

&lt;h2&gt;
  
  
  OSネイティブの音声認識・音声合成
&lt;/h2&gt;

&lt;h3&gt;
  
  
  macOS側
&lt;/h3&gt;

&lt;p&gt;macOSネイティブのオフライン音声認識ツールとしては、&lt;code&gt;NSSpeechRecognizer&lt;/code&gt;が、音声合成ツールとしては、コマンドラインツールとして&lt;code&gt;say&lt;/code&gt;があります。このうち、&lt;code&gt;say&lt;/code&gt;に関してはUnity上の&lt;code&gt;System.Diagnostics.Process&lt;/code&gt;から呼び出すことで実行できます（この点、Argsをいじるだけで声質とか速度を変えられるのでサイコー）&lt;/p&gt;

&lt;p&gt;一方の&lt;code&gt;NSSpeechRecognizer&lt;/code&gt;はOSネイティブAPIとして提供されている機能なので、実行するためには&lt;code&gt;Objective-C&lt;/code&gt;もしくは&lt;code&gt;Swift&lt;/code&gt;で記述されたコードから実行する必要があります。&lt;/p&gt;

&lt;p&gt;今回のフレームワークでは別途&lt;a href="https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity/tree/master/NSSpeechForUnity"&gt;NSSpeechForUnity&lt;/a&gt;として、&lt;code&gt;NSSpeechRecognizer&lt;/code&gt;を呼び出す&lt;code&gt;Objective-C&lt;/code&gt;コードを書き、外部ライブラリとして&lt;code&gt;.bundle&lt;/code&gt;ファイルを書き出し、それをUnityのPluginとすることで実行しています。&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows側
&lt;/h3&gt;

&lt;p&gt;逆にWindows側では&lt;code&gt;UnityEngine.Windows.Speech&lt;/code&gt;なるモジュールがあり、音声認識に関してはUnityから直接実行できる一方、音声合成に関しては別途WindowsのネイティブAPI＝&lt;a href="https://ja.wikipedia.org/wiki/Speech_Application_Programming_Interface"&gt;SAPI&lt;/a&gt;を叩く必要がありました。コード内で別途&lt;a href="https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity/tree/master/WindowsVoiceProject"&gt;WindowsVoiceProject&lt;/a&gt;として、Visual Studioから.dllをビルドできるプロジェクトを作り、その.dllをUnityのPluginにします。&lt;/p&gt;




&lt;p&gt;以上２つのOSに関して独自にライブラリを書き出すことによって実現しましたが、Unity上で非同期の動作を実現させるため、それぞれの処理がきちんと終わったかどうかを常に監視するためのコードを書く必要があります。たとえば&lt;a href="https://github.com/HassoPlattnerInstituteHCI/SpeechIOForUnity/blob/0ac6cfe8b468f970524b6dc558d0656bf501322c/NSSpeechForUnity/NSSpeechForUnity/native.m#L75"&gt;このように&lt;/a&gt;、内部のStateを逐一変えて、Unity側から監視することで、UnityのAsync/Awaitが進行するように若干HardCodedな感じではありますが、リアルタイムアプリケーションのための非同期処理を実現しています。&lt;/p&gt;




&lt;h2&gt;
  
  
  応用
&lt;/h2&gt;

&lt;p&gt;対話型アプリケーションのためとは言いましたが、VRアプリケーションなどのための目と手が離せない際のデバッグ（イベントが起こったときにどのフラグが立ったか喋って教えてくれる）や、視覚障害者向けアプリなど、様々な用途が考えられます。「デバッグのときになにか喋ってくれたら便利だな」とか、「アクセシビリティ機能の充実したアプリを作りたいな」などというときにはぜひ使ってみてください。&lt;/p&gt;

</description>
      <category>cs</category>
      <category>unity3d</category>
      <category>speechrecognition</category>
      <category>texttospeech</category>
    </item>
  </channel>
</rss>
