Windows Phone マイクロフォン プリーズ


あれ、MSCセッションのフォローは?…つー話はおいておいて、今度はマイクロフォンでマイ録音する方法を紹介します。・・・まぁいいじゃん。

マイクロフォンは、Microsoft.Xna.Framework.Audio 名前空間のMicrophoneクラスで操作します。名前空間から判るとおり、この機能はXNA Frameworkを使うので、プロジェクトの参照にMicrosoft.Xna.Frameworkコンポーネントを追加しておきます。
そして、適切な場所で名前空間のUsing宣言をしておきます。

using Microsoft.Xna.Framework.Audio;

Microphoneクラスのインスタンスは次のコードで取得できます。

var mic = Microphone.Default;

バイブレータのときも同じ形式でインスタンスを取得していましたね。デバイス系はこういう形式が多いです。クラスリファレンスでコンストラクタがないものは、この形式かな?と思ってみるとよいでしょう。
マイクロフォンを使うプログラムの手順は、こんな感じ

  1. マイクロフォンインスタンス参照取得
  2. サンプリングレートを設定(BufferDurationプロパティ)
  3. マイクロフォンの音データをサンプリングする度に呼ばれるハンドラを登録(BufferReadyイベント)
  4. サンプリングした音データを都度、そして、順次保持していくためのストリームを用意
  5. マイクロフォンの音サンプリングを開始(Startメソッド)
  6. 登録したハンドラがコールされるたびに、マイクロフォンから音データを取り出し(GetDataメソッド)、用意したストリームに書き込む
  7. マイクロフォンのサンプリングを終了(Stopメソッド)
  8. 取り込んだ音データをファイル化

これをコードで書くと・・・

先ず、クラスのメンバー変数で以下を用意して、

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();

 

Comments (0)

Skip to main content