[Xamarin.iOS] 実用をめざした翻訳アプリ

Xamarin

本エントリーは Xamarin Advent Calendar 2016 (その2) の8日目のエントリーです。

昨日のエントリーは qwerty2501 - Qiitaさんの 「Xamarin.Formsのソースコードをビルドしてテストを実行してみた」 でした。 明日の担当は tonkun - Qiitaさんです。よろしくお願いいたします。

1 はじめに

翻訳アプリを作成するために使用した技術は下記のとおりです。

  • 音声入力(SFSpeechRecognizer)
  • 翻訳(Microsoft Translator)
  • 読み上げ(AVFoundation)

これらを使用したアプリは既に書いたことが有るのですが・・・

「入力」も「読み上げ」もクライアント側で完結するし、翻訳もそこそこ早いので、今回は、単純に 「翻訳が出来る」 というだけでなく、低機能でもいいから 「少しでも実際の会話に使えるようなもの」 というのを目標に書いてみました。 (ので、大した技術要素はありません。また、記事の内容は、過去に書いたものと多数重複しております事をお許し下さい。)

2 何とか実際の会話に使えそうなもの

この目的を達成するため、次のような 仕様を考えてみました。

  • 起動すると、何もしなくても音声を受け付けるようになっている
  • 翻訳ボタンなんかは、押さない(存在しない)(端末の向きを変えた時、翻訳され読み上げられる)
  • 「日本語入力/英語入力」の切り替えボタンなんかは押さない(存在しない)(端末を「自分向き/相手向き」に変えると、いつでも直ちに切り替わる)

実際に、使用している様子です。

3 プロジェクト作成

プログラムの作成には、Visual Studio for Mac (Preview)を使用させて頂きました。

プロジェクトは、ファイル > 新しいソリューション で Single View App から作成しました。

001

今回使用した、SFSpeechRecognizer(音声入力)は、iOS 10以降の機能なので、ターゲットはiOS 10以降に設定しています。

002

4 追加パッケージ

パッケージの追加からSystem.Net.HttpJson.NETを追加しました。

004

また、参照の編集からSystem.Xml.Ling を追加しました。

005

追加後のソリューションの状況です。

006

5 画面の回転

本アプリでは、画面の上下変化で、日本語入力と英語入力を切り替えています。

まずは、画面の回転を上下のみを許可(横向きなし)するために、info.plistのDevice orientationで、PortraitUpside Downのみにチェックを入れます。

003

iPhoneの場合、デフォルトで回転の判定方法にマスクUIInterfaceOrientationMaskAllButUpsideDown がかかっているため、ViewController.csに以下の行を追加しました。

// 上下の回転を有効にする
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{
    return UIInterfaceOrientationMask.All;
}

続いて、画面回転のイベントが処理できるように、UIDeviceOrientationDidChangeNotificationの通知を処理します。

NSNotificationCenter.DefaultCenter.AddObserver((Foundation.NSString)"UIDeviceOrientationDidChangeNotification", DidRotate);
public async void DidRotate(NSNotification notification)
{
    var newLocation = UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.PortraitUpsideDown;
    if (newLocation) {
        // 画面は下向き(英語入力モード)
    } 
    else {
        // 画面は上向き(日本語入力モード)
    }
}

6 音声入力(SFSpeechRecognizer)

音声入力には、SFSpeechRecognizerを使用しました。

SFSpeechRecognizerは、リアルタイム音声及び、録音済み音声に対応していますが、今回利用したのはリアルタイム音声による入力です。 リアルタイム音声を利用する場合の作業は、概ね次のとおりです。

  • ユーザの許可(info.plist)
  • マイク利用(AVAudioEngine)
  • SFSpeechRecognizerの生成
  • リクエストの作成
  • リクエストの開始とデータ取得

(1) ユーザの許可(info.plist)

info.plistに下記の2つの設定を追加し、ユーザからの許可を得ます。

  • NSMicrophoneUsageDescription(マイクの用途について)
  • NSSpeechRecognitionUsageDescription(音声認識の用途について)

設定を追加するには、info.plitsをダブルクリックして開き、Sourceをタブを選択します。

007

Add New Entryをクリックして、新しい行を追加し、キーとその用途を設定します。 009

※実は、現時点(2016/12/7 Visual Studio for Mac Preview 1(7.0 build 347))で、上記の画面から日本語の入力ができなかったので、いったん、Visual Studio を終了した状態で、info.plistをVisual Studio Codeで直接編集しました。 008

ユーザに許可を求めるダイアログは、下記のように表示されます。どちらも許可することで、マイクと音声入力が可能になります。

010 011

(2) マイクの利用(AVAudioEngine)

マイクの利用には、AVAudioEngineを使用します。 利用の方法は、概ね次のとおりです。

// 生成
var audioEngine = new AVAudioEngine();

// 停止
audioEngine.Stop();

// 開始
audioEngine.Prepare();
audioEngine.StartAndReturnError(out err);

// 入力をSFSpeechRecognizerに送る 
var inputNode = audioEngine.InputNode;
var recordingFormat = inputNode.GetBusOutputFormat(0);
inputNode.InstallTapOnBus(0, 1024, recordingFormat, (buffer, when) =>
{
    recognitionRequest?.Append(buffer);
});

(3) SFSpeechRecognizerの作成

ロケールを指定してSFSpeechRecognizerを作成します。

var speechRecognizer = new SFSpeechRecognizer(new NSLocale("ja-JP"));

(4) リクエストの作成

マイク等のオーディオバッファを利用する場合は、SFSpeechAudioBufferRecognitionRequestを使用します。

var recognitionRequest = new SFSpeechAudioBufferRecognitionRequest
{
    ShouldReportPartialResults = true
};

(5) リクエストの開始とデータ取得

recognitionTaskでリクエストを開始してクロージャーで入力を取得します。 入力に変化があるたびに、開始後の全部の文字列が返されます。

recognitionTask = speechRecognizer.GetRecognitionTask(recognitionRequest, (result, error) =>
{
    if (result != null)
    {
        if (mode == Mode.Recording)
        {
            inputTextView.Text = result.BestTranscription.FormattedString;

        }
    }
}

音声の入力に関しては、サンプルコードのRecognizer.csに纏まっていますので、詳しくはそちらをご参照ください。

7 翻訳

翻訳については、Microsoft Translatorを利用させて頂きました。(とりあえず無料枠がある翻訳サービスは、今、これしかないと思います) 同サービスは、1ヶ月あたり200万文字まで無料で利用可能です。

012
https://datamarket.azure.com/dataset/bing/microsofttranslator

端末の向きが変わった時点で、SFSpeechRecognizerの出力したテキストを同サービスで翻訳して、直ちに読み上げています。

翻訳に関しては、サンプルコードのTranslator.csに纏まっていますので、詳しくはそちらをご参照ください。

また、過去の記事ですが、参考になれば幸いです。
Xamarin.Forms 機械翻訳

8 読み上げ

読み上げには、AVFoundationを使用しました。

使い方は、非常に簡単です。

var speechSynthesizer = new AVSpeechSynthesizer();
var speechUtterance = new AVSpeechUtterance(str)
{
    Voice = AVSpeechSynthesisVoice.FromLanguage("en"),
    Volume = 1.0f,
};
speechSynthesizer.SpeakUtterance(speechUtterance);

本アプリでは、翻訳が完了した時点で、直ちに読み上げを行っています。

なお、読み上げの際は、音声入力で使用していた、AVAudioSessionの設定変更を忘れないようにして下さい。

var audioSession = AVAudioSession.SharedInstance();
audioSession.SetCategory(AVAudioSessionCategory.Ambient);

読み上げに関しては、サンプルコードのSpeech.csに纏まっていますので、詳しくはそちらをご参照ください。

9 最後に

英会話超弱者な私は、なんとか使える翻訳機が欲しいです。 今後、なんとか、このアプリを鍛えたいと思います。

コードは下記に置きました。気になるところが有りましたら、ぜひ教えてやってください。
github [GitHub] https://github.com/furuya02/PracticalTranslator
※上記のコードを動作させるためには、翻訳サービスのキーが必要です。各自で別途ご用意下さい。

10 参考資料


メジャーアップデートしたXamarin.iOSでiOS 10のアプリ(翻訳アプリ)を作ってみた
Xamarin.Forms 機械翻訳
Xamarin記事一覧(SAPPOROWORKSの覚書)
[Developers.IO] Xamarinシリーズ
素材Library.com (イラストは、素材Library.com様のものを利用させて頂きました。)