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.
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.
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.
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:
- Download and install Microsoft Expression Encoder 2.
- Open Expression Encoder.
- Import the existing wmv files. Either using File Import menu or by licking on the Import button at the bottom of the window.
- Select the Encode tab.
- In the profile audio group expand the advanced properties.
- Change the properties to a smaller size to optimise the smaller size.
- Codec WMA
- Mode CBR
- Bitrate 20kps
- Sample Rate 44.1kHz
- Bits Per Sample 16
- Channels Mono
- Start the encoding process by click the encode button at the bottom of the window or the Encode File menu item.
- Once the encoding is complete select Output tab in the top right.
- 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.
- 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.