2015年9月19日土曜日

XNAでマイク入力

XNAでマイク入力を試してみた。
XNAは開発が終了してしまったが、まだDLは可能(なはず)。XNAをインストールするときにはVisual Studio C# 2010が必要になるみたいなのでそれを先に入れる。一旦インストールしてしまえば、ライブラリはVisual Studio 2015のC#からも使用可能。XNAは音声(WAVE)IOやXbox360コントローラなど、C#では珍しくハードウェアアクセスが豊富なので入れておくと便利。

さて、マイク入力だが、今回はスレッドを1本作って無限ループとした。ただ作ってから気がついたけどタイマとかで定期的に読めば問題なさそう。今回試した環境では16bit1chのデータが読めた。リファレンスによると8bit or 16bit / 1ch or 2chということなので、データ数からビット数やチャンネル数を予測するのは不可能っぽい。実際に使うには何らかの対策が必要そう。
それとVS2010がインストールされていたのがデスクトップだったので、そっちで開発をしているが、ノートにEXEを投げると正常に動作してくれないという問題がある。ノート側でビルドすれば動きそうな気もするけど、まだVS2010が入ってないので確認ができない(そもそもVS2015も入れてないが)。

音声出力も動作確認はしたが、また次の機会に。

/* 例:Microphone Mic = Microphone.Default; */
/* Microphone.Allですべてのデバイスを獲得できるのでそこから選んでも良い */

Mic.Start();

while (IsLoop)
{
    byte[] buffer = new byte[Mic.GetSampleSizeInBytes(TimeSpan.FromSeconds(0.1))];
    int bytesRead = 0;

    DateTime ReadTime = DateTime.Now;

    while (bytesRead < buffer.Length)
    { bytesRead += Mic.GetData(buffer, bytesRead, buffer.Length - bytesRead); Thread.Sleep(10); }

    short[,] ROW = new short[buffer.Length / 2, 1];

    for (int i = 0; i < buffer.Length; i += 2)
    { ROW[i / 2, 0] = BitConverter.ToInt16(buffer, i); }

    this.ROW = ROW;
}

Mic.Stop();

軽く動作の説明をすると、最初の方の0.1を渡すメソッドでバッファ数を決めている。これは0.1秒分のバッファサイズとなる。
次にMic.GetDataでデータを読む。これは引数にオフセットを渡せるので、バッファ全体を読み込むまでループする。データを纏めて読む必要が無い場合は1回に読める分だけ処理してもいい。
またGetDataのループの中ではThread.Sleep(10)で10ミリ秒のスリープを入れている。これはこのwhite(true)でCPUリソースを浪費しないようにするためだ。
そしてshort(符号付き16bit)の2次元配列を作る。今回は1ch16bitで決め打ちしているのでバッファの半分の長さで1ch分となっている。
あとはforで回してBitConverterでshortに戻している。これはビットシフトとかでもいいと思うが、BitConverterのほうが確実(エンディアンが一致している限りは)。
最後にthis.ROWにROWを代入している。コレとは別のループでthis.ROWを監視しておき、データが入ったら処理を行い、処理が終わったらnullを入れてデータがないことを示す という感じでマイク入力のWAVEデータを扱えばいい。

配列をBitmapにGraphicsのDrawLineでグラフにすれば生の波形を表示することができる。PCにステレオミキサが入ってればそれを録音することによりPCの音が表示されるので、iTunesとかてきとーな音源を見てみると面白い。

0 件のコメント:

コメントを投稿