Windows Phone マイクからオーディオ入力を取得する

今回は、Silverlight アプリケーションでの Windows Phoneマイクからオーディオ入力を取得するサンプルを紹介します。
このプログラムで実装する機能の動作を、下記に解説しておきます。
実行すると、[記録]、[再生]、[中止]の3つのボタンが表示されます。最初に[記録]ボタンをクリックします。画面に「記録中・・・・」の文字が表示されます。この状態からマイクに向かって何か喋ると、音声が記録されます。筆者はPCにWebカメラを装着していますので、Webカメラに向かって喋りテストしました。
次に、[中止]をクリックします。「再生準備完了」の文字が表示されますので、この状態から[再生]ボタンをクリックします。「再生中・・・・」と表示され、いま記録した音声が再生されます。再生が終わると、「[再生]または[記録]ボタンをクリック」と表示されます(図1)。
| 図1: [記録]、[再生]、[中止]の3つのボタンで音声を記録再生する(クリックで拡大) |
サンプルは以下よりダウンロードできます。
→ 「Windows Phone マイクからオーディオ入力を取得する」のサンプルファイル(298KB)
※サンプル実行でエラーが発生した場合は、「ソリューションのビルド」を実行後、再度、デバッグ開始を行ってください
プロジェクトの作成
VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]を選択します。次に、「Windows Phone アプリケーション」を選択して、「名前(N)」に任意のプロジェクト名を指定します。ここでは「WP7_Microphone」という名前を付けています。Windows Phoneのバージョンは、今回は7.0を選択します。
MainPage.xamlの編集とコントロールの追加
x:NameがPageTitleというTextBlockのTextプロパティに「Microphone」と指定します。
ツールボックスからButtonコントロールを3個、TextBlockコントロールを1個配置します。ButtonのContentとx:Nameには図2のように指定します。[再生]と[中止]ボタンのIsEnabledのチェックは外して、最初表示された時点ではクリック不可としておきます。またTexBlockコントロールの、プロパティウィンドウの[ブラシ]パネルにある、ForegroundにGoldを指定し文字色を黄色系統色にしています。[テキスト]パネル内の文字サイズには36と指定しておきます。
| 図2: Buttonコントロールを3個、TextBlockコントロールを1個配置する(クリックで拡大) |
またVS2010のメニューから「プロジェクト(P)/参照の追加(R)」と選択して、Microsoft.Xna.Frameworkを追加しておきます(図3)。
| 図3: Microsoft.Xna.Framework を追加する(クリックで拡大) |
日本語表示設定
Windows Phone 7.1 SDK RC 日本語版では、フォントの設定なしにアプリケーションを実行し、タイトルやテキストに日本語を使った場合、日本語フォントが使われないで変な表示になってしまうことがあります。これを解消するには、書き出されるXAMLコードのアプリケーションのトップである
書き出されるXAMLコードは省略します。
ソリューションエクスプローラー内のMainPage.xamlを展開して表示される、MainPage.xaml.vbをダブルクリックして、リスト1のコードを記述します。
ロジックコードを記述する
リスト1 (MainPage.xaml.vb)
Option Strict On
指定した時間の間隔で実行されるタイマーである、DispatcherTimerクラスの含まれる、System.Windows.Threading名前空間をインポートします。
Imports System.Windows.Threading
ゲームクラス (タイマー、ゲーム ループなど) を提供するクラスの含まれる、Microsoft.Xna.Framework名前空間をインポートします。フレームワークコンポーネント (メディアなど)の状態を更新する、FrameworkDispatcher.Update()メソッドを利用するために、この名前空間が必要です。
Imports Microsoft.Xna.Framework
オーディオ再生用のプログラミング・インターフェース (API) を提供するクラスの含まれる、Microsoft.Xna.Framework.Audio名前空間をインポートします。
Imports Microsoft.Xna.Framework.Audio
Imports System.IO
Partial Public Class MainPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
End Sub
マイクのオーディオ データのキャプチャに、プロパティ、メソッド、およびフィールドとイベントを提供するクラスであるMicrophoneのメンバ変数myMicrophoneを宣言し、Microphone.Defaultで、デフォルトで接続されているマイクを取得します。
Dim myMicrophone As Microphone = Microphone.Default
マイクからオーディオ データを取得する動的バッファーを、Byte型のmyBuffer配列メンバ変数として宣言します。
Dim myBuffer() As Byte
バッキング ストアとしてメモリを使用するストリームを作成するクラスである、MemoryStream型のメンバ変数myStreamを宣言します。
Dim myStream As New MemoryStream
SoundEffectサウンドの単一再生、一時停止、または停止インスタンスを提供するクラスである、SoundEffectInstanceクラス型のメンバ変数mySoundを宣言します。
Dim mySound As SoundEffectInstance
サウンド再生の状態を監視するフラグとして、Boolean型のメンバ変数myStateを宣言します。
Dim myState As Boolean = False
ページが読み込まれた時の処理
タイマーを表す新しいDispatcherTimerクラスのインスタンスmyTimerオブジェクトを宣言します。
タイマーの実行される間隔を50ミリセコンドに指定します。
AddHandlerメソッドで、指定したタイマーの間隔が経過した時に発生するTickイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を実行します。
FrameworkDispatcher.Updateメソッドで、いろいろなフレームワークコンポーネント (メディアなど) の状態を更新します。XNA FrameworkDispatcherや、サウンドが再生されているかどうかをチェックして更新します。
サウンド再生の準備はできていて、SoundEffectのインスタンスが再生されていない場合は、サウンドの再生状態を監視するmyState変数にFalseを指定し、TextBlockにメッセージを表示します。[記録]ボタンの使用は可能、[中止]ボタンの使用は不可とします。Startメソッドでタイマーを実行します。
AddHandlerメソッドで、オーディオ キャプチャバッファーを処理する準備ができている時に発生するイベントである、BufferReadyイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。GetDataメソッドでオーディオデータを取得します。MemoryStreamのWriteメソッドで、オーディオデータをストリームに格納します。Writeメソッドの書式は下記の通りです。
MemoryStream.Write(データの書き込み元となるBuffer,書き込むデータの開始位置,書き込む最大Byte数)
Private Sub MainPage_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Dim myTimer As New DispatcherTimer()
myTimer.Interval = TimeSpan.FromMilliseconds(50)
AddHandler myTimer.Tick, Sub()
FrameworkDispatcher.Update()
If myState = True AndAlso mySound.State <> SoundState.Playing Then
myState = False
TextBlock1.Text = "[再生]または[記録]ボタンをクリック"
recordButton.IsEnabled = True
stopButton.IsEnabled = False
End If
End Sub
myTimer.Start()
AddHandler myMicrophone.BufferReady, Sub()
myMicrophone.GetData(myBuffer)
myStream.Write(myBuffer, 0, myBuffer.Length)
End Sub
End Sub





