Windows Phoneアプリケーション開発入門

第29回WebServiceを利用してみよう!(2)

はじめに

4月12日から14日にかけて、米ラスベガスで開催されたWeb開発者とWebデザイナー向けのカンファレンス「MIX11」が開催されました。毎年次世代のWebテクノロジーについて発表されます。連載第10回では去年開催された「MIX10」での「Windows Phone 7 Series(当時⁠⁠」が発表された様子をお伝えしました。⁠MIX11」についてはgihyo.jpにもレポート記事が上がっていますので、そちらを参考にしてください。

前回から触っているMicrosoft Translator APIですが、これも去年の「MIX10」で紹介された技術のうちのひとつなのをご存知だったでしょうか。今回はMicrosoft Translator APIを使ってテキストの読みあげをおこなって行きたいと思います。

テキストの読みあげには、Translator APIのSpeakメソッドを使用します。このSpeakメソッドは、テキストと言語情報をサーバーへリクエストします。サーバーサイドで音声ファイルを作成するので、アプリケーションでは音声ファイルをダウンロードし、MediaElementを使って再生を行います。

端末内に音声データをダウンロードしておく必要がありますので、Speakメソッドのお話を書かせて頂く前に分離ストレージ(Isolated Storage)についての基本的な使い方についてご紹介いたします。

分離ストレージ(Isolated Storage)の基本的な利用の仕方

Windows Phone 7アプリケーションでは、以前のようにExprolerを使って自由に閲覧・削除等のファイル操作ができません。では永続的にデータを保存するためにはどうすればよいのかというと、⁠分離ストレージ(Isolated Storage⁠⁠」と呼ばれる仕組みを利用します。

分離ストレージは、分離性と安全性を提供するデータストレージ機構です。ストレージへのアクセス権限を持たないほかのアプリケーションからデータを保護することができるようになり、ストレージの特定のパスを示すためのハードコーディングをする必要がなくなります。これにより悪意のあるアプリケーションからの不正アクセスや意図しないデータの汚染を防ぐことができます。

データの保存には、IsolatedStorageSettingsクラスのApplicationSettingsを利用する方法、IsolatedStorageFileクラスのGetUserStoreForApplicationメソッドで取得したユーザーストアを利用する方法の2通りあります。

キー値でのデータ保存と取得

IsolatedStorageSettingsクラスのApplicationSettingsプロパティを使用して、分離ストレージにキーと値のペアを格納します。ApplicationSettingsはアプリケーションごとの固有の設定になっています。コレクションになっているのでAddメソッドでキー値を追加するか、インデクサでキーを指定して値を設定するかで追加することができます。

using System.IO;
using System.IO.IsolatedStorage;

private void btnStoreKeyValue_Click(object sender, RoutedEventArgs e)
{
    IsolatedStorageSettings store = IsolatedStorageSettings.ApplicationSettings;
    store["text"] = "こんにちは";
    store.Save(); // ApplicationSettingsを保存する
}

private void btnLoadKeyValue_Click(object sender, RoutedEventArgs e)
{
    IsolatedStorageSettings store = IsolatedStorageSettings.ApplicationSettings;

    if (store.Contains("text"))
    {
        textBox.Text = (string)store["text"];
    }
    else
    {
        textBox.Text = "keyが見つかりませんでした";
    }
}

インデクサでのアクセスを行うと、キーが無かった場合に例外処理が発生しています。存在しないキーに対してのアクセスが頻繁に発生する場合は、TryGetValueメソッドを使用したほうが一般的に効率的と言われています。<string>の部分は任意の型としてください。

    string text = "";
    if (store.TryGetValue<string>("text", out text))
    {
        textBox.Text = text;
    }

ユーザーストアでのデータ保存と取得

アプリケーションIDに基づくユーザースコープに対応する分離ストレージを取得し、その分離ストレージに対してファイルを作成します。ストリームを使ってデータの保存と取得を行います。

using System.IO;
using System.IO.IsolatedStorage;

private void btnStoreFile_Click(object sender, RoutedEventArgs e)
{
    var file = IsolatedStorageFile.GetUserStoreForApplication();

    // 分離ストレージにtest.txtというファイルを作成しストリームを開く
    using (IsolatedStorageFileStream strm = file.CreateFile("test.txt"))
    using (StreamWriter writer = new StreamWriter(strm))
    {
        // データを書き込む
        writer.Write("酢酸の実験室へようこそ!");
        writer.Write("これはテストアプリです。");
    }
}

private void btnLoadFile_Click(object sender, RoutedEventArgs e)
{
    var file = IsolatedStorageFile.GetUserStoreForApplication();

    // 分離ストレージ内のtest.txtというファイルを作成しストリームを開く
    using (IsolatedStorageFileStream strm 
        = file.OpenFile("test.txt", FileMode.Open, FileAccess.Read))
    using (var reader = new StreamReader(strm))
    {
        textBox.Text = reader.ReadToEnd();
    }
}

分離ストレージに格納したデータの削除

分離ストレージに格納したデータの削除を行います。

ApplicationSettingsに格納でしたデータを削除するには、IsolatedStorageSettings.Clearメソッドにて削除を行った後にSaveメソッドを実行します。分離ストレージに格納されたすべてのディレクトリとファイルの削除を行うには、IsolatedStorageFile.Removeメソッドを使用します。

using System.IO;
using System.IO.IsolatedStorage;

private void btnDeleteStrage_Click(object sender, RoutedEventArgs e)
{
    // ApplicationSettingsの削除
    IsolatedStorageSettings store = IsolatedStorageSettings.ApplicationSettings;
    store.Clear();
    store.Save();

    // このアプリケーションのユーザーストア領域の削除
    var file = IsolatedStorageFile.GetUserStoreForApplication();
    file.Remove();
}

ストレージの空き容量の取得

ストレージの空き容量には仕様上の制限は存在しないのですが、現実的に考えて無制限に使用するというわけにはいきません。大きなサイズのファイルをダウンロードする場合などは空き容量が気になります。AvailableFreeSpaceプロパティでユーザーが利用可能な空き容量が取得できます。

using System.IO;
using System.IO.IsolatedStorage;

private void btnFreeSpace_Click(object sender, RoutedEventArgs e)
{
    var file = IsolatedStorageFile.GetUserStoreForApplication();
    var spaceBytes = file.AvailableFreeSpace;
    var msg = string.Format(
        "空き容量は、{0:#,##0} Mbytesです。", spaceBytes / 1000000);
    MessageBox.Show(msg);
}

以上がIsolated Strageの基本的な使い方です。ダウンロードした音声データを分離ストレージのファイルへ書き出すのに使用します。サンプルプロジェクトを用意しておりますので、空き容量のチェック処理などを追加して触ってみてください。

テキストを読みあげさせる

前回はTranslator APIを使って入力した文章を翻訳しTextBlockへ表示しました。翻訳後の文章を音声で読みあげさせましょう。

読み上げ開始のトリガーとなるButtonをデザイナを使って配置します。以前使ったTranslateボタンの隣に配置しましょう。名前はbtnSpeakとします。

画像

ボタンのイベントハンドラに以下のコードを書きます。サービス参照の追加で作成したクライアントクラスのインスタンスを生成し、音声ファイル作成完了イベントのSpeakCompletedのハンドラにラムダ式でダウンロード処理を設定しています。最後にSpeakメソッドを非同期にて実行します。

少し複雑ですのでSpeakCompletedのラムダ式の中についても説明します。Translator APIのSpeakメソッドのレスポンスには、音声ファイルのURLが含まれています。得られたURLのデータをダウンロードするためにWebClientクラスのOpenReadAsyncメソッドを使っています。

private void btnSpeak_Click(object sender, RoutedEventArgs e)
{
    // 翻訳後のテキストがTextBlockにあるか判定
    if (string.IsNullOrEmpty(textAfter.Text))
    {
        MessageBox.Show("翻訳を行ってください.");
        return;
    }

    // MediaElementの初期化
    mediaElement.Source = null;

    Translator.LanguageServiceClient client = new Translator.LanguageServiceClient();
    // waveファイルの作成完了後、サーバーからwaveファイルをダウンロードする
    client.SpeakCompleted += (sx, ex) => {
        if (ex.Error != null) return;

        WebClient wc = new WebClient();
        wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
        wc.OpenReadAsync(new Uri(ex.Result, UriKind.Absolute));
    };
    // TextBlockに入力した文章の読ませたwaveファイルの作成を行う
    client.SpeakAsync("{Bing AppID}", textBefore.Text, "ja", null, null); 
}

上記のサンプルコードにあるSpeakAsyncメソッドの第一引数の "{Bing AppID}" は、Bing Developer Centerにて登録したAppIDを入力しておく必要があります。このままでは実行できませんので気をつけてください。

デザイナに戻り、音声の再生に利用するMediaElementを配置します。動画と違い見えないコントロールですのでどこに配置しても問題ありません。ここではTranslateボタンの右下に配置しました。名前をmediaElementとしています。

画像

再生を行うMediaElementの準備は整いました。ただ、この時点では再生するデータは設定されていません。

WebClientのOpenReadCompletedイベントのハンドラ内で読み込んだストリームを分離ストレージのファイルに書き出し、ダウンロードを完了させた後、分離ストレージ側のストリームをMediaElementに設定します。

void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if (e.Error != null) return;

    string fileName = "translate_test.wav";
    var store = IsolatedStorageFile.GetUserStoreForApplication();

    // 以前に作成したファイルが残っている場合は削除する
    if (store.FileExists(fileName))
    {
        store.DeleteFile(fileName);
    }

    // 読み込んだストリームを分離ストレージのファイルに書き出す
    using (var strm = store.CreateFile(fileName))
    {
        var bytes = new byte[256*1024];
        while (true)
        {
            int read = e.Result.Read(bytes, 0, bytes.Length);
            if (read <= 0) break;
            strm.Write(bytes, 0, read);
        }

        // 指定されたストリームを使ってSourceプロパティに設定します
        mediaElement.SetSource(strm);
        // 設定されたSourceの再生の開始
        mediaElement.Play();
    }
}

インターネットに接続されている環境なら、翻訳後のテキストに入力した「ハロー ワールド」が読みあげられたのが確認できましたでしょうか。無事、音声が再生されていれば英和翻訳アンドテキスト読みあげアプリは完成です。

画像

さいごに

音声ですのでスクリーンショットの確認だけでは限界があるため、是非サンプルプロジェクトを実行してWindows Phoneエミュレータで実行できるのを確認してください。英語を入力した場合と日本語を入力した場合の発音の違いを確かめてください。

以上で今回は終わりです。ありがとうございました。

おすすめ記事

記事・ニュース一覧