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

Xamarin 日本語情報

Xamarin(ザマリン) の代理店だったエクセルソフト田淵のブログです。主に Xamarin に関するエントリーをアップしていきます。(なるべく正しい有益な情報を掲載していきたいと考えていますが、このブログのエントリーは所属組織の公式見解ではありませんのでご注意ください)

Xamarin.Forms for Windows で Text To Speech を Dependency Service で実装する

Xamarin Xamarin.Forms

こんにちは。エクセルソフトの田淵です。

Xamarin.Forms for Windows でストアアプリにチャレンジしています。

Accessing Native Features via the DependencyService - Xamarin

で Text To Speech (以下 TTS) の機能を Dependency Service で使用するサンプルがあるので、それを Windows ストアで実装しました。

Windows ストアアプリで TTS を使用するには

WinRT/Metro TIPS:Windows 8.1の新機能、テキスト読み上げを利用するには?[Windows 8.1ストア・アプリ開発] - @IT

WinRT/Metro TIPS:アプリに埋め込んだ効果音を鳴らすには?[Win 8/WP 8] - @IT

を参考に、

using XF_Slider.Windows81;
using Xamarin.Forms;

using Windows.Media.SpeechSynthesis;
using Windows.UI.Xaml.Controls;

[assembly: Dependency(typeof(TextToSpeech_Windows81))]

namespace XF_Slider.Windows81
{
    class TextToSpeech_Windows81 : ITextToSpeech
    {
        public TextToSpeech_Windows81() { }

        public async void Speak(string text)
        {
            SpeechSynthesisStream stream;
            // MediaElement をインスタンス化
            var media = new MediaElement();

            // SpeechSynthesizerオブジェクトを作る
            using (var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer())
            {
                // プレーン・テキストから合成音声ストリームを生成する
                stream = await synth.SynthesizeTextToStreamAsync(text);
            }

            // ストリームをMediaElement のインスタンスに渡して再生させる
            media.SetSource(stream, stream.ContentType);
            media.Play();

        }
    }
}

で大丈夫でした。半日くらい悩んだんですが、良かったです。

Xamarin 気になった方は

是非 ダウンロード(直接) / ダウンロード(弊社経由) して触ってみてください。 学習用リソースJXUG リンクページ に参考資料を纏めてますので併せてどうぞ。

以上です。

以下は色んなやり方があるからコントロールの使い方をまずは調べろよ?っていう自分メモとして残しておきます。






















MainPage.xaml<MediaElement x:Name="mediaElement1" Volume="100" /> を追加して… フムフム

コードビハインド MainPage.xaml.cs

string text = ……省略……; // 読み上げるテキスト

// 合成した音声を受け取るストリーム
Windows.Media.SpeechSynthesis.SpeechSynthesisStream stream;

// SpeechSynthesizerオブジェクトを作る
using (var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer())
{
  // プレーン・テキストから合成音声ストリームを生成する
  stream = await synth.SynthesizeTextToStreamAsync(text);
}

// ストリームをMediaElementコントロールに渡して、再生させる
this.mediaElement1.SetSource(stream, stream.ContentType);
this.mediaElement1.Play();

を書くと。フムフム

でも、Xamarin.Forms for WindowsDependency Service を使うので、私は Froms プロジェクトに ITextToSpeech.cs を、 Windows ストアプロジェクトに TextToSpeech_Windows81.cs を追加して、そこに Dependency の記述を追加しないと行けなくてですね。

ITextToSpeech.cs はこんな感じで

public interface ITextToSpeech
{
    void Speak (string text);
}

TextToSpeech_Windows81.cs はこんな感じ

using XXXXX.Windows81;
using Xamarin.Forms;

using Windows.Media.SpeechSynthesis;

[assembly: Dependency(typeof(TextToSpeech_Windows81))]

namespace XXXXX.Windows81
{
    class TextToSpeech_Windows81 : ITextToSpeech
    {
        public TextToSpeech_Windows81() { }

        public async void Speak(string text)
        {
            // テスト1 Windows Phone のをそのまま持ってきてみる。
            // Windows.Phone.Speech.Synthesis には SpeakTextAsync() メソッドがあるが、Windows.Media.SpeechSynthesis には存在しない
            //SpeechSynthesizer synth = new SpeechSynthesizer();
            //await synth.SpeakTextAsync(text);

            // テスト2 WinRT/Metro TIPS:Windows 8.1の新機能、テキスト読み上げを利用するには?[Windows 8.1ストア・アプリ開発] - @IT
            // http://www.atmarkit.co.jp/ait/articles/1311/07/news088.html
            // をそのまま使ってみる。
            SpeechSynthesisStream stream;

            // SpeechSynthesizerオブジェクトを作る
            using (var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer())
            {
                // プレーン・テキストから合成音声ストリームを生成する
                stream = await synth.SynthesizeTextToStreamAsync(text);
            }

            // ストリームをMediaElementコントロールに渡して、再生させる
            this.mediaElement1.SetSource(stream, stream.ContentType);
            this.mediaElement1.Play();

        }
    }
}

'XXXXX.Windows81.TextToSpeech_Windows81' に 'mediaElement1' の定義が含まれておらず、型 'XXXXX.Windows81.TextToSpeech_Windows81' の最初の引数を受け付ける拡張メソッドが見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。

まぁそりゃそうですよね。コードビハインドじゃないし。

XXXXX.Windows81.MainPage.mediaElement1 って参照すればいいのかしら?とやってみたところ、

'XXXXX.Windows81.MainPage.mediaElement1' はアクセスできない保護レベルになっています。

ウムム…

で、ウチの技術に助けを求めてみたところ

  • MediaElement に x:FieldModifier="public" の属性を追加してみる : 静的でないフィールド、メソッド、またはプロパティ 'XXXXX.Windows81.MainPage.mediaElement1' で、オブジェクト参照が必要です エラーでダメでした
  • Forms の ITextToSpeech インターフェイスで string を渡していますが、MediaElement ごと渡してしまう? : PCL だから Windows.Media.SpeechSynthesis を using できずダメでした

という感じでどうやら Custom Renderer を使って、Windows ストアの場合は MediaElement を配置してあげないとダメじゃないですかね?という所に落ち着きました。

何か良いアイディアないですかね…?

以上です。。