眠いしお腹すいたし(´・ω・`)

C#関連を主に書きます。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

WatsonのSpeech To TextをXamarin.Formsで試してみたよ('◇')ゞ

音声認識の実装に関して興味があったのでWatsonのSpeech To Textを使用してXamarin.Fromsで音声認識を行ってみました。

www.ibm.com

なぜWatsonにしたか

GooleのCloud Speech APIが50回の回数制限があったから。

です。

Xamarin.Formsで音声入力を文字化する実装を考えたときにAndroidの方はSpeechRecognizerを使用すればできるんですが

developer.android.com

iOSの方がなかなか難しいんです。

最初はGoogle Cloud Speech APIを使って音声認識を試してみようかと思ったのですが使用回数が50/dayだったりでほんとにちょっとしたテストしかできませんでした。

ということで別の方法を探してました。

qiita.com

この記事を読んでいたら

Watsonは有料となっていたのですがサイトを見てみたら最初の1000分までは無料とのことだったので試すにはちょうど良いと思いWatsonを試してみました。

CMとかもやってますしねぇ。Watson。

www.ibm.com

登録とか

Bluemixのアカウントを作成します。

最初の30日は無料ですべてのサービスにアクセスできるみたいです。

Bluemixのアカウントを作成すると組織とスペースを決めます。

組織は日本語で大丈夫でしたがスペースは日本語だめかもしれません。

最初に日本語を入れてみたのですが、登録は成功するけど反映されないみたいなおかしな状態になったので英語にしたほうが良いかと思います。

ホーム画面からWatsonを選択します。

f:id:tamafuyou:20160605151600p:plain

右上の「+」ボタンをクリックします。

f:id:tamafuyou:20160605151759p:plain

Speech To Textを選択します。

f:id:tamafuyou:20160605152133p:plain

特に考えずに作成を行います。

f:id:tamafuyou:20160605152720p:plain

資格情報の作成を行います。

f:id:tamafuyou:20160605152912p:plain

usernameとpasswordは認証情報として使用します。

f:id:tamafuyou:20160605153150p:plain

APIについて

APIReferenceはちゃんと用意されています。

www.ibm.com

主にHTTPを使用したセッションありとセッションなしのAPI、WebSocketを使用したAPIがあります。

HTTPを使用したセッションは保存済みのデータをテキストに変換するのに適していてWebSocketはリアルタイムに変換する事に向いていると考えてよいかと思います。

Java用とnode.js用のライブラリは用意されています。

またUnity用のC#ライブラリもありますので、お手軽にっていうのであればそちらを利用するのも手です。

今回はAPIの理解を得たい面もあったのでそれらは使用せずに実装します。

リアルタイム変換を行いたいのでWebSocketのAPIをします。

実装

とりあえずソースコード

gist.github.com

Observer/Observableパターンで実装してます。

使用しているライブラリは

WebSocket-Sharp

www.nuget.org

Json.NET

www.nuget.org

認証

まずWebSocketで接続を行います。

接続URLはwss://stream.watsonplatform.net/speech-to-text/api/v1/recognize

クエリストリングにてmodelを指定できます。

modelは言語に使用する言語に対応した物を指定します。

今回は日本語ですのでja-JP_BroadbandModelを使います。

資格情報としてSpeechToTextの資格情報を設定します。

_client.SetCredentials(user, password, true);

そして接続を行います。

接続に成功した場合、クライアントからスタート情報をjsonで送信することで変換ストリーミングを開始できます。

            var startjson = JsonConvert.SerializeObject(
                new Connection
                {
                    Action = "start",
                    content_Type = $"audio/l16;rate={SampleRate};channels={Channel}",
                    InterimResults = InterimResults,
                    Continuous = Continuous,
                    InactivityTimeout = -1,
                    MaxAlternatives = 1,
                    Timestamps = false,
                    WordConfidence = false
                }, Formatting.Indented);
            Debug.WriteLine(startjson);
            _client.Send(startjson);
            _isSending = true;

今回はPCM音声データを使用しますのでcontent-typeにはl16を指定しrateとchannelsを追加で指定します。

Interim_resultsは変換が確定しない時点でもストリーミング的に途中結果を受け取ることができます。

continuousを有効にすることで断続した変換を行うことができます。

スタート要求を送信するとstate : "listening"というjsonを返答してくれます。

スタートを送信したらあとは、PCMデータをWebSocketのBinaryFrameにて送信することで結果を返答してくれます。

            if (!_isConnected) return;
            if (value.IsStop == false)
            {
                if (!_isSending)
                {
                    StartRecognize();
                }
                _client.Send(value.PcmStream);
            }
            else
            {
                _client.Send("{\"Action\": \"stop\"}");
                _isSending = false;
                Debug.WriteLine("Stop");
            }

結果に関しては Speech to Text Service Documentation | Watson Developer Cloudを読んでください。

受信処理は

                        var result = JsonConvert.DeserializeObject<SpeechResult>(args.Data);
                        Debug.WriteLine(args.Data);
                        result.Results.ForEach(res =>
                        {
                            if (res.Alternatives.Any())
                            {
                                var speechtext = new SpeechText
                                {
                                    IsFainel = res.Final,
                                    Text = res.Alternatives.First().Transcript
                                };
                                _speechTextSubject.OnNext(speechtext);
                            }
                        });

こんな感じで書くことができます。

今回はXamarin.Forms側のプログラムは説明しませんがソースコード

github.com

こちらで確認することができます。

精度的には他と比較していないので何ともです。

おそらく多と比較検討してくれる記事などを書いてくれる人が出てくると思うので期待です。

このように実装することでオンライン限定ですがクロスプラットフォームでの音声認識を実装できます。

このケースでは音声認識部分はAndroidiOSでコード共有率100パーセントです。

Xamarin素晴らしい。

以上です。

ToReactiveProperty拡張メソッド

特に書くことがないのでReactiveProperty使うときに追加している拡張メソッドを紹介します。

gist.github.com

ToReactivePropertyAsOneWaySync

ModelからReadOnlyReactivePropertyを作成するときに使います。

むっちゃ使います。

INotifyPropertyChangedクラスからViewModelのプロパティ作成するときはまずこれです。

基本はViewModelのプロパティは基本がReadOnlyReactivePropertyでありReadOnlyObservvableCollectionでありReadOnlyReactiveCollectionです。

編集が必要な時のみReactivePropertyを使ってます。

ToReactivePropertyAsOneTime

たまに使います。

ReactiveProperty.FromObjectを使いたい時によくなんだっけ?って忘れるのでToって書けばインテリジェンスで候補が表示されれば幸せになれると思います。

IDisposableとusing

今更なんですけどC#初心者な感じの話です。

最近ReactiveExtentionsを勉強しててDisposableによく触れるのですが自分でDisposableを実装するってやった事なかったなぁと思ってちょこっと作ってみました。

gist.github.com

よくあるtry catchパターンの代替としてusingを使用する例です。

DisposableにてCommitするかRollBackするかを制御しています。

もっと色々なパターンでIDisposableって活用できそうですよね。

IObservable/IObserverもそうなんですけど,.NET Frameworkで用意されているInterfaceって色々と意味があるんだなぁと再認識させられます。

.NETってデザインパターンの見本になるしオブジェクト指向を勉強するのにすごく良いんだなって思いました○

NSpeex.Reactiveをリリースしてみました

この度

www.nuget.org

NSpeex.Reactiveというライブラリをリリースしました。

現在のバージョンは0.0.1です。

このライブラリはNSpeex

nspeex.codeplex.com

と、NSpeexをObserver/Observableな感じで使用するための余計なライブラリが含まれています。

NSpeex単体で使いたい場合は本家を使用してください。

NSpeex単体でnugetパッケージを作らなかったのはワザとです(^◇^)

このライブラリは.NET4、Xamarin.Android、Xamarin.iOSで利用することができます。

github.com

にて管理を行っています。

どんなライブラリ?

こんなライブラリです。

NSpeex - Speex for .Net and Silverlight - Home

プラスしてRxのサブジェクトっぽくNSpeexを使えるようにしてあるだけです。

強いていえば、XamarinでNSpeexが使えるよ(^◇^)っていうのが特徴です?

サンプルは?

すいません。間に合っていません。そのうちサンプルアプリを作ろうと思います。

コードのイメージはこんな感じです。

gist.github.com

どっかで見た気がします。

ObservableVoiceCaptureでキャプチャしたPCMをNSpeex.Reactiveでエンコード・デコードした後にDelayを1000msecかけて再生している例です。

どんなことに使えるの?

PCMデータをSpeexでエンコードしてネットワーク経由で送信して受信してデコードして再生するとVoIPになったりします。

現在の新しいVoIPなコーデックといえばOpusなのですが、Speexだってレイテンシも悪くないしイケてると思います。

たぶんそのうちOpusのライブラリ作ると思いますけど(^◇^)

おまけ

NSpeex/src/NSpeex.TypeScript at master · yuka1984/NSpeex · GitHub

以前のエントリー Netjsを使ってC#からTypeScriptへの変換をしてみた。 - 眠いしお腹すいたし(´・ω・`) で紹介したNSpeexのデコードの一部(NarrowBandにのみ対応)をTypeScriptで使用できるようにしたライブラリはこちらに管理を移動しました。

一応ブラウザで動かす例をちゃっかり載せときます。

gist.github.com

サンプルはWebSocket経由でSpeexエンコードされた音声データを受け取ってJSにてデコードしてWebAudioAPIを使用して再生している感じです。

ObservableVoiceCaptureをリリースしてみました。

この度

www.nuget.org

ObservableVoiceCaptureというライブラリをnugetにリリースしました。

現在のバージョンは0.0.2です。まだ破壊的な変更をするかと思います。

このライブラリは.NET4.5以上、Xamarin.Android、Xamarin.iOSで利用することができます。

github.com

にて管理を行っています。

どんなライブラリ?

音声をキャプチャしたり再生したりできます。

.NET45版ではNAudio

naudio.codeplex.com

を使用して音声データの入出力を行っています。

Xamarin.Android版ではNativeのAudioRecoed/AudioTrackを使っています。

Xamarin.iOS版ではInputAudioQueue/OutputAudioQueueを使っています。

PCMデータをbyteの形で取り扱う非常に低レベルなライブラリです。

特徴は?

インターフェースが全プラットフォームで共通になっています。

サウンドキャプチャはIObservable<byte>でサウンド再生はIObserver<byte[]>になっていて非常にシンプルです。

現時点ではXamairn Pluginの形で提供されていないのですが、近日中にXamarin Pluginに対応しようと思っています。

要するにXamarin Formsで低レベルなオーディオインターフェースをPCL上にて扱えるということになる予定です。

サンプルは?

すいません。間に合っていません。そのうちサンプルアプリを作ろうと思います。

コードのイメージはこんな感じです。

gist.github.com

キャプチャしたPCMデータを1000msecディレイさせてそのまま再生させる例です。

実際に動かすとむっちゃハウリングします(^◇^)

割と簡単にPCMデータのやり取りを行えるようにしているつもりです。

どんなことに使えるの?

これ単体ではあんまり使い道がないかもしれません。

このライブラリは私が今作ろうとしている物の一部をライブラリ化したものです。

PCMデータをエンコードしてネットワーク経由で送信して受信してデコードして再生するとVoIPになったりします。

要するに単体では使えん(^◇^)

ということです。

以上、すごく無駄なエントリーでした(^^)/

Netjsを使ってC#からTypeScriptへの変換をしてみた。

github.com

アイコンがイケメンです。素晴らしいライブラリです。間違いないです。

ではなくてC#をTypeScript/JavaScriptに変換してくれるライブラリです。

仕組み的にはC#で作成したクラスライブラリファイル(.dll)を読み込んで.ts/.jsファイルを作成するイメージになります。

使い方

  1. GitHubからプロジェクトをクローンしてビルドします。

  2. 引数に変換したいdllを指定してexeをコマンドラインから実行します。

  3. そのフォルダにファイルが作成されます。

  4. mscorlib.tsを作成されたtsファイルと同じ階層に置きます。

.NetFrameworkはどこまでカバーされているのか?

基本的にほとんど変換されません。

using Systemの範囲内は少しカバーされています。

具体的には

Netjs/mscorlib.ts at master · praeclarum/Netjs · GitHub

この範囲です。

ようするにNetjsは純粋にC#プログラムをTypeScriptに変換してくれます。

だから既存のC#資産をTypeScirptに。。。ぐへへぇ。みたいな事は出来ません。

私の使い方

既存のC#資産をTypeScriptに変換して使いました。

さっきと言っていることが違うのですが、C#で書いていても.NetFrameworkをあまり使っていない資産というものもあるということです。

NSpeex - Speex for .Net and Silverlight - Source Code

こういう類の資産です。

現在、私の知る限り

github.com

duoco.de

emscriptenでC変換されたjsは結構見かけます。

duocodeeが現時点で継続しているプロダクトとしては最新の環境になると思いますが

連載:「○○してみた」日記:C#→JavaScriptコード変換ってどうよ? DuoCodeを試してみた - @IT

出力されるコードを見て(´・ω・`)となってしまったため試しませんでした。

Netjsでは

SimpleVoiceDeliver/NSpeex.Decoder.ts at master · yuka1984/SimpleVoiceDeliver · GitHub

こんな感じのコードが出力されます。

これなら手を入れようかって気になるかなぁと思います。

使ってみて

元コードがかなり.NETを使っていないコードだったので、すんなり変換できましたが、.NETを使っている部分で足りない部分はmscorlib.tsに書き足しました。

たしかArray.CopyとRandomだったと思います。

ようするに足りなかったら自分で書けば良いんです。

Reference Source

ソースコードは載ってます。

変換精度ですが、一部(´・ω・`)な部分がありました。

IL詳しくないのでわかんないのですが、配列の値セットが array[index] = value;みたいに変換されたいのですがarray.set_item(index, value);という風に変換されることがあって、その部分は手で修正しました。

後は

  • byte[] short[]number[]に変換されるのでUint8Array、Int16Arrayに書き直した。

  • C#の2次元配列[,]に対応していないため、元コードをジャグ配列に直してからビルドした。

ぐらいです。

大体1日もかからず目的のtsファイルを作れたのですごく助かりました。

生かせる部分は限定的ですがアイディア次第では楽することができるかもしれません。

Xamarin.FormsでOnSleepとOnResumeの呼ばれるタイミングをAndroidとiOSで似た感じにしたい

Xamarin.FromsのPCLプロジェクトのApplicationクラスにはOnSleep/OnResumeという仮想関数が用意されています。

Working with the App Lifecycle - Xamarin

  • OnSleep - Called each time the application goes to the background.

  • OnResume - Called when the application is resumed, after being sent to the background.

となっているわけですが、AndroidiOSで呼ばれるタイミングが全然違ったりします。

Androidでは画面上部から設定画面をプルダウンしたりしてもOnSleepは呼ばれませんが、iOSでは画面上部、画面下部から設定画面を引っ張ったりするだけでOnSleepが呼ばれたりします。

なのでタイミングが違いすぎてあまり役に立たなかったりします。

iOSAndroidに合わせたい場合には以下のようにすると一応合わせることができます。

gist.github.com

一応と書いてあるのはAppDelegate.csのOnResignActivationの基底をコールしないことによる副作用が見えないためです。

現時点で副作用らしい副作用は出ていませんが不安である場合には各プラットフォームのMainActivity/AppDelegateにて動作を実装してOnSleep/OnResumeを使用しないほうが良いかもしれません。