Category Archives: Tech

Speech API (SAPI)からCeVIO AI Voiceで読み上げ .NET C# 実装編

前回、CeVIO AIがSAPIではSelectVoiceした時点でエラーが出る件の続き。(SAPIでの読み上げは断念)

仕組みとしては、CeVIO AIでインストールされるDLL (CeVIO.Talk.RemoteService2.dll)から.NETアセンブリとしてAPIをコールする。APIコールからCeVIO トークエディタをプロパティ付きで起動してアプリから読み上げ(Speak)をする。できればDLLのAPIからアプリの起動なしで読み上げしてほしかった。(UIとか.NETとかメモリ食いでCPUパワーを使ってしまう)

さて置き、実装は単純なのでSAPIの部分を置き換えて、両方使えるようにするのがメインの作業。

CeVIO AIをC#から読み上げるサンプル

インストールされているボイスはSAPI経由でGetInstalledVoicesで取ってくるサンプルがあるけれど、レジストリに登録されているボイス名とCastに設定する名前は一致していない。

SAPIに登録されるボイス名は、弦巻マキ、スターターパック(日本語、英語)の場合、CeVIO-AI-弦巻マキ(英語)とCeVIO-AI-弦巻マキ(日本語)(SAPI用レジストリ)。Castに設定する名前は、弦巻マキ(英)と弦巻マキ(日)。setting.cfgファイルに記述あり。しかし英語のsetting.cfgファイルは英語表記されていて、CeVIO DLLに含まれるAPI AvailableCastsのリストも一致しない。

.NETアセンブリとして登録する、dllの参照の追加元はC:\Program Files\CeVIO\CeVIO AI\CeVIO.Talk.RemoteService2.dllから。(CeVIOのサイトでは再配布はしないでねと書かれているので注意)

やってみて思い出した。メインにしたアプリが.NET COREで、CeVIOのサイトには明確にサポート外。これで30分くらい悩む。(参考にさせて頂いたサイトのコードのActivateでエラーが消えず)

結局.NETアプリで常駐するコマンドアプリにする。CMDバージョンと、Formバージョンで試作。すでに起動中の時にはIPC経由でイベントを発生させて文字列を渡してプログラムを抜ける。FormバージョンはUIにテキストを設定して読み上げボタンイベントを発生させる。

しかし、CeVIO自身の実装はいたって簡単。一度に読み上げる文字列の長さが200文字の制限以外はSAPIほど初期化の処理がすくなくて快適。逆に.exeにアセンブリを実装する前にファイルチェックをしたうえでAssemblyをコード上からインポートして実行する必要がある。これをやらないと、トークエディタがインストールされていないマシンではアプリは走らない。。。マイクロソフトのSAPIとも共存したい。

twitch, YouTube チャットを読み込んで自動応答してBotに使用。マイクロソフトの音声認識はもうちょっと制度を上げてほしい。認識精度悪すぎ。登録単語モードはほぼほぼつかえない。フリーワードモードは自由度高すぎで発音した単語が正しく認識されることはまずない。

とりあえず、SAPIでCeVIOがインストールされている時はVoiceCallCmd.exe、VoiceCallForm.exeを読み上げ文章をつけて実行する。今のところメールチェック、メールのタイトルの読み上げ、処理状況の読み上げはいつも通り読めている。

読み上げ中の場合は、読み上げテキストをキューに設定して、キューがなくなるまで繰り返す。

VoiceCallForm.exeには各種パラメータをつけて感情表現をできるようにする。その前に参考にさせてもらったサイトのコードは他のボイスエンジンとの互換性の為に、クラスにはAPIがすべて網羅されていないのでパラメータの数値(0-100)、感情値の設定をそのまま使えるようにクラスを作り直すことにする。

(コードは完成するまでは未公開)

C# WASAPI NAudioで音量レベルメーターを作る

最低限必要なオーディオレベルメーターです。緑のメーターが音量、黄色CH1,CH2がそれぞれ左右のチャンネルです。オーディオデバイスが5.1chだと黄色いメーターが6個表示されます。5.1の”.1″は5ch + ウーハーのチャンネル。ドルビーとかの映画とかでしか使わないと思われる。(ゲームでも使われるのかな)

今回は、カスタムコントロール内でデバイス選択用のコンボボックスと、プログレスバーのオーバーライド(標準のままだと時間制御が入っていて音声の反応に追いつかないので、ただの四角で対応しています)

作ったきっかけ

最近、Twitchで音楽配信をやりたくなってドラムマシン(BOSS DR-880)とKORG Gadget 2のゲーム音源を使ってサンプリング音源で遊んでたりしてます。その時に音が出ているか目で確認したくて作りました。

前にも仕事でWASAPI+D2DでOSDとかWin32で作ってたけど、C#で 名前空間を 書き直したラッパーを公開している人がいるみたいなので使ってみました。Win32C++でCOMをマスターしてれば、MSDNそのまま使えるから必要ないんだけど。時間と作業効率上の問題か。それとバグった時の…しかし人が書いたコードを理解する時間と、自分で書くのとどっちが早いかが勝負。WASAPIを書き直したこの人の労力はすごいかも。C#でWASAPI理解するなら、C++でもいいじゃん。C++だと、アプリの動作が7割早いらしいね。(Win32 + COM最強!)

配信でOBSを使うならバックグランドを淡色にすれば背景を消せるので、これでもいいといえばいい。

あとは、アニメーションを作るときのエフェクトとか合わせるときの問題か。DXならブレンディングできるし。今後の課題。今回はAudioRenderデバイス(再生デバイス)からメインボリュームと、使えるチャンネルを表示している。

AudioCaptureデバイスもモニタ出来るけれど、Captureデバイスからサブスクリプションで有効なデータを受け取るイベントを受け取ってバッファを読むようだ。これだと生データが読めるのでFFTもできそう。実際はAudioRenderをループバックして、バッファを読んでデータを表示。スペアナの表示もできるっていうことらしい。ちなみにAudioCaptureのバッファのデータは、WaveExフォーマットでステレオデータを読むのでこれまたC++の方が使い勝手がいい(Win32 APIがSDKに用意されている)気がする

ダウンロードはこちら

Gitとかは相変わらず使いにくいし、シェアする気もないのでソースはZIPでアップしておく。(ご利用はご自由ですが一切責任は負いかねますのでよろしくお願いします)

このサイトは、プログラミングの知識のある上級者向けですのでソースコードに関する不具合は環境によって書き直してください。(サイトの管理者Nは対応しません)

これをエンジンとして、ビジュアル的なエフェクトが作れればいいなと思います。

Windows 10 VisualStudio 2019 C#WinFormで作成しています。必要なNuGetパッケージはスクショのリストの通り。NuGetからNAudio周りのパッケージをDLしてください。

次は、またSPEECH APIでコマンド管理アプリを上げていこうか。OpenCVで目、口、鼻トラックもできるようになったのでそっちかな。あとは、Youtubeチャット読み上げアプリとか絡めて、VTuber用アプリとか。

自分のTwitchアプリを作っていこう。

ちなみにTwitchチャンネルはこちらです。

C#(String.Format)で現在の日付時刻表示

珍しくTech。(自分のメモに残したかったので)
C#のデバッグでログを日付と時間を書式付きで表示したい場合がある。

時間表示は、hh:mm:ss:fff 13:35:23:123
カスタム表記で、時:分:秒:ミリ秒を2桁で0表示ありの場合は下の通り。

String.Format(“{0:hh:mm:ss:fff}”, DateTime.Now);

主な記号とサンプル:
y (year)
M (month)
d (day)
h (hour 12)
H (hour 24)
m (minute)
s (second)
f (second fraction)
F (second fraction, trailing zeroes are trimmed)
t (P.M or A.M)
z (time zone).

サンプル:
String.Format(“{0:y yy yyy yyyy}”, dt); // “8 08 008 2008” year
String.Format(“{0:M MM MMM MMMM}”, dt); // “3 03 Mar March” month
String.Format(“{0:d dd ddd dddd}”, dt); // “9 09 Sun Sunday” day
String.Format(“{0:h hh H HH}”, dt); // “4 04 16 16” hour 12/24
String.Format(“{0:m mm}”, dt); // “5 05” minute
String.Format(“{0:s ss}”, dt); // “7 07” second
String.Format(“{0:f ff fff ffff}”, dt); // “1 12 123 1230” sec.fraction
String.Format(“{0:F FF FFF FFFF}”, dt); // “1 12 123 123” without zeroes
String.Format(“{0:t tt}”, dt); // “P PM” A.M. or P.M.
String.Format(“{0:z zz zzz}”, dt); // “-6 -06 -06:00” time zone

パターンの表記は以下の通り:
Specifier DateTimeFormatInfo property Pattern value (for en-US culture)
t ShortTimePattern h:mm tt
d ShortDatePattern M/d/yyyy
T LongTimePattern h:mm:ss tt
D LongDatePattern dddd, MMMM dd, yyyy
f (combination of D and t) dddd, MMMM dd, yyyy h:mm tt
F FullDateTimePattern dddd, MMMM dd, yyyy h:mm:ss tt
g (combination of d and t) M/d/yyyy h:mm tt
G (combination of d and T) M/d/yyyy h:mm:ss tt
m, M MonthDayPattern MMMM dd
y, Y YearMonthPattern MMMM, yyyy
r, R RFC1123Pattern ddd, dd MMM yyyy HH’:’mm’:’ss ‘GMT’ (*)
s SortableDateTi­mePattern yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss (*)
u UniversalSorta­bleDateTimePat­tern yyyy’-‘MM’-‘dd HH’:’mm’:’ss’Z’ (*)

サンプル:
String.Format(“{0:t}”, dt); // “4:05 PM” ShortTime
String.Format(“{0:d}”, dt); // “3/9/2008” ShortDate
String.Format(“{0:T}”, dt); // “4:05:07 PM” LongTime
String.Format(“{0:D}”, dt); // “Sunday, March 09, 2008” LongDate
String.Format(“{0:f}”, dt); // “Sunday, March 09, 2008 4:05 PM” LongDate+ShortTime
String.Format(“{0:F}”, dt); // “Sunday, March 09, 2008 4:05:07 PM” FullDateTime
String.Format(“{0:g}”, dt); // “3/9/2008 4:05 PM” ShortDate+ShortTime
String.Format(“{0:G}”, dt); // “3/9/2008 4:05:07 PM” ShortDate+LongTime
String.Format(“{0:m}”, dt); // “March 09” MonthDay
String.Format(“{0:y}”, dt); // “March, 2008” YearMonth
String.Format(“{0:r}”, dt); // “Sun, 09 Mar 2008 16:05:07 GMT” RFC1123
String.Format(“{0:s}”, dt); // “2008-03-09T16:05:07” SortableDateTime
String.Format(“{0:u}”, dt); // “2008-03-09 16:05:07Z” UniversalSortableDateTime