Part 20: Recording an Audio Wav File

Part 20: Recording an Audio Wav File

Update: 2013-06-26
Share

Description

Source Code: https://aka.ms/absbeginnerdevwp8
PDF Version: https://aka.ms/absbeginnerdevwp8pdf

In this lesson we'll write the code required to record the custom sound. We'll employ the Coding4Fun Toolkit to help make this easier, but we'll still need to understand things like MemoryStreams and the phone's IsolatedStorage.

Here's our game plan in this lesson:

  1. We'll modify the ToggleButton wiring up event handler methods to the Checked and Unchecked events.
  2. We'll use the MicrophoneRecord class in the Coding4Fun Toolkit's Audio namespace to begin and stop the recording process.
  3. When we stop recording, we'll need to temporarily save the sound stored in the phone's memory to a location on disk so it can be played back or saved permanently.
  4. We'll add a MediaElement control so we can enable playback of the sound.
  5. Manage the state of the Play sound button, turning it off and on depending on the recording action of the user.

Let me just say that this is perhaps one of the most challenging lessons in this entire series because it deals with some slightly more advanced material. You should embrace this ... you only learn when you struggle, and challenging yourself with difficult concepts will help you grow faster. Be sure to not only watch this video, but also read the MSDN articles that I reference for more information. So put on your thinking cap and let's get started.

 

1. Modify the ToggleButton Control wiring up Event Handler Methods

Edit the XAML code on the RecordAudio.xaml page for the ToggleButton as follows:

Generic Episode Image

In lines 39 and 40 we wire up method handlers for the two states of the ToggleButton.

 

2. Create a private instance of the Coding4Fun.Toolkit.Audio.MicrophoneRecord class

In the RecordAudio.xaml.cs file, add the following line of code:

Generic Episode Image

 

We create a new private instance of the MicrophoneRecorder class, and use the hover-over-the-blue-dash technique to add a using statement for the Coding4Fun.Toolkit.Audio namespace.

Now, we can start and stop the MicrophoneRecorder by adding code to the ToggleButton's Checked and Unchecked event handler methods:

 

Generic Episode Image

 

3. Saving the sound data collected by the MicrophoneRecorder into a file

As we're recording, the MicrophoneRecorder object is collecting the sound information in a buffer. A buffer is just a pocket of memory devoted to storing data. Buffers are typically used when there is a difference between the rate at which data is received and the rate at which it can be processed, or in the case that these rates are variable. So, it may take us 10 seconds to record a 10 second sound and during that time data is being added to the buffer. That said, the computer could process that data in a fraction of a second. The buffer is just a queue ... we can write the data at one rate of speed while reading it at another rate of speed. In programming, buffers are usually used between physical hardware and software, or when moving data from memory to disk and back, or data from memory to a network connection and back. I'm not a computer science guy, so I just think of a buffer as a bucket that you slowly collect things in until you're ready to work with the entire bucket at one time. So, I'm collecting shells on the beach and placing them into my bucket. Once I get a full bucket, I start processing them, deciding which to keep and which to throw away. I collect over a long period of time, then once I've filled my bucket, I process very quickly. That's how I think of a buffer.

When we call the Stop() method, the MicrophoneRecord stops adding sound information, but is holding that data in memory, in a buffer and NOW we need to process the data in the buffer. In this case, when I use the term "process" what I mean is that I want to grab the sound data out of the buffer and place it as a WAV file into a temporary file.

Once it's in a file sitting on my Phone's storage, I'll be able to hand that file over to a MediaElement and direct it to play that temporary WAV file. If the user wants to keep the file, I can re-name it and store it permanently.

So, let's talk about storing files on a Windows Phone. The storage space on the phone is partitioned into isolated areas. Each app installed on the phone gets one of these isolated areas. I use the term "isolated" because one app can't look at the storage area of another app. This is for security ... one app can't rummage through your photos or notes or other secret data and upload it to a secret malicious server or corrupt it in some evil way.

This isolated permanent storage area that's dedicated to your app is called IsolatedStorage. It's just a tidy way of keeping each app's data safe since each app is only able to write and read from its own storage area.

So, back to the problem at hand ... the MicrophoneRecorder object has a bunch on data sitting in a buffer in memory, a MemoryStream object. My job is to save that data from the MemoryStream to a file—a temporary file—in IsolatedStorage. To accomplish this, I'll create a helper method that will take a MemoryStream as an input parameter and then in the body of the helper method, I'll create a new file in IsolatedStorage and then dump all the MemoryStream buffer data into that file.

That's the plan, let's build it:

Generic Episode Image

 

As the screenshot indicates, the input parameter is of type MemoryStream and will need a using statement to reference System.IO.

Next, we'll employ a different type of using statement:

 

Generic Episode Image

 

In this context, the using statement will create a context for an instance of System.IO.IsolatedStorage.IsolatedStorageFile. Any code inside of the code block defined by the using statement will have access to the isoStore variable. Once the flow of execution leaves the closing curly brace, the isoStore variable will be disposed from memory properly.

You use this using syntax when you want to work with classes that implement IDisposable ... typically these are managed types in the .NET Base Class Library (or in our case, the Windows Phone API) that access UNMANAGED resources. So the primary use of the IDisposable interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a MANAGED object when that object is no longer used. That said, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of UNMANAGED resources such as window handles, or open files and streams. The danger is that two or more processes (apps) attempt to access the same resources at the same time and cause an unrecoverable error condition. Types implementing IDisposable handle these scenarios correctly. For a more complete explanation of these topics:

using Statement (C# Reference)
https://msdn.microsoft.com/en-us/library/yh598w02.aspx

IDisposable Interface
https://msdn.microsoft.com/en-us/library/system.idisposable.aspx

The IsolatedStorageFile class provides methods that help you manage the files and folder for use by your app. We use the GetUserStoreForApplication() to retrieve the IsolatedStorage area for just our app.

Next, we'll grab the buffer and attempt to create a file in our IsolatedStorage area:

 

Generic Episode Image

 

In line 69, I add a line of code that will retrieve values from the buffer (passed in to the helper method) and convert it to the format of a wav (audio) file. As you can see, the MemoryBuffer doesn't implement this method. Instead, we want to use an extension method from the Coding4Fun.Toolkit.Audio.Helpers namespace. So, in order to apply this extension method, we'll add another using statement at the top of our code file:

 

Generic Episode Image

 

An extension method in .NET allows you to attach a method to any type. So, I could add some utilities to the int or string or, in this case, the System.IO.MemoryStream. The extension method allows you to work with the members of that type just like any public method could. For more information on extension methods, and how to create your own, check out:

https://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx

Note: this is an advanced topic ... as long as you understand what they do and what purpose they serve, that's enough for now. Later you can learn how to create your own.

Ok, so now we have the buffer in wav (audio) format, we just need to actually put it into a new file on the device's IsolatedStorage area:

 

<img src="ht

Comments 
00:00
00:00
x

0.5x

0.8x

1.0x

1.25x

1.5x

2.0x

3.0x

Sleep Timer

Off

End of Episode

5 Minutes

10 Minutes

15 Minutes

30 Minutes

45 Minutes

60 Minutes

120 Minutes

Part 20: Recording an Audio Wav File

Part 20: Recording an Audio Wav File

Bob Tabor, Clint Rutkas