Using XNA Interop to Record Audio

0
129

Before the Tailspin mobile client application can handle events raised by XNA objects, such as a Microphone object, it must create an XNA asynchronous dispatcher service. The following code example from the App.xaml.cs file shows how this is done.

C#
public App()
{

this.ApplicationLifetimeObjects.Add(
new XnaAsyncDispatcher(TimeSpan.FromMilliseconds(50)));
}

The VoiceQuestionView.xaml file defines two buttons, one toggles recording on and off, and the other plays back any saved audio. The recording toggle button is bound to the DefaultAction Command command in the view model, and the play button is bound to the PlayCommand command in the view-model.

The DefaultAction command uses the StartRecording and StopRecording methods in the VoiceQuestionViewModel class to start and stop audio recording. The following code example shows the StartRecording method.

C#
private void StartRecording()
{
var mic = Microphone.Default;
if (mic.State == MicrophoneState.Started)
{
mic.Stop();
}
this.formatter = new WaveFormatter(
this.wavFileName, (ushort)mic.SampleRate, 16, 1);
this.observableMic = Observable.FromEvent<EventArgs>(

h => mic.BufferReady += h, h => mic.BufferReady -= h)
.Subscribe(p =>
{
var content =
new byte[mic.GetSampleSizeInBytes(mic.BufferDuration)];
mic.GetData(content);
if (this.formatter != null)
{
this.formatter.WriteDataChunk(content);
}
});
mic.Start();
}

This method gets a reference to the default microphone on the device and creates a WaveFormatter instance to convert the raw audio data to the WAV format.

The method uses the Observable.FromEvent method to subscribe to the microphone’s BufferReady event, and whenever the event is raised, the application uses the WaveFormatter instance to write the audio data to isolated storage. Finally, the method starts the microphone.

The following code example shows the StopRecording method that disposes of the Microphone and WaveFormatter instances and attaches the name of the saved audio file to the question.

C#
private void StopRecording()
{
Microphone.Default.Stop();
this.observableMic.Dispose();
this.formatter.Dispose();
this.formatter = null;
this.Answer.Value = this.wavFileName;
}

The play button in the VoiceQuestionView view plays the recorded audio by using the SoundEffect class from the Microsoft. Xna.Framework.Audio namespace. The following code example shows the Play method from the VoiceQuestionViewModel class that loads audio data from isolated storage and plays it back.

C#
private void Play()
{
this.IsPlaying = true;
using (var fileSystem =
IsolatedStorageFile.GetUserStoreForApplication())
{
using (var dat = fileSystem.OpenFile(
this.wavFileName, FileMode.Open, FileAccess.Read))
{
try
{
using (var effect = SoundEffect.FromStream(dat))
{
var instance = effect.CreateInstance();
instance.Play();
while (instance.State == SoundState.Playing)
{
System.Threading.Thread.Sleep(100);
}
}
}
catch (ArgumentException)
{
}
}
}
this.IsPlaying = false;