Windows Phone マイクロフォン プリーズ
あれ、MSCセッションのフォローは?…つー話はおいておいて、今度はマイクロフォンでマイ録音する方法を紹介します。・・・まぁいいじゃん。
マイクロフォンは、Microsoft.Xna.Framework.Audio 名前空間のMicrophoneクラスで操作します。名前空間から判るとおり、この機能はXNA Frameworkを使うので、プロジェクトの参照にMicrosoft.Xna.Frameworkコンポーネントを追加しておきます。
そして、適切な場所で名前空間のUsing宣言をしておきます。
using Microsoft.Xna.Framework.Audio;
Microphoneクラスのインスタンスは次のコードで取得できます。
var mic = Microphone.Default;
バイブレータのときも同じ形式でインスタンスを取得していましたね。デバイス系はこういう形式が多いです。クラスリファレンスでコンストラクタがないものは、この形式かな?と思ってみるとよいでしょう。
マイクロフォンを使うプログラムの手順は、こんな感じ
- マイクロフォンインスタンス参照取得
- サンプリングレートを設定(BufferDurationプロパティ)
- マイクロフォンの音データをサンプリングする度に呼ばれるハンドラを登録(BufferReadyイベント)
- サンプリングした音データを都度、そして、順次保持していくためのストリームを用意
- マイクロフォンの音サンプリングを開始(Startメソッド)
- 登録したハンドラがコールされるたびに、マイクロフォンから音データを取り出し(GetDataメソッド)、用意したストリームに書き込む
- マイクロフォンのサンプリングを終了(Stopメソッド)
- 取り込んだ音データをファイル化
これをコードで書くと・・・
先ず、クラスのメンバー変数で以下を用意して、
private Microphone mic;
private MemoryStream stream;
private byte[] buffer;
どこか適当な起動場所(例えばボタンのクリックハンドラとかタップハンドラなど)に以下のコードを記述します。
// 1.~5.までのコード
mic = Microphone.Default;
mic.BufferDuration = TimeSpan.FromMilliseconds(100);
buffer = new byte[mic.GetSampleSizeInBytes(mic.BufferDuration)];
mic.BufferReady += new EventHandler<EventArgs>(mic_BufferReady);
stream = new MemoryStream();
mic.Start();
これで5番目までが完了。ここではサンプリングを100msecに設定しています。ハンドラの中で音データを取り出すために必要なバッファのサイズはここで確定でき、あとは再利用していくので、ここでnewして用意しています。ストリームはMemoryStreamを使います。
そして、ハンドラーは、
private void mic_BufferReady(object sender, EventArgs e)
{
int size = mic.GetData(buffer);
Deployment.Current.Dispatcher.BeginInvoke(()=>
{
stream.Write(buffer, 0, size);
}
}
こんな感じ。用意したバッファにマイクから音データを取り出し、ストリームに書き込んでいます。6番目のステップね。ストリームに書き込むときは、BufferReadyのハンドラをコールするスレッドのオーナーとストリームのオーナーが違うので、Dispatcherへの委譲が必要。
で、例えば終了用のボタンを用意して、そのクリックハンドラで、
mic.Stop();
とやれば、サンプリングが終了します。
これでOK…とはいきません。残念ながらこれではうまく動かないんですね。何故かというと、MicrophoneクラスはXNAフレームワークの機能で、サンプリングするには、XNAフレームワークの処理ループを回さないと、サンプリングしてくれないからなんです。そのために、先ず、名前空間参照として以下を追加します。
using System.Windows.Threading;
using Microsoft.Xna.Framework;
クラスのメンバー変数として、
private DispatcherTimer timer;
を加え、そして、1.~5.のコードの前に、
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliSeconds(50);
timer.Tick = delegate { try { FrameworkDispatcher.Update() } catch { } };
timer.Start();
を加えます。これで、マイクのサンプリングを行う為の更新ループが動くことになります。これで、メモリストリームへの書き込みは完了です。あ、あと、micのStop()メソッドをコールしたら、timer.Stop()メソッドのコールも忘れずにやっておきましょう。
さて、このままだと、サンプリングしたプログラムの中だけでしかデータを使うことが出来ないので、最後にファイルに落とす方法を書いておきます。例えばこんな感じ。
string fileName = "...wav";
var storage = IsolatedStorageFile.GetUserStoreForApplication();
if (storage.FileExists(fileName))
{
storage.DeleteFile(fileName);
}
var fileStream = storage.CreateFile(fleName);
var recordedData=stream.ToArray();
fileStream.Write(recordedData, 0, recordedData.Length);
fileStream.Close();
fileStream.Dispose();
stream.Close();
stream.Dispose();
これでアイソレーテッドストレージ領域に音ファイルとして永続化されます。
ちゃんちゃん。
…って、え?再生したい?ならコードはこれで。
var storage = IsolatedStorageFile.GetUserStoreForApplication();
var fileStream = storage.OpenFile(fileName, FileMode.Open, FileAccess.Read);
byte[] playBuffer = new byte[fileStream.Length];
fileStream.Read(playBuffer, 0, playBuffer.Length);
SoundEffect effect = new SoundEffect(playBuffer, myMic.SampleRate, AudioChannels.Mono);
effect.Play();