Saving Recorded Audio to IsolatedStorage

So, after the Windows Phone 7 Developer Launch events, I've had several questions about how someone should store audio captured from the microphone for later playback.  I said IsolatedStorage was the way to do it, but I left it to the attendees to figure it out. 

It turns out some folks were having a little difficulty figuring it out, so here's a little cheater code for you. 

This is a very simple bit of code that does three things... one, it allows you to record audio... two, it allows you to save that audio in IsolatedStorage and three, it allows you to play that audio back from IsolatedStorage.

I was going to write a tremendously long blog post about how to do this... however, the code is already commented very well... so here are the three important methods instead (plus the delegate handler.)  :-)

 

        private void startBtn_Click(object sender, RoutedEventArgs e)
        {
            // Don't start if we are already recording
            if (recording == false)                        
            {
                // We're recording 1/10th of a second buffers at a time
                microphone.BufferDuration = TimeSpan.FromMilliseconds(100);

                // Here we size our byte array to hold the audio
                buffer = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];

                // This is our delegate handler for when the buffer get's full
                microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);

                // yep... we're recording now!
                recording = true;
            }

            // Activate the Microphone
            microphone.Start();
        }

        // This is our delegate (event) handler for when the buffer get's full
        void microphone_BufferReady(object sender, EventArgs e)
        {
            // copy the microphone data into our buffer
            microphone.GetData(buffer);

            // tell the dispatcher to run this
            this.Dispatcher.BeginInvoke(() =>
            {
                // copy it to our stream (remember, we need the stream to pass to the audio player)
                stream.Write(buffer, 0, buffer.Length);
            }
        );

        }

        private void stopBtn_Click(object sender, RoutedEventArgs e)
        {
            //ok user doesn't want to record anymore
            if (microphone.State == MicrophoneState.Started)
            {
                // so, if we were recording, we're not going to be after this line!
                microphone.Stop();

                // ok... no longer recording
                recording = false;
            }

            // ok, here is where we store the file

            // first, we grab the current apps isolated storage handle
            IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();

            // we give our file a filename
            string strSaveName = "MyRecording.wav";

            // if that file exists... 
            if (isf.FileExists(strSaveName))
            {
                // then delete it
                isf.DeleteFile(strSaveName);
            }

            // now we set up an isolated storage stream to point to store our data
            IsolatedStorageFileStream isfStream =
                     new IsolatedStorageFileStream(strSaveName,
                     FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication());

            // tell it to actually write it out (remember, it's just raw data)
            isfStream.Write(stream.ToArray(), 0, stream.ToArray().Length);

            // ok, done with isolated storage... so close it
            isfStream.Close();

        }

        // magic method
        private void playBtn_Click(object sender, RoutedEventArgs e)
        {
            // again, grab the current apps isolated storage
            IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();

            // yep... we want to play the same file we recorded
            string strFileName = "MyRecording.wav";

            // let's reverse what we did earlier... so we still need to get a
            // file stream from isolated storage... but it's read mode
            IsolatedStorageFileStream isfStream =
                 new IsolatedStorageFileStream(strFileName,
                 FileMode.Open, IsolatedStorageFile.GetUserStoreForApplication());

            // remember, our data is raw, so we need to create a new buffer again
            // to hold it (big enough to hold everything)
            byte[] b = new byte[isfStream.Length];

            // now we copy our file back in to our buffer
            isfStream.Read(b, 0, b.Length);

            // then we can pass it into our sound effect object...
            // but tell it current samplerate and audio channels from the current hardware

            // NOTE: if you wanted to get adventerous and have a mechanism where you play these on a different machine, 
            // you'll also need to encode the samplerate and audiochannels in your file store and restore them as well
            // because those settings might be different for a different piece of hardware (phone)
            // luckily, since we're using the same hardware, the settings won't change
            SoundEffect se = new SoundEffect(b.ToArray(), microphone.SampleRate, AudioChannels.Mono);

            // lastly... a miracle occurs
            se.Play();

        }

Note, the form is really simple... it looks like this.

 

The only other thing I had to do was follow the instructions to hook up the XNA Dispatcher to Silverlight here.

https://www.silverlightshow.net/items/Exploring-Silverlight-XNA-integration-on-Windows-Phone-7.aspx

Naturally, I've attached the code to this post... Have fun!

Bill

 

SoundSaver.zip