# Friday, December 19, 2008

Silverlight BabySmash Audio Files

Overview

In this post I will provide an overview of the changes from the original wav media files, to wma files required by the Silverlight version.

The main sections are:

  • Introduction – Discusses the background behind the use of audio files in the original WPF version and an overview of the changes required.
  • Code Changes – Discusses the changes required to move from win32 api implementation to the MediaElement.
  • Audio File Changes – Discusses uses Microsoft Expression Media Encoder 2 to convert the wav files to wma files.
  • Summary – Overview of the changes made and the advantages of the change.

Introduction

As Scott indicated in his first post Introducing BabySmash, he started using techniques that he already knew. As a result the laughs and giggles played when a key is pressed where included as embedded wav files. When moving to the Silverlight environment this approach require some modifications to optimise the download experience and cater for the differences of running cross platform within a browser.

Code Changes

The original audio files used by the WPF application where wav files as in made use of class called Win32Audio, which wrapped calls to the underlying Windows unmanaged win32 api’s.

    public class Win32Audio
    {
        #region WIN32 Const Definitions
        public const UInt32 SND_ASYNC = 0x0001;
        public const UInt32 SND_LOOP = 0x0008;
        public const UInt32 SND_MEMORY = 0x0004;
        public const UInt32 SND_NOSTOP = 0x0010;
        #endregion

        // this is the overload we want to play embedded resource...
        public static Dictionary<string, string> cachedWavs = new Dictionary<string, string>();
        public static object cachedWavsLock = new object();

        [DllImport("winmm.dll")]
        public static extern bool PlaySound(byte[] data, IntPtr hMod, UInt32 dwFlags);

        [DllImport("winmm.dll", SetLastError = true)]
        private static extern bool PlaySound(string pszSound, IntPtr hmod, UInt32 fdwSound);

        public void PlayWavResource(string wav)
        {
            string s = GetWavResource(wav);
            PlaySound(s, IntPtr.Zero, SND_ASYNC);
        }

For the Silverlight version pinvokes to the underlying operating system are not allowed from  both a security point and cross platform point of view. The answer was to implement a new class XamlAudio that makes use of the MediaElement class present in both WPF and Silverlight to play the audio files.

    public class XamlAudio
    {
        private MediaElement player;
        readonly Queue<string> soundsToPlay = new Queue<string>();
        private bool inPlay;

        private Dictionary<string, Stream> media = new Dictionary<string, Stream>();

        //TODO Add lock and config value for sound queue limit
        public void PlayWavResourceYield(string s)
        {
            if (player == null)
                return;

            if (inPlay && soundsToPlay.Count < 5)
            {
                soundsToPlay.Enqueue(s);
                return;
            }

            PlaySound(s);
        }

The second major difference in the code is the shift from  the use of embedded audio files, as indicated in my earlier post Silverlight BabySmash Performance – The Asynchronous Story, the Silverlight version asynchronously downloads the audio files on demand. As result the initial download size for the deployed application is smaller.

Audio File Changes

The encoding format was also a major difference, changing from the use of wav files to Window Media  Audio files (*.wma). To convert the files I used Microsoft Expression Encoder.

The steps I used to convert the files where as follows:

  1. Download and install Microsoft Expression Encoder 2.
  2. Open Expression Encoder.
  3. Import the existing wmv files. Either using File Import menu or by licking on the Import button at the bottom of the window.
  4. Select the Encode tab.
  5. In the profile audio group expand the advanced properties.
  6. Change the properties to a smaller size to optimise the smaller size.
    1. Codec WMA
    2. Mode CBR
    3. Bitrate 20kps
    4. Sample Rate 44.1kHz
    5. Bits Per Sample 16
    6. Channels Mono
  7. Start the encoding process by click the encode button at the bottom of the window or the Encode File menu item.
  8. Once the encoding is complete select Output tab in the top right.
  9. Open the output folder by clicking o the Open Job button in the Job Output Section.

From the the output folder I copied the converted wma files to the ClientBin folder of the web site so that they where easily accessible  to the Silverlight application when using a WebClient asynchronous download request.

File WAV Encoding (kbps) WAV Files Size (KB) WMA Encoding (kbps) WMA File Size (KB)
babygigl2 20 6 20 15
babylaugh 88 14 20 11
ccgiggle 88 9 20 10
EditedJackPlaysBabySmash 352 227 20 25
falling 128 29 20 14
giggle 88 15 20 13
laugingmice 89 17 20 14
rising 128 26 20 13
scooby2 20 5 20 13
smallbumblebee 705 862 20 31

One interesting point from the comparison of the conversion is that for the small files with the same bit rate encoding the WMA files where larger. If further optimisation in terms of files size is required, then this is an area that could be further investigated to determine the exact encoding settings to trade-off audio quality against file size.

Summary

  • Changes to the C# code to make use of the built in MediaElement to play the audio files.
  • Cross platform audio support using wma files instead of wmv files.
  • Use of Expression Encoder to convert the source wmv files to a web optimised encoding.
Comments are closed.