スマフォのアプリを作りたい(26):スマフォだけで動作する音声認識②
プログラミング [2020/06/27]
前回、Juliusの導入説明をしてくれているチュートリアル文書を読んで、PC上で単語認識をさせてみるところをやって見ました。
使えそうなので、Androidスマフォ上に移植することを試行錯誤してみます。
「経過や失敗事項は要らない。旨くいく手順だけ書け。」と言われそうですが、
さるの自分のための備忘録なので、その辺りはご容赦の程。
今回の場合、React Native(JavaScript)→ Androidネイティブ(Java)→ Juliusライブラリ(C)と呼び出しが掛かりそうなので・・・
Ⅰ.まずはJavaコードからC関数を呼び出すようなアプリの作り方を調べます。
Ⅱ.Javaコード(Cライブラリ含む)をReact Nativeで使えるパッケージ化方法を調べます。
Ⅲ.React Nativeにパッケージを取り込んで、Build&Go。
こんな感じなのかな~
自信ないなー。汗)
以降、図の表示が小さくて見えない場合は、クリックすると文字が見える程度の画像で表示すると思います。
◆Android向けCプログラムのビルド環境
全くの素人です。Javaでプログラムを組んだことすらないし、AndroidStudioをIDEとして使うのも初。
なので、説明してくれているページを探します。そしたら、
参考:https://qiita.com/sanoh/items/ef0b99fc1dd2f1484d7a
タイトルもばっちし。
読みつつマネしていきます。
AndroidStudioは、React Nativeアプリの動作確認をするためのエミュレータ(AVD)の前提だったのでインストール済みです。
SDK(Android6,0/APIレベル23とAndroid4.0.3/APIレベル15)インストール済みです。
(インストール手順は「スマフォのアプリを作りたい(2):・・・」とかに書いてます。)
まずは、AndroidStudioのプロジェクトを作成するところから。
1)AndroidStudioを起動します
2)C++プロジェクトを作成します
2-1)「+ Start a new Android Studio project」をクリック
2-2)タイル風の絵の中から「C++」と書かれたものをクリックして[Next]
2-3)プロジェク名、パッケージ名、プロジェクトフォルダを入力
2-3)言語には「Java」を選択、ミニマムAPIレベルを指定して[Next]
※APIレベルは、エミュレーターの制限の23にしようか、Sound系パッケージの制限16にしようか迷ったのですが、Android6.0(23)にしました。
2-4)[finish]します。以下のような画面でした。
※ここで、OpenJDKが通信を使って何かしだしたようで、以下の警告が出ました。
何をする気なのか分かりませんが、拒否して後で何かが「古いんじゃ!」とか言われると面倒そうなので、許可しちゃいました。
参考サイトの説明だと、このテンプレートの状態でJavaからCを使うようになってるんだそうです。
JavaのコードはMainActivity.javaで、Cはnative-lib.cppのようです。
それっぽいですね。
MainActivity.javaを画面に表示してみました。
さっぱり、よくわかりません。
native-lib.cppの方はこんな内容。
これまた、短い割には何だかわかりません。
併せて見ると、
Java側がonCreateで何やらやろうとして、コード末尾の「public native String stringFromJNI();」がnative-libの中に実装されている処理のようです。
C側では何だか長たらしい名前の関数「Java_com_teburarec_call_1julius_MainActivity_stringFromJNI」として定義されてますが、ここをコールしているんでしょう。
この状態でしばらく放置していたら・・・
使えそうなので、Androidスマフォ上に移植することを試行錯誤してみます。
「経過や失敗事項は要らない。旨くいく手順だけ書け。」と言われそうですが、
さるの自分のための備忘録なので、その辺りはご容赦の程。
今回の場合、React Native(JavaScript)→ Androidネイティブ(Java)→ Juliusライブラリ(C)と呼び出しが掛かりそうなので・・・
Ⅰ.まずはJavaコードからC関数を呼び出すようなアプリの作り方を調べます。
Ⅱ.Javaコード(Cライブラリ含む)をReact Nativeで使えるパッケージ化方法を調べます。
Ⅲ.React Nativeにパッケージを取り込んで、Build&Go。
こんな感じなのかな~
自信ないなー。汗)
以降、図の表示が小さくて見えない場合は、クリックすると文字が見える程度の画像で表示すると思います。
◆Android向けCプログラムのビルド環境
全くの素人です。Javaでプログラムを組んだことすらないし、AndroidStudioをIDEとして使うのも初。
なので、説明してくれているページを探します。そしたら、
参考:https://qiita.com/sanoh/items/ef0b99fc1dd2f1484d7a
タイトルもばっちし。
読みつつマネしていきます。
AndroidStudioは、React Nativeアプリの動作確認をするためのエミュレータ(AVD)の前提だったのでインストール済みです。
SDK(Android6,0/APIレベル23とAndroid4.0.3/APIレベル15)インストール済みです。
(インストール手順は「スマフォのアプリを作りたい(2):・・・」とかに書いてます。)
まずは、AndroidStudioのプロジェクトを作成するところから。
1)AndroidStudioを起動します
2)C++プロジェクトを作成します
2-1)「+ Start a new Android Studio project」をクリック
2-2)タイル風の絵の中から「C++」と書かれたものをクリックして[Next]
2-3)プロジェク名、パッケージ名、プロジェクトフォルダを入力
2-3)言語には「Java」を選択、ミニマムAPIレベルを指定して[Next]
※APIレベルは、エミュレーターの制限の23にしようか、Sound系パッケージの制限16にしようか迷ったのですが、Android6.0(23)にしました。
2-4)[finish]します。以下のような画面でした。
※ここで、OpenJDKが通信を使って何かしだしたようで、以下の警告が出ました。
何をする気なのか分かりませんが、拒否して後で何かが「古いんじゃ!」とか言われると面倒そうなので、許可しちゃいました。
参考サイトの説明だと、このテンプレートの状態でJavaからCを使うようになってるんだそうです。
JavaのコードはMainActivity.javaで、Cはnative-lib.cppのようです。
それっぽいですね。
MainActivity.javaを画面に表示してみました。
さっぱり、よくわかりません。
native-lib.cppの方はこんな内容。
----native-lib.cpp---------------------------------
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_teburarec_call_1julius_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
---------------------------------------------------
これまた、短い割には何だかわかりません。
併せて見ると、
Java側がonCreateで何やらやろうとして、コード末尾の「public native String stringFromJNI();」がnative-libの中に実装されている処理のようです。
C側では何だか長たらしい名前の関数「Java_com_teburarec_call_1julius_MainActivity_stringFromJNI」として定義されてますが、ここをコールしているんでしょう。
この状態でしばらく放置していたら・・・
AndroidStudioの画面下部の「Sync」タブに何やらエラーのようなものが出ています。
!マークの行を選択すると、右側のスペースにメッセージ内容が表示されます。
先頭のエラーは、こんな内容。
ERROR: CMake '3.10.2' was not found in PATH or by cmake.dir property.
- CMake '3.12.2' found in PATH did not match requested version '3.10.2'.
Install CMake 3.10.2
CMakeが無いと言ってます。
はい。インストールした記憶はないから。
3)Cmakeをインストールします
メッセージ最後の「Install CMake 3.10.2」にリンクが貼ってありそうなので、クリックします。
ダイアログが表示されてインストールを始めたようです。(らくちんだ。)
しばらくするとインストールのダイアログに「Done」と出ます。
結果のメッセージが上に出てるので一応確認して[Finish]。
元の「Sync」タブ内の表示(行の左側アイコン)がくるくるしていて、再処理を行っているようです。
しばらくして、
正常にビルド?されたみたいです。
4)実行してみます
4-1)AndroidStudioのメニューから[Run]-[Run]とやってみました。
エミュレータが起動されました。
以前テストしてたVTChatの画面が出てます。
しばらく待ってみましたが、何も起きた感じが・・・
再度、[Run]-[Run 'app']とやってみます。
エミュレータの画面上に一瞬何やら表示されましたが、直ぐに消えました。
なので、画面上に表示されているMainActivity.javaのコード23行目の左側をクリックしてみました。
案の定、BreakPointらしきものが設定されたようで、赤い丸印が表示されました。
(AndroidStudio的には「Suspend」ポイントと呼ぶのかも。)
その状態で、メニュー[Run]-[Debug 'app']をクリックすると、
エミュレータ上に「Wait For Debugger」とメッセージが表示されてしばらく待つと、一時停止したようです。
AndroidStudioの下の方は、以下の感じになります。
ただし、エミュレータ上の表示は真っ白
なので、上の画面の「Go」らしきマークをクリックしたところ以下の内容がエミュレータ上に表示されました。
(この表示はAndroidStudio側の「Go」マークの2つ下の■「Stop」らしきマークをクリックするまで出てます。)
まずは、Cライブラリの移植環境はこれで準備できたのかなーと思います。
◆AndroidStudio環境へのJuliusLib移植のための調べ
まずは、改めてJuliusLibを使用するためのサンプルjulius-simple.cを見てみよう。
・先頭に「#include <julius/juliuslib.h>」のみ、#includeとして存在するので、ライブラリを使うサンプルで間違いなさそうです。
・status_recready()とstatus_recstart()という関数があります。コメントでCallbackとあるので何かのイベントで呼ばれるコールバック関数なんですね。
・put_hypo_phoneme():コメントによれば、音素列を出力するためのサブファンクション。
・output_result()は認識の結果を通知するためのコールバック関数なんでしょう。
ここまでは、主にコールバックで呼ばれて、標準出力、エラー出力にメッセージを出力するようになってます。
・最後にmain()です。
-起動パラメタが指定されてないとj_put_version()をコールします。引数にstderrを指定しています。※1
-j_config_load_args_new()という関数をコールしています。
「動作パラメタをjconfファイルで指定できる。」とチュートリアル文書に書いてあった(前回記事)ので、パラメタファイルを処理しているんでしょう。
-j_create_instance_from_jconf()という関数をコール:コメントでは音声認識クラスのインスタンス生成のようです。
-前出のコールバック関数(status_recready()等)をインスタンスに設定(callback_add())しているようです。
-j_adin_init()という関数をコール:コメントでは音声入力デバイスの初期化だそうです。
マイクなのか音声ファイルなのかは、jconfで指定するのかな?
-j_recog_info()という関数をコール:コメントではログにシステム情報を出力するとなっている。
-jconf->input.speech_inputという変数の値で処理が降り分けられています。
一方は、
-get_line_from_stdin()関数でファイル名を標準入力から指定させるているらしい。ファイル指定されている間はループ。
-j_open_stream()関数で音声データをファイルから入力して、j_recognize_stream()関数で認識させているみたい。
もう一方は、
-j_open_stream()でマイク入力をオープンし、j_recognize_stream()で音声認識させているみたい。
認識のループは、j_recognize_stream()内で行うようです。※2
-j_close_stream()関数でクローズ処理を行って、j_recog_free()関数でインスタンスの解放を行って終わり。
※1:ライブラリ本体側にもファイルポインタを使用する処理がある。→OS依存部の可能性がある。
※2:今回のアプリでは、音声データは録音部と共有するため認識処理にはバッファ渡しで処理してもらう必要がある。なので、j_recognize_stream()に手を入れなければならなくなるのかなぁ。
使用する関数と順番の概要はだいたい分かった気がする。
JuliusBookを読めば全部書いてあるかもしれないのに、サンプルソースを見たのは、大雑把に理解するには近いと思ったから。
詳しく書いてあるだろうから、長々した文章を読むのは疲れてしまうし。
でも、ここで初めてJuliusBookを開いて見ました。
100ページ以上あります。
コンパイルの仕方とか、フォルダ構成を見て気になっていたlibsendのことも書いてあった。
libsendは、「汎用ライブラリであり,入出力や特徴量抽出,音響モデル,言語モデル,出力確率 計算などの関数が定義されている.
」だそうです。
一方libjuliusは、「認識エンジンのコアライブラリであり,実際の認識処理を担当する.」だそうです。
この2つがあれば動かせるんですよねたぶん。
OS毎のビルドの方法等も記載されているが、Android向けの記述はやっぱありません。
また、音声データの入力方法についても記載があったが、やはりバッファ渡しのインタフェースは用意されていないようです。
ここが、最大の難関ですね。
まずは、目指す最終仕様のライブラリ化は置いておいて、
julius-simple.cの如き仕様のままをAndroid上で動作させてみることをやって見ます。
まだまだ、先が長ーくなりそうなので、中途半端ですが、ここで一旦切ります。
続きはまた次回。では、御機嫌よう。
m(__m)
スポンサーサイト