Wednesday 19 November 2008

Visual Studio Debugging Feature - Tracepoints

While watching the PDC 2008 session on Visual Studio Debugger Tips and Tricks (TL59), I came across a handy Visual Studio debugging feature I didn't know about - tracepoints. A tracepoint is simply a breakpoint that will emit a debug trace statement when it is reached. It can emit things like the current function name, stack trace, or the contents of a variable. What's really cool is that you don't have to actually stop execution. This allows you to quickly add debugging statements without the need to check out your code or remember to take the Debug.WriteLine statements out afterwards.

It's really handy for working out what order things are getting called in multi-threaded code, when setting normal breakpoints would change the order of execution. I have also used them a bit for performance measurements, although I still need to create and start a Stopwatch instance in the code itself (perhaps there is another trick I am missing).

To create a tracepoint, simply create a normal breakpoint and right-click it, and select the "When Hit..." option.

Creating a tracepoint step 1

This brings up a dialog that allows you to specify the format of the trace statement, as well as allowing you to specify that it should continue execution (otherwise this will just remain a normal breakpoint). Finally, you can specify a macro to be run as well. The dialog gives good instructions for how to specify the tracepoint message. Most useful is being able to put an expression in curly braces. For example, {stopwatch.ElapsedMilliseconds}

Creating a tracepoint step 2

Once you have done this, the tracepoint is indicated by a diamond instead of the normal circle:

A tracepoint

It's available in both Visual Studio 2005 and 2008.

Monday 17 November 2008

SourceSafe Item Change Counter

Although I remain hopeful that we will switch to TFS soon, my work currently uses SourceSafe for our source control. I wanted to identify which files in our repository had been changed the most times, and which files had been changed by the most different people. This data is to be used as part of a presentation I will be doing on dependencies and the impact they have on code quality (low-level components that are frequently changing cause a lot of pain).

Using the SourceSafe COM object makes this a simple task. It's not quick (and my code isn't optimised in any way), but it does provide a useful view into which are the classes subject to constant change. The project parameter of the Count method should be of the form $/MyProject.

Here's the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SourceSafeTypeLib;

namespace SourceSafeAnalysis
{
    class SourceSafeChangeCounter : IDisposable
    {
        VSSDatabase db;
        List<SourceSafeChange> changes;

        public SourceSafeChangeCounter(string sourceSafeIni, string user, string password)
        {
            db = new VSSDatabase();
            db.Open(sourceSafeIni, user, password);            
        }

        public void Count(string project)
        {
            changes = new List<SourceSafeChange>();
            VSSItem item = db.get_VSSItem(project, false);
            CountItem(item);
            changes.Sort((x,y) => y.Changes - x.Changes);
        }

        private void CountItem(IVSSItem item)
        {
            if (item.Type == (int)VSSItemType.VSSITEM_PROJECT)
            {
                IVSSItems children = item.get_Items(false);
                foreach (IVSSItem child in children)
                {
                    CountItem(child);
                }
            }
            else
            {
                if (item.Name.EndsWith(".cs"))
                {
                    IVSSVersions versions = item.get_Versions((int)VSSFlags.VSSFLAG_RECURSNO);
                    SourceSafeChange change = new SourceSafeChange();
                    change.FileName = item.Spec;

                    foreach (IVSSVersion version in versions)
                    {
                        // ignore labels
                        if (String.IsNullOrEmpty(version.Label))
                        {
                            change.AddUser(version.Username);
                            change.Changes++;
                        }
                    }
                    changes.Add(change);
                }
            }
        }

        public IList<SourceSafeChange> Results
        {
            get { return changes; }
        }

        public void Dispose()
        {
            db.Close();
            db = null;
        }
    }

    class SourceSafeChange
    {
        private List<string> users;

        public SourceSafeChange()
        {
            users = new List<string>();
        }

        public string FileName { get; set; }
        public int Changes { get; set; }
        public IList<string> Users { get { return users; } }

        public void AddUser(string username)
        {
            if (!users.Contains(username))
            {
                users.Add(username);
            }
        }

        public override string ToString()
        {
            return string.Format("{0}: {1} ({2} users)", FileName, Changes, Users.Count);
        }
    }
}

Thursday 13 November 2008

WaveOutOpen Callbacks in NAudio

The waveOutOpen Windows API allows you to specify a variety of callback modes to receive information about when a buffer has finished playing. The choices are:

CALLBACK_EVENT The dwCallback parameter is an event handle.
CALLBACK_FUNCTION The dwCallback parameter is a callback procedure address.
CALLBACK_NULL No callback mechanism. This is the default setting.
CALLBACK_THREAD The dwCallback parameter is a thread identifier.
CALLBACK_WINDOW The dwCallback parameter is a window handle.

Of these, only the CALLBACK_FUNCTION and CALLBACK_WINDOW are of interest to us in NAudio, as they are the only two that will actually give back information about which buffer in particular has finished playing.

My preference was to use CALLBACK_FUNCTION as this means that the user has no need to pass Window handles to the WaveOut open constructor. There are of course implications to this. It means that the callback function itself will not be running on the GUI thread. However, so long as you are aware of this and don't attempt to talk to GUI components, all is well.

The company I work for has been using CALLBACK_FUNCTION for a large .NET application installed on thousands of PCs worldwide. However, we have discovered that certain audio chipsets have intermittent problems hanging in waveOutReset or waveOutPause if the CALLBACK_FUNCTION is used. Early versions of Realtek drivers exhibited this problem, but the latest drivers work correctly. However, the SoundMAX chipset found on a lot of modern laptops has this problem, and we have not been able to find a workaround.

So no problem, we decided to switch over to the CALLBACK_WINDOW mechanism. This works great on all chipsets we have tested. There is however one big problem. If you decide you want to stop playing, close the WaveOut device, and immediately create a new one and start playing, it all falls over horribly, and the .NET framework crashes with an execution engine exception.

The problem is related to the use of a native window to intercept the WaveOut messages. Here's the NativeWindow used by NAudio:

private class WaveOutWindow : System.Windows.Forms.NativeWindow
{
    private WaveInterop.WaveOutCallback waveOutCallback;

    public WaveOutWindow(WaveInterop.WaveOutCallback waveOutCallback)
    {
        this.waveOutCallback = waveOutCallback;
    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == (int)WaveInterop.WaveOutMessage.Done)
        {
            IntPtr hOutputDevice = m.WParam;
            WaveHeader waveHeader = new WaveHeader();
            Marshal.PtrToStructure(m.LParam, waveHeader);

            waveOutCallback(hOutputDevice, WaveInterop.WaveOutMessage.Done, 0, waveHeader, 0);
        }
        else if (m.Msg == (int)WaveInterop.WaveOutMessage.Open)
        {
            waveOutCallback(m.WParam, WaveInterop.WaveOutMessage.Open, 0, null, 0);
        }
        else if (m.Msg == (int)WaveInterop.WaveOutMessage.Close)
        {
            waveOutCallback(m.WParam, WaveInterop.WaveOutMessage.Close, 0, null, 0);
        }
        else
        {
            base.WndProc(ref m);
        }
    }
}

When the WaveOut device is created we attach our NativeWindow to the handle passed in. Then when the WaveOut device is closed, we dispose of our buffers and detach from the NativeWindow:

protected void Dispose(bool disposing)
{
    Stop();
    lock (waveOutLock)
    {
        WaveInterop.waveOutClose(hWaveOut);
    }
    if (disposing)
    {
        if (buffers != null)
        {
            for (int n = 0; n < numBuffers; n++)
            {
                if (buffers[n] != null)
                {
                    buffers[n].Dispose();
                }
            }
            buffers = null;
        }
        if (waveOutWindow != null)
        {
            waveOutWindow.ReleaseHandle();
            waveOutWindow = null;
        }
    }
}

This works fine with CALLBACK_FUNCTION, as by the time the call to waveOutReset (which happens in the Stop function) returns, all the callbacks have been made. In CALLBACK_WINDOW mode, this is not the case. We might still get Done and Closed WaveOutMessages. What happens to those messages? Well in the normal case they simply will be ignored by the message loop of the main window now that we have unregistered our NativeWindow. But if we immediately open another WaveOut device, using the same Window handle, then messages for the (now disposed) WaveOut device will come through to be handled by the new WaveOut's callback function. This means that the associated buffer GCHandle will be to a disposed object.

Could accessing an invalid GCHandle cause an ExecutionEngineException? I'm not sure. I put in various safety checks to ensure we didn't access the Target of a dead GCHandle, but that didn't solve the problem. Sadly there is no stack trace available to point to the exact cause of the fault.

The solution? Don't use an existing window. Instead of inheriting from NativeWindow, inherit directly from Form. No attaching of handles is needed any more. The form doesn't even need to be shown. I will do some more testing on this, but if it looks robust enough, the change will be checked in to NAudio.

Of course the CALLBACK_FUNCTION method continues to work fine, and there are no known issues with the current CALLBACK_WINDOW implementation so long as you don't recreate a new one based on the same window handle immediately after closing the last. There will be an additional benefit to this change - the need for Window handles to be passed to the WaveOut constructor will be completely removed.

Saturday 8 November 2008

Model View View-Model (MVVM) in Silverlight

I watched an excellent screencast by Jason Dolinger recently, showing how to implement the Model View View-Model pattern in WPF. A lot of the documentation on the MVVM pattern seems unnecessarily complicated, but Jason's demonstration explains it very clearly.

The basic idea of MVVM is that we would like to use data binding to connect our View to our Model, but data binding is often tricky because our model doesn't have the right properties. So we create a View Model that is perfectly set up to have just the right properties for our View to bind to, and gets its actual data from the Model.

To try the technique out I decided to refactor a small piece of a Silverlight game I have written, called SilverNibbles, which is a port of the old QBasic Nibbles game, keeping the graphics fairly similar. At the top of the screen there is a scoreboard, whose role it is to keep track of the scores, number of lives, level, speed etc. This is the piece I will attempt to modify to use MVVM.

SilverNibbles Scoreboard

Let's have a look at the original code-behind for the Scoreboard user control. As you can see, there is a not lot going on here. Whenever a property on the Scoreboard is set, the appropriate changes are made to the graphical components. This is very similar to the typical code that would be written for a Windows Forms user control.

using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverNibbles
{
    public partial class Scoreboard : UserControl
    {
        private int players;
        private int level;
        private int speed;
        private int jakeScore;
        private int sammyScore;

        public Scoreboard()
        {
            InitializeComponent();
        }

        public int Players
        {
            get 
            {
                return players; 
            }
            set 
            {
                players = value;
                jakeLives.Visibility = players == 2 ? Visibility.Visible : Visibility.Collapsed;
                jakeScoreLabel.Visibility = players == 2 ? Visibility.Visible : Visibility.Collapsed;
                jakeScoreTextBlock.Visibility = players == 2 ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        public int Level
        {
            get
            {
                return level;
            }
            set
            {
                level = value;
                levelTextBlock.Text = value.ToString();
            }
        }

        public int Speed
        {
            get
            {
                return speed;
            }
            set
            {
                speed = value;
                speedTextBlock.Text = value.ToString();
            }
        }

        public int SammyScore
        {
            get
            {
                return sammyScore;
            }
            set
            {
                sammyScore = value;
                sammyScoreTextBlock.Text = value.ToString();
            }
        }

        public int JakeScore
        {
            get
            {
                return jakeScore;
            }
            set
            {
                jakeScore = value;
                jakeScoreTextBlock.Text = value.ToString();
            }
        }

        public int JakeLives
        {
            get
            {
                return jakeLives.Lives;
            }
            set
            {
                jakeLives.Lives = value;
            }
        }

        public int SammyLives
        {
            get
            {
                return sammyLives.Lives;
            }
            set
            {
                sammyLives.Lives = value;
            }
        }
    }
}

Instead of having all these properties, the Scoreboard will become a very simple view. Now the code-behind of Scoreboard is completely minimalised:

namespace SilverNibbles
{
    public partial class Scoreboard : UserControl
    {
        public Scoreboard()
        {
            InitializeComponent();
        }
    }
}

Now it is the job of whoever creates Scoreboard to give it a ScoreboardViewModel as its DataContext. It doesn't even have to be a ScoreboardViewModel either, so long as it has the appropriate properties. This means that a graphic designer could use an XML file instead to create dummy data to help while designing the appearance. Here's my code elsewhere in the project that sets up the data context of the Scoreboard with its View Model.

scoreData = new ScoreboardViewModel();
scoreboard.DataContext = scoreData;

Now I simply modify the scoreData object's properties, and the Scoreboard will update its view automatically.

What has changed in the Scoreboard user control's XAML? Well first, it has Binding statements for every property that gets its value from the view model. I was also able to remove all the x:Name attributes from the markup, which is a sign that MVVM has been done right. I also needed to make my Lives property on my LivesControl user control into a dependency property to allow it to accept the binding syntax as a value.

<UserControl x:Class="SilverNibbles.Scoreboard"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:sn="clr-namespace:SilverNibbles"
     >
    <Grid x:Name="LayoutRoot" Background="LightYellow" ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20*" />
            <ColumnDefinition Width="35*" />
            <ColumnDefinition Width="25*" />
            <ColumnDefinition Width="10*" />
        </Grid.ColumnDefinitions>
        
        <!-- row 0 -->
        <TextBlock 
            Grid.Row="0" 
            Grid.Column="0"
            Text="High Score" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen" />
        <TextBlock 
            Grid.Row="0" 
            Grid.Column="1"
            Margin="5,0,5,0"
            Text="{Binding Record}" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen" />
        
        <TextBlock 
            Grid.Column="2" 
            Text="Level" 
            HorizontalAlignment="Right" 
            Margin="5,0,5,0"
            FontSize="18"
            FontFamily="teen bold.ttf#Teen" />
        <TextBlock 
            Grid.Column="3" 
            Margin="5,0,5,0"
            Text="{Binding Level}" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen" />
                
        <!-- row 1 -->        
        <TextBlock 
            Grid.Row="1"
            Text="Sammy" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen" />
       <sn:LivesControl
            Grid.Row="1"
            Grid.Column="1"
            HorizontalAlignment="Right"
           Fill="{StaticResource SammyBrush}"
           Lives="{Binding SammyLives}"
             />        
       <TextBlock 
            Grid.Row="1"
            Grid.Column="1"
            Margin="5,0,5,0"
            Text="{Binding SammyScore}" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen"
            />
        
       <TextBlock 
           Grid.Row="1" 
           Grid.Column="2" 
            Text="Speed" 
            HorizontalAlignment="Right" 
            Margin="5,0,5,0"
            FontSize="18"
            FontFamily="teen bold.ttf#Teen"
           />
        <TextBlock 
            Grid.Row="1"
            Grid.Column="3" 
            Margin="5,0,5,0"
            Text="{Binding Speed}" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen"
            />
        
        <!-- row 2 -->
        <TextBlock 
            Grid.Row="2"
            Grid.Column="0"
            Text="Jake" 
            FontSize="18"
            FontFamily="teen bold.ttf#Teen"
            Visibility="{Binding JakeVisible}"            
            />
        <sn:LivesControl
            Grid.Row="2"
            Grid.Column="1"
            HorizontalAlignment="Right"
            Fill="{StaticResource JakeBrush}"
            Visibility="{Binding JakeVisible}"
            Lives="{Binding JakeLives}"
             />
       <TextBlock 
            Grid.Row="2"
            Grid.Column="1"
            FontSize="18"
            Margin="5,0,5,0"
            Text="{Binding JakeScore}" 
            FontFamily="teen bold.ttf#Teen"
            Visibility="{Binding JakeVisible}"
           />
    </Grid>
</UserControl>

Here's what my ScoreboardViewModel looks like. The main thing to notice is that I have implemented the INotifyPropertyChanged interface. I rather lazily raise the changed event every time the setter is called irrespective of whether the value really changed. Notice also I have created a JakeVisible property. This highlights how the View Model can be used to create properties that are exactly what the View needs.

namespace SilverNibbles
{
    public class ScoreboardViewModel : INotifyPropertyChanged
    {
        private int players;
        private int level;
        private int speed;
        private int jakeScore;
        private int sammyScore;

        public int Players
        {
            get
            {
                return players;
            }
            set
            {
                players = value;
                RaisePropertyChanged("Players");
                RaisePropertyChanged("JakeVisible");
            }
        }

        public Visibility JakeVisible
        {
            get
            {
                return players == 2 ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        public int Level
        {
            get
            {
                return level;
            }
            set
            {
                level = value;
                RaisePropertyChanged("Level");
            }
        }

        public int Speed
        {
            get
            {
                return speed;
            }
            set
            {
                speed = value;
                RaisePropertyChanged("Speed");
            }
        }

        public int SammyScore
        {
            get
            {
                return sammyScore;
            }
            set
            {
                sammyScore = value;
                RaisePropertyChanged("SammyScore");
            }
        }

        public int JakeScore
        {
            get
            {
                return jakeScore;
            }
            set
            {
                jakeScore = value;
                RaisePropertyChanged("JakeScore");
            }
        }

        int jakeLives;
        int sammyLives;

        public int JakeLives
        {
            get
            {
                return jakeLives;
            }
            set
            {
                jakeLives = value;
                RaisePropertyChanged("JakeLives");
            }
        }

        public int SammyLives
        {
            get
            {
                return sammyLives;
            }
            set
            {
                sammyLives = value;
                RaisePropertyChanged("SammyLives");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}

I think there are alternatives to using INotifyPropertyChanged such as creating dependency properties or inheriting from DependencyObject. I don't know what the advantages or disadvantages of taking that approach would be. That is something for a future investigation.

There are lots of other parts of the SilverNibbles application that could be refactored to use this pattern, but that is also a task for another day. View the code at CodePlex, and play SilverNibbles here.

Saturday 1 November 2008

Using NAudio to Replace the BabySmash Audio Stack

After adding MIDI in support to BabySmash, the next obvious step was to replace the audio playback mechanism with NAudio too, which would allow better mixing of sounds, and doing cool things like controlling volume and panning of sounds. It also gives me a chance to write some more example documentation for NAudio.

To be able to play from one of the embedded WAV files, we need to create a WaveStream derived class that can read from an embedded resource, and convert the audio into a common format ready for mixing. One problem with BabySmash is that the current embedded audio files represent a whole smorgasbord of formats:

babygigl2.wav
scooby2.wav
MP3 11025Hz mono
babylaugh.wav
ccgiggle.wav
giggle.wav
PCM 11kHz mono 8 bit
EditedJackPlaysBabySmash.wav PCM 22kHz mono 16 bit
falling.wav
rising.wav
PCM 8kHz mono 16 bit
laughingmice.wav PCM 11127Hz! mono 8 bit
smallbumblebee PCM 22kHz stereo 16 bit

So I created WavResourceStream whose job it was to take an embedded resource and output a 32bit IEEE floating point stereo stream at 44.1kHz. I could equally have chosen 22kHz, which would reduce the amount of data that needs to be passed around. The choice of floating point audio is important for the mixing phase, as it gives us plenty of headroom.

The constructor is the most interesting part of this class. It takes the resource name, and uses a WaveFileReader to read from that resource (n.b. the constructor for WaveFileReader that takes a Stream has only recently been checked in to NAudio, there were other ways of doing this in the past, but in the latest code I am trying to clean things up a bit).

The next step is to convert to PCM if it is not already (there are two files whose audio is actually MP3, even though they are contained within a WAV file). The WaveFormatConversionStream looks for an ACM codec that can perform the requested format conversion. The BlockAlignReductionStream helps us ensure we call the ACM functions with sensible buffer sizes.

The step afterwards is to get ourselves to 44100kHz. You can't mix audio unless all streams are at the same sample rate. Again we use a BlockAlignmentReductionStream to help with the buffer sizing. Finally we go into a WaveChannel32 stream, which converts us to 32 bit floating point stereo stream, and allows us to  set volume and pan if required. So the audio graph depth is already potentially six streams deep. It may seem confusing at first, but once you get the hang of it, chaining WaveStreams together is quite simple.

class WavResourceStream : WaveStream
{
    WaveStream sourceStream;

    public WavResourceStream(string resourceName)
    {
        // get the namespace 
        string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;

        // get the resource into a stream
        Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + resourceName);
        sourceStream = new WaveFileReader(stream);
        var format = new WaveFormat(44100, 16, sourceStream.WaveFormat.Channels);
            
        if (sourceStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
        {
            sourceStream = WaveFormatConversionStream.CreatePcmStream(sourceStream);
            sourceStream = new BlockAlignReductionStream(sourceStream);
        }
        if (sourceStream.WaveFormat.SampleRate != 44100 ||
            sourceStream.WaveFormat.BitsPerSample != 16)
        {
            sourceStream = new WaveFormatConversionStream(format, sourceStream);
            sourceStream = new BlockAlignReductionStream(sourceStream);
        }
        
        sourceStream = new WaveChannel32(sourceStream);            
    }

The rest of the WavResourceStream is simply implementing the WaveStream abstract class members by calling into the source stream we constructed:

    public override WaveFormat WaveFormat
    {
        get { return sourceStream.WaveFormat; }
    }

    public override long Length
    {
        get { return sourceStream.Length; }
    }

    public override long Position
    {
        get { return sourceStream.Position; }
        set { sourceStream.Position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return sourceStream.Read(buffer, offset, count);
    }

    protected override void Dispose(bool disposing)
    {
        if (sourceStream != null)
        {
            sourceStream.Dispose();
            sourceStream = null;
        }
        base.Dispose(disposing);
    }
}

Now we need to create a mixer that can take multiple WavResourceStreams and mix their contents together into a single stream. NAudio includes the WaveMixer32Stream, but it is designed more for sequencer use, where you want exact sample level control over the positioning of the source streams, and also can reposition itself. BabySmash's needs are simpler - we simply want to play sounds once through. So I created a simpler MixerStream, which may find its way in modified form into NAudio in the future.

The first part of the code simply allows us to add inputs to the mixer. Our mixer doesn't really care what the sample rate is as long as all inputs have the same sample rate. The PlayResource function simply creates one of our WavResourceStream instances and adds it to our list of inputs. Currently I have no upper limit on how many inputs can be added, but it would make sense to limit it in some way (probably by throwing away some existing inputs rather than failing to play new ones).

public class MixerStream : WaveStream
{
    private List<WaveStream> inputStreams;
    private WaveFormat waveFormat;
    private int bytesPerSample;

    public MixerStream()
    {
        this.waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);
        this.bytesPerSample = 4;
        this.inputStreams = new List<WaveStream>();
    }

    public void PlayResource(string resourceName)
    {
        WaveStream stream = new WavResourceStream(resourceName);
        AddInputStream(stream);
    }

    public void AddInputStream(WaveStream waveStream)
    {
        if (waveStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
            throw new ArgumentException("Must be IEEE floating point", "waveStream.WaveFormat");
        if (waveStream.WaveFormat.BitsPerSample != 32)
            throw new ArgumentException("Only 32 bit audio currently supported", "waveStream.WaveFormat");

        if (inputStreams.Count == 0)
        {
            // first one - set the format
            int sampleRate = waveStream.WaveFormat.SampleRate;
            int channels = waveStream.WaveFormat.Channels;
            this.waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels);
        }
        else
        {
            if (!waveStream.WaveFormat.Equals(waveFormat))
                throw new ArgumentException("All incoming channels must have the same format", "inputStreams.WaveFormat");
        }

        lock (this)
        {
            this.inputStreams.Add(waveStream);
        }
    }

The real work of MixerStream is done in the Read method. Here we loop through all the inputs and mix them together. We also detect when an input stream has finished playing and dispose it and remove it from our list of inputs. The mixing is performed using unsafe code so you need to set the unsafe flag on the project to get it to compile. One important note is that we always return a full empty buffer even if we have no inputs, because our IWavePlayer expects full reads if it is to keep going.

public override int Read(byte[] buffer, int offset, int count)
{
    if (count % bytesPerSample != 0)
        throw new ArgumentException("Must read an whole number of samples", "count");            

    // blank the buffer
    Array.Clear(buffer, offset, count);
    int bytesRead = 0;

    // sum the channels in
    byte[] readBuffer = new byte[count];
    lock (this)
    {
        for (int index = 0; index < inputStreams.Count; index++)
        {
            WaveStream inputStream = inputStreams[index];

            int readFromThisStream = inputStream.Read(readBuffer, 0, count);
            System.Diagnostics.Debug.Assert(readFromThisStream == count, "A mixer input stream did not provide the requested amount of data");
            bytesRead = Math.Max(bytesRead, readFromThisStream);
            if (readFromThisStream > 0)
            {
                Sum32BitAudio(buffer, offset, readBuffer, readFromThisStream);
            }
            else
            {
                inputStream.Dispose();
                inputStreams.RemoveAt(index);
                index--;
            }
        }
    }
    return count;
}

static unsafe void Sum32BitAudio(byte[] destBuffer, int offset, byte[] sourceBuffer, int bytesRead)
{
    fixed (byte* pDestBuffer = &destBuffer[offset],
              pSourceBuffer = &sourceBuffer[0])
    {
        float* pfDestBuffer = (float*)pDestBuffer;
        float* pfReadBuffer = (float*)pSourceBuffer;
        int samplesRead = bytesRead / 4;
        for (int n = 0; n < samplesRead; n++)
        {
            pfDestBuffer[n] += pfReadBuffer[n];
        }
    }
}

The remaining functions of the MixerStream are quite simple. We don't need to report position or length as BabySmash simply plays a continuous stream.

public override long Length
{
    get { return 0; }
}

public override long Position
{
    get { return 0; }
    set 
    {
        throw new NotImplementedException("This mixer is not repositionable");
    }
}

public override WaveFormat WaveFormat
{
    get { return waveFormat; }
}

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (inputStreams != null)
        {
            foreach (WaveStream inputStream in inputStreams)
            {
                inputStream.Dispose();
            }
            inputStreams = null;
        }
    }
    else
    {
        System.Diagnostics.Debug.Assert(false, "WaveMixerStream32 was not disposed");
    }
    base.Dispose(disposing);
}

Finally we are ready to set up BabySmash to play its audio using MixerStream. We add two new members to the Controller class:

private MixerStream mainOutputStream;
private IWavePlayer wavePlayer;

And then in the Controller.Launch method, we create a new MixerStream, and use WaveOut to play it. We have chosen a read-ahead of 300 milliseconds which should mean that we don't get stuttering on a reasonably powerful modern PC. We need to pass the window handle to WaveOut as I have found that some laptop chipsets (most notably SoundMAX) have issues with running managed code in their callback functions. We don't have to use WaveOut if we don't want to. WASAPI works as well if you have Vista (although I found it was stuttering a bit for me).

IntPtr windowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
wavePlayer = new WaveOut(0, 300, windowHandle);
//wavePlayer = new WasapiOut(AudioClientShareMode.Shared, 300);
mainOutputStream = new MixerStream();
wavePlayer.Init(mainOutputStream);
wavePlayer.Play();

The call to wavePlayer.Play will mean we start making calls into the Read method of the MixerStream, but initially it will just be silence. When we are ready to make a sound, simply call the MixerStream.PlayResource method instead of the PlayWavResourceYield method:

//audio.PlayWavResourceYield(".Resources.Sounds." + "rising.wav");
mainOutputStream.PlayResource(".Resources.Sounds." + "rising.wav");

So what does it sound like? Well I haven't tested it too much, but it certainly is possible to have a large number of simultaneous laughs on my PC. "Cacophony" would sum up it up pretty well. The next step of course would be to implement the "Play notes from songs on keypress" feature request. Another obvious enhancement would be to cache the converted audio so that we didn't need to continually pass the same files through ACM again and again.