読者です 読者をやめる 読者になる 読者になる

よいちろ日記

忘れないようにメモ。

iOSでBluetoothヘッドセット音声認識アプリを作りかけた。(UIDictationController 編)

やりたいこと。

iOS(9.3)で音声認識アプリを作りかけたので備忘録。Bluetoothヘッドセットで発話の音を拾って認識する。Xcodeは8.1を使用。
 
音声認識エンジンをどうするか。
 ┗ UIDictaionControllerを利用する。
 ┗ Google Speech API(Cloud & Not Cloudの2種類)を利用する。
・その他の機能について。
 ┗ 音声認識開始トリガーのためにマイク音量を取得する。
 ┗ 音声認識対象の音声データの保存する。
 ┗ (これは実装できてないけど)保存する音声データをシリアル化して端末に保存。
 

音声認識をどうするか。

この記事を参考に取りうる手段を決定。

お試しかつ初心者なので、有償のものやドキュメントが少なそうなものは脱落。
長時間の音声データを認識させたかったという点でSpeech.framework(端末ごとに認識回数の厳しい制約がある)は脱落。
また、認識エンジン自体をいじくり回すのが面倒だったので、(組み込みに集中したかったので)Juliusは脱落。面白そうなので次回。

その他の機能について。

ヘッドセット(ハンズフリーイヤホン?)でアプリ操作なく音声認識の開始終了を行いたかったため、認識前後、認識中のマイク音量を取得する機能も実装した。認識対象の音声データが保存されていれば、認識エンジンを変えて、より精度のよい結果が得られるため可能であればwaveファイルなどでデータ保存したい。音声データって結構大きくなってしまうかもだから圧縮して、しかも端末に保存できるといいなあというのも。

 

 

今回はUIDictationControllerを使った音声認識についてメモ。

 サンプルコードはこちら。(大半が先人の知恵をお借りしたコピペです。)

UIDictaionControllerを利用する。

図式すると、以下のような仕組み。

f:id:yoichiro0903:20161203153655p:plain

  • 無料。
  • 高い音声認識率。(Appleのキーボードの音声入力と同じ)
  • 端末ごとや時間ごとの音声認識回数制限なし。
  • 音声データ秒数制限は1回の認識につき15秒程度。

 

UIDictationControllerクラスが非公開クラスなので実際に審査とかは通らないらしいけど、遊んでみる分には良い。


【Objective-C】iOSで音声認識サンプル(UIDictationController) | AS blind side

このブログがめちゃんこ参考になりました。ありがとうございます。

 

ここにUIDictationControllerで使用できるメソッドがわかる。

 

コメント見る感じ、このメソッド一覧はRuntimeBrowserで調べたっぽい。


キーボード(UITextInput)に含まれるクラスらしく、デリゲートとしてUITextInputをしていしたUIViewクラス(UIDictContRecognitionと命名)を作る。UITextInputクラス必須のデリゲートメソッドは中身カラで書いておかないとエラーになる。

この辺、いつもテキトーにやってしまっているから改めて書いておいた。

 

 コード部に入る。
+ (id)sharedInstance; //インスタンス- (float)audioLevel; //音声取得中のマイク音量取得
- (void)startDictation; //音声取得開始
- (void)stopDictation; //音声取得終了&音声認識開始
- (void)cancelDictation; //音声取得中止
UIDictationControllerクラスのメソッドは上記を使った。
ViewControllerにて、
_dictationController = [NSClassFromString(@"UIDictationController") performSelector:@selector(sharedInstance)]; 
でUIDictationControllerクラスのインスタンス生成。
 
ボタンなどでViewControllerクラスに実装したstartDictationなどを呼び出して、その中でUIDictationControllerのstartDicataionメソッドを呼び出す。(紛らわしいので違う名前にしたら良かったけども。)
- (void)stopDictation {
    [_dictationController stopDictation];
}
最初は再帰的に見えて、わけがわからなかったけど、
[self startDictaion] = [ViewController startDictation]
ってこと(ViewController.mの話なので)で、
[_dictaitonController startDictaion] = [UIDictationController startDictaion]
ってこと。
 
で、startDictaionで音声取得を開始、stopDictationで音声取得を終了、すると音声データがAppleのサーバーに送られて、音声認識結果が返ってくる。
返ってきた音声認識結果は、UIDictContRecognitionクラスで通知される。
 
UIDictContRecognitionにて、
-(void)insertDictationResult:(NSArray *)dictationResult {
    [
     [NSNotificationCenter defaultCenter]
     postNotificationName:@"DictationRecognitionSucceededNotification"
     object:self
     userInfo:[NSDictionary dictionaryWithObject:dictationResult forKey:@"DictationResultKey"]
     ];
}
insertDictationResultで通知されるので、それをViewControllerクラスに通知。userInfoに音声認識結果がNSDictionary形式でkey=DictationResultKey, value=音声認識結果、という感じで格納されているので渡してあげる。
ViewControllerにて、
[
     [NSNotificationCenter defaultCenter]
        addObserver:self
        selector:@selector(dictationRecognitionSucceeded:)
        name:@"DictationRecognitionSucceededNotification"
        object:nil
];
音声認識結果を受け取って、予め実装しておいたdictationRecognitionSucceededメソッド内でNSLogとかで確認。
- (void)dictationRecognitionSucceeded:(NSNotification *)notification {
    //Output result.
    NSDictionary *userInfo = notification.userInfo;
    NSArray *dictationResult = [userInfo objectForKey:@"DictationResultKey"];
    NSString *resultText = [self wholeTextWithDictationResult:dictationResult]; //音声認識結果を取り出すメソッド
}
音声認識中(音声取得中)のマイク音量は、
_audioLevelTimer = [NSTimer
                     scheduledTimerWithTimeInterval:1
                     target:self
                     selector:@selector(audioLevel)
                     userInfo:nil repeats:YES
                   ];
- (float)audioLevel {
    float audioLevel;
    audioLevel = [_dictationController audioLevel];
    NSLog(@"audioLevel: %f", audioLevel);
    return audioLevel;
}
と取れる。この値が閾値以下になったら音声取得終了&音声認識開始とかするとスマート。(音声取得開始は別途他の方法でトリガー作る必要あるけど。後述。)
 
一旦UIDictationControllerに関してはここまで。