<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9 - Entries tagged with Audio</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Tags/audio/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9 - Entries tagged with Audio</title>
      <link>http://channel9.msdn.com/Tags/audio</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Tags/audio</link>
    <language>en</language>
    <pubDate>Sun, 19 May 2013 11:19:22 GMT</pubDate>
    <lastBuildDate>Sun, 19 May 2013 11:19:22 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>31</c9:totalResults>
    <c9:pageCount>2</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>A Look at the SoundLab</title>
      <description><![CDATA[ <p>The Microsoft SoundLab is a group at Microsoft that supports our needs for sounds and sound effects, mostly for video games. They have handled most of the Microsoft Game Studio sounds, for games like Halo, Fable,&nbsp;and Forza. Mike Caviezel walks us through the SoundLab and talks about what it's like to create interesting noises for a living.</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:95155743fb404a4094509ee6011fa962">]]></description>
      <comments>http://channel9.msdn.com/Series/CampusTours/A-Look-at-the-SoundLab</comments>
      <itunes:summary> The Microsoft SoundLab is a group at Microsoft that supports our needs for sounds and sound effects, mostly for video games. They have handled most of the Microsoft Game Studio sounds, for games like Halo, Fable,&amp;nbsp;and Forza. Mike Caviezel walks us through the SoundLab and talks about what it&#39;s like to create interesting noises for a living. </itunes:summary>
      <itunes:duration>588</itunes:duration>
      <link>http://channel9.msdn.com/Series/CampusTours/A-Look-at-the-SoundLab</link>
      <pubDate>Wed, 18 May 2011 21:56:10 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Series/CampusTours/A-Look-at-the-SoundLab</guid>
      <media:thumbnail url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_100_ch9.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_220_ch9.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_512_ch9.jpg" height="384" width="512"></media:thumbnail>
      <media:group>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_2MB_ch9.wmv" expression="full" duration="588" fileSize="390475565" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_ch9.mp3" expression="full" duration="588" fileSize="4709656" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_ch9.wma" expression="full" duration="588" fileSize="4766319" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_ch9.wmv" expression="full" duration="588" fileSize="126280962" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_high_ch9.mp4" expression="full" duration="588" fileSize="250816417" type="video/mp4" medium="video"></media:content>
        <media:content url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_low_ch9.mp4" expression="full" duration="588" fileSize="50679040" type="video/mp4" medium="video"></media:content>
        <media:content url="http://smooth.ch9.ms/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab.ism/manifest" expression="full" duration="588" fileSize="8362" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://ak.channel9.msdn.com/ch9/a962/95155743-fb40-4a40-9450-9ee6011fa962/Soundlab_ch9.wmv" length="126280962" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Larry Larsen</dc:creator>
      <itunes:author>Larry Larsen</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Series/CampusTours/A-Look-at-the-SoundLab/RSS</wfw:commentRss>
      <category>Audio</category>
    </item>
  <item>
      <title>Autotune.NET</title>
      <description><![CDATA[<p>We've all cringed as a hopelessly out of tune contestant appears on the latest episode of “American Idol.” Occasionally, there's a contestant who manages to be pitch perfect all the way through—right until they flub the final note. And in the cutthroat world
 of televised auditions, sing one slightly flat note and you're out. </p>
<p>So what takes care of a bad-pitch day? Autotune—an effect that corrects the pitch of your voice so you'll never again sing out of tune. And now, with the power of modern microprocessors, autotune is possible in real-time, allowing singers to benefit from
 its almost magical powers during live concerts.</p>
<p>The company most famous for its autotune effect is Antares. <a href="http://www.antarestech.com/products/auto-tune-evo.shtml">
Antares Auto-Tune</a> currently retails for $249, and a stripped down version is available for $100. In addition to simply improving the pitch of a dodgy singer, autotune can be used to create unique robotic sounding vocal effects, a technique massively popular
 in recent years thanks to its use by artists such as T-Pain and the group behind the “<a href="http://www.youtube.com/show/autotunethenews">Auto-Tune the News</a>” YouTube videos. In 1998, when the effect was first used on
<a href="http://en.wikipedia.org/wiki/Believe_%28Cher_song%29">Cher's “Believe” single</a>, the producer used such extreme settings that instead of subtly adjusting the pitch, autotune “snapped” instantaneously to the nearest “correct” note.
</p>
<p>Here is a nerdy example of what Autotune can do.</p>
<div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:d3d009f2-6f0d-4a64-96f9-8bbf864e4e06" class="wlWriterEditableSmartContent">
<div></div>
</div>
<h2>How does Autotune work?</h2>
<p>An autotune effect has two parts. The first is <b>pitch detection</b>, which calculates the dominant frequency of the incoming signal, and is the reason autotune is normally used on monophonic audio sources (i.e. playing one note at a time, not whole chords).
 So, if your guitar is out of tune, you're out of luck (<a href="http://www.celemony.com/cms/">Celemony's Melodyne</a> product, however, features some incredible capabilities for pitch-shifting polyphonic audio).</p>
<p>The second stage is <b>pitch shifting</b>, or “correcting” a given note. However, the bigger the pitch shift required, the more artificial the end result will be, and it is worth noting that absolutely perfect pitch is not always desirable. Sometimes the
 blended notes resulting from vibrato, for example, are an important part of the performance, and eliminating them would be detrimental.</p>
<h2>Creating a .NET Autotune Algorithm</h2>
<p>For this project, we will be creating an autotune effect for .NET. Serious recording enthusiasts should just go out and buy a decent autotune effect, but to have a little fun, we'll see if we can make an autotune that can give us a poor man's Cher effect
 (or T-Pain effect, if you prefer).</p>
<p>To get started, I searched to see if there were some pre-existing open source autotune implementations, which brought me to
<a href="http://decabear.com/awesomebox.html">awesomebox</a>, a project created by Ravi Parikh and Keegan Poppen while they were students at Stanford University. They kindly gave me permission to make use of their code, which uses an auto-correlator for pitch
 detection and an open source pitch-shifting algorithm from audio DSP expert <a href="http://www.dspdimension.com">
Stephan M. Bernsee</a>.</p>
<h3>Porting C&#43;&#43; to C#</h3>
<p>Although porting from C/C&#43;&#43; to C# is not exactly fun, there is enough similarity in the syntax that it is possible to complete without too many changes. You need to remember, however, that a
<b>long</b> in C is an <b>int</b> in C# (i.e. 32 bits long not 64). </p>
<p>Additionally, the C# compiler is fussier than C/C&#43;&#43; when it comes to casting between floats, doubles, and ints. Putting the “f” suffix on numeric literals sorts out most of these compiler errors.
</p>
<p>Pointers can be a pain. I tend to replace them with integer variables used to index into an array. You can of course use unsafe code, but that limits your options if you plan to port to Silverlight or Windows Phone 7 at a later date, neither of which allow
 unsafe code or interop into unmanaged code. The necessary mathematical functions are available in the System.Math class.</p>
<p>To see an example, compare this pitch shifting <a href="http://downloads.dspdimension.com/smbPitchShift.cpp">
C&#43;&#43; source file</a> with my <a href="http://voicerecorder.codeplex.com/SourceControl/changeset/view/f067d3f5a443#VoiceRecorder.Audio%2fSmbPitchShift.cs">
C# conversion</a> of it.</p>
<h2>Capturing Audio with NAudio</h2>
<p>Interop wrappers for the NAudio Windows WaveIn APIs capture the audio. Here is the code used to start recording:</p>
<p><strong>c#:</strong></p>
<pre class="csharpcode">waveIn = <span class="kwrd">new</span> WaveIn();
waveIn.DeviceNumber = recordingDevice;
waveIn.DataAvailable &#43;= waveIn_DataAvailable;
waveIn.RecordingStopped &#43;= <span class="kwrd">new</span> EventHandler(waveIn_RecordingStopped);
waveIn.WaveFormat = recordingFormat;
waveIn.StartRecording();</pre>
<p><strong>VB.Net:</strong></p>
<pre class="csharpcode">waveIn = <span class="kwrd">New</span> WaveIn
waveIn.DeviceNumber = recordingDevice
<span class="kwrd">AddHandler</span> waveIn.DataAvailable, <span class="kwrd">AddressOf</span> waveIn_DataAvailable
<span class="kwrd">AddHandler</span> waveIn.RecordingStopped, <span class="kwrd">AddressOf</span> waveIn_RecordingStopped
waveIn.WaveFormat = _recordingFormat
waveIn.StartRecording()</pre>
<p>The steps are:</p>
<ol>
<li>Create a new <b>WaveIn</b> device </li><li>[Optional] set up the device number (0 for default recording device) </li><li>Add a handler to the <b>DataAvailable</b> event—this is where we will receive the raw audio data
</li><li>Add a handler for the <b>RecordingStopped</b> event. This allows us to close the temporary WAV file we created
</li><li>Set up the recording format. For this project we are going to record in mono (i.e. one channel), 16 bit, 44.1kHz audio—the default setting for most microphones
</li><li>Call the <b>StartRecording</b> method </li></ol>
<p>Whenever the soundcard reports a new buffer of recorded audio, we receive it in the
<b>DataAvailable</b> event handler:</p>
<p><strong>c#:</strong></p>
<pre class="csharpcode"><span class="kwrd">void</span> waveIn_DataAvailable(<span class="kwrd">object</span> sender, WaveInEventArgs e)
{
    <span class="kwrd">byte</span>[] buffer = e.Buffer;
    <span class="kwrd">int</span> bytesRecorded = e.BytesRecorded;
    WriteToFile(buffer, bytesRecorded);

    <span class="kwrd">for</span> (<span class="kwrd">int</span> index = 0; index &lt; e.BytesRecorded; index &#43;= 2)
    {
        <span class="kwrd">short</span> sample = (<span class="kwrd">short</span>)((buffer[index &#43; 1] &lt;&lt; 8) |
                                buffer[index &#43; 0]);
        <span class="kwrd">float</span> sample32 = sample / 32768f;
        sampleAggregator.Add(sample32);
    }
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> waveIn_DataAvailable(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> WaveInEventArgs)
    <span class="kwrd">Dim</span> buffer() = e.Buffer
    <span class="kwrd">Dim</span> bytesRecorded = e.BytesRecorded
    WriteToFile(buffer, bytesRecorded)

    <span class="kwrd">For</span> index = 0 <span class="kwrd">To</span> e.BytesRecorded - 1 <span class="kwrd">Step</span> 2
        <span class="kwrd">Dim</span> sample = <span class="kwrd">CShort</span>(buffer(index &#43; 1)) &lt;&lt; 8 <span class="kwrd">Or</span> <span class="kwrd">CShort</span>(buffer(index &#43; 0))
        <span class="kwrd">Dim</span> sample32 = sample / 32768.0F
        _sampleAggregator.Add(sample32)
    <span class="kwrd">Next</span> index
<span class="kwrd">End</span> Sub</pre>
<p>The <b>WaveInEventArgs</b> contains the number of bytes recorded (<b>e.BytesRecorded</b>) and a pointer to the buffer containing those bytes (<b>e.Buffer</b>). The handler does two things with the recorded data. First, it calls WriteToFile, which uses the
<b>WaveFileWriter </b>class from NAudio to write the data to disk:</p>
<p><strong>c#:</strong></p>
<pre class="csharpcode"><span class="rem">// before we start recording, set up a WaveFileWriter...</span>
writer = <span class="kwrd">new</span> WaveFileWriter(waveFileName, recordingFormat);

<span class="rem">// ... every block we receive we write it to the WaveFileWriter:</span>
writer.WriteData(buffer, 0, bytesRecorded);

<span class="rem">// ... and when recording stops we must call Dispose to finalize the</span>
<span class="rem">// .WAV file properly</span>
writer.Dispose()</pre>
<p><strong>VB.Net:</strong></p>
<pre class="csharpcode">writer = <span class="kwrd">New</span> WaveFileWriter(waveFileName, _recordingFormat)
writer.WriteData(buffer, 0, bytesRecorded)
writer.Dispose()</pre>
<h3>Converting Audio to Floating Point and Back Again</h3>
<p>Once recording has completed, we have a WAV file on which to perform our autotune effect. However, our WAV file consists of 16 bit samples (i.e.
<b>System.Int16</b> aka <b>short</b>). In other words, we have a sequence of byte pairs, each of which represent a number in the range -32768 to 32767. For the digital signal processing we will be performing, it's best to have a sequence of floating point numbers
 (<b>System.Single</b> or <b>float</b>) in the range -1.0f to 1.0f. This is a common requirement, so NAudio provides a utility class to convert audio from short to float called
<b>Wave16ToFloatProvider</b>. Here's the code that takes a WAV file and implements the autotune algorithm on it:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ApplyAutoTune(<span class="kwrd">string</span> fileToProcess, <span class="kwrd">string</span> tempFile, AutoTuneSettings autotuneSettings)
{
    <span class="kwrd">using</span> (WaveFileReader reader = <span class="kwrd">new</span> WaveFileReader(fileToProcess))
    {
        IWaveProvider stream32 = <span class="kwrd">new</span> Wave16toFloatProvider(reader);
        IWaveProvider streamEffect = <span class="kwrd">new</span> AutoTuneWaveProvider(stream32, autotuneSettings);
        IWaveProvider stream16 = <span class="kwrd">new</span> WaveFloatTo16Provider(streamEffect);
        <span class="kwrd">using</span> (WaveFileWriter converted = <span class="kwrd">new</span> WaveFileWriter(tempFile, stream16.WaveFormat))
        {
            <span class="rem">// buffer length needs to be a power of 2 for FFT to work nicely</span>
            <span class="rem">// however, make the buffer too long and pitches aren't detected fast enough</span>
            <span class="rem">// successful buffer sizes: 8192, 4096, 2048, 1024</span>
            <span class="rem">// (some pitch detection algorithms need at least 2048)</span>
            <span class="kwrd">byte</span>[] buffer = <span class="kwrd">new</span> <span class="kwrd">byte</span>[8192]; 
            <span class="kwrd">int</span> bytesRead;
            <span class="kwrd">do</span>
            {
                bytesRead = stream16.Read(buffer, 0, buffer.Length);
                converted.WriteData(buffer, 0, bytesRead);
            } <span class="kwrd">while</span> (bytesRead != 0 &amp;&amp; converted.Length &lt; reader.Length);
        }
    }
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Sub</span> ApplyAutoTune(<span class="kwrd">ByVal</span> fileToProcess <span class="kwrd">As</span> <span class="kwrd">String</span>,
    <span class="kwrd">ByVal</span> tempFile <span class="kwrd">As</span> <span class="kwrd">String</span>,
    <span class="kwrd">ByVal</span> autotuneSettings <span class="kwrd">As</span> AutoTuneSettings)
    Using reader <span class="kwrd">As</span> <span class="kwrd">New</span> WaveFileReader(fileToProcess)
        <span class="kwrd">Dim</span> stream32 <span class="kwrd">As</span> IWaveProvider = <span class="kwrd">New</span> Wave16ToFloatProvider(reader)
        <span class="kwrd">Dim</span> streamEffect <span class="kwrd">As</span> IWaveProvider = <span class="kwrd">New</span> AutoTuneWaveProvider(stream32, autotuneSettings)
        <span class="kwrd">Dim</span> stream16 <span class="kwrd">As</span> IWaveProvider = <span class="kwrd">New</span> WaveFloatTo16Provider(streamEffect)
        Using converted <span class="kwrd">As</span> <span class="kwrd">New</span> WaveFileWriter(tempFile, stream16.WaveFormat)
            <span class="rem">' buffer length needs to be a power of 2 for FFT to work nicely</span>
            <span class="rem">' however, make the buffer too long and pitches aren't detected fast enough</span>
            <span class="rem">' successful buffer sizes: 8192, 4096, 2048, 1024</span>
            <span class="rem">' (some pitch detection algorithms need at least 2048)</span>
            <span class="kwrd">Dim</span> buffer(8191) <span class="kwrd">As</span> <span class="kwrd">Byte</span>
            <span class="kwrd">Dim</span> bytesRead <span class="kwrd">As</span> <span class="kwrd">Integer</span>
            <span class="kwrd">Do</span>
                bytesRead = stream16.Read(buffer, 0, buffer.Length)
                converted.WriteData(buffer, 0, bytesRead)
            <span class="kwrd">Loop</span> <span class="kwrd">While</span> bytesRead &lt;&gt; 0 <span class="kwrd">AndAlso</span> converted.Length &lt; reader.Length
        <span class="kwrd">End</span> Using
    <span class="kwrd">End</span> Using
<span class="kwrd">End</span> Sub</pre>
<p>Here's how it works:</p>
<ol>
<li>First we use a <b>WaveFileReader</b> to open the file that we've just created, which contains 16 bit audio samples
</li><li>Then we use the <b>Wave16ToFloatProvider</b> to perform the conversion to floating point samples
</li><li>Next we pass it through our autotune effect (the <b>AutotuneWaveProvider</b>). We'll explain how this works this later
</li><li>Then we use the <b>WaveFloatTo16Provider</b> to convert back to 16 bit samples ready for saving to WAV (we could save a 32 bit WAV, but it would be rather wasteful of disk space)
</li><li>Having set up the audio pipeline, we can read from the WaveFloatTo16Provider and pull audio right through from the WAV file. We need to read in block sizes that are a power of 2, since we are passing the data through FFTs. If we want to read arbitrary block
 sizes, we need to introduce another element into our pipeline to buffer up enough data to pass through FFTs
</li><li>Finally, we use the <b>WaveFileWriter </b>to write the data we have read into a WAV file
</li></ol>
<h2>The AutoTuneWaveProvider</h2>
<p>As we saw in the last code snippet, the <b>AutoTuneWaveProvider</b> is the piece in our audio pipeline that actually performs the autotune effect. It implements the NAudio
<b>IWaveProvider</b> interface, which allows it to be used in the pipeline for real-time playback if necessary, even though our example code is not doing this (see the section on performance later). Here's the AutoTuneWaveProvider constructor:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> AutoTuneWaveProvider(IWaveProvider source, AutoTuneSettings autoTuneSettings)
{
    <span class="kwrd">this</span>.autoTuneSettings = autoTuneSettings;
    <span class="kwrd">if</span> (source.WaveFormat.SampleRate != 44100)
        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">&quot;AutoTune only works at 44.1kHz&quot;</span>);
    <span class="kwrd">if</span> (source.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">&quot;AutoTune only works on IEEE floating point audio data&quot;</span>);
    <span class="kwrd">if</span> (source.WaveFormat.Channels != 1)
        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">&quot;AutoTune only works on mono input sources&quot;</span>);

    <span class="kwrd">this</span>.source = source;
    <span class="kwrd">this</span>.pitchDetector = <span class="kwrd">new</span> AutoCorrelator(source.WaveFormat.SampleRate);
    <span class="kwrd">this</span>.pitchShifter = <span class="kwrd">new</span> SmbPitchShifter(Settings);
    <span class="kwrd">this</span>.waveBuffer = <span class="kwrd">new</span> WaveBuffer(8192);
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode">Public Sub New(ByVal source As IWaveProvider, ByVal autoTuneSettings As AutoTuneSettings)
    Me.autoTuneSettings = autoTuneSettings
    If source.WaveFormat.SampleRate &lt;&gt; 44100 Then
        Throw New ArgumentException(<span class="str">&quot;AutoTune only works at 44.1kHz&quot;</span>)
    End If
    If source.WaveFormat.Encoding &lt;&gt; WaveFormatEncoding.IeeeFloat Then
        Throw New ArgumentException(<span class="str">&quot;AutoTune only works on IEEE floating point audio data&quot;</span>)
    End If
    If source.WaveFormat.Channels &lt;&gt; 1 Then
        Throw New ArgumentException(<span class="str">&quot;AutoTune only works on mono input sources&quot;</span>)
    End If

    Me.source = source
    Me.pitchDetector = New AutoCorrelator(source.WaveFormat.SampleRate)
    <span class="str">' alternative pitch detector:
    '</span> Me.pitchDetector = New FftPitchDetector(source.WaveFormat.SampleRate)
    Me.pitchShifter = New SmbPitchShifter(Settings, source.WaveFormat.SampleRate)
    Me.waveBuffer = New WaveBuffer(8192)
End Sub</pre>
<p>Some points to notice:</p>
<ol>
<li>We pass in a source <b>IWaveProvider</b>—this is where the data will be coming from
</li><li>We check that the source is in the right format—floating point mono input. </li><li>We also pass in an <b>AutoTuneSettings</b> object. This not only encapsulates the settings for autotune, it is important if you want to adjust the settings in real-time while the effect is running
</li><li>We then create the two key components of our autotune effect: a pitch detector (which uses an autocorrelator), and a pitch shifter
</li><li>Finally we create a buffer to use for audio processing. This can be a byte[] array, but we use
<b>WaveBuffer </b>from NAudio because it uses <a href="http://mark-dot-net.blogspot.com/2008/06/wavebuffer-casting-byte-arrays-to-float.html">
a clever trick</a> that allows us to cast a byte[] into a float[] without using unsafe code or having to copy all of the data
</li></ol>
<p>The key method on any implementation of <b>IWaveProvider</b> is its <b>Read</b> method. This is where the audio consumer, usually the sound card or a WaveFileWriter, asks for data. The data must be supplied as a byte array, and if at all possible you should
 return exactly the number of bytes you were asked for (if you can't, an extra layer of buffering is usually required, or audio playback will be choppy). Here's our implementation of the Read method:</p>
<p><strong>c#:</strong></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">int</span> Read(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
{
    <span class="kwrd">if</span> (waveBuffer == <span class="kwrd">null</span> || waveBuffer.MaxSize &lt; count)
    {
        waveBuffer = <span class="kwrd">new</span> WaveBuffer(count);
    }

    <span class="kwrd">int</span> bytesRead = source.Read(waveBuffer, 0, count);

    <span class="rem">// the last bit sometimes needs to be rounded up:</span>
    <span class="kwrd">if</span> (bytesRead &gt; 0) bytesRead = count;

    <span class="kwrd">int</span> frames = bytesRead / <span class="kwrd">sizeof</span>(<span class="kwrd">float</span>); 
    <span class="kwrd">float</span> pitch = pitchDetector.DetectPitch(waveBuffer.FloatBuffer, frames);
        
    <span class="rem">// an attempt to make it less &quot;warbly&quot; by holding onto the pitch </span>
    <span class="rem">// for at least one more buffer</span>
    <span class="kwrd">if</span> (pitch == 0f &amp;&amp; release &lt; maxHold)
    {
        pitch = previousPitch;
        release&#43;&#43;;
    }
    <span class="kwrd">else</span>
    {
        <span class="kwrd">this</span>.previousPitch = pitch;
        release = 0;
    }
    
    WaveBuffer outBuffer = <span class="kwrd">new</span> WaveBuffer(buffer);

    pitchShifter.ShiftPitch(waveBuffer.FloatBuffer, pitch, 0.0f, outBuffer.FloatBuffer, frames);

    <span class="kwrd">return</span> frames * 4;
}</pre>
<p><strong>VB.Net:</strong></p>
<pre class="csharpcode">Public Function Read(ByVal buffer() As Byte, ByVal offset As Integer,
                        ByVal count As Integer) As Integer Implements NAudio.Wave.IWaveProvider.Read
    If waveBuffer Is Nothing OrElse waveBuffer.MaxSize &lt; count Then
        waveBuffer = New WaveBuffer(count)
    End If

    Dim bytesRead = source.Read(waveBuffer, 0, count)
    <span class="str">'Debug.Assert(bytesRead = count)

    '</span> the last bit sometimes needs to be rounded up:
    If bytesRead &gt; 0 Then
        bytesRead = count
    End If

    <span class="str">'pitchsource-&gt;getPitches()
    Dim frames = bytesRead \ Len(New Single) '</span> MRH: was count
    Dim pitch = pitchDetector.DetectPitch(waveBuffer.FloatBuffer, frames)

    ' MRH: an attempt to make it less <span class="str">&quot;warbly&quot;</span> by holding onto the pitch <span class="kwrd">for</span> at least one more buffer
    If pitch = 0.0F AndAlso release &lt; maxHold Then
        pitch = previousPitch
        release &#43;= 1
    Else
        Me.previousPitch = pitch
        release = 0
    End If

    Dim midiNoteNumber = 40
    Dim targetPitch = CSng(8.175 * Math.Pow(1.05946309, midiNoteNumber))

    Dim outBuffer As New WaveBuffer(buffer)

    pitchShifter.ShiftPitch(waveBuffer.FloatBuffer, pitch, targetPitch, outBuffer.FloatBuffer, frames)

    Return frames * 4
End Function</pre>
<p>Here's what's going on</p>
<ol>
<li>First we need to read from our source (in our case, a WAV file converted to floating point samples)
</li><li>If we get less data than we were expecting, we know that means we're at the end of the file, so we'll just pretend we got a full buffer
</li><li>We then work out how many audio ‘frames' are present (which is the same as the number of samples since this is mono audio). It's floating point audio, so frames equal bytes divided by four
</li><li>We then pass the data through our pitch detector algorithm (see below) </li><li>Next we use some experimental code to stabilize pitch detection by reporting the previous frequency when no pitch is picked up
</li><li>Finally we pass the data into our pitch shifter, including details of the detected pitch
</li></ol>
<p>Now that we've seen the big picture of the <b>AutotuneWaveProvider</b>, let's drill down into its two main components—the pitch detector and pitch shifter.</p>
<h2>Pitch Detection with Autocorrelation</h2>
<p>The pitch detection part of autotune is vital to getting good results. If it can't accurately detect the input pitch, it will incorrectly calculate how much the pitch needs to be adjusted. However, high quality pitch detection is quite difficult to get right.
 First of all, the microphone may well pick up background noise. Second, when you sing a into a microphone, the signal consists not only of a single frequency, but also “harmonics” at different frequencies.</p>
<p>The good news is that we need to detect only the primary pitch. </p>
<p>The awesomebox algorithm makes use of “<a href="http://en.wikipedia.org/wiki/Autocorrelation">autocorrelation</a>” for its pitch detection, but I made a few small tweaks to how the algorithm is implemented in an attempt to improve its accuracy. Autocorrelation
 has the advantage of being a relatively quick process. The basic principle is that if a signal is periodic, it will “correlate” well with itself when shifted forward (or backwards) one cycle.
</p>
<p>Let's say we are looking to see if the note “Middle C” is being sung. The frequency of Middle C is around 262Hz. If we are sampling at 44.1kHz (which is standard for CD quality audio), then we will expect the signal to repeat at approximately every 168 samples
 (44100/262). Accordingly, for every sample in the buffer, we calculate the sum of squares of that sample and the sample 168 samples previous. We do this for every possible offset that measures a frequency in the range we want to detect (I am using 85Hz to
 300Hz, which is adequate for pitch detecting vocals). The offset with the highest score is the most likely frequency.</p>
<p>Let's have a look at the code for an autocorrelation algorithm, starting with the constructor for the
<b>AutoCorrelator</b> class:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> AutoCorrelator(<span class="kwrd">int</span> sampleRate)
{
    <span class="kwrd">this</span>.sampleRate = (<span class="kwrd">float</span>)sampleRate;
    <span class="kwrd">int</span> minFreq = 85;
    <span class="kwrd">int</span> maxFreq = 255;

    <span class="kwrd">this</span>.maxOffset = sampleRate / minFreq;
    <span class="kwrd">this</span>.minOffset = sampleRate / maxFreq;
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> sampleRate <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
    <span class="kwrd">Me</span>.sampleRate = <span class="kwrd">CSng</span>(sampleRate)
    <span class="kwrd">Dim</span> minFreq = 85
    <span class="kwrd">Dim</span> maxFreq = 255

    <span class="kwrd">Me</span>.maxOffset = sampleRate \ minFreq
    <span class="kwrd">Me</span>.minOffset = sampleRate \ maxFreq
<span class="kwrd">End</span> Sub</pre>
<p>First of all, we pre-calculate some values based on the minimum and maximum frequencies we are looking for. Remember that lower frequencies are harder to detect than higher frequencies, so don't set minFreq too low. MaxOffset and MinOffset are the maximum
 and minimum backwards distances we will be seeking while looking for a match.</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">float</span> DetectPitch(<span class="kwrd">float</span>[] buffer, <span class="kwrd">int</span> frames)
{
    <span class="kwrd">if</span> (prevBuffer == <span class="kwrd">null</span>)
    {
        prevBuffer = <span class="kwrd">new</span> <span class="kwrd">float</span>[frames];
    }

    <span class="kwrd">float</span> maxCorr = 0;
    <span class="kwrd">int</span> maxLag = 0;

    <span class="rem">// starting with low frequencies, working to higher</span>
    <span class="kwrd">for</span> (<span class="kwrd">int</span> lag = maxOffset; lag &gt;= minOffset; lag--)
    {
        <span class="kwrd">float</span> corr = 0; <span class="rem">//  sum of squares</span>
        <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; frames; i&#43;&#43;)
        {
            <span class="kwrd">int</span> oldIndex = i - lag;
            <span class="kwrd">float</span> sample = ((oldIndex &lt; 0) ? prevBuffer[frames &#43; 
            corr &#43;= (sample * buffer[i]);
        }
        <span class="kwrd">if</span> (corr &gt; maxCorr)
        {
            maxCorr = corr;
            maxLag = lag;
        }

    }
    <span class="kwrd">for</span> (<span class="kwrd">int</span> n = 0; n &lt; frames; n&#43;&#43;)
    { 
        prevBuffer[n] = buffer[n]; 
    }
    <span class="kwrd">float</span> noiseThreshold = frames / 1000f;

    <span class="kwrd">if</span> (maxCorr &lt; noiseThreshold || maxLag == 0) <span class="kwrd">return</span> 0.0f;
    <span class="kwrd">return</span> <span class="kwrd">this</span>.sampleRate / maxLag;
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> DetectPitch(<span class="kwrd">ByVal</span> buffer() <span class="kwrd">As</span> <span class="kwrd">Single</span>, <span class="kwrd">ByVal</span> frames <span class="kwrd">As</span> <span class="kwrd">Integer</span>) <span class="kwrd">As</span> <span class="kwrd">Single</span> <span class="kwrd">Implements</span> IPitchDetector.DetectPitch
    <span class="kwrd">If</span> prevBuffer <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        prevBuffer = <span class="kwrd">New</span> <span class="kwrd">Single</span>(frames - 1){}
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Dim</span> secCor <span class="kwrd">As</span> <span class="kwrd">Single</span> = 0
    <span class="kwrd">Dim</span> secLag = 0

    <span class="kwrd">Dim</span> maxCorr <span class="kwrd">As</span> <span class="kwrd">Single</span> = 0
    <span class="kwrd">Dim</span> maxLag = 0

    <span class="rem">' starting with low frequencies, working to higher</span>
    <span class="kwrd">For</span> lag = maxOffset <span class="kwrd">To</span> minOffset <span class="kwrd">Step</span> -1
        <span class="kwrd">Dim</span> corr <span class="kwrd">As</span> <span class="kwrd">Single</span> = 0 <span class="rem">' this is calculated as the sum of squares</span>
        <span class="kwrd">For</span> i = 0 <span class="kwrd">To</span> frames - 1
            <span class="kwrd">Dim</span> oldIndex = i - lag
            <span class="kwrd">Dim</span> sample = (<span class="kwrd">If</span>(oldIndex &lt; 0, prevBuffer(frames &#43; oldIndex), buffer(oldIndex)))
            corr &#43;= (sample * buffer(i))
        <span class="kwrd">Next</span> i
        <span class="kwrd">If</span> corr &gt; maxCorr <span class="kwrd">Then</span>
            maxCorr = corr
            maxLag = lag
        <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">If</span> corr &gt;= 0.9 * maxCorr <span class="kwrd">Then</span>
            secCor = corr
            secLag = lag
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Next</span> lag
    <span class="kwrd">For</span> n = 0 <span class="kwrd">To</span> frames - 1
        prevBuffer(n) = buffer(n)
    <span class="kwrd">Next</span> n
    <span class="kwrd">Dim</span> noiseThreshold = frames / 1000.0F
    <span class="rem">'Debug.WriteLine(String.Format(&quot;Max Corr: {0} ({1}), Sec Corr: {2} ({3})&quot;, Me.sampleRate / maxLag, maxCorr, Me.sampleRate / secLag, secCor))</span>
    <span class="kwrd">If</span> maxCorr &lt; noiseThreshold <span class="kwrd">OrElse</span> maxLag = 0 <span class="kwrd">Then</span>
        <span class="kwrd">Return</span> 0.0F
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="rem">'Return 44100.0f / secLag '--works better for singing</span>
    <span class="kwrd">Return</span> <span class="kwrd">Me</span>.sampleRate / maxLag
<span class="kwrd">End</span> Function</pre>
<p>A few things to notice:</p>
<ol>
<li>Notice that the audio comes in as an array of floating point numbers. NAudio performs this conversion from 16 bit audio for us by using
<b>Wave16ToFloatProvider</b> </li><li>We store the previous buffer. This allows us to look backwards for correlation
</li><li>We then work through each and every possible integer offset within our range, and calculate a correlation value
</li><li>The correlation is calculated as the sum of squares </li><li>If it is the largest so far, we store the “lag” value (i.e. number of samples back that we correlated with)
</li><li>Notice that we return 0 (i.e. no frequency detected) if we don't find a strong frequency. This noise threshold may need to be tweaked depending on your input
</li><li>Finally, we convert into a frequency with the formula <b>sampleRate / maxLag</b>
</li></ol>
<p>I wrote some unit tests to measure the accuracy of detection with sine waves (which admittedly are the easiest to detect). Here are the results for audio sampled at 44.1kHz:</p>
<p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="140">
<p><b>Test Frequency</b></p>
</td>
<td valign="top" width="132">
<p><b>Detected Pitch</b></p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>109.99Hz</p>
</td>
<td valign="top" width="132">
<p>108.35Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>116.53Hz</p>
</td>
<td valign="top" width="132">
<p>118.23Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>123.46Hz</p>
</td>
<td valign="top" width="132">
<p>123.18Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>130.80Hz</p>
</td>
<td valign="top" width="132">
<p>129.71Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>138.58Hz</p>
</td>
<td valign="top" width="132">
<p>140.00Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>146.82Hz</p>
</td>
<td valign="top" width="132">
<p>148.48Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>155.55Hz</p>
</td>
<td valign="top" width="132">
<p>154.74Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>164.80Hz</p>
</td>
<td valign="top" width="132">
<p>163.33Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>174.60Hz</p>
</td>
<td valign="top" width="132">
<p>172.94Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>184.98Hz</p>
</td>
<td valign="top" width="132">
<p>183.75Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>195.98Hz</p>
</td>
<td valign="top" width="132">
<p>194.27Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>207.63Hz</p>
</td>
<td valign="top" width="132">
<p>206.07Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>219.98Hz</p>
</td>
<td valign="top" width="132">
<p>219.40Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>233.06Hz</p>
</td>
<td valign="top" width="132">
<p>234.57Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>246.92Hz</p>
</td>
<td valign="top" width="132">
<p>247.75Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>261.60Hz</p>
</td>
<td valign="top" width="132">
<p>256.40Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>277.16Hz</p>
</td>
<td valign="top" width="132">
<p>139.56Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>293.64Hz</p>
</td>
<td valign="top" width="132">
<p>146.03Hz</p>
</td>
</tr>
</tbody>
</table>
</p>
<p>Notice that the detected frequencies from the final two tests are actually half the correct amount. This doesn't actually matter for our purposes, since this just means the frequency has been detected as one octave below the correct note.</p>
<p>To improve on the accuracy of the autocorrelator's results, there are a couple of things you can do:</p>
<ul>
<li>Run a band-pass filter before-hand, to remove any frequencies outside of the desired range
</li><li>Combine the results with those obtained from a different technique, such as counting zero-crossings
</li></ul>
<h2>Pitch Detection with the Fast Fourier Transform</h2>
<p>I decided to implement an alternative pitch detection algorithm to see if I could get better results. A different approach is to use the
<a href="http://en.wikipedia.org/wiki/Fast_Fourier_transform">Fast Fourier Transform</a>, which converts signals from the “time domain” into the “frequency domain.”
</p>
<p>The basic approach is to take a block of samples (which must be a power of 2 – e.g. 1024), and run the FFT on them. The FFT takes complex numbers as inputs, which for audio signals are entirely real. The implementation I am using expects real and complex
 parts interleaved for the input buffer. Here's our code setting up <b>fftBuffer </b>
with interleaved samples:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">float</span>[] fftBuffer;
<span class="kwrd">private</span> <span class="kwrd">float</span>[] prevBuffer;

<span class="kwrd">public</span> <span class="kwrd">float</span> DetectPitch(<span class="kwrd">float</span>[] buffer, <span class="kwrd">int</span> inFrames)
{
    Func&lt;<span class="kwrd">int</span>, <span class="kwrd">int</span>, <span class="kwrd">float</span>&gt; window = HammingWindow;
    <span class="kwrd">if</span> (prevBuffer == <span class="kwrd">null</span>)
    {
        prevBuffer = <span class="kwrd">new</span> <span class="kwrd">float</span>[inFrames];
    }
 
    <span class="rem">// double frames since we are combining present and previous buffers</span>
    <span class="kwrd">int</span> frames = inFrames * 2;
    <span class="kwrd">if</span> (fftBuffer == <span class="kwrd">null</span>)
    {
        fftBuffer = <span class="kwrd">new</span> <span class="kwrd">float</span>[frames * 2]; <span class="rem">// times 2 because it is complex input</span>
    }
 
    <span class="kwrd">for</span> (<span class="kwrd">int</span> n = 0; n &lt; frames; n&#43;&#43;)
    {
        <span class="kwrd">if</span> (n &lt; inFrames)
        {
            fftBuffer[n * 2] = prevBuffer[n] * window(n, frames);
            fftBuffer[n * 2 &#43; 1] = 0; <span class="rem">// need to clear out as fft modifies buffer</span>
        }
        <span class="kwrd">else</span>
        {
            fftBuffer[n * 2] = buffer[n-inFrames] * window(n, frames);
            fftBuffer[n * 2 &#43; 1] = 0; <span class="rem">// need to clear out as fft modifies buffer</span>
        }
    }</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> fftBuffer() <span class="kwrd">As</span> <span class="kwrd">Single</span>
<span class="kwrd">Private</span> prevBuffer() <span class="kwrd">As</span> <span class="kwrd">Single</span>

<span class="kwrd">Public</span> <span class="kwrd">Function</span> DetectPitch(<span class="kwrd">ByVal</span> buffer() <span class="kwrd">As</span> <span class="kwrd">Single</span>,
                            <span class="kwrd">ByVal</span> inFrames <span class="kwrd">As</span> <span class="kwrd">Integer</span>) <span class="kwrd">As</span> <span class="kwrd">Single</span> <span class="kwrd">Implements</span> IPitchDetector.DetectPitch
    <span class="kwrd">Dim</span> window <span class="kwrd">As</span> Func(Of <span class="kwrd">Integer</span>, <span class="kwrd">Integer</span>, <span class="kwrd">Single</span>) = <span class="kwrd">AddressOf</span> HammingWindow
    <span class="kwrd">If</span> prevBuffer <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        prevBuffer = <span class="kwrd">New</span> <span class="kwrd">Single</span>(inFrames - 1) {}
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="rem">' double frames since we are combining present and previous buffers</span>
    <span class="kwrd">Dim</span> frames = inFrames * 2
    <span class="kwrd">If</span> fftBuffer <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        fftBuffer = <span class="kwrd">New</span> <span class="kwrd">Single</span>(frames * 2 - 1) {} <span class="rem">' times 2 because it is complex input</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">For</span> n = 0 <span class="kwrd">To</span> frames - 1
        <span class="kwrd">If</span> n &lt; inFrames <span class="kwrd">Then</span>
            fftBuffer(n * 2) = prevBuffer(n) * window(n, frames)
            fftBuffer(n * 2 &#43; 1) = 0 <span class="rem">' need to clear out as fft modifies buffer</span>
        <span class="kwrd">Else</span>
            fftBuffer(n * 2) = buffer(n - inFrames) * window(n, frames)
            fftBuffer(n * 2 &#43; 1) = 0 <span class="rem">' need to clear out as fft modifies buffer</span>
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Next</span> n</pre>
<p>Notice that we prepend the previous buffer we were passed. This is a common way of increasing the accuracy and resolution of an FFT by using overlapping windows, and can be further extended to store three previous buffers, allowing us to have 75% overlapping
 windows instead of just the 50% that we have in this example. </p>
<p>For better peak frequency detection, the signal that is passed into the FFT is best pre-processed with a
<a href="http://en.wikipedia.org/wiki/Window_function">“windowing” function</a>. There are several to choose from, each with its own strengths and weaknesses. I used the Hamming window, which is a fairly common choice:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">float</span> HammingWindow(<span class="kwrd">int</span> n, <span class="kwrd">int</span> N) 
{
    <span class="kwrd">return</span> 0.54f - 0.46f * (<span class="kwrd">float</span>)Math.Cos((2 * Math.PI * n) / (N - 1));
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> HammingWindow(<span class="kwrd">ByVal</span> n <span class="kwrd">As</span> <span class="kwrd">Integer</span>, <span class="kwrd">ByVal</span> _N <span class="kwrd">As</span> <span class="kwrd">Integer</span>) <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Return</span> 0.54F - 0.46F * <span class="kwrd">CSng</span>(Math.Cos((2 * Math.PI * n) / (_N - 1)))
<span class="kwrd">End</span> Function</pre>
<p>The next step is to pass on our interleaved buffer to the FFT algorithm. I am using Stephan Bernsee's here, though there is an alternative implementation in NAudio that I could have used. Since the same function can be used for an inverse FFT, the -1 parameter
 means (rather counter-intuitively), do a forwards FFT. It processes the data in place, which is fine since we don't need to keep the contents of the input buffer:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="rem">// assuming frames is a power of 2</span>
SmbPitchShift.smbFft(fftBuffer, frames, -1);</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="rem">' assuming frames is a power of 2</span>
SmbPitchShift.smbFft(fftBuffer, frames, -1)</pre>
<p>Once we have completed the FFT, we are ready to interpret its output. The output of the FFT consists of complex numbers (again real followed by imaginary in our buffer), which represent frequency “bins.”</p>
<p>We start off by calculating the bin size and working out which bins correspond to the range of frequencies we are interested in detecting:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">float</span> binSize = sampleRate / frames;
<span class="kwrd">int</span> minBin = (<span class="kwrd">int</span>)(85 / binSize);
<span class="kwrd">int</span> maxBin = (<span class="kwrd">int</span>)(300 / binSize);</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Dim</span> binSize = sampleRate / frames
<span class="kwrd">Dim</span> minBin = <span class="kwrd">CInt</span>(Fix(85 / binSize))
<span class="kwrd">Dim</span> maxBin = <span class="kwrd">CInt</span>(Fix(300 / binSize))</pre>
<p>For example, if our sample rate is 44.1kHz and we analyse a block of 1024 samples, then each bin represents 43Hz, which is hardly the granularity we are looking for. To increase resolution, our options are to either sample at a higher rate or analyse a bigger
 chunk. Our approach is to use overlapping blocks of 8192 samples, as we read 4096 samples each time. This means we have a resolution of around 5Hz, which is much more acceptable.</p>
<p>Now we can calculate the magnitude or “intensity” for each frequency by calculating the sum of squares (strictly we should then take the square root, but we don't need to since we are just looking for the largest value):</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">float</span> maxIntensity = 0f;
<span class="kwrd">int</span> maxBinIndex = 0;

<span class="kwrd">for</span> (<span class="kwrd">int</span> bin = minBin; bin &lt;= maxBin; bin&#43;&#43;)
{
    <span class="kwrd">float</span> real = fftBuffer[bin * 2];
    <span class="kwrd">float</span> imaginary = fftBuffer[bin * 2 &#43; 1];
    <span class="kwrd">float</span> intensity = real * real &#43; imaginary * imaginary;
    <span class="kwrd">if</span> (intensity &gt; maxIntensity)
    {
        maxIntensity = intensity;
        maxBinIndex = bin;
    }
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Dim</span> maxIntensity = 0.0F
<span class="kwrd">Dim</span> maxBinIndex = 0
<span class="kwrd">For</span> bin = minBin <span class="kwrd">To</span> maxBin
    <span class="kwrd">Dim</span> real = fftBuffer(bin * 2)
    <span class="kwrd">Dim</span> imaginary = fftBuffer(bin * 2 &#43; 1)
    <span class="kwrd">Dim</span> intensity = real * real &#43; imaginary * imaginary
    <span class="kwrd">If</span> intensity &gt; maxIntensity <span class="kwrd">Then</span>
        maxIntensity = intensity
        maxBinIndex = bin
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">Next</span> bin</pre>
<p>Since we have identified the bin with the maximum intensity, we can calculate the detected frequency:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">return</span> binSize * maxBinIndex;</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Return</span> binSize * maxBinIndex</pre>
<p>I don't currently specify a minimum threshold for maxIntensity, but perhaps if it were very low, the FFT pitch detector would return zero to indicate no pitch detected instead of returning an answer that is probably not accurate.</p>
<p>Let's have a look at how the FFT pitch detector does:
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="140">
<p><b>Test Frequency</b></p>
</td>
<td valign="top" width="132">
<p><b>Detected Pitch</b></p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>109.99Hz</p>
</td>
<td valign="top" width="132">
<p>107.67Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>116.53Hz</p>
</td>
<td valign="top" width="132">
<p>118.43Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>123.46Hz</p>
</td>
<td valign="top" width="132">
<p>123.82Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>130.80Hz</p>
</td>
<td valign="top" width="132">
<p>129.20Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>138.58Hz</p>
</td>
<td valign="top" width="132">
<p>139.97Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>146.82Hz</p>
</td>
<td valign="top" width="132">
<p>145.35Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>155.55Hz</p>
</td>
<td valign="top" width="132">
<p>156.12Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>164.80Hz</p>
</td>
<td valign="top" width="132">
<p>166.88Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>174.60Hz</p>
</td>
<td valign="top" width="132">
<p>172.27Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>184.98Hz</p>
</td>
<td valign="top" width="132">
<p>183.03Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>195.98Hz</p>
</td>
<td valign="top" width="132">
<p>193.80Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>207.63Hz</p>
</td>
<td valign="top" width="132">
<p>209.95Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>219.98Hz</p>
</td>
<td valign="top" width="132">
<p>220.72Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>233.06Hz</p>
</td>
<td valign="top" width="132">
<p>231.48Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>246.92Hz</p>
</td>
<td valign="top" width="132">
<p>247.63Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>261.60Hz</p>
</td>
<td valign="top" width="132">
<p>263.78Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>277.16Hz</p>
</td>
<td valign="top" width="132">
<p>274.55Hz</p>
</td>
</tr>
<tr>
<td valign="top" width="140">
<p>293.64Hz</p>
</td>
<td valign="top" width="132">
<p>296.08Hz</p>
</td>
</tr>
</tbody>
</table>
</p>
<p>As can be seen, it correctly picks out the primary frequencies of the higher notes, but overall it doesn't get that much closer than the autocorrelator, so I've left that as the default algorithm. You, however, can swap in the FFT detector in the code if
 it works better for the material you are auto-tuning.</p>
<p>There are ways of using the phase information from the FFT output to increase the accuracy of pitch detection even further, but I have left that as an exercise for the reader!</p>
<h4>Pitch Shifting</h4>
<p>The next step is to determine how much we will shift the pitch. The simplest way to do this is to look for the musical pitch that is closest to the detected pitch. Then, the amount of the shift by is simply the ratio of those two notes.
</p>
<p>There are, however, some additional considerations. First, we may want to select a subset of musical notes that are acceptable. For example, only notes in the key of C#, or maybe F# minor pentatonic. This may require a slightly more radical adjustment.</p>
<p>Second, depending on the effect we are after, we may not want to instantaneously jump to the new frequency. The code I am using utilizes a fairly rudimentary “attack” time parameter, allowing you to gradually move to the new frequency.
</p>
<p>The actual DSP for the pitch-shifting effect is more or less untouched from Stephan Bernsee's code, and this is because it works really well. The Bernsee's code makes use of the Fast Fourier Transform, plus a bunch of clever mathematics, which I
<i>almost </i>understand, but not quite well enough to try and explain here! You're better off reading an article in which the man himself explains
<a href="http://www.dspdimension.com/admin/pitch-shifting-using-the-ft/">how it works</a>.</p>
<p>The class that manages the pitch-shifting algorithm is called <b>SmbPitchShifer
</b>and inherits from a <b>PitchShifter</b> base class. This does the bulk of its work in the
<b>ShiftPitch</b> function:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> ShiftPitch(<span class="kwrd">float</span>[] inputBuff, <span class="kwrd">float</span> inputPitch,
                       <span class="kwrd">float</span> targetPitch, <span class="kwrd">float</span>[] outputBuff, <span class="kwrd">int</span> nFrames)
{
     UpdateSettings();
     detectedPitch = inputPitch;</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> ShiftPitch(<span class="kwrd">ByVal</span> inputBuff() <span class="kwrd">As</span> <span class="kwrd">Single</span>, <span class="kwrd">ByVal</span> inputPitch <span class="kwrd">As</span> <span class="kwrd">Single</span>,
                    <span class="kwrd">ByVal</span> targetPitch <span class="kwrd">As</span> <span class="kwrd">Single</span>, <span class="kwrd">ByVal</span> outputBuff() <span class="kwrd">As</span> <span class="kwrd">Single</span>, <span class="kwrd">ByVal</span> nFrames <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
    UpdateSettings()
    detectedPitch = inputPitch</pre>
<p>The <b>inputPitch</b> parameter is set to the frequency detected by the PitchDetector. The
<b>targetPitch</b> parameter is currently unused, but will be used to specify the target pitch in real-time when accepting input from, say, a MIDI keyboard. In any case, we call
<b>UpdateSettings</b> in order to see if any of the autotune algorithm settings have changed since last time.</p>
<p>Next we calculate the amount we need to shift the pitch shift. A shift factor of 1 means no change. We don't allow the shift factor to go above 2 or below 0.5, since these figures represent a whole octave change:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">float</span> shiftFactor = 1.0f;

<span class="kwrd">if</span> (inputPitch &gt; 0)
{
    shiftFactor = snapFactor(inputPitch);
}

<span class="kwrd">if</span> (shiftFactor &gt; 2.0) shiftFactor = 2.0f;
<span class="kwrd">if</span> (shiftFactor &lt; 0.5) shiftFactor = 0.5f;</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Dim</span> shiftFactor = 1.0F

<span class="kwrd">If</span> inputPitch &gt; 0 <span class="kwrd">Then</span>
   shiftFactor = snapFactor(inputPitch)
   shiftFactor &#43;= addVibrato(nFrames)
<span class="kwrd">End</span> <span class="kwrd">If</span>

<span class="kwrd">If</span> shiftFactor &gt; 2.0 <span class="kwrd">Then</span>
   shiftFactor = 2.0F
<span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">If</span> shiftFactor &lt; 0.5 <span class="kwrd">Then</span>
   shiftFactor = 0.5F
<span class="kwrd">End</span> If</pre>
<p>The decision of what the target note is takes place in the <b>snapFactor</b> function:</p>
<p><strong>c#:</strong></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">float</span> snapFactor(<span class="kwrd">float</span> freq)
{
    <span class="kwrd">float</span> previousFrequency = 0.0f;
    <span class="kwrd">float</span> correctedFrequency = 0.0f;
    <span class="kwrd">int</span> previousNote = 0;
    <span class="kwrd">int</span> correctedNote = 0;
    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; i &lt; 120; i&#43;&#43;)
    {
        <span class="kwrd">bool</span> endLoop = <span class="kwrd">false</span>;
        <span class="kwrd">foreach</span> (<span class="kwrd">int</span> note <span class="kwrd">in</span> <span class="kwrd">this</span>.settings.AutoPitches)
        {
            <span class="kwrd">if</span> (i % 12 == note)
            {
                previousFrequency = correctedFrequency;
                previousNote = correctedNote;
                correctedFrequency = (<span class="kwrd">float</span>)(8.175 * Math.Pow(1.05946309, (<span class="kwrd">float</span>)i));
                correctedNote = i;
                <span class="kwrd">if</span> (correctedFrequency &gt; freq) { endLoop = <span class="kwrd">true</span>; }
                <span class="kwrd">break</span>;
            }
        }
        <span class="kwrd">if</span> (endLoop)
        {
            <span class="kwrd">break</span>;
        }
    }
    <span class="kwrd">if</span> (correctedFrequency == 0.0) { <span class="kwrd">return</span> 1.0f; }
    <span class="kwrd">int</span> destinationNote = 0;
    <span class="kwrd">double</span> destinationFrequency = 0.0;
    <span class="rem">// decide whether we are shifting up or down</span>
    <span class="kwrd">if</span> (correctedFrequency - freq &gt; freq - previousFrequency)
    {
        destinationNote = previousNote;
        destinationFrequency = previousFrequency;
    }
    <span class="kwrd">else</span>
    {
        destinationNote = correctedNote;
        destinationFrequency = correctedFrequency;
    }
    <span class="kwrd">if</span> (destinationNote != currPitch)
    {
        numElapsed = 0;
        currPitch = destinationNote;
    }
    <span class="kwrd">if</span> (attack &gt; numElapsed)
    {
        <span class="kwrd">double</span> n = (destinationFrequency - freq) / attack * numElapsed;
        destinationFrequency = freq &#43; n;
    }
    numElapsed&#43;&#43;;
    <span class="kwrd">return</span> (<span class="kwrd">float</span>)(destinationFrequency / freq);
}</pre>
<p><strong>VB.Net:</strong></p>
<pre class="csharpcode"><span class="kwrd">Protected</span> <span class="kwrd">Function</span> snapFactor(<span class="kwrd">ByVal</span> freq <span class="kwrd">As</span> <span class="kwrd">Single</span>) <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Dim</span> previousFrequency = 0.0F
    <span class="kwrd">Dim</span> correctedFrequency = 0.0F
    <span class="kwrd">Dim</span> previousNote = 0
    <span class="kwrd">Dim</span> correctedNote = 0
    <span class="kwrd">For</span> i = 1 <span class="kwrd">To</span> 119
        <span class="kwrd">Dim</span> endLoop = <span class="kwrd">False</span>
        <span class="kwrd">For</span> <span class="kwrd">Each</span> note <span class="kwrd">As</span> <span class="kwrd">Integer</span> <span class="kwrd">In</span> <span class="kwrd">Me</span>.settings.AutoPitches
            <span class="kwrd">If</span> i <span class="kwrd">Mod</span> 12 = note <span class="kwrd">Then</span>
                previousFrequency = correctedFrequency
                previousNote = correctedNote
                correctedFrequency = <span class="kwrd">CSng</span>(8.175 * Math.Pow(1.05946309, <span class="kwrd">CSng</span>(i)))
                correctedNote = i
                <span class="kwrd">If</span> correctedFrequency &gt; freq <span class="kwrd">Then</span>
                    endLoop = <span class="kwrd">True</span>
                <span class="kwrd">End</span> <span class="kwrd">If</span>
                <span class="kwrd">Exit</span> <span class="kwrd">For</span>
            <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">Next</span> note
        <span class="kwrd">If</span> endLoop <span class="kwrd">Then</span>
            <span class="kwrd">Exit</span> <span class="kwrd">For</span>
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Next</span> i
    <span class="kwrd">If</span> correctedFrequency = 0.0 <span class="kwrd">Then</span>
        <span class="kwrd">Return</span> 1.0f
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Dim</span> destinationNote = 0
    <span class="kwrd">Dim</span> destinationFrequency = 0.0
    <span class="rem">' decide whether we are shifting up or down</span>
    <span class="kwrd">If</span> correctedFrequency - freq &gt; freq - previousFrequency <span class="kwrd">Then</span>
        destinationNote = previousNote
        destinationFrequency = previousFrequency
    <span class="kwrd">Else</span>
        destinationNote = correctedNote
        destinationFrequency = correctedFrequency
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> destinationNote &lt;&gt; currPitch <span class="kwrd">Then</span>
        numElapsed = 0
        currPitch = destinationNote
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> attack &gt; numElapsed <span class="kwrd">Then</span>
        <span class="kwrd">Dim</span> n = (destinationFrequency - freq) / attack * numElapsed
        destinationFrequency = freq &#43; n
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    numElapsed &#43;= 1
    <span class="kwrd">Return</span> <span class="kwrd">CSng</span>(destinationFrequency / freq)
<span class="kwrd">End</span> Function</pre>
<p>The way this function works is that it runs through the MIDI notes 0-120 and, if that note is selected as one of the valid pitches we support, we remember the “corrected frequency,” which can be calculated from the MIDI note number with the following formula:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode">correctedFrequency = (<span class="kwrd">float</span>)(8.175 * Math.Pow(1.05946309, (<span class="kwrd">float</span>)midiNoteNumber));</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode">correctedFrequency = <span class="kwrd">CSng</span>(8.175 * Math.Pow(1.05946309, <span class="kwrd">CSng</span>(i)))</pre>
<p>Obviously, a pitch is likely to fall somewhere in between two valid notes, so we choose the which pitch to correct by determining which one is closest to the detected frequency.</p>
<p>The <b>snapFactor </b>function is also responsible for implementing the attack time parameter. This allows the destinationFrequency to be slowly moved to the target note over the duration of the attack period. Having calculated our shift factor, we are now
 ready to pass our data on to the actual pitch-shifting algorithm:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">int</span> fftFrameSize = 2048;
<span class="kwrd">int</span> osamp = 8; <span class="rem">// 32 is best quality</span>
SmbPitchShift.smbPitchShift(shiftFactor, nFrames, fftFrameSize, osamp, <span class="kwrd">this</span>.sampleRate, inputBuff, outputBuff);</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Dim</span> fftFrameSize = 2048
<span class="kwrd">Dim</span> osamp = 8 <span class="rem">' 32 is best quality</span>
SmbPitchShift.smbPitchShift(shiftFactor, nFrames, fftFrameSize, osamp, <span class="kwrd">Me</span>.sampleRate, inputBuff, outputBuff)</pre>
<p>The final thing we do in the <b>ShiftPitch </b>function is keep a record of the pitch shifts we have made. These are stored in a queue (maximum of 5000 entries) and are very useful for diagnosing what is going on if you are not getting the results you wanted
 from the algorithm:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode">shiftedPitch = inputPitch * shiftFactor;
updateShifts(detectedPitch, shiftedPitch, <span class="kwrd">this</span>.currPitch);</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode">shiftedPitch = inputPitch * shiftFactor
updateShifts(detectedPitch, shiftedPitch, <span class="kwrd">Me</span>.currPitch)</pre>
<h2>Performance</h2>
<p>Performance, as you might expect in a managed application that has not been extensively optimized, was not good. Using my laptop, I could autotune one minute of audio in about 90 seconds. Obviously, that rules out real-time autotuning. I decided to profile
 the application to see if there were any quick ways I could improve things.</p>
<p>The profiling tools in Visual Studio revealed that 20% of the time was spent on pitch detection and 80% pitch shifting. Unfortunately, there were not too many options available for optimisation, since further investigation pointed to calls to
<b>Math.Sin</b> taking the bulk of the time. Possibly creating lookup tables could save a bit more time.
</p>
<p>Fortunately, we have another option for speeding things up. The pitch-shifting algorithm takes an “oversampling” parameter, which by default is set to 32, the highest value. However, we can trade off speed for quality. Setting it to 16 meant that I could
 autotune a minute of audio in 55ms (on my 2.4GHz Core2Duo laptop) – realtime but only just. Setting it to 8 reduced that down to 36s. The results still sounded reasonable, so I have left it set at 8 in the code.
</p>
<p>An alternative way of speeding it up though would be to swap in a different pitch-shifting algorithm. You could start by trying out one I created as part of the
<a href="http://blogs.msdn.com/b/coding4fun/archive/2009/02/02/9391048.aspx">Skype Voice Changer project</a> previously featured on Coding4Fun, which is also able to operate in real-time (although I haven't done any quality comparisons).</p>
<h2>Creating a Test GUI</h2>
<p>Rather than starting from scratch, I decided to build upon <a href="http://voicerecorder.codeplex.com/">
.NET Voice Recorder</a>, a WPF application I created for <a href="http://blogs.msdn.com/b/coding4fun/archive/2009/10/08/9905168.aspx">
a previous Coding4Fun article</a>. This takes advantage of the <a href="file:///C:/Users/crutkas/AppData/Local/Microsoft/Windows/Temporary Internet Files/Content.IE5/SMJQO6XL/naudio.codeplex.com">
NAudio</a> .NET audio library for audio recording and playback capabilities. The GUI has three screens. On the first is the input device used for recording. The second records a short voice clip. And the third allows you to edit a small portion of saved audio.</p>
<p>Here's a screenshot of the second screen showing a recording in progress:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image_thumb.png" width="320" height="380"></a></p>
<p>And here's the screen that allows you to trim the recording, preview it, and save it as WAV:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image_3.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image_thumb_3.png" width="320" height="380"></a></p>
<p>As you can see, I have added a new button allowing access to the autotune effect settings. On this screen, you can select which notes are valid, and you can also adjust the “attack time” if you prefer to not go for the robotic effect. I've included a drop-down
 menu that automatically selects the appropriate notes from various keys.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image_4.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10112293/image_thumb_4.png" width="320" height="360"></a></p>
<p><b></b></p>
<p>When you click “Apply,” the autotune effect is applied (while you wait on a background thread) and then you are returned to the screen, allowing you to play back your recording and see how it sounds. If you'd like, you can then go back and change the autotune
 settings (or turn it off).</p>
<h3>MVVM Light</h3>
<p>The original VoiceRecorder application used a <a href="http://en.wikipedia.org/wiki/Model_View_ViewModel">
MVVM</a> (model-view-viewmodel) architecture for binding data to each view. I have updated it to make use of Laurent Bugnion's excellent
<a href="http://www.galasoft.ch/mvvm/getstarted/">MVVM Light</a> library. This removes the need for my own RelayCommand and ViewModelBase classes, and also enables me to replace my ViewManager with a more extensible framework using the event aggregator (“<a href="http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx">Messenger</a>”)
 that is included with MVVM light. This allows me to quickly navigate from one view to another by sending out a message on the event aggregator:</p>
<p><strong>c#:</strong> </p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToSaveView()
{
   Messenger.Default.Send(<span class="kwrd">new</span> NavigateMessage(SaveViewModel.ViewName, <span class="kwrd">this</span>.voiceRecorderState));
}</pre>
<p><strong>VB.Net</strong></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> NavigateToSaveView()
    Messenger.<span class="kwrd">Default</span>.Send(<span class="kwrd">New</span> NavigateMessage(SaveViewModel.ViewName, <span class="kwrd">Me</span>.voiceRecorderState))
<span class="kwrd">End</span> Sub</pre>
<h3>Getting the Best out of Autotune</h3>
<p>Unfortunately, Autotune is an effect that doesn't always produce the desired result . Obviously, if you want great autotune, you're best off buying a commercial implementation, but here are a few tips for getting the most out of an autotune algorithm:</p>
<ul>
<li><b>Get a good quality recording</b>. Avoid background noise, hum, and too quiet or too loud (distorted) recordings. If you need to sing against a backing track, play it in headphones so the microphone doesn't pick it up.
</li><li><b>Know what key you are singing in</b>. This is where the test application won't help you out, since if you don't know what key you are singing in, you can hardly expect to be able to select the appropriate key from the list. You might even be singing
 in between two keys! If you have an in-tune musical instrument at hand, play a note to give yourself a starting pitch.
</li><li><b>Choose your scale. </b>The easiest option is to just go with a chromatic scale, which means all 12 notes are valid. However, you can try to make the autotune force you into a monotone. Pentatonic scales are useful for instant gratification. They have
 five notes in them, and so long as you stick to those five, almost anything you sing will fit in with a backing track in your chosen key.
</li><li><b>Adjust the attack time</b>. An attack time of zero is great for the robot effect. A longer attack time will smooth out transitions.
</li><li><b>Why is it “warbling”? </b>With this autotune algorithm, it is quite common to get a “warbling” effect. This is because it is either changing its mind about what note to pitch shift to (because the pitch detector is not providing stable pitch detection),
 or because the pitch detector couldn't determine a pitch at all, so your voice isn't being pitch shifted. You can play around with the release slider (and may need to modify the release algorithm) if you want to eliminate warbling.
</li></ul>
<h2>Taking it further</h2>
<p>.NET Voice Recorder is open source <a href="http://voicerecorder.codeplex.com">
and hosted on CodePlex</a> in a Mercurial repository. So what you waiting for? Make a fork and have a go at improving it:</p>
<ul>
<li><b>Improve the pitch detector algorithm</b>. I have already given some suggestions for how this can be done. One idea that might be worth experimenting with is making it “hold” the detected frequency for a short period until a strong, new frequency is detected.
</li><li><b>Display the detected pitches.</b> The autotune effect stores data of the detected pitches as well as the pitches it attempts to convert to. You might display this information to the user, perhaps underneath the waveform, so they can see what it is detecting.
 (It currently outputs this information with Debug.WriteLine, which is useful for debugging purposes).
</li><li><b>Suggest an appropriate scale? </b>Instead of leaving it to the user to select what key to snap the notes to, how about auto-selecting the detected notes?
</li><li><b>Allow direct input of desired pitch</b>. Instead of letting the autotune effect try to work out what note it should be targeting at any given time, it is far more effective to let the user input what note they would like to shift to. This could be done
 by entering the note using a MIDI keyboard in real-time, or by drawing the notes in, perhaps on a “piano-roll” control. Or, users could implement a simple, domain-specific language to specify the desired note. For example:
<ul>
<li>0:00.0 C# </li><li>0:01.5 E </li><li>0:02.7 G# </li></ul>
</li><li><b>Port it to Windows Phone 7</b>. This would be quite a cool effect to have on your phone. Of course, you might need to optimize performance a bit more to save battery life. And you'll want to put your graphic designer hat on to give it a more beautiful
 look than it currently has. </li></ul>
<h2>About the Author</h2>
<p>Mark Heath is the author of several open source .NET applications and libraries, including
<a href="http://naudio.codeplex.com">
NAudio</a> and the <a href="http://skypefx.codeplex.com">
Skype Voice Changer</a>. He works for <a href="http://nice.com/">NICE Systems</a>, developing applications that search, display, and play back vast amounts of multimedia data. He has a blog,
<a href="http://mark-dot-net.blogspot.com">Sound Code</a>, and you can follow him on his sporadically updated
<a href="http://twitter.com/mark_heath">Twitter account</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:f73dedce787c457fb8b09e7600c6e4d6">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/AutotuneNET</comments>
      <itunes:summary>We&#39;ve all cringed as a hopelessly out of tune contestant appears on the latest episode of “American Idol.” Occasionally, there&#39;s a contestant who manages to be pitch perfect all the way through—right until they flub the final note. And in the cutthroat world
 of televised auditions, sing one slightly flat note and you&#39;re out.  
So what takes care of a bad-pitch day? Autotune—an effect that corrects the pitch of your voice so you&#39;ll never again sing out of tune. And now, with the power of modern microprocessors, autotune is possible in real-time, allowing singers to benefit from
 its almost magical powers during live concerts. 
The company most famous for its autotune effect is Antares. 
Antares Auto-Tune currently retails for $249, and a stripped down version is available for $100. In addition to simply improving the pitch of a dodgy singer, autotune can be used to create unique robotic sounding vocal effects, a technique massively popular
 in recent years thanks to its use by artists such as T-Pain and the group behind the “Auto-Tune the News” YouTube videos. In 1998, when the effect was first used on
Cher&#39;s “Believe” single, the producer used such extreme settings that instead of subtly adjusting the pitch, autotune “snapped” instantaneously to the nearest “correct” note.
 
Here is a nerdy example of what Autotune can do. 



How does Autotune work?
An autotune effect has two parts. The first is pitch detection, which calculates the dominant frequency of the incoming signal, and is the reason autotune is normally used on monophonic audio sources (i.e. playing one note at a time, not whole chords).
 So, if your guitar is out of tune, you&#39;re out of luck (Celemony&#39;s Melodyne product, however, features some incredible capabilities for pitch-shifting polyphonic audio). 
The second stage is pitch shifting, or “correcting” a given note. However, the bigger the pitch shift required, the more artificial the end result will be, and it is worth noting that absolutely perfect</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/AutotuneNET</link>
      <pubDate>Wed, 05 Jan 2011 22:19:46 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/AutotuneNET</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10112293_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10112293_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Mark Heath</dc:creator>
      <itunes:author>Mark Heath</itunes:author>
      <slash:comments>20</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/AutotuneNET/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>MVVM</category>
      <category>WPF</category>
    </item>
  <item>
      <title>Mini Speakers. Mighty Sound. Springy Bass.</title>
      <description><![CDATA[ <p>Whenever I’m travelling, one of the first things I do when I get into my hotel room is look for an MP3 player dock. Having my own music playing in the room really helps to settle me in, but sadly, not all hotels provide a dock for guest use.</p><p>I really should pick up some portable speakers, but the ones I’ve checked out previously are either way too big for true portability, or a small, tinny and gobble up batteries like there’s no tomorrow.</p><p>The <a href="http://www.x-mini.com/en/stereo-speakers/x-mini-max-ii">X Mini Max II</a> may lift my downer on portable speakers. They’re small, and are held together in an egg shape by magnets for portability. There’s a simple 3.5” connector jack for plugging into your MP3 player or laptop, and forget the need for batteries – the X Mini Max II has a rechargable battery that charges via USB, so that’s one less power cable to bring along.</p><p>The speakers have a couple of additional tricks that set them apart from the rest. Firstly, you can connect multiple sets of speakers together in daisy-chain formation to spread the sound around the room. Finally, unscrew the speaker and it springs open accordion style to effectively mimic a sub-woofer. </p><p>Small speaker, big sound, large bass, no hassle. Love it. There’s a range of speakers on offer in a choice of colours, plus one model with an integrated audio player and SD card slot. That’s another item on my Christmas gift list filled.&nbsp;</p><p>&nbsp;</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:431228dbe4aa4760b3629e17007d92bb">]]></description>
      <comments>http://channel9.msdn.com/Blogs/coolstuff/Mini-Speakers-Mighty-Sound-Springy-Bass</comments>
      <itunes:summary> Whenever I’m travelling, one of the first things I do when I get into my hotel room is look for an MP3 player dock. Having my own music playing in the room really helps to settle me in, but sadly, not all hotels provide a dock for guest use. I really should pick up some portable speakers, but the ones I’ve checked out previously are either way too big for true portability, or a small, tinny and gobble up batteries like there’s no tomorrow. The X Mini Max II may lift my downer on portable speakers. They’re small, and are held together in an egg shape by magnets for portability. There’s a simple 3.5” connector jack for plugging into your MP3 player or laptop, and forget the need for batteries – the X Mini Max II has a rechargable battery that charges via USB, so that’s one less power cable to bring along. The speakers have a couple of additional tricks that set them apart from the rest. Firstly, you can connect multiple sets of speakers together in daisy-chain formation to spread the sound around the room. Finally, unscrew the speaker and it springs open accordion style to effectively mimic a sub-woofer.  Small speaker, big sound, large bass, no hassle. Love it. There’s a range of speakers on offer in a choice of colours, plus one model with an integrated audio player and SD card slot. That’s another item on my Christmas gift list filled.&amp;nbsp; &amp;nbsp; </itunes:summary>
      <link>http://channel9.msdn.com/Blogs/coolstuff/Mini-Speakers-Mighty-Sound-Springy-Bass</link>
      <pubDate>Fri, 22 Oct 2010 07:41:27 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/coolstuff/Mini-Speakers-Mighty-Sound-Springy-Bass</guid>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/0130d87c-ee7c-4cc8-98ee-bde4523b1538.jpg" height="66" width="100"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/76a6505f-92d6-4b67-914d-d64014d75ced.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://files.channel9.msdn.com/thumbnail/8bf199a9-29f2-4720-80fe-9e47c8d51c50.jpg" height="240" width="320"></media:thumbnail>      
      <dc:creator>Terry Walsh</dc:creator>
      <itunes:author>Terry Walsh</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/coolstuff/Mini-Speakers-Mighty-Sound-Springy-Bass/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>speakers</category>
      <category>MP3</category>
      <category>Audio gear</category>
    </item>
  <item>
      <title>Generating Sound Waves with C# Wave Oscillators</title>
      <description><![CDATA[
<p>For the longest time, I've been baffled by the concept of sound in computing. How in the world is sound store? How is it played back? In classic Coding4Fun style, we'll learn by doing in this article—by building a wave oscillator application.
</p>
<h3>Optional Reading</h3>
<p>I cover the basics of this article in a multi-part blog series, which you should check out if you have trouble:</p>
<p><a href="http://blogs.msdn.com/dawate/archive/2009/06/22/intro-to-audio-programming-part-1-how-audio-data-is-represented.aspx">Part 1 - How Audio Data is Represented</a>
<br>
<a href="http://blogs.msdn.com/dawate/archive/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format.aspx">Part 2 - Demystifying the WAV Format</a>
<br>
<a href="http://blogs.msdn.com/dawate/archive/2009/06/24/intro-to-audio-programming-part-3-synthesizing-simple-wave-audio-using-c.aspx">Part 3 - Synthesizing Simple WAV Audio Using C#</a>
<br>
<a href="http://blogs.msdn.com/dawate/archive/2009/06/25/intro-to-audio-programming-part-4-algorithms-for-different-sound-waves-in-c.aspx">Part 4 - Algorithms for Different Sound Waves in C#</a></p>
<h3>What's An Oscillator?</h3>
<p>An oscillator is a device or application that generates a waveform. In electrical engineering terms, it's a device that outputs an electrical current with varying voltage. If you plot the voltage over time, you get a regular wave in a particular form, such
 as a sine, square, triangle or sawtooth.</p>
<p>An oscillator is the most basic type of synthesizer. Analog synths use electrical circuits to output a sound wave. Digital synthesizers do the same thing, but with software.</p>
<p>You can create a pretty neat sounding instrument by combining the outputs of multiple oscillators. For example, if you have three oscillators oscillating at a frequency of 440Hz (concert A pitch), but each of them has a different waveform (saw, square, sine)
 you get a very interesting, layered sound. </p>
<p>But before we get too deep into this subject, let's briefly explore the physics of sound.</p>
<h3>The Physics of Sound</h3>
<p>Sound happens when air pressure changes on your ear drum. When you clap in an empty room, pressure waves bounce all over the place and dance on your eardrum. The changes in pressure are detected continuously by your ear.
</p>
<p>Digitally, “pressure” is referred to by a scalar value called <i>amplitude. </i>
The amplitude (loudness) of the wave is measured thousands of times per second (44,100 times per second on CDs). Every measurement of pressure (aka
<i>amplitude</i>) is called a <i>sample</i>—CDs are recorded with 44,100 <i>samples</i> per second, each with a value between the minimum and maximum amplitude for the bit depth.
</p>
<p>Think about 44,100 samples per second. That's a <i>lot</i> of stuff for your ear to detect. That's how we're able to hear so much stuff going on in the mix of a song, especially in stereo tracks where you have 44,100 samples per second, per ear.
</p>
<p>It turns out that there is a <a href="http://en.wikipedia.org/wiki/Nyquist-Shannon_sampling_theorem">
horribly intense mathematical theorem</a> which basically tells us that 44,100 samples per second is enough to accurately represent a pitch as high as 22 KHz. The human ear can really hear only up to 20KHz, so a 44.1KHz sampling rate is a more than high-enough
 sampling rate. </p>
<p>This whole section is expanded in detail on my blog:</p>
<p><a href="http://blogs.msdn.com/dawate/archive/2009/06/22/intro-to-audio-programming-part-1-how-audio-data-is-represented.aspx">Part 1 - How Audio Data is Represented</a></p>
<h3>Terminology</h3>
<p>So now you have a rather glancing overview of how sound works, and perhaps some clues as to how we should go about representing it in computers. Let's go over all this new terminology (plus some even newer terms) in delicious, bulleted format:</p>
<p>· <b>Sample: </b>A measurement of a sound wave at a very small point in time. 44,100 of these measurements in a row form a single channel of CD-quality audio.</p>
<p>· <b>Amplitude: </b>The value of a sample. Max and min values are dependent upon the bit depth.</p>
<p>· <b>Bit depth: </b>The number of bits used to represent a sample. 16-bit, 32-bit, etc. Max amplitude is (2^depth) / 2 – 1.</p>
<p>· <b>Sample rate (aka sampling rate, aka bit rate): </b>The number of samples per second of audio. 44,100 is standard for CD-quality audio.</p>
<h3>How sound is represented</h3>
<p>By now, you've probably surmised that a second of audio data is somehow represented by an array of some integer data type, which has a length of 44,100. You would be correct in that assumption. However, if you want sound to play from a computer's sound card,
 that data has to be accompanied with a bunch of format information. WAV is probably the easiest format to deal with.
</p>
<p>See more in the following article:</p>
<p><a href="http://blogs.msdn.com/dawate/archive/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format.aspx">Part 2 - Demystifying the WAV Format</a></p>
<p>You can also see how to build out a WAV file, old school and binary style, in the 3<sup>rd</sup> part of that series:</p>
<p><a href="http://blogs.msdn.com/dawate/archive/2009/06/24/intro-to-audio-programming-part-3-synthesizing-simple-wave-audio-using-c.aspx">Part 3 - Synthesizing Simple WAV Audio Using C#</a></p>
<p>However, we are taking a slightly easier route, by using DirectSound. DirectSound gives us a lot of nice classes for all the format information, abstracting all that stuff away and allowing us to pump a stream of data into a DirectSound object and play it.
 Perfect for a synthesizer app!</p>
<p>So, let's get started!</p>
<h3>Building the app</h3>
<p>I learned some Blend while working with this app, since it's built on WPF. The image buttons are just radio buttons. I had to differentiate the group number per instance of the user control at runtime (in the constructor of the Oscillator class).</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_2.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_thumb.png" width="379" height="442"></a>
</p>
<p>I'm a terrible UI designer for the most part, so this is about as sexy as I'm willing to make this application. But feel free to make it look and act better!</p>
<h4>Designing the UI</h4>
<p>There's a dirty little secret in this application. It says it can oscillate 3 waves, but in truth, there's a constant (set to 3) that you can modify. You could have six if you wanted. How did I accomplish this? Each synth that you see is an instance of a
 WPF user control called Oscillator.xaml:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_4.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_thumb_1.png" width="380" height="102"></a>
</p>
<p>I have a StackPanel called Oscs in the main window. In the Window_Loaded event handler of the main window, I use this bit of code to add instances of the usercontrol:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="rem">// Add 3 oscillators</span>
Oscillator tmp;
<span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; NUM_GENERATORS; i&#43;&#43;)
{
    tmp = <span class="kwrd">new</span> Oscillator();
    Oscs.Children.Add(tmp);
    mixer.Oscillators.Add(tmp);
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="rem">' Add 3 oscillators</span>
<span class="kwrd">Dim</span> tmp <span class="kwrd">As</span> Oscillator
<span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0
<span class="kwrd">While</span> i &lt; NUM_GENERATORS
    tmp = <span class="kwrd">New</span> Oscillator()
    Oscs.Children.Add(tmp)
    mixer.Oscillators.Add(tmp)
    System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1)
<span class="kwrd">End</span> While</pre>
<p></p>
<p>The long rectangular canvas is used to plot the values of the generated wave, so you can visualize the wave as it's played. It is scaled along the X axis so you can see the general shape of the wave, which would be impossible without scaling it with 44,100
 samples per second.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_6.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_thumb_2.png" width="376" height="441"></a>
</p>
<p>Earlier in the article, I noted that a sound file is basically a <i>really, really long array</i> of 16- or 32-bit floating point numbers between -1 and 1. We use this data to plot the graph as well. More on that later.</p>
<p>Now that we have the UI figured out (dynamic addition of oscillators), let's take a look at exactly how the sound is produced.
</p>
<h3>Bzzzzt! Making Sounds and the Mixer</h3>
<p>One of the many cool things about DirectSound is that it basically wraps the WAV format for you. You set the buffering/format options and then shove a bunch of data into it, and it will play. Magic.</p>
<p>The way I've architected the solution is a little more modular. None of the oscillators has the ability to play itself—rather, uses its UI to control some values such as frequency, amplitude and wave type. These values are tied to public properties. The
 Oscillator component does virtually no audio work at all. </p>
<p>The generation of audio data is handled by the custom Mixer class, which takes a collection of Oscillators and, based on their properties, creates a composite of all the generators. This is done by averaging the samples in every oscillator and putting them
 into a new array of data.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_8.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_thumb_3.png" width="345" height="189"></a>
</p>
<p>The <b>Mixer</b> class looks like this:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_10.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/10006604/image_thumb_4.png" width="343" height="372"></a>
</p>
<p>One of the workhorses of the Mixer class is the method <b>GenerateOscillatorSampleData</b>. This takes an Oscillator as an argument to give access to the public properties set in the UI. From there, the algorithm generates 1 second of sample data (specified
 by the member <b>bufferDurationSeconds</b>) based on the wave type that has been selected in the UI. This is where the mathy stuff comes in to play. Check out this method and the different cases in the switch statement that determine what kind of wave to create
 below.</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">short</span>[] GenerateOscillatorSampleData(Oscillator osc)
{
    <span class="rem">// Creates a looping buffer based on the params given</span>
    <span class="rem">// Fill the buffer with whatever waveform at the specified frequency            </span>
    <span class="kwrd">int</span> numSamples = Convert.ToInt32(bufferDurationSeconds * 
        waveFormat.SamplesPerSecond);
    <span class="kwrd">short</span>[] sampleData = <span class="kwrd">new</span> <span class="kwrd">short</span>[numSamples];
    <span class="kwrd">double</span> frequency = osc.Frequency;
    <span class="kwrd">int</span> amplitude = osc.Amplitude;
    <span class="kwrd">double</span> angle = (Math.PI * 2 * frequency) / 
        (waveFormat.SamplesPerSecond * waveFormat.Channels);            

    <span class="kwrd">switch</span> (osc.WaveType)
    {
        <span class="kwrd">case</span> WaveType.Sine:
            {
                <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; numSamples; i&#43;&#43;)
                    <span class="rem">// Generate a sine wave in both channels.</span>
                    sampleData[i] = Convert.ToInt16(amplitude * 
        Math.Sin(angle * i));
            }
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WaveType.Square:
            {
                <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; numSamples; i&#43;&#43;)
                {
                    <span class="rem">// Generate a square wave in both channels.</span>
                    <span class="kwrd">if</span> (Math.Sin(angle * i) &gt; 0)
                        sampleData[i] = Convert.ToInt16(amplitude);
                    <span class="kwrd">else</span>
                        sampleData[i] = Convert.ToInt16(-amplitude);
                }
            }
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WaveType.Sawtooth:
            {
                <span class="kwrd">int</span> samplesPerPeriod = Convert.ToInt32(
        waveFormat.SamplesPerSecond / 
        (frequency / waveFormat.Channels));
                <span class="kwrd">short</span> sampleStep = Convert.ToInt16(
        (amplitude * 2) / samplesPerPeriod);
                <span class="kwrd">short</span> tempSample = 0;

                <span class="kwrd">int</span> i = 0;
                <span class="kwrd">int</span> totalSamplesWritten = 0;
                <span class="kwrd">while</span> (totalSamplesWritten &lt; numSamples)
                {
                    tempSample = (<span class="kwrd">short</span>)-amplitude;
                    <span class="kwrd">for</span> (i = 0; i &lt; samplesPerPeriod &amp;&amp; 
        totalSamplesWritten &lt; numSamples; i&#43;&#43;)
                    {
                        tempSample &#43;= sampleStep;
                        sampleData[totalSamplesWritten] = tempSample;

                        totalSamplesWritten&#43;&#43;;
                    }
                }
            }
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WaveType.Noise:
            {
                Random rnd = <span class="kwrd">new</span> Random();
                <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; numSamples; i&#43;&#43;)
                {
                    sampleData[i] = Convert.ToInt16(
        rnd.Next(-amplitude, amplitude));
                }
            }
            <span class="kwrd">break</span>;
    }
    <span class="kwrd">return</span> sampleData;
}</pre>
<p></p>
<p><b>VB.Net <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> GenerateOscillatorSampleData(<span class="kwrd">ByVal</span> osc <span class="kwrd">As</span> Oscillator) <span class="kwrd">As</span> <span class="kwrd">Short</span>()
    <span class="rem">' Creates a looping buffer based on the params given</span>
    <span class="rem">' Fill the buffer with whatever waveform at the specified frequency </span>
    <span class="kwrd">Dim</span> numSamples <span class="kwrd">As</span> <span class="kwrd">Integer</span> = Convert.ToInt32(
     bufferDurationSeconds * waveFormat.SamplesPerSecond)
    <span class="kwrd">Dim</span> sampleData <span class="kwrd">As</span> <span class="kwrd">Short</span>() = <span class="kwrd">New</span> <span class="kwrd">Short</span>(numSamples - 1) {}
    <span class="kwrd">Dim</span> frequency <span class="kwrd">As</span> <span class="kwrd">Double</span> = osc.Frequency
    <span class="kwrd">Dim</span> amplitude <span class="kwrd">As</span> <span class="kwrd">Integer</span> = osc.Amplitude
    <span class="kwrd">Dim</span> angle <span class="kwrd">As</span> <span class="kwrd">Double</span> = (Math.PI * 2 * frequency) /
     (waveFormat.SamplesPerSecond * waveFormat.Channels)

    <span class="kwrd">Select</span> <span class="kwrd">Case</span> osc.WaveType
        <span class="kwrd">Case</span> WaveType.Sine
            <span class="kwrd">If</span> <span class="kwrd">True</span> <span class="kwrd">Then</span>
                <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> numSamples - 1
                    <span class="rem">' Generate a sine wave in both channels.</span>
                    sampleData(i) =
                     Convert.ToInt16(amplitude * Math.Sin(angle * i))
                <span class="kwrd">Next</span>
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> WaveType.Square
            <span class="kwrd">If</span> <span class="kwrd">True</span> <span class="kwrd">Then</span>
                <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> numSamples - 1
                    <span class="rem">' Generate a square wave in both channels.</span>
                    <span class="kwrd">If</span> Math.Sin(angle * i) &gt; 0 <span class="kwrd">Then</span>
                        sampleData(i) = Convert.ToInt16(amplitude)
                    <span class="kwrd">Else</span>
                        sampleData(i) = Convert.ToInt16(-amplitude)
                    <span class="kwrd">End</span> <span class="kwrd">If</span>
                <span class="kwrd">Next</span>
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> WaveType.Sawtooth
            <span class="kwrd">If</span> <span class="kwrd">True</span> <span class="kwrd">Then</span>
                <span class="kwrd">Dim</span> samplesPerPeriod <span class="kwrd">As</span> <span class="kwrd">Integer</span> =
                 Convert.ToInt32(waveFormat.SamplesPerSecond /
                      (frequency / waveFormat.Channels))
                <span class="kwrd">Dim</span> sampleStep <span class="kwrd">As</span> <span class="kwrd">Short</span> =
                 Convert.ToInt16((amplitude * 2) / samplesPerPeriod)
                <span class="kwrd">Dim</span> tempSample <span class="kwrd">As</span> <span class="kwrd">Short</span> = 0

                <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0
                <span class="kwrd">Dim</span> totalSamplesWritten <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0
                <span class="kwrd">While</span> totalSamplesWritten &lt; numSamples
                    tempSample = <span class="kwrd">CShort</span>(-amplitude)
                    i = 0
                    <span class="kwrd">While</span> i &lt; samplesPerPeriod <span class="kwrd">AndAlso</span> totalSamplesWritten &lt; numSamples
                        tempSample &#43;= sampleStep
                        sampleData(totalSamplesWritten) = tempSample

                        totalSamplesWritten &#43;= 1
                        i &#43;= 1
                    <span class="kwrd">End</span> <span class="kwrd">While</span>
                <span class="kwrd">End</span> <span class="kwrd">While</span>
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> WaveType.Noise
            <span class="kwrd">If</span> <span class="kwrd">True</span> <span class="kwrd">Then</span>
                <span class="kwrd">Dim</span> rnd <span class="kwrd">As</span> <span class="kwrd">New</span> Random()
                <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> numSamples - 1
                    sampleData(i) = Convert.ToInt16(
                     rnd.[<span class="kwrd">Next</span>](-amplitude, amplitude))
                <span class="kwrd">Next</span>
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
    <span class="kwrd">End</span> <span class="kwrd">Select</span>
    <span class="kwrd">Return</span> sampleData
<span class="kwrd">End</span> Function</pre>
<p></p>
<p>The Mixer is the heart of the app, and it's a beautiful example of object orientation and cohesion. Give it three things (oscillators) and it spits out a new thing you can use (an array of sample data).
</p>
<p>Now that we have the sample data, all we have to do is play it back using DirectSound.</p>
<h3>Sound Playback with DirectSound</h3>
<p>As I mentioned, DirectSound provides a wrapper over the WAV format. You set up your buffer and format information and then feed it a bunch of data in the form of an array of shorts (arrays of trousers are known to cause errors).</p>
<p>First, we initialize the format information and buffer in the Window_Loaded event handler of the main form. The values below are not really arbitrary; there is an explanation of them in the Optional Reading section above (see
<a href="http://blogs.msdn.com/dawate/archive/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format.aspx">
Demystifying the WAV Format</a>). This code also contains the code to add the oscillators, as shown earlier in the article.</p>
<p><b>C#</b> <br>
</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> Window_Loaded(<span class="kwrd">object</span> sender, System.Windows.RoutedEventArgs e)
{
    WindowInteropHelper helper = 
        <span class="kwrd">new</span> WindowInteropHelper(Application.Current.MainWindow);
    device.SetCooperativeLevel(helper.Handle, CooperativeLevel.Normal);

    waveFormat = <span class="kwrd">new</span> Microsoft.DirectX.DirectSound.WaveFormat();
    waveFormat.SamplesPerSecond = 44100;
    waveFormat.Channels = 2;
    waveFormat.FormatTag = WaveFormatTag.Pcm;
    waveFormat.BitsPerSample = 16;
    waveFormat.BlockAlign = 4;
    waveFormat.AverageBytesPerSecond = 176400;

    bufferDesc = <span class="kwrd">new</span> BufferDescription(waveFormat);
    bufferDesc.DeferLocation = <span class="kwrd">true</span>;
    bufferDesc.BufferBytes = Convert.ToInt32(
        bufferDurationSeconds * waveFormat.AverageBytesPerSecond / waveFormat.Channels);

    <span class="rem">// Add 3 oscillators</span>
    Oscillator tmp;
    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; NUM_GENERATORS; i&#43;&#43;)
    {
        tmp = <span class="kwrd">new</span> Oscillator();
        Oscs.Children.Add(tmp);
        mixer.Oscillators.Add(tmp);
    }            
}</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> Window_Loaded(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.Windows.RoutedEventArgs)
    <span class="kwrd">Dim</span> helper <span class="kwrd">As</span> <span class="kwrd">New</span> WindowInteropHelper(Application.Current.MainWindow)
    device.SetCooperativeLevel(helper.Handle, CooperativeLevel.Normal)

    waveFormat = <span class="kwrd">New</span> Microsoft.DirectX.DirectSound.WaveFormat()
    waveFormat.SamplesPerSecond = 44100
    waveFormat.Channels = 2
    waveFormat.FormatTag = WaveFormatTag.Pcm
    waveFormat.BitsPerSample = 16
    waveFormat.BlockAlign = 4
    waveFormat.AverageBytesPerSecond = 176400

    bufferDesc = <span class="kwrd">New</span> BufferDescription(waveFormat)
    bufferDesc.DeferLocation = <span class="kwrd">True</span>
    bufferDesc.BufferBytes = Convert.ToInt32(
     bufferDurationSeconds * waveFormat.AverageBytesPerSecond / waveFormat.Channels)

    <span class="rem">' Add 3 oscillators</span>
    <span class="kwrd">Dim</span> tmp <span class="kwrd">As</span> Oscillator
    <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> NUM_GENERATORS - 1
        tmp = <span class="kwrd">New</span> Oscillator()
        Oscs.Children.Add(tmp)
        mixer.Oscillators.Add(tmp)
    <span class="kwrd">Next</span>
<span class="kwrd">End</span> Sub</pre>
<p></p>
<p>When you click the Play button, the application takes its collection of oscillators and passes the values of the UI controls to the Mixer (which is initialized on each click with a reference to the main form window, so it can grab the Oscillator user controls).</p>
<p>The mixer outputs an array of shorts, which we write to a DirectSound buffer.</p>
<p>Here is the code for the Play button's click event handler:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> btnPlay_Click(<span class="kwrd">object</span> sender, System.Windows.RoutedEventArgs e)
{                                    
    mixer.Initialize(Application.Current.MainWindow);

    <span class="kwrd">short</span>[] sampleData = mixer.MixToStream();
    buffer = <span class="kwrd">new</span> SecondaryBuffer(bufferDesc, device);            
    buffer.Write(0, sampleData, LockFlag.EntireBuffer);
    buffer.Play(0, BufferPlayFlags.Default);            

    GraphWaveform(sampleData);
}</pre>
<p></p>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> btnPlay_Click(sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, e <span class="kwrd">As</span> System.Windows.RoutedEventArgs)
    mixer.Initialize(Application.Current.MainWindow)

    <span class="kwrd">Dim</span> sampleData <span class="kwrd">As</span> <span class="kwrd">Short</span>() = mixer.MixToStream()
    buffer = <span class="kwrd">New</span> SecondaryBuffer(bufferDesc, device)
    buffer.Write(0, sampleData, LockFlag.EntireBuffer)
    buffer.Play(0, BufferPlayFlags.[<span class="kwrd">Default</span>])

    GraphWaveform(sampleData)
<span class="kwrd">End</span> Sub</pre>
<p></p>
<h3>Drawing Pretty Graphs</h3>
<p>All that's left is to draw the graph of the waveform on the canvas. Below is the GraphWaveform method. This method could graph anything it wanted to, as long as it was an array of shorts (not trousers). It's reminiscent of trying to graph things using Flash
 back in the day, when you had to actually figure out points and lines (most likely on paper), but WPF's Polyline object makes this rather trivial.</p>
<p><b>C#</b> <br>
</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> GraphWaveform(<span class="kwrd">short</span>[] data)
{
    cvDrawingArea.Children.Clear();

    <span class="kwrd">double</span> canvasHeight = cvDrawingArea.Height;
    <span class="kwrd">double</span> canvasWidth = cvDrawingArea.Width;

    <span class="kwrd">int</span> observablePoints = 1800;
            
    <span class="kwrd">double</span> xScale = canvasWidth / observablePoints;
    <span class="kwrd">double</span> yScale = (canvasHeight / 
        (<span class="kwrd">double</span>)(amplitude * 2)) * ((<span class="kwrd">double</span>)amplitude / MAX_AMPLITUDE);            

    Polyline graphLine = <span class="kwrd">new</span> Polyline();
    graphLine.Stroke = Brushes.Black;
    graphLine.StrokeThickness = 1;

    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; observablePoints; i&#43;&#43;)
    {
        graphLine.Points.Add(
            <span class="kwrd">new</span> Point(i * xScale, (canvasHeight / 2) - (data[i] * yScale) ));
    }

    cvDrawingArea.Children.Add(graphLine);            
}</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> GraphWaveform(<span class="kwrd">ByVal</span> data <span class="kwrd">As</span> <span class="kwrd">Short</span>())
    cvDrawingArea.Children.Clear()

    <span class="kwrd">Dim</span> canvasHeight <span class="kwrd">As</span> <span class="kwrd">Double</span> = cvDrawingArea.Height
    <span class="kwrd">Dim</span> canvasWidth <span class="kwrd">As</span> <span class="kwrd">Double</span> = cvDrawingArea.Width

    <span class="kwrd">Dim</span> observablePoints <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 1800

    <span class="kwrd">Dim</span> xScale <span class="kwrd">As</span> <span class="kwrd">Double</span> = canvasWidth / observablePoints
    <span class="kwrd">Dim</span> yScale <span class="kwrd">As</span> <span class="kwrd">Double</span> = (canvasHeight / <span class="kwrd">CDbl</span>((amplitude * 2))) * (<span class="kwrd">CDbl</span>(amplitude) / MAX_AMPLITUDE)

    <span class="kwrd">Dim</span> graphLine <span class="kwrd">As</span> <span class="kwrd">New</span> Polyline()
    graphLine.Stroke = Brushes.Black
    graphLine.StrokeThickness = 1

    <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> observablePoints - 1
        graphLine.Points.Add(
         <span class="kwrd">New</span> Point(i * xScale, (canvasHeight / 2) - (data(i) * yScale)))
    <span class="kwrd">Next</span>

    cvDrawingArea.Children.Add(graphLine)
<span class="kwrd">End</span> Sub</pre>
<p></p>
<h3>Conclusion</h3>
<p>This was a really fun little project that took way less time to code than it does to explain. It's a great exercise because it requires you to think about an ancillary field of science before you can sit down and code, which is really what coding for fun's
 all about, anyway!</p>
<p>If you want to try this out, the download link for the source code is at the top of the article.</p>
<h3>About The Author</h3>
<p>Dan Waters is an Academic Evangelist at Microsoft, covering schools in the Pacific Northwest, Alaska, and Hawaii. He is based in Bellevue, WA. Dan has way too many guitars at home and tries to entice both of his young daughters to learn how to play them.
 Music, technology, and music&#43;technology are among his favorite hobbies, along with snowboarding and trying to maintain cool dad status. You can find his blog at
<a href="http://www.danwaters.com">www.danwaters.com</a> or follow him on Twitter at
<a href="http://www.twitter.com/danwaters">www.twitter.com/danwaters</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:2bd34398dc634955bf3a9e7600c975ca">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Generating-Sound-Waves-with-C-Wave-Oscillators</comments>
      <itunes:summary>
For the longest time, I&#39;ve been baffled by the concept of sound in computing. How in the world is sound store? How is it played back? In classic Coding4Fun style, we&#39;ll learn by doing in this article—by building a wave oscillator application.
 
Optional Reading
I cover the basics of this article in a multi-part blog series, which you should check out if you have trouble: 
Part 1 - How Audio Data is Represented

Part 2 - Demystifying the WAV Format

Part 3 - Synthesizing Simple WAV Audio Using C#

Part 4 - Algorithms for Different Sound Waves in C# 
What&#39;s An Oscillator?
An oscillator is a device or application that generates a waveform. In electrical engineering terms, it&#39;s a device that outputs an electrical current with varying voltage. If you plot the voltage over time, you get a regular wave in a particular form, such
 as a sine, square, triangle or sawtooth. 
An oscillator is the most basic type of synthesizer. Analog synths use electrical circuits to output a sound wave. Digital synthesizers do the same thing, but with software. 
You can create a pretty neat sounding instrument by combining the outputs of multiple oscillators. For example, if you have three oscillators oscillating at a frequency of 440Hz (concert A pitch), but each of them has a different waveform (saw, square, sine)
 you get a very interesting, layered sound.  
But before we get too deep into this subject, let&#39;s briefly explore the physics of sound. 
The Physics of Sound
Sound happens when air pressure changes on your ear drum. When you clap in an empty room, pressure waves bounce all over the place and dance on your eardrum. The changes in pressure are detected continuously by your ear.
 
Digitally, “pressure” is referred to by a scalar value called amplitude. 
The amplitude (loudness) of the wave is measured thousands of times per second (44,100 times per second on CDs). Every measurement of pressure (aka
amplitude) is called a sample—CDs are recorded with 44,100 samples per second, each w</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Generating-Sound-Waves-with-C-Wave-Oscillators</link>
      <pubDate>Mon, 03 May 2010 17:24:35 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Generating-Sound-Waves-with-C-Wave-Oscillators</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10006604_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/10006604_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Dan Waters</dc:creator>
      <itunes:author>Dan Waters</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Generating-Sound-Waves-with-C-Wave-Oscillators/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>DirectX</category>
      <category>Media</category>
    </item>
  <item>
      <title>Halloween Gremlins</title>
      <description><![CDATA[
<p>This article describes a quick and easy application to play Halloween tricks on the PC.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image001_2.jpg"><img title="clip_image001" border="0" alt="clip_image001" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image001_thumb.jpg" width="282" height="135"></a></p>
<h3>Introduction</h3>
<p>This article describes “Gremlin”, a quick and easy application that lets you play Halloween tricks. When your victim's computer is idle, Gremlin moves windows around on the screen, changes the focus window, moves your mouse, scrolls windows, and types nonsensical
 stuff. When there is background noise – like someone talking – it will shake the screen, even as your victim is typing away.</p>
<h3>Deployment</h3>
<p><b>Run it right away</b>. You can download, copy theGremlin.exe executable and NAudio.dll to the victim's computer (say in c:\ directory), and then double click on the executable to run it.</p>
<p><b>Run it later.</b> The other option is to copy the executable and dll files (or a shortcut to it) to the Startup folder on the victim's machine and watch the fun begin when they start up their machine in the morning!</p>
<p>If the computer you're using runs on Windows XP the path is: </p>
<blockquote>
<p>C:\Documents and Settings\All Users\Start Menu\Programs\Startup</p>
</blockquote>
<p>With Vista and Windows 7 the path looks like: </p>
<blockquote>
<p>C:\Users\<i>USERNAME</i>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup</p>
</blockquote>
<p>Just remember to change <i>USERNAME</i> to the name of the user on your machine.</p>
<p></p>
<h4>Commandline</h4>
<p>Gremlin is compiled as a windows application, so it won't popup a terminal window if you double click on it, etc. But you can run it from the command line with flags:</p>
<blockquote>
<p><b>-aggressive</b> will make the gremlin's actions more obvious</p>
<p><b>-help</b> will display the command line options</p>
<p><b>-name</b> <i>NAME</i> is useful for testing. Gremlin will only use windows with this specific title or from this specific application. (Remember to drop the &quot;.exe&quot; from the application filename)</p>
</blockquote>
<p>To stop the program, press CTRL&#43;F2.</p>
<h3>And now … the dodgy bits</h3>
<p>The overall structure of the program is broken down into three kinds of functionality – actions, triggers and some interstitial glue:</p>
<p>Actions</p>
<ul>
<li>The screen-shaker is a window that makes the monitor look like it is shaking. Sort of like a loose cable on the back of the monitor.
</li><li>A random event might kick the windows around—either friction will slow them down, or...
</li><li>Gremlin will type nonsensical messages from the keyboard. These messages are then sent from a virtual keyboard, or they:
</li><li>Move the mouse around, or </li><li>Press the mouse buttons, or </li><li>Randomly switch the focus to another window </li></ul>
<p>Triggers</p>
<ul>
<li>An audio module listens for sounds that trigger the module that shakes your screen.
</li><li>Otherwise, the software uses a p/invoke to <strong>GetLastInputInfo()</strong> and waits for the user to be idle for a minute or two. When it detects that the user is inactive, it randomly selects and carries out actions.
</li></ul>
<p>Other</p>
<ul>
<li>A hidden window receives key press events. I tend to reuse this module a lot, as a way to
<i>stop</i> experimental programs that may have made my machine unusable. </li></ul>
<p>For fun, I'll describe a couple of these modules below.</p>
<p></p>
<h4>Screen shaker</h4>
<p>My favorite bit is the screen shaker. It grabs a picture of the screens, creates a window that spreads across them, and then moves that image back and forth a few pixels every 30ms or so, with a little bit of random rotation. (Faster computers, of course,
 get a better effect).</p>
<p>The screen shaker is special in four ways:</p>
<ul>
<li>It is a top-level window – no other windows are allowed to go over it. </li><li>This top-level window never becomes the focus window (the window that gets the keyboard events).
</li><li>Mouse button events (e.g. clicks and double-clicks) are passed through to the windows and desktop underneath. This gives the illusion that this is the &quot;real&quot; desktop shaking, by allowing a person to click on a button or text that passes the click thru to
 the <i>real</i> button or text. </li><li>It shakes each of the monitor's screens independently </li></ul>
<p>Some background: to create a window that looks like the shaking screen, I used two classes. The first is ScrShake (in ScreenShake.cs), which derives from the second class UnfocusableForm.&nbsp; I'll describe ScrShake first.</p>
<p>The screen shaking process requires five instance variables:</p>
<ul>
<li><i>animTimer</i> is a System.Windows.Forms.Timer used to force painting of a new frame on the screen.
</li><li><i>bx</i>, and <i>by </i>are how far the screen has shaken up or down, left or right.
</li><li><i>angle </i>is how much the screen has twisted during shaking. </li><li><i>screenBitmap</i> is an array of bitmaps, one for each of the monitors. </li></ul>
<p>This creates a window without a border or other trappings, then makes it the topmost window and sets a flag in the method variable ExStyle to ignore mouse clicks. More on this flag in a little while.</p>
<p></p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> ScrShake : UnfocusableForm
{
   <span class="kwrd">public</span> ScrShake(<span class="kwrd">double</span> ShakeCoef, <span class="kwrd">double</span> AngleCoef) : <span class="kwrd">base</span>(<span class="kwrd">true</span>)
   {
      <span class="kwrd">this</span>.SuspendLayout();
      … other setup code …
      <span class="rem">// This is needed since we're over the whole display, and we don't</span>
      <span class="rem">// want the other areas to be blurry</span>
      TransparencyKey =  BackColor = ForeColor = System.Drawing.Color.Fuchsia;
      DoubleBuffered = <span class="kwrd">true</span>;
      TopMost = <span class="kwrd">true</span>;
      FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

      ClientSize = <span class="kwrd">new</span> System.Drawing.Size(300, 300);
      Name = <span class="str">&quot;topimage&quot;</span>;
      ResumeLayout(<span class="kwrd">false</span>);

      <span class="rem">// This is need to pass mouse clicks thru to lower layers</span>
      ExStyle |= (<span class="kwrd">int</span>) WS . EX_TRANSPARENT;

      … More code that will be described later…
   }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b><br>
</b></p>
<p>When the timer has done a given number of animations, it will call the Stop() method. This will stop the animation, clean it up, and hide the window:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">void</span> Stop()
{
   animTimer . Stop();
   Hide();
   screenBitmap = <span class="kwrd">null</span>;
}</pre>
<p>When the main loops that start the animated screen shaking process, it calls the Screens() method. This grabs an image of the screens, determines the shape of each monitor, and starts the animation for 10 frames.</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> Screens()
{
   <span class="kwrd">if</span> (Visible)
   {
      Stop();
      <span class="kwrd">return</span> ;
   }
   <span class="rem">// Grab the screens</span>
   screenBitmap = Program.GrabScreens();
   CountDown = 10;

   animTimer.Start();
   angle = 0.0f;
   … code to display the window and get shape of monitors (see below)…
}</pre>
<p><b><br>
</b></p>
<p>The screen capture portion is in ScreenCapture.cs. The method GrabScreens() creates an individual bitmap for each monitor and returns them as an array.</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> Screens()
{
   <span class="kwrd">if</span> (Visible)
   {
      Stop();
      <span class="kwrd">return</span> ;
   }
   <span class="rem">// Grab the screens</span>
   screenBitmap = Program.GrabScreens();
   CountDown = 10;

   animTimer.Start();
   angle = 0.0f;
   … code to display the window and get shape of monitors (see below)…
}</pre>
<p><b><br>
</b></p>
<p>The code below determines the bounds of each screen and builds up a size of all of the screens put together. The window will be set to be this size.
</p>
<p><b>C# </b></p>
<pre class="csharpcode">Screen[] AllScreens = Screen.AllScreens;

<span class="rem">// full width/height of all monitors combined</span>
Rectangle fullSize = AllScreens[0].Bounds;

<span class="rem">// find a rectangle that will encompass all monitors on the system</span>
<span class="rem">// (assuming the primary monitor is on the left/top!)</span>
<span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; i &lt; AllScreens.Length &amp;&amp; i &lt; screenBitmap.Length; i&#43;&#43;)
{
    Rectangle Bounds = AllScreens[i].Bounds;

    <span class="kwrd">if</span> (Bounds.Left &lt; fullSize.Left)
        fullSize.X = Bounds.X;

    <span class="kwrd">if</span> (Bounds.Right &gt; fullSize.Right)
        fullSize.Width = Bounds.Right - fullSize.X;

    <span class="kwrd">if</span> (Bounds.Top &lt; fullSize.Top)
        fullSize.Y = Bounds.Y;

    <span class="kwrd">if</span> (Bounds.Bottom &gt; fullSize.Bottom)
        fullSize.Height = Bounds.Bottom - fullSize.Y;
}</pre>
<p>The code to show the window, fill the whole screen, and move it to the top looks like:</p>
<p><b>C# </b></p>
<pre class="csharpcode">Show();
WindowState = FormWindowState.Normal;
<span class="rem">// cover all monitors with one gigantic window</span>
Location = <span class="kwrd">new</span> Point(fullSize.Left, fullSize.Top);
Size = <span class="kwrd">new</span> Size(fullSize.Width, fullSize.Height);

<span class="rem">// bring it to the top</span>
BringToFront();</pre>
<p>The constructor also created a timer that drives the screen shaking effect. The timer has a delegate that randomly selects the angle of rotation and the offset of the image, and triggers a repaint of the window. (The amount of shaking is controlled by two
 external variables called <i>AngleCoef</i> and <i>ShakeCoef</i>).</p>
<p><b>C# </b></p>
<pre class="csharpcode">animTimer = <span class="kwrd">new</span> System.Windows.Forms.Timer();
animTimer.Tick &#43;= <span class="kwrd">delegate</span>(<span class="kwrd">object</span> A, EventArgs E)
{
    <span class="kwrd">if</span> (--CountDown &lt; 1)
        Stop();

    angle &#43;= (<span class="kwrd">float</span>)((Program.Rnd.NextDouble() - 0.5) * AngleCoef);
    bx = (<span class="kwrd">float</span>)((Program.Rnd.NextDouble() - 0.5) * ShakeCoef);
    by = (<span class="kwrd">float</span>)((Program.Rnd.NextDouble() - 0.5) * ShakeCoef);
    Invalidate();
};

<span class="rem">// Sets the timer interval to 30 milliseconds.</span>
animTimer.Interval = 30;</pre>
<p>Although each monitor shifts up &amp; down, left &amp; right by the same amount, and rotates by the same angle, they are painted independently. This gives the illusion that each monitor has a shaky image. Paint the window is using the following code.
</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPaint(PaintEventArgs e)
{
    <span class="kwrd">base</span>.OnPaint(e);
    Graphics g = e.Graphics;
    g.CompositingQuality = CompositingQuality.HighQuality;

    <span class="rem">// for each monitor, draw the effect</span>
    Screen[] AllScreens = Screen.AllScreens;
    <span class="kwrd">for</span>(<span class="kwrd">int</span> i = 0; i &lt; screenBitmap.Length; i&#43;&#43;)
    {
        <span class="kwrd">if</span> (<span class="kwrd">null</span> == screenBitmap[i])&nbsp;&nbsp; <span class="kwrd">continue</span>;
        g.SmoothingMode = SmoothingMode.HighQuality;

        <span class="rem">// grab the size of the current monitor</span>
        Rectangle region = AllScreens[i].Bounds;

        <span class="kwrd">double</span> ImWidth = screenBitmap[i].Width  * <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.Graphics.DpiX / screenBitmap[i].HorizontalResolution;
        <span class="kwrd">double</span> ImHeight= screenBitmap[i].Height * <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.Graphics.DpiY / screenBitmap[i].VerticalResolution;
        Matrix m = <span class="kwrd">new</span> Matrix();
        m.Translate( (<span class="kwrd">float</span>)(- ImWidth  /2), 
                  (<span class="kwrd">float</span>)(- ImHeight /2), MatrixOrder.Append);

        <span class="rem">// rotate the bitmap about the center</span>
        m.RotateAt(angle, <span class="kwrd">new</span> Point(0,0), MatrixOrder.Append);

        <span class="rem">// center the image no matter what its size is</span>
        m.Translate( region.Width /2 - bx, 
                  region.Height/2 - by, MatrixOrder.Append);

        <span class="rem">// assign our transformation matrix</span>
        g.Transform = m;

        <span class="rem">// draw it</span>
        g.DrawImage(screenBitmap[i], region.Left, region.Top);
    }</pre>
<h4>The Form that does nothing!</h4>
<p>The ScrShaker class uses a help class called UnfocusableForm (in UnfocusableForm.cs) to create a window that never becomes the focus window – it never receives key presses, etc.</p>
<p>This window has no trappings – no border, no resize gripper, no icon, no minimize / maximize buttons, no title bar.</p>
<p></p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> UnfocusableForm : Form
{
   <span class="kwrd">public</span> UnfocusableForm(<span class="kwrd">bool</span> X) : <span class="kwrd">base</span>()
   {
      <span class="kwrd">if</span> (X)
        {
           ControlBox = <span class="kwrd">false</span>;
           FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
           ShowInTaskbar = <span class="kwrd">false</span>;
           ShowIcon = <span class="kwrd">false</span>;
           MinimizeBox = <span class="kwrd">false</span>;
           SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
           StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        }
   }</pre>
<p>Then it overrides the ShowWithoutActivation method so that the window will <i>
not</i> become the active when it is shown.</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> ShowWithoutActivation
{ get {  <span class="kwrd">return</span> <span class="kwrd">true</span>; } }</pre>
<p>The UnfocusableForm class also overrides the CreateParams() method to set extra styles when creating the window. I haven't found a way to set these styles flexibly. Instead, the UnfocusableForm uses a method variable called ExStyle that allows derived classes
 to specify what flags they desire. In this case, The ScrShake class used the method variable to set a flag that ignore mouse clicks:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> CreateParams CreateParams
{
  get
  {
     CreateParams cp=<span class="kwrd">base</span>.CreateParams;
     cp . ExStyle |= ExStyle;
     <span class="kwrd">return</span> cp;
  }
}</pre>
<p><b><br>
</b>Finally, it captures a couple of events that ask a window if it would like to become the active window. (These usually happen when the user clicks on an inactive window):</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">const</span> <span class="kwrd">int</span> MA_NOACTIVATE = 0x0003;
<span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> WndProc(<span class="kwrd">ref</span> Message m)
{
  <span class="kwrd">if</span> (m.Msg == (<span class="kwrd">int</span>) WM.MOUSEACTIVATE)
  {
     m.Result = (IntPtr) MA_NOACTIVATE;
     <span class="kwrd">return</span>;
  }
  <span class="kwrd">if</span> (m.Msg == (<span class="kwrd">int</span>) WM.FOCUS)
  {
     m.Result = (IntPtr)1;
     <span class="kwrd">return</span>;
  }
  <span class="kwrd">base</span>.WndProc(<span class="kwrd">ref</span> m);
}</pre>
<h4>Sending Mouse Events</h4>
<p>Sending Mouse Events is simple, but not trivial. The wiki at Pinvoke.net provides the signature to the procedures and structures we need to pass to it. (Note: these structures are a bit different, based on
<a href="http://blogs.msdn.com/oldnewthing/archive/2009/08/13/9867383.aspx">a blog posting by Raymond Chen</a>)</p>
<p><b>C# </b></p>
<pre class="csharpcode">[DllImport(<span class="str">&quot;user32.dll&quot;</span>, EntryPoint = <span class="str">&quot;SendInput&quot;</span>, SetLastError = <span class="kwrd">true</span>)]
<span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">uint</span> SendInput(<span class="kwrd">uint</span> nInputs, INPUT[] Inputs, <span class="kwrd">int</span> cbSize);
[DllImport(<span class="str">&quot;user32.dll&quot;</span>, EntryPoint = <span class="str">&quot;GetMessageExtraInfo&quot;</span>, SetLastError = <span class="kwrd">true</span>)]
<span class="kwrd">static</span> <span class="kwrd">extern</span> IntPtr GetMessageExtraInfo();

[StructLayout(LayoutKind.Sequential)]
<span class="kwrd">struct</span> INPUT
{
   <span class="kwrd">internal</span> INPUTTYPE   type;
   <span class="kwrd">internal</span> INPUT_UNION i;
}

 <span class="rem">// This generates the anonymous union</span>
[StructLayout(LayoutKind.Explicit)]
<span class="kwrd">struct</span> INPUT_UNION
{
   [FieldOffset(0)]
   <span class="kwrd">public</span> MOUSEINPUT mi;
   [FieldOffset(0)]
   <span class="kwrd">public</span> KEYBDINPUT ki;
   [FieldOffset(0)]
   <span class="kwrd">public</span> HARDWAREINPUT hi;
};

[StructLayout(LayoutKind.Sequential)]
<span class="kwrd">struct</span> MOUSEINPUT
{
   <span class="kwrd">public</span> <span class="kwrd">int</span>    dx;
   <span class="kwrd">public</span> <span class="kwrd">int</span>    dy;
   <span class="kwrd">public</span> <span class="kwrd">int</span>    mouseData;
   <span class="kwrd">public</span> MOUSEEVENTF dwFlags;
   <span class="kwrd">public</span> <span class="kwrd">int</span>    time;
   <span class="kwrd">public</span> IntPtr dwExtraInfo;
}

[Flags]
<span class="kwrd">enum</span> MOUSEEVENTF : <span class="kwrd">int</span>
{
   MOVE       = 0x01,
   LEFTDOWN   = 0x02,
   LEFTUP     = 0x04,
   RIGHTDOWN  = 0x08,
   RIGHTUP    = 0x10,
   MIDDLEDOWN = 0x20,
   MIDDLEUP   = 0x40,
   ABSOLUTE   = 0x8000
}</pre>
<p><b><br>
</b></p>
<p>Each of these pieces go together in a specific way. To do a mouse movement, a mouse event structure needs to be created. This involves setting dwFlags to the kind of mouse event (a relative movement in this case), dx and dy to the number of pixels moved.
 It is also important to set dwExtraInfo to whatever GetMessageExtraInfo() is set to.</p>
<p><b>C# </b></p>
<pre class="csharpcode">MOUSEINPUT MEvent = <span class="kwrd">new</span> MOUSEINPUT();
MEvent.dwFlags = MOUSEEVENTF.MOVE;
MEvent.dx = Rnd . Next(-8, 8) ;
MEvent.dy = Rnd . Next(-8, 8);
MEvent.dwExtraInfo = GetMessageExtraInfo();
Send(MEvent);</pre>
<p>Sending the event takes a few more steps that are all wrapped in a helper methdo called Send(). Send these
<i>human interface device</i> events via the SendInput() procedure (earlier). The procedure takes an array of events, for different kinds of devices. We have to create the array, set the event type, copy the event data, and then make the call:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">bool</span> Send(MOUSEINPUT Event)
{
  INPUT[] Events = <span class="kwrd">new</span> INPUT[1];
  Events[0] . type = INPUTTYPE . MOUSE;
  Events[0] . i.mi = MEvent;
  <span class="kwrd">return</span> SendInput((<span class="kwrd">uint</span>)Events.Length, Events, Marshal.SizeOf(Events[0])) &gt; 0; 
}</pre>
<p><b><br>
</b></p>
<p>From here, sending a mouse button click is pretty straight forward. A mouse click is really a mouse button press event, followed by a mouse button release event. To make things interesting the mouse button is choosen at random. The “ugly” part is that each
 of the mouse buttons is assigned a bit, so a binary shift is used to convert a button number to its bit. And the button release is yet another bit, so the second message shifts the flags, to move the bit from the “button pressed” state to the “button released
 state”.</p>
<p><b>C# </b></p>
<pre class="csharpcode">MOUSEINPUT MEvent = <span class="kwrd">new</span> MOUSEINPUT();
MEvent.dwFlags = (MOUSEEVENTF) (1 &lt;&lt; (2*Rnd.Next(0, 3)&#43;1)) ;
MEvent.dwExtraInfo = GetMessageExtraInfo ();
Send(MEvent);

MEvent.dwFlags = (MOUSEEVENTF)((<span class="kwrd">int</span>) MEvent.dwFlags &lt;&lt; 1);
MEvent.dwExtraInfo = GetMessageExtraInfo ();
Send(MEvent);</pre>
<p><b><br>
</b></p>
<h4>Generating deranged text</h4>
<p>The gremlin can also type deranged sentences that will appear in editors, if the user left one open. The SendWait() method in the SendKeys class does the typing itself:</p>
<p><b>C#</b>&nbsp;</p>
<pre class="csharpcode">SendKeys . SendWait(GenerateSentence());
SendKeys . SendWait(<span class="str">&quot;{ENTER}&quot;</span>);</pre>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image001_5B6_5D.jpg"><img title="clip_image001[6]" border="0" alt="clip_image001[6]" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image001_5B6_5D_thumb.jpg" width="282" height="135"></a></p>
<p>Generating the sentences is not difficult; I used a simplistic Markov generator. This generator starts by randomly selecting a word that can start a sentence. The
<i>Starts</i> variable is array which holds just these words. Then, in the Transition method, this word is used to find the
<i>next</i> word that can be included in the sentence. It does this by using a dictionary, called
<i>NonStart</i>, which given the word as a key, will return a list of all the words that can come after it. This process then repeats, appending the words onto the end of a string. It stops if it finds a word that can end a sentence.</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">static</span> Dictionary&lt;<span class="kwrd">string</span>,<span class="kwrd">string</span>[]&gt; NonStart ;
<span class="kwrd">static</span> <span class="kwrd">string</span>[] Starts;
<span class="kwrd">static</span> Dictionary&lt;<span class="kwrd">string</span>,<span class="kwrd">string</span>&gt; Terminal ;

<span class="kwrd">static</span> <span class="kwrd">string</span> GenerateSentence()
{
  StringBuilder SB = <span class="kwrd">new</span> StringBuilder();
  <span class="kwrd">string</span> Word = Starts[ Rnd.Next(0, Starts.Length) ];

  Transition(SB, Word);
  <span class="kwrd">return</span> SB.ToString();
}

<span class="kwrd">static</span> <span class="kwrd">void</span> Transition(StringBuilder SB, <span class="kwrd">string</span> Word)
{
  <span class="kwrd">while</span> (<span class="kwrd">true</span>)
  {
     SB.Append(Word);
     SB.Append(<span class="str">' '</span>);

     <span class="rem">// Look up word after this</span>
     <span class="kwrd">string</span>[] Nexts;
     <span class="kwrd">if</span> (!NonStart.TryGetValue(Word, <span class="kwrd">out</span> Nexts))
       <span class="kwrd">break</span>;
     <span class="kwrd">int</span> Idx = Rnd.Next(Terminal . ContainsKey(Word) ? -1 :0, Nexts.Length);
     <span class="kwrd">if</span> (Idx &lt; 0)
       <span class="kwrd">break</span>;
     Word = Nexts[Idx];
  }
}</pre>
<p><b><br>
</b></p>
<p>Building these two dictionaries and array is a pretty simple process. The BuildSuffixTree() method takes a string and splits it up into sentences. Then it splits each sentence into (lower case) words. The first word of the sentence goes onto the end of the
<i>Starts</i> array. Otherwise, the previous word is used to look up a list in a dictionary, and the current word is appended on to the list. This dictionary will become the
<i>NonStarts</i> dictionary. The last word of the sentence is also placed into the
<i>Terminal</i> dictionary, to indicate that this might be the end of a sentence.</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> BuildSuffixTree()
{
  <span class="rem">// First, build up a list of words that start sentence, and transitions</span>
  List&lt;<span class="kwrd">string</span>&gt; Starts1 = <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;();
  Dictionary&lt;<span class="kwrd">string</span>,List&lt;<span class="kwrd">string</span>&gt;&gt; Trans = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>,List&lt;<span class="kwrd">string</span>&gt;&gt;();
  <span class="kwrd">foreach</span>(<span class="kwrd">string</span> S1 <span class="kwrd">in</span> S.Split(<span class="kwrd">new</span> <span class="kwrd">char</span>[]{<span class="str">'.'</span>,<span class="str">'?'</span>,<span class="str">'!'</span>}))
  {
     <span class="kwrd">string</span> Prev=<span class="kwrd">null</span>;
     <span class="kwrd">foreach</span>(<span class="kwrd">string</span> S2 <span class="kwrd">in</span> S1.Split(<span class="kwrd">new</span> <span class="kwrd">char</span>[]{<span class="str">' '</span>,<span class="str">'\n'</span>,<span class="str">'\r'</span>,<span class="str">'\t'</span>,<span class="str">','</span>,<span class="str">';'</span>}))
     {
        <span class="kwrd">if</span> (S2 . Length &lt; 1)
          <span class="kwrd">continue</span>;
        <span class="kwrd">if</span> (<span class="kwrd">null</span> == Prev)
          {
             Starts1.Add(<span class="kwrd">string</span>.Intern(S2.ToLower()));
             Prev = <span class="kwrd">string</span>.Intern(S2.ToLower());
             <span class="kwrd">continue</span>;
          }
        List&lt;<span class="kwrd">string</span>&gt; Nextsa;
        <span class="kwrd">if</span> (! Trans.TryGetValue(Prev, <span class="kwrd">out</span> Nextsa))
          Trans[Prev] = Nextsa = <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;();
        Prev = <span class="kwrd">string</span>.Intern(S2.ToLower());
        Nextsa.Add(Prev);
     }
     <span class="kwrd">if</span> (<span class="kwrd">null</span> != Prev)
       Terminal[Prev] = Prev;
 }

 <span class="rem">// Next, flatten the list of words that start a sentence</span>
 Starts = Starts1.ToArray();

 <span class="rem">// Flatten the transition table</span>
 <span class="kwrd">foreach</span> (<span class="kwrd">string</span> S3 <span class="kwrd">in</span> Trans.Keys)
  NonStart[S3] = Trans [S3].ToArray();
}</pre>
<p><b><br>
</b></p>
<h3>The things that trigger action</h3>
<h4>The audio trigger</h4>
<p>The audio module (in file AudioTrigger.cs) listens in on all of the microphones. It uses NAudio, with a basic setup and delegate structure swiped from Mark Heath's article “.NET Audio Recording”. The first difference is that it registers
<i>all</i> audio input devices:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">static</span> WaveIn[] StartMics()
{
  <span class="kwrd">int</span> NumDevices = WaveIn.DeviceCount;
  WaveIn[] AudIns = <span class="kwrd">new</span> WaveIn[NumDevices];
  <span class="kwrd">for</span> (<span class="kwrd">int</span> waveInDevice = 0; waveInDevice &lt; NumDevices ; waveInDevice&#43;&#43;)
  {
     AudIns[waveInDevice] = <span class="kwrd">new</span> WaveIn();
     AudIns[waveInDevice].DeviceNumber = waveInDevice;
     AudIns[waveInDevice].DataAvailable &#43;= waveIn_DataAvailable;
     AudIns[waveInDevice].WaveFormat = <span class="kwrd">new</span> WaveFormat(8000, 1);
     AudIns[waveInDevice].StartRecording();
  }
  <span class="kwrd">return</span> AudIns;
}</pre>
<p>The real magic in the trigger is a modified version of the waveIn_DataAvailable delegate. Instead of saving the audio, it checks for any sound activity. It starts by checking to see if any of the sound amplitudes are greater than a pre-defined, very high
 threshold. Then the samples are squared and summed up, and the result is compared with a threshold. If it exceeds the threshold, the trigger is set. These two are good at catching the kind of sound made when a person is talking, futzing on the desk, or typing.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image002_2.jpg"><img title="clip_image002" border="0" alt="clip_image002" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9915768/clip_image002_thumb.jpg" width="372" height="210"></a></p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">double</span> AudioThresh  = 0.8;
<span class="kwrd">static</span> <span class="kwrd">double</span> AudioThresh2 = 0.09;

<span class="kwrd">static</span> <span class="kwrd">void</span> waveIn_DataAvailable(<span class="kwrd">object</span> sender, WaveInEventArgs e)
{
  <span class="kwrd">bool</span> Tr = <span class="kwrd">false</span>;
  <span class="kwrd">double</span> Sum2  = 0;
  <span class="kwrd">int</span> Count = e.BytesRecorded / 2;
  <span class="kwrd">for</span> (<span class="kwrd">int</span> index = 0; index &lt; e.BytesRecorded; index &#43;= 2)
  {
     <span class="kwrd">double</span> Tmp = (<span class="kwrd">short</span>)((e.Buffer[index &#43; 1] &lt;&lt; 8) | e.Buffer[index &#43; 0]);
     Tmp /= 32768.0;
     Sum2 &#43;= Tmp*Tmp;
     <span class="kwrd">if</span> (Tmp &gt; AudioThresh)
       Tr = <span class="kwrd">true</span>;
  }
  Sum2 /= Count;

  <span class="rem">// If the Mean-Square is greater than a threshold, set a flag to indicate that noise has happened</span>
  <span class="kwrd">if</span> (Tr || Sum2 &gt; AudioThresh2)
    Interlocked.Exchange(<span class="kwrd">ref</span> AudioTrigger, 1);
}</pre>
<p><b><br>
</b></p>
<p>This sets a flag – AudioTrigger – which will be seen (and reset) in the main loop, with a bit of code that looks like:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">while</span> (0 == Shutdown)
{
    <span class="rem">// Do some lovely events</span>
    Application . DoEvents();
    Thread . Sleep (20);

    <span class="rem">//… do some other stuff ..</span>

    <span class="rem">// Check for a kick from the sound system</span>
    <span class="kwrd">if</span> (0 != AudioTrigger)
    {
        Interlocked . Exchange(<span class="kwrd">ref</span> AudioTrigger, 0);
        …
        ScreenShaker . Screens();
        <span class="kwrd">continue</span>;
    }
    <span class="rem">//… more checks for the user idle trigger…</span>
}<b><br></b></pre>
<h4>Waiting for the user to be idle</h4>
<p>The check to see if the user is not doing anything, the main loop uses a helper method called LastInputTime(), which returns the number of milliseconds the user did any input activity. The loop ensures that the user has been idle for long enough, and then
 calls the method that selects random gremlin actions:</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">uint</span> LastTime = Win32.LastInputTime();
<span class="kwrd">if</span> ((<span class="kwrd">uint</span>) Environment.TickCount &lt; IdleTimeTrigger &#43; LastTime)
    <span class="kwrd">continue</span>;</pre>
<p>The LastInputTime() helper method uses a p/invoke call to the GetLastInputInfo() API call. The wiki at Pinvoke.net provides the signature to the procedure, and a suitable structure that we need to pass to it:</p>
<p><b>C# </b></p>
<pre class="csharpcode">[DllImport(<span class="str">&quot;User32.dll&quot;</span>)]
<span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">bool</span> GetLastInputInfo(<span class="kwrd">ref</span> LASTINPUTINFO LastInfo);

[StructLayout(LayoutKind.Sequential)]
<span class="kwrd">struct</span> LASTINPUTINFO
{
  <span class="kwrd">public</span> <span class="kwrd">uint</span> cbSize;

  <span class="rem">/// &lt;summary&gt;</span>
  <span class="rem">/// Number of system tickes</span>
  <span class="rem">/// &lt;/summary&gt;</span>
  <span class="kwrd">public</span> <span class="kwrd">uint</span> dwTime;
}</pre>
<p>Then, these two structures are wrapped up into the LastInputTime() helper procedure, which does the dirty work of allocating and initializing a structure.
</p>
<p><b>C# </b></p>
<pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">static</span> <span class="kwrd">uint</span> LastInputTime()
{
  LASTINPUTINFO lastInput=<span class="kwrd">new</span> LASTINPUTINFO();
  lastInput.cbSize = (<span class="kwrd">uint</span>)Marshal.SizeOf(lastInput);
  GetLastInputInfo(<span class="kwrd">ref</span> lastInput);
  <span class="kwrd">return</span> lastInput . dwTime;
}<b><br></b></pre>
<h3>Conclusion</h3>
<p>The tricks gremlin plays are intended to be somewhat subtle. There is an aggressive option to make it react more, and move windows around more visibly.
</p>
<p>If you want to try this out, the download link for the <a href="http://gremlin.codeplex.com/Release/ProjectReleases.aspx">
executable</a> and <a href="http://gremlin.codeplex.com/SourceControl/ListDownloadableCommits.aspx">
source code</a> are at the top of the article!</p>
<h4>Resources and References</h4>
<p>This article is a blatant grab bag of experimental and reused code from earlier experiments and other demo programs. Below are some of the projects I lifted code examples from:</p>
<ul>
<li><a href="http://pinvoke.net/">Pinvoke.net</a> – a wiki-style site with many useful bits of example code related to calling the Windows API from within .NET.
</li><li><a href="http://blogs.msdn.com/coding4fun/archive/2009/10/08/9905168.aspx">“.NET Audio Recorder”</a> by Mark Heath, from which I stole code to make the audio trigger.
</li><li><a href="http://blogs.msdn.com/coding4fun/archive/2007/10/29/5773776.aspx">“Possessed PC Pranks for Halloween”</a> by Brian Peek, from which I stole the basic code for sending keystrokes.
</li><li><a href="http://blogs.msdn.com/coding4fun/archive/2007/03/29/1991785.aspx">“April Fools' Day Application”</a> by Brian Peek, from which I stole code to grab the screen and rotate it.
</li></ul>
<h3>About The Author</h3>
<p>Randall Maas writes firmware for medical devices, and consults in embedded software. Before that he did a lot of other things… like everyone else in the software industry. You can contact him at
<a href="mailto:randym@acm.org">randym@acm.org</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:144c71c45bb4497091de9e7600caf138">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Halloween-Gremlins</comments>
      <itunes:summary>
This article describes a quick and easy application to play Halloween tricks on the PC. 
 
Introduction
This article describes “Gremlin”, a quick and easy application that lets you play Halloween tricks. When your victim&#39;s computer is idle, Gremlin moves windows around on the screen, changes the focus window, moves your mouse, scrolls windows, and types nonsensical
 stuff. When there is background noise – like someone talking – it will shake the screen, even as your victim is typing away. 
Deployment
Run it right away. You can download, copy theGremlin.exe executable and NAudio.dll to the victim&#39;s computer (say in c:\ directory), and then double click on the executable to run it. 
Run it later. The other option is to copy the executable and dll files (or a shortcut to it) to the Startup folder on the victim&#39;s machine and watch the fun begin when they start up their machine in the morning! 
If the computer you&#39;re using runs on Windows XP the path is:  

C:\Documents and Settings\All Users\Start Menu\Programs\Startup 

With Vista and Windows 7 the path looks like:  

C:\Users\USERNAME\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 

Just remember to change USERNAME to the name of the user on your machine. 
 
Commandline
Gremlin is compiled as a windows application, so it won&#39;t popup a terminal window if you double click on it, etc. But you can run it from the command line with flags: 

-aggressive will make the gremlin&#39;s actions more obvious 
-help will display the command line options 
-name NAME is useful for testing. Gremlin will only use windows with this specific title or from this specific application. (Remember to drop the &amp;quot;.exe&amp;quot; from the application filename) 

To stop the program, press CTRL&amp;#43;F2. 
And now … the dodgy bits
The overall structure of the program is broken down into three kinds of functionality – actions, triggers and some interstitial glue: 
Actions 

The screen-shaker is a window that makes the monitor look like it i</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Halloween-Gremlins</link>
      <pubDate>Sat, 31 Oct 2009 22:37:42 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Halloween-Gremlins</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9915768_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9915768_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Randall Maas</dc:creator>
      <itunes:author>Randall Maas</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Halloween-Gremlins/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Halloween</category>
      <category>Pranks</category>
      <category>Holiday</category>
    </item>
  <item>
      <title>.NET Voice Recorder</title>
      <description><![CDATA[
<p>In this article I demonstrate how to record from the microphone in .NET, with support for setting the recording level, trimming noise from the start and end, visualizing the waveform in WPF and converting to MP3.</p>

<h2>Audio Recording in .NET</h2>
<h4></h4>
<p>The .NET framework does not provide any direct support for recording audio, so I will make use of the open source
<a href="http://naudio.codeplex.com">NAudio</a> project, which includes wrappers for a number of Windows audio recording APIs.
</p>
<blockquote>
<p><b>Note: </b>It is important to point out that .NET is not an appropriate choice for high sample rate and
<i>low latency</i> audio recording, such as that found in Digital Audio Workstation software used in recording studios. This is because the .NET garbage collector can interrupt the process at any point. However, for purposes of recording speech from the microphone,
 the .NET framework is more than capable. By default, NAudio asks the soundcard to give us data every 100ms, which gives plenty of time for the garbage collector to run as well as our own code.</p>
</blockquote>
<p>We will make use of the wrappers for the waveIn API's, as these are the most universally supported, and allow us freedom to choose the sample rate. We will record in mono, 16 bit at 8kHz, which is more than good enough audio quality for speech, and will
 not overly tax the processor, which is important as we want to visualize the waveform as well.</p>
<h4>Choosing a Capture Device</h4>
<p>Normally, you will be able to use the default audio capture device without any difficulties, but should you need to offer the user a choice, NAudio will allow you to do so. You can use the
<b>WaveIn.DeviceCount</b> and <b>WaveIn.GetDeviceCapabilities</b> to find out how many recording devices are present, and query for their name and number of supported channels.</p>
<p>On my computer, I have a single waveIn device (Microphone Array) until I plug my headset in, at which point, a new device appears and becomes the default (device 0 is always the default).</p>
<pre class="csharpcode"><span class="kwrd">int</span> waveInDevices = WaveIn.DeviceCount;
<span class="kwrd">for</span> (<span class="kwrd">int</span> waveInDevice = 0; waveInDevice &lt; waveInDevices; waveInDevice&#43;&#43;)
{
    WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
    Console.WriteLine(<span class="str">&quot;Device {0}: {1}, {2} channels&quot;</span>, 
        waveInDevice, deviceInfo.ProductName, deviceInfo.Channels);
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This produces the following output on my computer:</p>
<blockquote>
<p>Device 0: Microphone / Line In (SigmaTel , 2 channels <br>
Device 1: Microphone Array (SigmaTel High, 2 channels</p>
</blockquote>
<p>Unfortunately these device names are truncated because the WAVEINCAPS structure only supports 31 characters. There is
<a href="http://stackoverflow.com/questions/1449162/get-the-full-name-of-a-wavein-device">
a way of getting the full device name</a>, but it is rather convoluted.</p>
<p>Normally, you will choose Device 0 (the default), but if you wish to select a different input device, simply set the
<b>DeviceNumber</b> property on your WaveIn object to the desired number.</p>
<h4>Checking the Recording Level</h4>
<p>The first step in recording is usually to help the user determine if their microphone is working or not. This is especially important if the user has more than one input on their soundcard. The way we achieve this is simply by starting recording and displaying
 the level of audio detected to the user with a volume meter. The waveIn APIs do not write anything to disk, so no audio is actually being ‘recorded' at this point, we are simply examining the input level and then throwing the captured audio samples away.</p>
<p>To begin capturing audio from the soundcard, we use the <b>WaveIn</b> class in NAudio. We configure it with the WaveFormat in which we would like to record (in our case 8kHz mono), before calling
<b>StartRecording</b>, to start capturing audio from the device.</p>
<pre class="csharpcode">waveIn = <span class="kwrd">new</span> WaveIn();
waveIn.DeviceNumber = selectedDevice;
waveIn.DataAvailable &#43;= waveIn_DataAvailable;
<span class="kwrd">int</span> sampleRate = 8000; <span class="rem">// 8 kHz</span>
<span class="kwrd">int</span> channels = 1; <span class="rem">// mono</span>
waveIn.WaveFormat = <span class="kwrd">new</span> WaveFormat(sampleRate, channels);
waveIn.StartRecording();</pre>
<p>The <b>DataAvailable</b> event handler will notify us whenever a buffer of audio has been returned to us from the sound card. The data comes back as an array of bytes, representing PCM sample data. This is fine if we are planning to write the audio directly
 to disk, but what if we wish to have a look at the audio data itself? Each audio sample is 16 bits, i.e. two bytes, meaning that we will need to convert pairs of bytes into shorts to be able to make sense of the data.</p>
<blockquote>
<p><b>Note:</b> if we were recording in stereo, the 16 bit samples would themselves come in pairs, first the left sample, then the right sample.</p>
</blockquote>
<p>The following code shows how we might process the raw bytes in the <b>DataAvailable</b> event, and read the individual audio samples out. Notice that we use the
<b>BytesRecorded</b> field, not the buffer's Length property. Also, I have chosen to convert the samples to 32 bit floating point format and scaled them so the maximum volume is 1.0f. This makes processing them through effects and visualizing them much easier.</p>
<pre class="csharpcode"><span class="kwrd">void</span> waveIn_DataAvailable(<span class="kwrd">object</span> sender, WaveInEventArgs e)
{
    <span class="kwrd">for</span> (<span class="kwrd">int</span> index = 0; index &lt; e.BytesRecorded; index &#43;= 2)
    {
        <span class="kwrd">short</span> sample = (<span class="kwrd">short</span>)((e.Buffer[index &#43; 1] &lt;&lt; 8) | 
                                e.Buffer[index &#43; 0]);
        <span class="kwrd">float</span> sample32 = sample / 32768f;
        ProcessSample(sample32);
    }
}</pre>
<p></p>
<blockquote>
<p><b>Note: </b>One complication of using the waveIn and waveOut APIs is deciding on a callback mechanism. NAudio offers three options. First is
<b>function</b> callbacks. This means that the waveIn API is given a (pinned) function pointer which it calls back onto. This means that your DataAvailable callback will come in on a background thread. In some ways this is the cleanest approach, but you need
 to beware of rogue soundcard drivers that can hang in calls to waveOutReset when using function callbacks (the SoundMAX chipset found on a lot of laptops is particularly prone to this problem).</p>
<p>The second is to supply a <b>window handle</b>. The waveIn APIs will post a message back to be handled on the message queue of that window handle. This method tends to be the most reliable and most commonly used. One gotcha to watch out for is that if you
 stop recording and <i>immediately</i> restart, a message from the old recording session could get handled in the new session resulting in a nasty exception.
</p>
<p>The third is to let NAudio create its own <b>new window</b> and post messages to that. This gets round any danger of messages from one recording session getting muddled up with another. This is the callback method that NAudio will use by default if you call
 the default <b>WaveIn</b> constructor. But don't use this from a background thread or from a console application, or the new window that NAudio creates won't actually get round to processing its message queue.</p>
</blockquote>
<h4>Visualizing the Recording Level</h4>
<p>We have seen how we can begin to capture audio from the soundcard for the purposes of checking the recording level. Now we need to give the user some visual feedback. We will use WPF for our sample recording application. The simplest control we have available
 to display a single numeric value graphically is the <b>ProgressBar</b>. And because it is WPF, we can fully customize the graphical appearance of the progress bar to look a little more like a volume meter. I have used a gradient going from green to red to
 show the current volume level. You can read more about how I created this ProgressBar template
<a href="http://mark-dot-net.blogspot.com/2009/09/styling-wpf-volume-meter.html">
here</a>. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_12.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_thumb_5.png" width="296" height="37"></a>
<br>
<strong>Figure 1 - A Progress Bar Showing the Current Microphone Volume Level</strong></p>
<p>To help provide the volume level to display, I have created a <b>SampleAggregator</b> class. This is passed every audio sample value we receive and keeps track of the maximum and minimum values. Then, after a specified number of samples, it raises an event
 allowing the GUI components to respond. We need to be careful not to raise too many of these events or performance will be badly affected. I am raising one every 800 samples, meaning we get 10 updates per second to the screen.</p>
<p>Because I am using data binding, when one of these updates fires, I must raise a
<b>PropertyChangedEvent</b> on my DataContext object (also known as the “ViewModel” in the MVVM pattern). Here's the XAML syntax for binding to my
<b>CurrentInputLevel</b> property:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">ProgressBar</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> 
    <span class="attr">Value</span><span class="kwrd">=&quot;{Binding CurrentInputLevel, Mode=OneWay}&quot;</span> 
    <span class="attr">Height</span><span class="kwrd">=&quot;20&quot;</span> <span class="kwrd">/&gt;</span></pre>
<p>And here's the code in the ViewModel that ensures that the GUI updates whenever we calculate a new maximum input level:</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">float</span> lastPeak;

<span class="kwrd">void</span> recorder_MaximumCalculated(<span class="kwrd">object</span> sender, MaxSampleEventArgs e) 
{
    lastPeak = Math.Max(e.MaxSample, Math.Abs(e.MinSample));
    RaisePropertyChangedEvent(<span class="str">&quot;CurrentInputLevel&quot;</span>);
}

<span class="rem">// multiply by 100 because the Progress bar's default maximum value is 100 </span>
<span class="kwrd">public</span> <span class="kwrd">float</span> CurrentInputLevel { get { <span class="kwrd">return</span> lastPeak * 100; } }</pre>
<p></p>
<blockquote>
<p><b>Note: </b>Model View ViewModel (MVVM) is a pattern that is growing in popularity amongst WPF and Silverlight developers. The basic idea is that you have no code behind whatsoever on your View (i.e. your xaml markup file), and simply specify all communications
 with your business logic by means of data binding. The ViewModel serves as an adapter to ease the process of data binding. This approach gives very good separation of appearance and behavior. For the most part, this pattern works very well, but there are a
 few tricky areas, for which you will need to either write a few lines of code behind, or make use of some cunning tricks such as attached dependency properties or custom triggers. There are several excellent open source helper libraries that can take some
 of the work out of getting an MVVM application up and running. Have a look <a href="http://stackoverflow.com/questions/1409553/what-framework-for-mvvm-should-i-use">
here</a> for a comprehensive list.</p>
</blockquote>
<h4>Adjusting the Recording Level</h4>
<p>Suppose the current input level is too high or too soft. We would like to be able to support modifying the recording level. Again, we would like to use data binding to do so, so we will add a volume slider to our XAML:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Slider</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> 
    <span class="attr">Value</span><span class="kwrd">=&quot;{Binding MicrophoneLevel, Mode=TwoWay}&quot;</span> 
    <span class="attr">Maximum</span><span class="kwrd">=&quot;100&quot;</span> 
    <span class="attr">Margin</span><span class="kwrd">=&quot;5&quot;</span> <span class="kwrd">/&gt;</span></pre>
<p>Now we have to get hold of the <b>MixerLine</b> that will allow us to access the input volume control for our waveIn device. This requires us to make use of the Windows mixer APIs, which also have wrappers in NAudio. Getting hold of this volume control is
 not always as straightforward as you might hope (and can require different approaches for XP and Vista), but the following is code that seems to work on most systems:</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> TryGetVolumeControl()
{
    <span class="kwrd">int</span> waveInDeviceNumber = 0;
    var mixerLine = <span class="kwrd">new</span> MixerLine((IntPtr)waveInDeviceNumber, 
                                   0, MixerFlags.WaveIn);
    <span class="kwrd">foreach</span> (var control <span class="kwrd">in</span> mixerLine.Controls)
    {
        <span class="kwrd">if</span> (control.ControlType == MixerControlType.Volume)
        {
            volumeControl = control <span class="kwrd">as</span> UnsignedMixerControl;        
            <span class="kwrd">break</span>;
        }
    }
}</pre>
<p></p>
<p>Now we can use the <b>Percent</b> property on the UnsignedMixerControl to set volume to a value anywhere between 0 and 100.</p>
<h4>Starting Recording</h4>
<p>Now we have got our recording levels set up correctly, we are ready to actually start recording. But since we have already opened our waveIn device, all we need to do is start writing the data we have received into a file.
</p>
<p>NAudio has a class called <b>WaveFileWriter </b>which will allow us to write our recorded data to a file. For now, we will write it to a temporary file in PCM format, and convert it later into a better compressed format such as MP3. The following code creates
 a new WAV file:</p>
<pre class="csharpcode">writer = <span class="kwrd">new</span> WaveFileWriter(waveFileName, recordingFormat);</pre>
<p>Now we can write to the file as we receive notifications from the waveIn device:</p>
<pre class="csharpcode"><span class="kwrd">void</span> waveIn_DataAvailable(<span class="kwrd">object</span> sender, WaveInEventArgs e)
{
    <span class="kwrd">if</span> (recordingState == RecordingState.Recording)
        writer.WriteData(e.Buffer, 0, e.BytesRecorded);            

   <span class="rem">// ...</span>
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<blockquote>
<p><b>Note:</b> There are three main options for how to store audio while it is being recorded. First, you can write it to a
<b>MemoryStream</b>. This saves the inconvenience of dealing with a temporary file, but you need to be careful not to run out of memory. Also, if your recording program crashes half way through, you have lost everything. At the sample rate we are using for
 this demo, one minute of audio takes just under 1 MB of memory, but if you were recording at 44.1kHz stereo (the standard for music), you would need about 10 MB per minute.</p>
<p>Second, you can write to a temporary WAV file to be converted to another format later, as we are doing here. While this is not a disk space efficient format, it is very easy to work with, and particularly useful if you are planning to apply any effects or
 edit the audio in any way after recording. </p>
<p>Third, you can pass the audio directly to an encoder (such as WMA or MP3) as it is being recorded. This might be the best option if you are making a longer recording, and have no need to edit it after recording.</p>
</blockquote>
<h4>Stopping Recording</h4>
<p>Obviously we will stop when the user clicks the stop recording button, but we might also want to set a maximum recording duration to stop the user inadvertently filling up their hard disk. For this example, we will allow one minute of recording.</p>
<pre class="csharpcode"><span class="kwrd">long</span> maxFileLength = <span class="kwrd">this</span>.recordingFormat.AverageBytesPerSecond * 60;
 
<span class="kwrd">int</span> toWrite = (<span class="kwrd">int</span>)Math.Min(maxFileLength - writer.Length, bytesRecorded);
<span class="kwrd">if</span> (toWrite &gt; 0)
    writer.WriteData(buffer, 0, bytesRecorded);
<span class="kwrd">else</span>
    Stop();</pre>
<p><b></b></p>
<blockquote>
<p><b>Note: </b>Something that can be slightly confusing for users is that when using window callbacks with WaveIn, the last bit of audio you recorded comes in
<i>after</i> you have asked recording to stop, so make sure you don't close the file you are saving to until you have got all the audio back. The
<b>FinishedRecording</b> event on the WaveIn object will help you determine when it is safe to close the WaveFileWriter and clean up your resources.</p>
</blockquote>
<h4>Visualizing the Wave Form</h4>
<p>It is often desirable to display the audio waveform to the user. Displaying the waveform while you are recording is sometimes called “confidence recording”, because it allows you to see that audio is being recorded as expected and the levels are still right.</p>
<p>There are a variety of possible approaches for drawing audio waveforms. The simplest is to draw a vertical line showing the minimum and maximum values every time our sample aggregator fires:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_10.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_thumb_4.png" width="190" height="76"></a>
<br>
<strong>Figure 2 - Audio Waveform using vertical lines </strong></p>
<p>At first glance it may seem that this would be trivial to implement in WPF, but there is a real danger of consuming too many resources. For example, simply adding a new line to a Canvas every time a new maximum sample is calculated performs very badly, so
 it is better to have a fixed number of vertical lines and resize them dynamically.</p>
<p>Another approach is to create a polygon. This requires us to add two points to a Polygon's Points collection every time we receive a new sample. The trick is to add these points in the middle of the Points collection, rather than at the end, so that the
 end result is a single shape. This means our waveform can have a different outline color and fill color. To stop the edges from appearing too jagged, we plot points two units apart along on the X axis.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_8.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_thumb_3.png" width="383" height="105"></a><strong>
<br>
Figure 3 - Audio Waveform rendered using a Polygon</strong></p>
<p>Like the microphone volume meter, the waveform drawing control needs to receive several notifications a second of the maximum and minimum sample values received by the SampleAggregator. When each sample value is received, we either insert new points into
 our polygon, or, if the whole screen is full, we go back to the left-hand edge and continue drawing from there.</p>
<p>For the confidence recording display I have used the Polygon method, which is in a class called
<b>PolygonWaveFormControl</b>. Here's the code which calculates the new points or updated point locations as we receive a new maximum sample:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> AddValue(<span class="kwrd">float</span> maxValue, <span class="kwrd">float</span> minValue)
{
    <span class="kwrd">int</span> visiblePixels = (<span class="kwrd">int</span>)(ActualWidth / xScale);
    <span class="kwrd">if</span> (visiblePixels &gt; 0)
    {
        CreatePoint(maxValue, minValue);

        <span class="kwrd">if</span> (renderPosition &gt; visiblePixels)
        {
            renderPosition = 0;
        }
        <span class="kwrd">int</span> erasePosition = (renderPosition &#43; blankZone) % visiblePixels;
        <span class="kwrd">if</span> (erasePosition &lt; Points)
        {
            <span class="kwrd">double</span> yPos = SampleToYPosition(0);
            waveForm.Points[erasePosition] = 
               <span class="kwrd">new</span> Point(erasePosition * xScale, yPos);
            waveForm.Points[BottomPointIndex(erasePosition)] = 
               <span class="kwrd">new</span> Point(erasePosition * xScale, yPos);
        }
    }
}

<span class="kwrd">private</span> <span class="kwrd">void</span> CreatePoint(<span class="kwrd">float</span> topValue, <span class="kwrd">float</span> bottomValue)
{
    <span class="kwrd">double</span> topYPos = SampleToYPosition(topValue);
    <span class="kwrd">double</span> bottomYPos = SampleToYPosition(bottomValue);
    <span class="kwrd">double</span> xPos = renderPosition * xScale;
    <span class="kwrd">if</span> (renderPosition &gt;= Points)
    {
        <span class="kwrd">int</span> insertPos = Points;
        waveForm.Points.Insert(insertPos, <span class="kwrd">new</span> Point(xPos, topYPos));
        waveForm.Points.Insert(insertPos &#43; 1, <span class="kwrd">new</span> Point(xPos, bottomYPos));
    }
    <span class="kwrd">else</span>
    {
        waveForm.Points[renderPosition] = <span class="kwrd">new</span> Point(xPos, topYPos);
        waveForm.Points[BottomPointIndex(renderPosition)] = 
              <span class="kwrd">new</span> Point(xPos, bottomYPos);
    }
    renderPosition&#43;&#43;;
}</pre>
<p>The erase position calculation is to blank out some previous sample values to make it obvious where the new data is appearing after we have wrapped around once:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_14.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_thumb_6.png" width="291" height="53"></a>
<br>
<strong>Figure 4 PolygonWaveForm control's “blank zone”</strong></p>
<blockquote>
<p><b>Note:</b> There are faster ways to perform rendering in WPF. One option is to use the
<b>WriteableBitmap</b> class and draw directly onto it. This could be a good approach if you were using the vertical lines method of rendering. The second is to use
<b>DrawingVisual</b> objects, which are lightweight drawing objects offering better performance than using classes derived from Shape. The down-side is the loss of features such as DataBinding and the ability to fully describe the picture in XAML, but for WaveForm
 drawing this is not really a drawback. I use the DrawingVisual method in the Save Audio part of this application.</p>
</blockquote>
<p>Another challenge was how the waveform drawing control could receive notifications since I am using MVVM so I have no direct access to the SampleAggregator. A simple way around this was to create a Dependency Property on PolygonWaveFormControl:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty SampleAggregatorProperty = 
       DependencyProperty.Register(
          <span class="str">&quot;SampleAggregator&quot;</span>, 
          <span class="kwrd">typeof</span>(SampleAggregator), 
          <span class="kwrd">typeof</span>(PolygonWaveFormControl), 
          <span class="kwrd">new</span> PropertyMetadata(<span class="kwrd">null</span>, OnSampleAggregatorChanged));

<span class="kwrd">public</span> SampleAggregator SampleAggregator
{
    get { <span class="kwrd">return</span> (SampleAggregator)<span class="kwrd">this</span>.GetValue(SampleAggregatorProperty); }
    set { <span class="kwrd">this</span>.SetValue(SampleAggregatorProperty, <span class="kwrd">value</span>); }
}
        
<span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnSampleAggregatorChanged(<span class="kwrd">object</span> sender, DependencyPropertyChangedEventArgs e)
{
    PolygonWaveFormControl control = (PolygonWaveFormControl)sender;
    control.Subscribe();
}</pre>
<p></p>
<p>This allows us to bind the PolygonWaveFormControl to the SampleAggregator made public on our DataContext:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">my:PolygonWaveFormControl</span> 
    <span class="attr">Height</span><span class="kwrd">=&quot;40&quot;</span> 
    <span class="attr">SampleAggregator</span><span class="kwrd">=&quot;{Binding SampleAggregator}&quot;</span> <span class="kwrd">/&gt;</span></pre>
<h4>Trimming the Audio</h4>
<p>We have created a temporary WAV file, but before the user saves it to a file of their choosing, we want to allow them to trim off any unwanted parts from the start and end of the recording. To do this I would like to display the entire recorded waveform,
 with a selection rectangle superimposed on top to allow a sub-range to be selected.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_16.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9905168/image_thumb_7.png" width="289" height="159"></a>
<br>
<strong>Figure 5 - GUI to allow selection of a portion of the recorded audio</strong></p>
<p>To accomplish this kind of interface we need three components. The first is a <b>
ScrollViewer</b>. The ScrollViewer allows us to scroll left and right through the WaveForm if it is too big to fit onto a screen, which is likely if you record more than a few seconds of audio.
</p>
<p>The second is a new type of WaveForm renderer that will render an entire file, rather than my PolygonWaveFormControl which started again at the left when the screen filled up. For this I created
<b>WaveFormVisual</b> which uses DrawingVisual objects to draw the entire WaveForm. Obviously if we wanted to record for a long period, this approach would need to be optimised as the polygon it creates would have thousands of points, but for short recordings,
 it works fine.</p>
<p>The third piece was the hardest to get right – the selection rectangle to support mouse dragging selection of the waveform. For this I created the
<b>RangeSelectionControl</b>.</p>
<p>The <b>RangeSelectionControl</b> is simply a blue rectangle with a solid outline and semi-transparent fill sitting on a Canvas. The magic occurs in the mouse handler. We need to detect when the user hovers over the left or right edge of the rectangle, and
 set the cursor to show a horizontal resizing icon. This can be done in the MouseMove event, checking the X coordinate and then setting the Cursor property:</p>
<pre class="csharpcode">Cursor = Cursors.SizeWE;</pre>
<p>When the user clicks the left-button while over the edge, we begin to drag. Key to this is calling
<b>Canvas.CaptureMouse</b>. If we don't do this, as soon as you try to drag the rectangle bigger, the mouse move events are lost to other controls underneath.</p>
<pre class="csharpcode"><span class="kwrd">void</span> RangeSelectionControl_MouseDown(<span class="kwrd">object</span> sender, MouseButtonEventArgs e)
{
    <span class="kwrd">if</span> (e.LeftButton == MouseButtonState.Pressed)
    {
        Point position = e.GetPosition(<span class="kwrd">this</span>);
        Edge edge = EdgeAtPosition(position.X);
        DragEdge = edge;
        <span class="kwrd">if</span> (DragEdge != Edge.None)
        {
            mainCanvas.CaptureMouse();
        }
    }
}</pre>
<p></p>
<p>Now in the MouseMove methods, we can change the Canvas.Left and Width properties of the rectangle to resize it.</p>
<p>The <b>ScrollViewer</b> is quite straightforward to use, but you must remember to set CanContentScroll property to true, and also to set the size of the items within the ScrollViewer correctly.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">ScrollViewer</span> <span class="attr">CanContentScroll</span><span class="kwrd">=&quot;True&quot;</span> 
         <span class="attr">HorizontalScrollBarVisibility</span><span class="kwrd">=&quot;Visible&quot;</span> 
         <span class="attr">VerticalScrollBarVisibility</span><span class="kwrd">=&quot;Hidden&quot;</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">Grid</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">my:WaveFormVisual</span> <span class="attr">Height</span><span class="kwrd">=&quot;100&quot;</span> 
           <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Left&quot;</span> 
           <span class="attr">x:Name</span><span class="kwrd">=&quot;waveFormRenderer&quot;</span><span class="kwrd">/&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">my:RangeSelectionControl</span> 
           <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Left&quot;</span> 
           <span class="attr">x:Name</span><span class="kwrd">=&quot;rangeSelection&quot;</span> <span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ScrollViewer</span><span class="kwrd">&gt;</span></pre>
<p>We set the appropriate Width of the WaveFormVisual and RangeSelectionControl based on the total number of points we have drawn in the waveform.
</p>
<h4>Saving the Audio</h4>
<p>So we are finally ready to save the audio. We will offer the user two choices of format to save in. The first is simply to save as a WAV file. If the user has selected the entire recording, we only need to copy the audio across to their desired location.
 If, however, the user has selected a sub-range, then we need to trim the WAV file. This can be quickly accomplished using a
<b>TrimWavFile</b> utility function that copies from a WAV file reader to a WAV file writer, skipping over a certain number of bytes from the beginning and end.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> TrimWavFile(<span class="kwrd">string</span> inPath, <span class="kwrd">string</span> outPath, 
                TimeSpan cutFromStart, TimeSpan cutFromEnd)
{
    <span class="kwrd">using</span> (WaveFileReader reader = <span class="kwrd">new</span> WaveFileReader(inPath))
    {
        <span class="kwrd">using</span> (WaveFileWriter writer = 
               <span class="kwrd">new</span> WaveFileWriter(outPath, reader.WaveFormat))
        {
            <span class="kwrd">int</span> bytesPerMillisecond = 
                reader.WaveFormat.AverageBytesPerSecond / 1000;

            <span class="kwrd">int</span> startPos = (<span class="kwrd">int</span>)cutFromStart.TotalMilliseconds * 
                           bytesPerMillisecond;
            startPos = startPos - startPos % reader.WaveFormat.BlockAlign;

            <span class="kwrd">int</span> endBytes = (<span class="kwrd">int</span>)cutFromEnd.TotalMilliseconds * 
                           bytesPerMillisecond;
            endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
            <span class="kwrd">int</span> endPos = (<span class="kwrd">int</span>)reader.Length - endBytes; 

            TrimWavFile(reader, writer, startPos, endPos);
        }
    }
}

<span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> TrimWavFile(WaveFileReader reader, 
                    WaveFileWriter writer, <span class="kwrd">int</span> startPos, <span class="kwrd">int</span> endPos)
{
    reader.Position = startPos;
    <span class="kwrd">byte</span>[] buffer = <span class="kwrd">new</span> <span class="kwrd">byte</span>[1024];
    <span class="kwrd">while</span> (reader.Position &lt; endPos)
    {
        <span class="kwrd">int</span> bytesRequired = (<span class="kwrd">int</span>)(endPos - reader.Position);
        <span class="kwrd">if</span> (bytesRequired &gt; 0)
        {
            <span class="kwrd">int</span> bytesToRead = Math.Min(bytesRequired, buffer.Length);
            <span class="kwrd">int</span> bytesRead = reader.Read(buffer, 0, bytesToRead);
            <span class="kwrd">if</span> (bytesRead &gt; 0)
            {
                writer.WriteData(buffer, 0, bytesRead);
            }
        }
    }
}</pre>
<p>We also want to offer the ability to save as MP3. The easiest way to create MP3 files is to use the open source LAME MP3 encoder (do a web search for lame.exe to get hold of this application if you haven't already got it). Our application will look in the
 current directory, and prompt the user to find lame.exe if it is not present, as we do not include it in the application download. Assuming you do provide a valid path, we can then convert our (trimmed) WAV file to MP3 by simply calling lame.exe with the appropriate
 parameters.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ConvertToMp3(<span class="kwrd">string</span> lameExePath, 
     <span class="kwrd">string</span> waveFile, <span class="kwrd">string</span> mp3File)
{
   Process converter = Process.Start(lameExePath, <span class="str">&quot;-V2 \&quot;&quot;</span> &#43; waveFile 
                            &#43; <span class="str">&quot;\&quot; \&quot;&quot;</span> &#43; mp3File &#43; <span class="str">&quot;\&quot;&quot;</span>);
   converter.WaitForExit();
}</pre>
<p></p>
<p>We end up with a nice compact MP3 file containing the selected portion of our microphone recording.</p>
<h4>Exploring the Sample Code Solution</h4>
<p>The main WPF sample application is found in the <b>VoiceRecorder</b> project. This contains the main window along with the three views and their associated ViewModels.
<b>VoiceRecorder.Core</b> contains some WPF helper classes and user controls to help with the plumbing and GUI of the application, while
<b>VoiceRecorder.Audio</b> contains the classes that actually perform the recording, editing and converting of audio.</p>
<h4>About the Author</h4>
<p>Mark Heath is a software developer currently working for NICE CTI Systems in Southampton, UK. He specializes in .NET development with a particular focus on client side technologies and audio playback. He blogs about audio, WPF, Silverlight and software engineering
 best practices at <a href="http://mark-dot-net.blogspot.com">http://mark-dot-net.blogspot.com</a>. He is the author of several open source projects hosted at CodePlex, including NAudio, a low-level .NET audio toolkit (<a href="http://www.codeplex.com/naudio">http://www.codeplex.com/naudio</a>).</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:aa6148d11dc848f181989e7600cb3bf6">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder</comments>
      <itunes:summary>
In this article I demonstrate how to record from the microphone in .NET, with support for setting the recording level, trimming noise from the start and end, visualizing the waveform in WPF and converting to MP3. 

Audio Recording in .NET

The .NET framework does not provide any direct support for recording audio, so I will make use of the open source
NAudio project, which includes wrappers for a number of Windows audio recording APIs.
 

Note: It is important to point out that .NET is not an appropriate choice for high sample rate and
low latency audio recording, such as that found in Digital Audio Workstation software used in recording studios. This is because the .NET garbage collector can interrupt the process at any point. However, for purposes of recording speech from the microphone,
 the .NET framework is more than capable. By default, NAudio asks the soundcard to give us data every 100ms, which gives plenty of time for the garbage collector to run as well as our own code. 

We will make use of the wrappers for the waveIn API&#39;s, as these are the most universally supported, and allow us freedom to choose the sample rate. We will record in mono, 16 bit at 8kHz, which is more than good enough audio quality for speech, and will
 not overly tax the processor, which is important as we want to visualize the waveform as well. 
Choosing a Capture Device
Normally, you will be able to use the default audio capture device without any difficulties, but should you need to offer the user a choice, NAudio will allow you to do so. You can use the
WaveIn.DeviceCount and WaveIn.GetDeviceCapabilities to find out how many recording devices are present, and query for their name and number of supported channels. 
On my computer, I have a single waveIn device (Microphone Array) until I plug my headset in, at which point, a new device appears and becomes the default (device 0 is always the default). 
int waveInDevices = WaveIn.DeviceCount;
for (int waveInDevice = 0; waveInDevice &amp;lt</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder</link>
      <pubDate>Thu, 08 Oct 2009 18:29:39 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9905168_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9905168_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Mark Heath </dc:creator>
      <itunes:author>Mark Heath </itunes:author>
      <slash:comments>18</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Model-View-ViewModel</category>
      <category>MVVM</category>
      <category>WPF</category>
    </item>
  <item>
      <title>Elliot H Omiya, Larry Osterman and Frank Yerrace: Inside Windows 7 - Audio Stack</title>
      <description><![CDATA[One of the central engineering and design themes of Windows 7 is efficiency: efficiency in user experience (things work as and when expected, reliably), efficiency in processing, execution, diagnostics, performance, scheduling, window managment, graphics,
 desktop search, etc. Well, not surprisingly, Windows 7's audio system has been engineered to provide very efficient user experience (when you plug your headphones in the system streams music to your headphones as expected. When you remove them Windows will
 switch the stream to flow into your speakers&nbsp;- this is known as&nbsp;real time stream switching - but how does it work, exactly?). What, exactly, is new in the&nbsp;Windows audio system? What's been improved since Vista? What is sound, really? (Yes, we talk about this
 at the end of the interview - interesting stuff indeed). You first learned about some of the
<a shape="rect" href="http://channel9.msdn.com/posts/Charles/Inside-Windows-7-Larry-Osterman-on-new-audio-capabilities/" target="_blank" shape="rect">
updates to Windows audio in an interview with Larry in September '08</a>. We dig into more detail here (whiteboard included&nbsp;plus we&nbsp;discuss a few things you probably do not know about...)<br /><br />Here, Architect Elliot H Omiya, Principal Software Developer Larry Osterman&nbsp;and Principal&nbsp;Software Developer&nbsp;Frank Yerrace take us through the details of Windows 7 audio, including some history, some design decisions, some hard problems and overall a great
 conversation about how Windows makes noise (or music - it's all relative <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif' alt='Smiley' />).<br /><br />Enjoy. Lots to learn here. Elliot, Larry, Frank and the Windows audio team have done excellent work in this iteration of Windows. Find some time (I know. It's hard.) Get comfortable&nbsp;and learn all about the innerworkings of Windows 7's audio.<br /> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:755911f7e82742e28b469dea00433114">]]></description>
      <comments>http://channel9.msdn.com/Shows/Going+Deep/Elliot-H-Omiya-Larry-Osterman-and-Frank-Yerrace-Inside-Windows-7-Audio-Stack</comments>
      <itunes:summary>One of the central engineering and design themes of Windows 7 is efficiency: efficiency in user experience (things work as and when expected, reliably), efficiency in processing, execution, diagnostics, performance, scheduling, window managment, graphics,
 desktop search, etc. Well, not surprisingly, Windows 7&#39;s audio system has been engineered to provide very efficient user experience (when you plug your headphones in the system streams music to your headphones as expected. When you remove them Windows will
 switch the stream to flow into your speakers&amp;nbsp;- this is known as&amp;nbsp;real time stream switching - but how does it work, exactly?). What, exactly, is new in the&amp;nbsp;Windows audio system? What&#39;s been improved since Vista? What is sound, really? (Yes, we talk about this
 at the end of the interview - interesting stuff indeed). You first learned about some of the

updates to Windows audio in an interview with Larry in September &#39;08. We dig into more detail here (whiteboard included&amp;nbsp;plus we&amp;nbsp;discuss a few things you probably do not know about...)Here, Architect Elliot H Omiya, Principal Software Developer Larry Osterman&amp;nbsp;and Principal&amp;nbsp;Software Developer&amp;nbsp;Frank Yerrace take us through the details of Windows 7 audio, including some history, some design decisions, some hard problems and overall a great
 conversation about how Windows makes noise (or music - it&#39;s all relative ).Enjoy. Lots to learn here. Elliot, Larry, Frank and the Windows audio team have done excellent work in this iteration of Windows. Find some time (I know. It&#39;s hard.) Get comfortable&amp;nbsp;and learn all about the innerworkings of Windows 7&#39;s audio.</itunes:summary>
      <itunes:duration>3852</itunes:duration>
      <link>http://channel9.msdn.com/Shows/Going+Deep/Elliot-H-Omiya-Larry-Osterman-and-Frank-Yerrace-Inside-Windows-7-Audio-Stack</link>
      <pubDate>Tue, 11 Aug 2009 14:44:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/Going+Deep/Elliot-H-Omiya-Larry-Osterman-and-Frank-Yerrace-Inside-Windows-7-Audio-Stack</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/479820_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/479820_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_large_ch9.png" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_small_ch9.png" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_2MB_ch9.wmv" expression="full" duration="3852" fileSize="1205869051" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_ch9.mp3" expression="full" duration="3852" fileSize="30824280" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_ch9.mp4" expression="full" duration="3852" fileSize="379881146" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_ch9.wma" expression="full" duration="3852" fileSize="62325973" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_ch9.wmv" expression="full" duration="3852" fileSize="543196555" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_Zune_ch9.wmv" expression="full" duration="3852" fileSize="544460535" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_s_ch9.wmv" expression="full" duration="3852" fileSize="211" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/2/8/9/7/4/InsideWin7Audio_ch9.wmv" length="543196555" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Charles</dc:creator>
      <itunes:author>Charles</itunes:author>
      <slash:comments>23</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/Going+Deep/Elliot-H-Omiya-Larry-Osterman-and-Frank-Yerrace-Inside-Windows-7-Audio-Stack/RSS</wfw:commentRss>
      <category>Architecture</category>
      <category>Audio</category>
      <category>Larry Osterman</category>
      <category>Windows 7</category>
    </item>
  <item>
      <title>Creating Games with Silverlight: A Simple Shooter</title>
      <description><![CDATA[
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_2.png"><img title="image" border="0" alt="image" align="right" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_thumb.png" width="300" height="240"></a>This
 article will take you through some of the steps to creating the basics for writing games with Silverlight. This is a simple shooter style game that contains some of the building blocks for games that require abilities such as vectors, collision detection,
 a game loop, movement, and keyboard input. Please refer to the full source code for this project for any areas of the code that are not covered in detail in this article.</p>

<h3>Inspiration</h3>
<p>There are a number of examples and tutorials out there to help get started creating games. You will find the basics of this game to be very similar to a Visual C# Coding4Fun article
<a href="http://blogs.msdn.com/coding4fun/archive/2006/10/31/916430.aspx">here</a>. This article will show you how to create a shooter style game in Silverlight. My first Silverlight game experience was playing with a Asteroids style game by Bill Reiss. My
 usage of vectors and how to do a game loop came from great examples like his and others. There are a number of sites and blogs where you can get good info on game development with Silverlight. Here are just a few.</p>
<ul>
<li><a href="http://www.bluerosegames.com/brg/">BlueRoseGames.com</a> </li><li><a href="http://www.farseergames.com/">Farseer Games</a> </li><li><a href="http://www.cameronalbert.com/">Cameron Albert</a> </li><li><a href="http://silverlight.net/blogs/msnow/default.aspx">Mike Snow</a> </li></ul>
<h3>Basic Layout</h3>
<p>To begin, Open Visual Studio and create a new Silverlight Application in either C# or VB.net. First, we will start with the layout of the screen. First, I added a canvas to the grid inside the Page.xaml that is created for you. I set it's background to black,
 and named it 'gameRoot'. </p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">=&quot;SimpleShooter.Page&quot;</span>
    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span> 
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span> 
    <span class="attr">Width</span><span class="kwrd">=&quot;400&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;300&quot;</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">Canvas</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;gameRoot&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;500&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;400&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;Black&quot;</span> <span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">Canvas</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">UserControl</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next we will start adding controls to our project for things like game entities, and information displays. In this example. To complete layout of the game, add user controls to the progect called: Info, LivesRemaining, Score, and WaveInfo. In those controls,
 To begin I added basic TextBlocks to display information on the state of the game. Please note there are better ways to arrange things in a user control, beyond what I show here. I am keeping to a simple canvas and direct positioning to introduce the concept
 of Canvas.Top and Canvas.Left. I have now placed these controls on Page.xaml and assigned an x:Name to each. At this point, the controls have only a TextBlock in them.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">=&quot;SimpleShooter.Page&quot;</span>
    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span> 
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span> 
    <span class="attr">xmlns:SimpleShooter</span><span class="kwrd">=&quot;clr-namespace:SimpleShooter&quot;</span>
    <span class="attr">Width</span><span class="kwrd">=&quot;500&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;400&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">Canvas</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;gameRoot&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;500&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;400&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;Black&quot;</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">SimpleShooter:RemainingLives</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ctlLives&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">=&quot;380&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Left</span><span class="kwrd">=&quot;10&quot;</span> <span class="kwrd">/&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">SimpleShooter:Score</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ctlScore&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">=&quot;10&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Left</span><span class="kwrd">=&quot;10&quot;</span> <span class="kwrd">/&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">SimpleShooter:WaveInfo</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ctlWaveInfo&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Left</span><span class="kwrd">=&quot;440&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">=&quot;10&quot;</span> <span class="kwrd">/&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">SimpleShooter:Info</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ctlInfo&quot;</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">=&quot;10&quot;</span><span class="kwrd">/&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">Canvas</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">UserControl</span><span class="kwrd">&gt;</span></pre>
<p>To finish our layout lets add a star field. To do this, we will write function to generate random numbers, and another that will randomly distribute ellipses on our base canvas. We will need to inherit from System.Security.Cryptography for this:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Page : UserControl
{
    <span class="kwrd">public</span> Page()
    {
        InitializeComponent();

        GenerateStarField(350);
    }

    <span class="kwrd">void</span> GenerateStarField(<span class="kwrd">int</span> numberOfStars)
    {

        <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; numberOfStars; i&#43;&#43;)
        {

            Ellipse star = <span class="kwrd">new</span> Ellipse();
            <span class="kwrd">double</span> size = GetRandInt(10, 800) * .01;
            star.Width = size;
            star.Height = size;
            star.Opacity = GetRandInt(1, 5) * .1;
            star.Fill = <span class="kwrd">new</span> SolidColorBrush(Colors.White);
            <span class="kwrd">int</span> x = GetRandInt(0, (<span class="kwrd">int</span>)Math.Round(gameRoot.Height, 0));
            <span class="kwrd">int</span> y = GetRandInt(0, (<span class="kwrd">int</span>)Math.Round(gameRoot.Width, 0));
            star.SetValue(Canvas.TopProperty, (<span class="kwrd">double</span>)x);
            star.SetValue(Canvas.LeftProperty, (<span class="kwrd">double</span>)y);
            gameRoot.Children.Add(star);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">int</span> GetRandInt(<span class="kwrd">int</span> min, <span class="kwrd">int</span> max)
    {
        Byte[] rndBytes = <span class="kwrd">new</span> Byte[10];
        RNGCryptoServiceProvider rndC = <span class="kwrd">new</span> RNGCryptoServiceProvider();
        rndC.GetBytes(rndBytes);
        <span class="kwrd">int</span> seed = BitConverter.ToInt32(rndBytes, 0);
        Random rand = <span class="kwrd">new</span> Random(seed);
        <span class="kwrd">return</span> rand.Next(min, max);
    }
}</pre>
<b></b>
<p><b>VB </b></p>
<pre class="csharpcode">Partial <span class="kwrd">Public</span> <span class="kwrd">Class</span> Page
    <span class="kwrd">Inherits</span> UserControl

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()
        InitializeComponent()
        GenerateStarField(350)
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Private</span> <span class="kwrd">Sub</span> GenerateStarField(<span class="kwrd">ByVal</span> numberOfStars <span class="kwrd">As</span> <span class="kwrd">Integer</span>)

        <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> numberOfStars - 1

            <span class="kwrd">Dim</span> star <span class="kwrd">As</span> <span class="kwrd">New</span> Ellipse()
            <span class="kwrd">Dim</span> size <span class="kwrd">As</span> <span class="kwrd">Double</span> = GetRandInt(10, 800) * 0.01
            star.Width = size
            star.Height = size
            star.Opacity = GetRandInt(1, 5) * 0.1
            star.Fill = <span class="kwrd">New</span> SolidColorBrush(Colors.White)
            <span class="kwrd">Dim</span> x <span class="kwrd">As</span> <span class="kwrd">Integer</span> = GetRandInt(0, <span class="kwrd">CInt</span>(Math.Round(gameRoot.Height, 0)))
            <span class="kwrd">Dim</span> y <span class="kwrd">As</span> <span class="kwrd">Integer</span> = GetRandInt(0, <span class="kwrd">CInt</span>(Math.Round(gameRoot.Width, 0)))
            star.SetValue(Canvas.TopProperty, <span class="kwrd">CDbl</span>(x))
            star.SetValue(Canvas.LeftProperty, <span class="kwrd">CDbl</span>(y))
            gameRoot.Children.Add(star)
        <span class="kwrd">Next</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Function</span> GetRandInt(<span class="kwrd">ByVal</span> min <span class="kwrd">As</span> <span class="kwrd">Integer</span>, <span class="kwrd">ByVal</span> max <span class="kwrd">As</span> <span class="kwrd">Integer</span>) <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">Dim</span> rndBytes <span class="kwrd">As</span> [<span class="kwrd">Byte</span>]() = <span class="kwrd">New</span> [<span class="kwrd">Byte</span>](9) {}
        <span class="kwrd">Dim</span> rndC <span class="kwrd">As</span> <span class="kwrd">New</span> RNGCryptoServiceProvider()
        rndC.GetBytes(rndBytes)
        <span class="kwrd">Dim</span> seed <span class="kwrd">As</span> <span class="kwrd">Integer</span> = BitConverter.ToInt32(rndBytes, 0)
        <span class="kwrd">Dim</span> rand <span class="kwrd">As</span> <span class="kwrd">New</span> Random(seed)
        <span class="kwrd">Return</span> rand.[<span class="kwrd">Next</span>](min, max)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>
<span class="kwrd">End</span> Class</pre>
<b></b>
<p>We now have a function called GenerateStarField. Note that it is adding each ellipse to the 'Children' of our base gameRoot canvas, and how the Top and Left properties determine the positions of those ellipses. Now we have a basic layout of our game and
 a background.</p>
<h4></h4>
<h4><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_4.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_thumb_1.png" width="500" height="400"></a>
</h4>
<h4>Sprites and Vectors</h4>
<p>I am not going to go in to great detail on <a href="http://en.wikipedia.org/wiki/Sprite_(computer_graphics)">
sprites</a> or <a href="http://en.wikipedia.org/wiki/Euclidean_vector">vectors</a>. There are a number of great resources (see other articles linked to in this post), as well as
<a href="http://blogs.msdn.com/coding4fun/archive/2007/02/20/1727608.aspx">another good Coding4Fun article</a> on this topic. We are however, going to add a class to represent a sprite and a vector to our code:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> Sprite
{
    <span class="kwrd">public</span> <span class="kwrd">double</span> Width { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">double</span> Height { get; set; }
    <span class="kwrd">public</span> Vector Velocity { get; set; }
    <span class="kwrd">public</span> Canvas SpriteCanvas { get; set; }
    <span class="kwrd">private</span> Point _position;
    <span class="kwrd">public</span> Point Position
    {
        get
        {
            <span class="kwrd">return</span> _position;
        }
        set
        {
            _position = <span class="kwrd">value</span>;
            SpriteCanvas.SetValue(Canvas.TopProperty, _position.Y - (Height / 2));
            SpriteCanvas.SetValue(Canvas.LeftProperty, _position.X - (Width / 2));
        }
    }

    <span class="kwrd">public</span> Sprite(Double width, Double height, Point position)
    {
        Width = width;
        Height = height;

        SpriteCanvas = RenderSpriteCanvas();

        SpriteCanvas.Width = width;
        SpriteCanvas.Height = height;
        <span class="rem">//NOTE: because the setter for Position uses both Height and Width, it is important this comes after they are set.</span>
        Position = position;
    }

    <span class="kwrd">public</span> <span class="kwrd">abstract</span> Canvas RenderSpriteCanvas();

    <span class="kwrd">public</span> Canvas LoadSpriteCanvas(<span class="kwrd">string</span> xamlPath)
    {
        System.IO.Stream s = <span class="kwrd">this</span>.GetType().Assembly.GetManifestResourceStream(xamlPath);
        <span class="kwrd">return</span> (Canvas)XamlReader.Load(<span class="kwrd">new</span> System.IO.StreamReader(s).ReadToEnd());
    }

    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Update(TimeSpan elapsedTime)
    {
        Position = (Position &#43; Velocity * elapsedTime.TotalSeconds);
    }
}</pre>
<p><b>VB </b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">MustInherit</span> <span class="kwrd">Class</span> Sprite
    <span class="kwrd">Private</span> _Width <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Width() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _Width
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _Width = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _Height <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Height() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _Height
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _Height = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _Velocity <span class="kwrd">As</span> Vector
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Velocity() <span class="kwrd">As</span> Vector
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _Velocity
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> Vector)
            _Velocity = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _SpriteCanvas <span class="kwrd">As</span> Canvas
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> SpriteCanvas() <span class="kwrd">As</span> Canvas
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _SpriteCanvas
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> Canvas)
            _SpriteCanvas = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _position <span class="kwrd">As</span> Point
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Position() <span class="kwrd">As</span> Point
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _position
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> Point)
            _position = value
            SpriteCanvas.SetValue(Canvas.TopProperty, _position.Y - (Height / 2))
            SpriteCanvas.SetValue(Canvas.LeftProperty, _position.X - (Width / 2))
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> initialWidth <span class="kwrd">As</span> [<span class="kwrd">Double</span>], <span class="kwrd">ByVal</span> initialHeight <span class="kwrd">As</span> [<span class="kwrd">Double</span>], <span class="kwrd">ByVal</span> initialPosition <span class="kwrd">As</span> Point)
        Width = initialWidth
        Height = initialHeight

        SpriteCanvas = RenderSpriteCanvas()

        SpriteCanvas.Width = Width
        SpriteCanvas.Height = Height
        <span class="rem">'NOTE: because the setter for Position uses both Height and Width, it is important this comes after they are set. </span>
        Position = initialPosition
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">MustOverride</span> <span class="kwrd">Function</span> RenderSpriteCanvas() <span class="kwrd">As</span> Canvas

    <span class="kwrd">Public</span> <span class="kwrd">Function</span> LoadSpriteCanvas(<span class="kwrd">ByVal</span> xamlPath <span class="kwrd">As</span> <span class="kwrd">String</span>) <span class="kwrd">As</span> Canvas
        <span class="kwrd">Dim</span> s <span class="kwrd">As</span> System.IO.Stream = <span class="kwrd">Me</span>.[<span class="kwrd">GetType</span>]().<span class="kwrd">Assembly</span>.GetManifestResourceStream(xamlPath)
        <span class="kwrd">Return</span> <span class="kwrd">DirectCast</span>(XamlReader.Load(<span class="kwrd">New</span> System.IO.StreamReader(s).ReadToEnd()), Canvas)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overridable</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> elapsedTime <span class="kwrd">As</span> TimeSpan)
        Position = (Position &#43; Velocity * elapsedTime.TotalSeconds)
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<p>This Sprite class will give us the basis for entities in the game such as a ship, aliens, and projectiles. For all these items, we need to know the location of the item, the site, and what it looks like. We will take advantage of Point to track our position,
 and a property of type Canvas to display the XAML for each of these items. The constructor sets these initial parameters, and calls a RenderSpriteCanvas method to be implemented by each class that inherits from it. This method allows the inheriting class to
 set the contents of the canvas and therefore as control of the way the sprite looks.</p>
<p>Next we have our vector class that will help us control movement of our sprite. Again, I will not go into detail on vectors as this code is borrowed and adapted from many other readily available sources:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">struct</span> Vector
{
    <span class="kwrd">public</span> <span class="kwrd">double</span> X;
    <span class="kwrd">public</span> <span class="kwrd">double</span> Y;

    <span class="kwrd">public</span> Vector(<span class="kwrd">double</span> x, <span class="kwrd">double</span> y)
    {
        X = x;
        Y = y;
    }

    <span class="kwrd">public</span> <span class="kwrd">double</span> Length
    {
        get
        {
            <span class="kwrd">return</span> Math.Sqrt(LengthSquared);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">double</span> LengthSquared
    {
        get
        {
            <span class="kwrd">return</span> X * X &#43; Y * Y;
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> Normalize()
    {
        <span class="kwrd">double</span> length = Length;
        X /= length;
        Y /= length;
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> Vector <span class="kwrd">operator</span> -(Vector vector)
    {
        <span class="kwrd">return</span> <span class="kwrd">new</span> Vector(-vector.X, -vector.Y);
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> Vector <span class="kwrd">operator</span> *(Vector vector, <span class="kwrd">double</span> scalar)
    {
        <span class="kwrd">return</span> <span class="kwrd">new</span> Vector(scalar * vector.X, scalar * vector.Y);
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> Point <span class="kwrd">operator</span> &#43;(Point point, Vector vector)
    {
        <span class="kwrd">return</span> <span class="kwrd">new</span> Point(point.X &#43; vector.X, point.Y &#43; vector.Y);
    }

    <span class="kwrd">static</span> <span class="kwrd">public</span> Vector CreateVectorFromAngle(<span class="kwrd">double</span> angleInDegrees, <span class="kwrd">double</span> length)
    {
        <span class="kwrd">double</span> x = Math.Sin(DegreesToRadians(180 - angleInDegrees)) * length;
        <span class="kwrd">double</span> y = Math.Cos(DegreesToRadians(180 - angleInDegrees)) * length;
        <span class="kwrd">return</span> <span class="kwrd">new</span> Vector(x, y);
    }

    <span class="kwrd">static</span> <span class="kwrd">public</span> <span class="kwrd">double</span> DegreesToRadians(<span class="kwrd">double</span> degrees)
    {
        <span class="kwrd">double</span> radians = ((degrees / 360) * 2 * Math.PI);
        <span class="kwrd">return</span> radians;
    }
}</pre>
<p><b>VB </b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Structure</span> Vector
    <span class="kwrd">Public</span> X <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> Y <span class="kwrd">As</span> <span class="kwrd">Double</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> x__1 <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> y__2 <span class="kwrd">As</span> <span class="kwrd">Double</span>)
        X = x__1
        Y = y__2
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Length() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> Math.Sqrt(LengthSquared)
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> LengthSquared() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> X * X &#43; Y * Y
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Normalize()
        <span class="kwrd">Dim</span> length__1 <span class="kwrd">As</span> <span class="kwrd">Double</span> = Length
        X /= length__1
        Y /= length__1
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Operator</span> -(<span class="kwrd">ByVal</span> vector <span class="kwrd">As</span> Vector) <span class="kwrd">As</span> Vector
        <span class="kwrd">Return</span> <span class="kwrd">New</span> Vector(-vector.X, -vector.Y)
    <span class="kwrd">End</span> <span class="kwrd">Operator</span>

    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Operator</span> *(<span class="kwrd">ByVal</span> vector <span class="kwrd">As</span> Vector, <span class="kwrd">ByVal</span> scalar <span class="kwrd">As</span> <span class="kwrd">Double</span>) <span class="kwrd">As</span> Vector
        <span class="kwrd">Return</span> <span class="kwrd">New</span> Vector(scalar * vector.X, scalar * vector.Y)
    <span class="kwrd">End</span> <span class="kwrd">Operator</span>

    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Operator</span> &#43;(<span class="kwrd">ByVal</span> point <span class="kwrd">As</span> Point, <span class="kwrd">ByVal</span> vector <span class="kwrd">As</span> Vector) <span class="kwrd">As</span> Point
        <span class="kwrd">Return</span> <span class="kwrd">New</span> Point(point.X &#43; vector.X, point.Y &#43; vector.Y)
    <span class="kwrd">End</span> <span class="kwrd">Operator</span>


    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> CreateVectorFromAngle(<span class="kwrd">ByVal</span> angleInDegrees <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> length <span class="kwrd">As</span> <span class="kwrd">Double</span>) <span class="kwrd">As</span> Vector
        <span class="kwrd">Dim</span> x <span class="kwrd">As</span> <span class="kwrd">Double</span> = Math.Sin(DegreesToRadians(180 - angleInDegrees)) * length
        <span class="kwrd">Dim</span> y <span class="kwrd">As</span> <span class="kwrd">Double</span> = Math.Cos(DegreesToRadians(180 - angleInDegrees)) * length
        <span class="kwrd">Return</span> <span class="kwrd">New</span> Vector(x, y)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>

    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> DegreesToRadians(<span class="kwrd">ByVal</span> degrees <span class="kwrd">As</span> <span class="kwrd">Double</span>) <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Dim</span> radians <span class="kwrd">As</span> <span class="kwrd">Double</span> = ((degrees / 360) * 2 * Math.PI)
        <span class="kwrd">Return</span> radians
    <span class="kwrd">End</span> <span class="kwrd">Function</span>
<span class="kwrd">End</span> Structure</pre>
<p><b><br>
</b>Now we can implement Sprite with a new Ship class. Add a class called Ship, and a file called Ship.xaml to your project. Be sure to set the properties of Ship.xaml to 'Embedded Resource'. We now need to inherit from our Sprite class:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Ship : Sprite
{
    <span class="kwrd">public</span> Ship(<span class="kwrd">double</span> width, <span class="kwrd">double</span> height, Point firstPosition)
        : <span class="kwrd">base</span>(width, height, firstPosition)
    {

    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> Canvas RenderSpriteCanvas()
    {
        <span class="kwrd">return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Sprites.Ship.xaml&quot;</span>);
    }
}</pre>
<p><b>VB </b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Ship
    <span class="kwrd">Inherits</span> Sprite
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> width <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> height <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> firstPosition <span class="kwrd">As</span> Point)
        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(width, height, firstPosition)

    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Function</span> RenderSpriteCanvas() <span class="kwrd">As</span> Canvas
        <span class="kwrd">Return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Ship.xaml&quot;</span>)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>
<span class="kwrd">End</span> Class</pre>
<p>When Ship is instantiated, it calls the constructor of it's base, Sprite. It also implements the RenderSpriteCanvas method and specifies the XAML (a simple white square) to load into the sprite's canvas. Now we are ready to add a sprite to our main page.
 In this simple game, we will have only one ship (the others will be aliens), so lets add a property to our page, and a function that will instantiate our ship:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Canvas</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;30&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;30&quot;</span> 
    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/client/2007&quot;</span>
    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span> <span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">Rectangle</span> <span class="attr">Height</span><span class="kwrd">=&quot;30&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;30&quot;</span> <span class="attr">Fill</span><span class="kwrd">=&quot;White&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Canvas</span><span class="kwrd">&gt;</span></pre>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">void</span> InitializeGame()
{
    PlayerShip = <span class="kwrd">new</span> Ship(10, 10, <span class="kwrd">new</span> Point(100, 300));
    gameRoot.Children.Add(PlayerShip.SpriteCanvas);
}</pre>
<p><b>VB </b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> InitializeGame()
    PlayerShip = <span class="kwrd">New</span> Ship(10, 10, <span class="kwrd">New</span> Point(100, 300))
    gameRoot.Children.Add(PlayerShip.SpriteCanvas)
<span class="kwrd">End</span> Sub</pre>
<p>We can now call this method from our page constructor and when we run the project, we get a white square (our ship) at the bottom left of our Page. Taking a closer look, we set our page size to 500 x 400, and the InitializeGame method places our Ship at
 a point 100 pixels from the left of the gameRoot canvas, and 300pixels from the top.</p>
<h4>Keyboard Input and the Game Loop</h4>
<p>Now we are ready to make some things move. To start, we need choose keys on the keyboard to allow movement, and act on those events. We then need to capture those key presses and act on them if they are relevant to our game loop. Once again, may examples
 of key handlers and game loops are readily available, so I won't go into detail. The keyboard handler captures all key up and down events. We can therefore ask our instance of the handler if a key is pressed at any given time. The game loop is just that, a
 constant loop. It consists of a storyboard that has the start called on it and it immediately ends. The class raises an event, and starts the storyboard again. Subscribers to Update event are provided a value that reports the number of milliseconds since the
 last update. That value can be applied to vectors to apply smooth movement to sprites. To take advantage of these classes, we need to add an instance of both a KeyHandler and GameLoop to our Page. To do this, we update the InitializeGame and Page constructor,
 and add a handler for the GameLoop:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> Page()
{
    InitializeComponent();
    keyHandler = <span class="kwrd">new</span> KeyHandler(<span class="kwrd">this</span>);
    GenerateStarField(350);
    InitializeGame();
}

<span class="kwrd">void</span> InitializeGame()
{
    gameLoop = <span class="kwrd">new</span> GameLoop(<span class="kwrd">this</span>);
    gameLoop.Update &#43;= <span class="kwrd">new</span> GameLoop.UpdateHandler(gameLoop_Update);

    PlayerShip = <span class="kwrd">new</span> Ship(10, 10, <span class="kwrd">new</span> Point(100, 360));
    gameRoot.Children.Add(PlayerShip.SpriteCanvas);

    gameLoop.Start();
}

<span class="kwrd">void</span> gameLoop_Update(TimeSpan elapsed)
{
    <span class="rem">//clear the current vector so the sprite is not moving unless a keys is pressed</span>
    PlayerShip.Velocity = <span class="kwrd">new</span> Vector(0, 0);
    <span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Left))
    {
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(270, 125);
    }
    <span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Right))
    {
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(90, 125);
    }
    PlayerShip.Update(elapsed);
}</pre>
<p><b>VB </b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()
    InitializeComponent()
    keyHandler = <span class="kwrd">New</span> KeyHandler(<span class="kwrd">Me</span>)
    GenerateStarField(350)
    InitializeGame()
<span class="kwrd">End</span> <span class="kwrd">Sub</span>

<span class="kwrd">Private</span> <span class="kwrd">Sub</span> InitializeGame()
    gameLoop = <span class="kwrd">New</span> GameLoop(<span class="kwrd">Me</span>)
    <span class="kwrd">AddHandler</span> gameLoop.Update, <span class="kwrd">AddressOf</span> gameLoop_Update

    PlayerShip = <span class="kwrd">New</span> Ship(10, 10, <span class="kwrd">New</span> Point(100, 360))
    gameRoot.Children.Add(PlayerShip.SpriteCanvas)

    gameLoop.Start()
<span class="kwrd">End</span> <span class="kwrd">Sub</span>

<span class="kwrd">Private</span> <span class="kwrd">Sub</span> gameLoop_Update(<span class="kwrd">ByVal</span> elapsed <span class="kwrd">As</span> TimeSpan)
    <span class="rem">'clear the current vector so the sprite is not moving unless a keys is pressed </span>
    PlayerShip.Velocity = <span class="kwrd">New</span> Vector(0, 0)
    <span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Left) <span class="kwrd">Then</span>
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(270, 125)
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Right) <span class="kwrd">Then</span>
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(90, 125)
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    PlayerShip.Update(elapsed)
<span class="kwrd">End</span> Sub</pre>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_6.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_thumb_2.png" width="500" height="400"></a>
</p>
<p>Now we have a functioning game loop. Launch the app, click on the Silverlight control to give it focus, and you can now use the arrow keys to move our ship right and left. One problem however is that you are able to take the ship completely off the screen.
 To prevent this, we can add MinX and MaxX properties to our ship class and override the Update method it inherits from Sprite. Be sure to also add those min and max values after the Ship is instantiated in InitializeGame of our Page:
</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Ship : Sprite
{
    <span class="kwrd">public</span> <span class="kwrd">double</span> MaxX { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">double</span> MinX { get; set; }

    <span class="kwrd">public</span> Ship(<span class="kwrd">double</span> width, <span class="kwrd">double</span> height, Point firstPosition)
        : <span class="kwrd">base</span>(width, height, firstPosition)
    {

    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> Canvas RenderSpriteCanvas()
    {
        <span class="kwrd">return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Sprites.Ship.xaml&quot;</span>);
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Update(System.TimeSpan elapsedTime)
    {
        <span class="rem">//verify that this is a position we can move to</span>
        <span class="kwrd">if</span> (Position.X &gt; MaxX)
        {
            Position = <span class="kwrd">new</span> Point(MaxX, Position.Y);
            Velocity = <span class="kwrd">new</span> Vector(0, 0);
        }
        <span class="kwrd">if</span> (Position.X &lt; MinX)
        {
            Position = <span class="kwrd">new</span> Point(MinX, Position.Y);
            Velocity = <span class="kwrd">new</span> Vector(0, 0);
        }
        <span class="kwrd">base</span>.Update(elapsedTime);
    }
}</pre>
<b></b>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Ship
    <span class="kwrd">Inherits</span> Sprite
    <span class="kwrd">Private</span> _MaxX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MaxX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MaxX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MaxX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _MinX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MinX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MinX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MinX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> width <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> height <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> firstPosition <span class="kwrd">As</span> Point)
        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(width, height, firstPosition)

    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Function</span> RenderSpriteCanvas() <span class="kwrd">As</span> Canvas
        <span class="kwrd">Return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Ship.xaml&quot;</span>)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> elapsedTime <span class="kwrd">As</span> System.TimeSpan)
        <span class="rem">'verify that this is a position we can move to </span>
        <span class="kwrd">If</span> Position.X &gt; MaxX <span class="kwrd">Then</span>
            Position = <span class="kwrd">New</span> Point(MaxX, Position.Y)
            Velocity = <span class="kwrd">New</span> Vector(0, 0)
        <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">If</span> Position.X &lt; MinX <span class="kwrd">Then</span>
            Position = <span class="kwrd">New</span> Point(MinX, Position.Y)
            Velocity = <span class="kwrd">New</span> Vector(0, 0)
        <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">MyBase</span>.Update(elapsedTime)
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<h4>Prepare to Fire!</h4>
<p>We now have all the basic plumbing to add additional sprites such as aliens or projectiles. To begin, we will add additional classes inheriting from Sprite: Alien, Missle, and Bomb, along with Alien.xaml, Missle.xaml, and Bomb.xaml (these new .xaml files
 need to be set as Embedded Resources). These xaml files are just like our Ship.xaml with different sizes and colors. Make the Aliens and their bombs red, and shrink the bomb and missile height and width to 5. The xaml is very similar, but the classes themselves
 are going to have a few differing capabilities. Bomb and Missile are very similar. They only need to load their corresponding xaml. Here is our Bomb class for example:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Bomb : Sprite
{
    <span class="kwrd">public</span> <span class="kwrd">double</span> MaxX { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">double</span> MinX { get; set; }

    <span class="kwrd">public</span> Bomb(<span class="kwrd">double</span> width, <span class="kwrd">double</span> height, Point firstPosition)
        : <span class="kwrd">base</span>(width, height, firstPosition)
    {

    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> Canvas RenderSpriteCanvas()
    {
        <span class="kwrd">return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Sprites.Bomb.xaml&quot;</span>);
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Update(System.TimeSpan elapsedTime)
    {
        <span class="kwrd">base</span>.Update(elapsedTime);
    }
}</pre>
<b></b>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Bomb
    <span class="kwrd">Inherits</span> Sprite
    <span class="kwrd">Private</span> _MaxX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MaxX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MaxX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MaxX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _MinX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MinX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MinX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MinX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> width <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> height <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> firstPosition <span class="kwrd">As</span> Point)
        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(width, height, firstPosition)

    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Function</span> RenderSpriteCanvas() <span class="kwrd">As</span> Canvas
        <span class="kwrd">Return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Sprites.Bomb.xaml&quot;</span>)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> elapsedTime <span class="kwrd">As</span> System.TimeSpan)
        <span class="kwrd">MyBase</span>.Update(elapsedTime)
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<p>We now need to add an Alien class similar to our Ship class. These will both need a bit more capability. For one, we are going to have them both fire at each other. In the case of the Alien, it will be firing down, and it's monition of choice will be a bomb:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Alien : Sprite
{
    <span class="kwrd">public</span> <span class="kwrd">double</span> fireRateMilliseconds = 2000;
    <span class="kwrd">public</span> <span class="kwrd">double</span> fireVelocity = 250;
    <span class="kwrd">public</span> <span class="kwrd">double</span> wayPointMin;
    <span class="kwrd">public</span> <span class="kwrd">double</span> wayPointMax;
    <span class="kwrd">public</span> <span class="kwrd">double</span> speed = 100;
    <span class="kwrd">public</span> <span class="kwrd">bool</span> spawnWait;
    <span class="kwrd">public</span> DateTime spawnComplete;
    <span class="kwrd">public</span> <span class="kwrd">double</span> MaxX { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">double</span> MinX { get; set; }

    <span class="kwrd">public</span> Alien(<span class="kwrd">double</span> width, <span class="kwrd">double</span> height, Point firstPosition)
        : <span class="kwrd">base</span>(width, height, firstPosition)
    {

    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> CheckDirection()
    {
        <span class="kwrd">if</span> (Position.X &gt; wayPointMax)
        {
            Velocity = Vector.CreateVectorFromAngle(270, speed);
        }
        <span class="kwrd">if</span> (Position.X &lt; wayPointMin)
        {
            Velocity = Vector.CreateVectorFromAngle(90, speed);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> Canvas RenderSpriteCanvas()
    {
        <span class="kwrd">return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Sprites.Alien.xaml&quot;</span>);
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Update(TimeSpan elapsedTime)
    {
        CheckDirection();
        <span class="kwrd">base</span>.Update(elapsedTime);
    }

    <span class="kwrd">public</span> Bomb Fire()
    {
        Bomb bomb = <span class="kwrd">new</span> Bomb(5, 5, Position);
        bomb.Velocity = Vector.CreateVectorFromAngle(180, fireVelocity);
        <span class="kwrd">return</span> bomb;
    }
}</pre>
<b></b>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Alien
    <span class="kwrd">Inherits</span> Sprite
    <span class="kwrd">Public</span> fireRateMilliseconds <span class="kwrd">As</span> <span class="kwrd">Double</span> = 2000
    <span class="kwrd">Public</span> fireVelocity <span class="kwrd">As</span> <span class="kwrd">Double</span> = 250
    <span class="kwrd">Public</span> wayPointMin <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> wayPointMax <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> speed <span class="kwrd">As</span> <span class="kwrd">Double</span> = 100
    <span class="kwrd">Public</span> spawnWait <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Public</span> spawnComplete <span class="kwrd">As</span> DateTime
    <span class="kwrd">Private</span> _MaxX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MaxX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MaxX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MaxX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _MinX <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> MinX() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _MinX
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _MinX = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> width <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> height <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> firstPosition <span class="kwrd">As</span> Point)
        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(width, height, firstPosition)

    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> CheckDirection()
        <span class="kwrd">If</span> Position.X &gt; wayPointMax <span class="kwrd">Then</span>
            Velocity = Vector.CreateVectorFromAngle(270, speed)
        <span class="kwrd">End</span> <span class="kwrd">If</span>
        <span class="kwrd">If</span> Position.X &lt; wayPointMin <span class="kwrd">Then</span>
            Velocity = Vector.CreateVectorFromAngle(90, speed)
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Function</span> RenderSpriteCanvas() <span class="kwrd">As</span> Canvas
        <span class="kwrd">Return</span> LoadSpriteCanvas(<span class="str">&quot;SimpleShooter.Alien.xaml&quot;</span>)
    <span class="kwrd">End</span> <span class="kwrd">Function</span>

    <span class="kwrd">Public</span> <span class="kwrd">Overloads</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> elapsedTime <span class="kwrd">As</span> TimeSpan)
        CheckDirection()
        <span class="kwrd">MyBase</span>.Update(elapsedTime)
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>

    <span class="kwrd">Public</span> <span class="kwrd">Function</span> Fire() <span class="kwrd">As</span> Bomb
        <span class="kwrd">Dim</span> bomb <span class="kwrd">As</span> <span class="kwrd">New</span> Bomb(5, 5, Position)
        bomb.Velocity = Vector.CreateVectorFromAngle(180, fireVelocity)
        <span class="kwrd">Return</span> bomb
    <span class="kwrd">End</span> <span class="kwrd">Function</span>
<span class="kwrd">End</span> Class</pre>
<p>Now that we are going to add munitions to the game, we need to be able to know when these munitions collide with other sprites. To do this, we are going to add a collision detection method to our sprite class. As a form of simple collision detection, we
 will give each sprite a CollisionRadius from its center point. To keep it simple we will make the radius one half the width of our sprites. A vector created from these two points can then detect if the sum of those two radius is greater than the length of
 our vector. If it is, they have collided:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> Collides(Sprite s1, Sprite s2)
{
    Vector v = <span class="kwrd">new</span> Vector((s1.Position.X) - (s2.Position.X), (s1.Position.Y) - (s2.Position.Y));
    <span class="kwrd">if</span> (s1.CollisionRadius &#43; s2.CollisionRadius &gt; v.Length)
    {
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    }
    <span class="kwrd">else</span>
    {
        <span class="kwrd">return</span> <span class="kwrd">false</span>;
    }
}</pre>
<b></b>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> Collides(<span class="kwrd">ByVal</span> s1 <span class="kwrd">As</span> Sprite, <span class="kwrd">ByVal</span> s2 <span class="kwrd">As</span> Sprite) <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Dim</span> v <span class="kwrd">As</span> <span class="kwrd">New</span> Vector((s1.Position.X) - (s2.Position.X), (s1.Position.Y) - (s2.Position.Y))
    <span class="kwrd">If</span> s1.CollisionRadius &#43; s2.CollisionRadius &gt; v.Length <span class="kwrd">Then</span>
        <span class="kwrd">Return</span> <span class="kwrd">True</span>
    <span class="kwrd">Else</span>
        <span class="kwrd">Return</span> <span class="kwrd">False</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Function</pre>
<p>We are now ready to extend our game loop of our Page to do more than track the movement of our Ship. We begin by taking action on more than just the arrow keys. We will wire up the space bar for shooting. Lets add an enumeration to track the state of our
 game. We will also add a supporting class that will handle the firing of munitions and adding those to our game. We will keep this simple for now, but it is an obvious place to being extending this code to take advantage of things like partial classes that
 could contain functionality like our 'Fire' method:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">enum</span> GameState
{
    Ready = 0,
    Running = 1,
    Paused = 2,
    BetweenWaves = 3,
    GameOver = 4
}

<span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Space))
{
    <span class="kwrd">switch</span> (status)
    {
        <span class="kwrd">case</span> GameState.Ready:
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> GameState.Running:
            EntityFired(PlayerShip);
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> GameState.Paused:
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> GameState.BetweenWaves:
            status = GameState.Running;
            ctlInfo.GameInfo = <span class="str">&quot;&quot;</span>;
            StartWave();
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> GameState.GameOver:
            <span class="kwrd">break</span>;
        <span class="kwrd">default</span>:
            <span class="kwrd">break</span>;
    }
}

<span class="kwrd">void</span> EntityFired(Sprite shooter)
{
    Debug.WriteLine(shooter);
    <span class="kwrd">switch</span> (shooter.ToString())
    {
        <span class="kwrd">case</span> <span class="str">&quot;SimpleShooter.Ship&quot;</span>:
            <span class="kwrd">if</span> (missles.Count == 0)
            {
                Missle missle = ((Ship)shooter).Fire();
                missles.Add(missle);
                gameRoot.Children.Add(missle.SpriteCanvas);

            }
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> <span class="str">&quot;SimpleShooter.Alien&quot;</span>:
            Bomb bomb = ((Alien)shooter).Fire();
            bombs.Add(bomb);
            gameRoot.Children.Add(bomb.SpriteCanvas);
            <span class="kwrd">break</span>;
        <span class="kwrd">default</span>:
            <span class="kwrd">break</span>;
    }
}</pre>
<b></b>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Enum</span> GameState
    Ready = 0
    Running = 1
    Paused = 2
    BetweenWaves = 3
    GameOver = 4
<span class="kwrd">End</span> <span class="kwrd">Enum</span>

<span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Space) <span class="kwrd">Then</span>
    <span class="kwrd">Select</span> <span class="kwrd">Case</span> status
        <span class="kwrd">Case</span> GameState.Ready
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> GameState.Running
            EntityFired(PlayerShip)
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> GameState.Paused
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> GameState.BetweenWaves
            status = GameState.Running
            ctlInfo.GameInfo = <span class="str">&quot;&quot;</span>
            StartWave()
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> GameState.GameOver
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> <span class="kwrd">Else</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
    <span class="kwrd">End</span> <span class="kwrd">Select</span>
<span class="kwrd">End</span> <span class="kwrd">If</span>

<span class="kwrd">Private</span> <span class="kwrd">Sub</span> EntityFired(<span class="kwrd">ByVal</span> shooter <span class="kwrd">As</span> Sprite)
    Debug.WriteLine(shooter)
    <span class="kwrd">Select</span> <span class="kwrd">Case</span> shooter.ToString()
        <span class="kwrd">Case</span> <span class="str">&quot;SimpleShooter.Ship&quot;</span>
            <span class="kwrd">If</span> missles.Count = 0 <span class="kwrd">Then</span>
                <span class="kwrd">Dim</span> missle <span class="kwrd">As</span> Missle = <span class="kwrd">DirectCast</span>(shooter, Ship).Fire()
                missles.Add(missle)

                gameRoot.Children.Add(missle.SpriteCanvas)
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> <span class="str">&quot;SimpleShooter.Alien&quot;</span>
            <span class="kwrd">Dim</span> bomb <span class="kwrd">As</span> Bomb = <span class="kwrd">DirectCast</span>(shooter, Alien).Fire()
            bombs.Add(bomb)
            gameRoot.Children.Add(bomb.SpriteCanvas)
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">Case</span> <span class="kwrd">Else</span>
            <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
    <span class="kwrd">End</span> <span class="kwrd">Select</span>
<span class="kwrd">End</span> Sub</pre>
<p>To make it easier to track the state of our game, let's add public properties to our controls and let them be the keepers of those game states. For instance, give the ReamainingLives control a Lives property, and have the setter of that property also update
 the TextBlock on the control to show the user how many lives are left. Perform a similar task for the other three controls:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> RemainingLives : UserControl
{
    <span class="kwrd">private</span> <span class="kwrd">int</span> _lives;
    <span class="kwrd">public</span> <span class="kwrd">int</span> Lives
    {
        get { <span class="kwrd">return</span> _lives; }
        set
        {
            _lives = <span class="kwrd">value</span>;
            <span class="kwrd">string</span> livesString = <span class="kwrd">string</span>.Empty;
            <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; _lives - 1; i&#43;&#43;)
            {
                livesString = <span class="kwrd">string</span>.Format(<span class="str">&quot;{0}{1}&quot;</span>, livesString, <span class="str">&quot;A&quot;</span>);
            }
            txtRemainingLives.Text = livesString;
        }
    }

    <span class="kwrd">public</span> RemainingLives()
    {
        InitializeComponent();
    }
}</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode">Partial <span class="kwrd">Public</span> <span class="kwrd">Class</span> RemainingLives
    <span class="kwrd">Inherits</span> UserControl
    <span class="kwrd">Private</span> _lives <span class="kwrd">As</span> <span class="kwrd">Integer</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Lives() <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _lives
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
            _lives = value
            <span class="kwrd">Dim</span> livesString <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty
            <span class="kwrd">For</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0 <span class="kwrd">To</span> _lives - 2
                livesString = <span class="kwrd">String</span>.Format(<span class="str">&quot;{0}{1}&quot;</span>, livesString, <span class="str">&quot;A&quot;</span>)
            <span class="kwrd">Next</span>
            txtRemainingLives.Text = livesString
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>

    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()
        InitializeComponent()
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<p>Now we have a number of other things to add to our page class. We are going to have lots of entities to deal with in our game loop. We will have a ship, x number of Aliens, x number of Bombs, and at some points we will have our Missiles, though we restricted
 that to one at a time in our EntityFired method. We need to, in each game loop check if any missile hits any alien or leaves the game map, if any bomb hits our ship or leaves the game map, and if it is time for a Alien to fire at the ship. Our Page already
 has a property for our Ship, but the Aliens, Bombs, Missiles need to be collections. When we begin to loop through our Bombs for instance, we will want to remove a bomb if it strikes a Ship or leaves the game map. Since we are going to be iterating these collections,
 we cannot subtract from those collections as we are looping through them. There are a number of approaches for this, but to keep it simple, we will add a corresponding collection for each of our Bomb, Alien, and Missile collections to track the ones that need
 to be removed and removed from our game canvas. With this approach, our game loop can add to the &quot;remove these&quot; collection, and then take action on them when we leave the main loop for the parent collection:</p>
<p><b>C#</b></p>
<pre class="csharpcode">List&lt;Alien&gt; aliens;
List&lt;Alien&gt; aliensRemove;
List&lt;Alien&gt; alienShooters;
List&lt;Bomb&gt; bombs;
List&lt;Bomb&gt; bombsRemove;
List&lt;Missle&gt; missles;
List&lt;Missle&gt; misslesRemove;</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> aliens <span class="kwrd">As</span> List(Of Alien)
<span class="kwrd">Private</span> aliensRemove <span class="kwrd">As</span> List(Of Alien)
<span class="kwrd">Private</span> alienShooters <span class="kwrd">As</span> List(Of Alien)
<span class="kwrd">Private</span> bombs <span class="kwrd">As</span> List(Of Bomb)
<span class="kwrd">Private</span> bombsRemove <span class="kwrd">As</span> List(Of Bomb)
<span class="kwrd">Private</span> missles <span class="kwrd">As</span> List(Of Missle)
<span class="kwrd">Private</span> misslesRemove <span class="kwrd">As</span> List(Of Missle)</pre>
<p>We also want to add a class to our page that can track the waves of aliens we are going to send one at a time. In addition, we can add a collection to hold these waves. Each wave will track the number of aliens that spawn at once, the total number of aliens
 faced in the wave, how many aliens get to drop bombs, and how frequently they can fire.</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> WaveData
{
    <span class="kwrd">public</span> WaveData(<span class="kwrd">int</span> count, <span class="kwrd">double</span> fireRate, <span class="kwrd">int</span> atOnce, <span class="kwrd">int</span> fireatonce)
    {
        EnemyCount = count;
        fireRateMilliseconds = fireRate;
        enemiesAtOnce = atOnce;
        fireAtOnce = fireatonce;
        waveEmpty = <span class="kwrd">false</span>;
    }
    <span class="kwrd">public</span> <span class="kwrd">int</span> EnemyCount { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">double</span> fireRateMilliseconds { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">int</span> enemiesAtOnce { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">int</span> fireAtOnce { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">bool</span> waveEmpty { get; set; }
}</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> WaveData
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> count <span class="kwrd">As</span> <span class="kwrd">Integer</span>, <span class="kwrd">ByVal</span> fireRate <span class="kwrd">As</span> <span class="kwrd">Double</span>, <span class="kwrd">ByVal</span> atOnce <span class="kwrd">As</span> <span class="kwrd">Integer</span>, <span class="kwrd">ByVal</span> fireatonce__1 <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
        EnemyCount = count
        fireRateMilliseconds = fireRate
        enemiesAtOnce = atOnce
        fireAtOnce = fireatonce__1
        waveEmpty = <span class="kwrd">False</span>
    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
    <span class="kwrd">Private</span> _EnemyCount <span class="kwrd">As</span> <span class="kwrd">Integer</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> EnemyCount() <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _EnemyCount
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
            _EnemyCount = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _fireRateMilliseconds <span class="kwrd">As</span> <span class="kwrd">Double</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> fireRateMilliseconds() <span class="kwrd">As</span> <span class="kwrd">Double</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _fireRateMilliseconds
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Double</span>)
            _fireRateMilliseconds = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _enemiesAtOnce <span class="kwrd">As</span> <span class="kwrd">Integer</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> enemiesAtOnce() <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _enemiesAtOnce
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
            _enemiesAtOnce = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _fireAtOnce <span class="kwrd">As</span> <span class="kwrd">Integer</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> fireAtOnce() <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _fireAtOnce
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Integer</span>)
            _fireAtOnce = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
    <span class="kwrd">Private</span> _waveEmpty <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> waveEmpty() <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
        <span class="kwrd">Get</span>
            <span class="kwrd">Return</span> _waveEmpty
        <span class="kwrd">End</span> <span class="kwrd">Get</span>
        <span class="kwrd">Set</span>(<span class="kwrd">ByVal</span> value <span class="kwrd">As</span> <span class="kwrd">Boolean</span>)
            _waveEmpty = value
        <span class="kwrd">End</span> <span class="kwrd">Set</span>
    <span class="kwrd">End</span> <span class="kwrd">Property</span>
<span class="kwrd">End</span> Class</pre>
<p>We will need to setup an initialization method for our game, to setup all our collections for sprites, and add progressively difficult waves to our game. The meat of it all now lies in our game loop. For each collection of sprites we call methods that will
 iterate over its contents and make decisions based on collisions, locations of the sprites. After a loop on each main collection, we can use the 'remove us' collection to clear items from the main collection, remove their canvas from our game canvas, and delete
 them from the main collection. Finally, we check to see if enough time has elapsed to let the aliens drop another bomb:</p>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">void</span> gameLoop_Update(TimeSpan elapsed)
{
    <span class="rem">//clear the current Vector so the sprite is not moving unless a keys is pressed</span>
    PlayerShip.Velocity = <span class="kwrd">new</span> Vector(0, 0);
    <span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Left))
    {
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(270, 125);
    }
    <span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Right))
    {
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(90, 125);
    }
    <span class="kwrd">if</span> (keyHandler.IsKeyPressed(Key.Space))
    {
        <span class="kwrd">switch</span> (status)
        {
            <span class="kwrd">case</span> GameState.Ready:
                <span class="kwrd">break</span>;
            <span class="kwrd">case</span> GameState.Running:
                EntityFired(PlayerShip);
                <span class="kwrd">break</span>;
            <span class="kwrd">case</span> GameState.Paused:
                <span class="kwrd">break</span>;
            <span class="kwrd">case</span> GameState.BetweenWaves:
                status = GameState.Running;
                ctlInfo.GameInfo = <span class="str">&quot;&quot;</span>;
                StartWave();
                <span class="kwrd">break</span>;
            <span class="kwrd">case</span> GameState.GameOver:
                <span class="kwrd">break</span>;
            <span class="kwrd">default</span>:
                <span class="kwrd">break</span>;
        }
    }
    PlayerShip.Update(elapsed);

    BombLoop(elapsed);
    MissleLoop(elapsed);
    AlienLoop(elapsed);

    <span class="kwrd">foreach</span> (Alien alien <span class="kwrd">in</span> aliensRemove)
    {
        aliens.Remove(alien);
        gameRoot.Children.Remove(alien.SpriteCanvas);
        AlienShot(alien);
    }
    aliensRemove.Clear();

    <span class="kwrd">foreach</span> (Missle missle <span class="kwrd">in</span> misslesRemove)
    {
        missles.Remove(missle);
        gameRoot.Children.Remove(missle.SpriteCanvas);
    }
    misslesRemove.Clear();

    <span class="kwrd">if</span> (nextShot &lt;= DateTime.Now)
    {
        nextShot = DateTime.Now.AddMilliseconds(enemyShootMilliseonds).AddMilliseconds(elapsed.Milliseconds * -1);

        shotsThisPass = shotsAtOnce;
        <span class="kwrd">if</span> (shotsThisPass &gt; aliens.Count)
        {
            shotsThisPass = aliens.Count;
        }

        <span class="kwrd">if</span> (aliens.Count &gt; 0)
        {
            <span class="kwrd">foreach</span> (Alien alien <span class="kwrd">in</span> aliens)
            {
                alienShooters.Add(alien);
            }
        }

        <span class="kwrd">while</span> (alienShooters.Count &gt; shotsThisPass)
        {
            alienShooters.RemoveAt(GetRandInt(0, alienShooters.Count - 1));
        }

        <span class="kwrd">foreach</span> (Alien alien <span class="kwrd">in</span> alienShooters)
        {
            EntityFired(alien);
        }

        alienShooters.Clear();
    }
}</pre>
<p><b>VB <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> gameLoop_Update(<span class="kwrd">ByVal</span> elapsed <span class="kwrd">As</span> TimeSpan)
    <span class="rem">'clear the current Vector so the sprite is not moving unless a keys is pressed </span>
    PlayerShip.Velocity = <span class="kwrd">New</span> Vector(0, 0)
    <span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Left) <span class="kwrd">Then</span>
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(270, 125)
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Right) <span class="kwrd">Then</span>
        PlayerShip.Velocity = Vector.CreateVectorFromAngle(90, 125)
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">If</span> keyHandler.IsKeyPressed(Key.Space) <span class="kwrd">Then</span>
        <span class="kwrd">Select</span> <span class="kwrd">Case</span> status
            <span class="kwrd">Case</span> GameState.Ready
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
            <span class="kwrd">Case</span> GameState.Running
                EntityFired(PlayerShip)
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
            <span class="kwrd">Case</span> GameState.Paused
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
            <span class="kwrd">Case</span> GameState.BetweenWaves
                status = GameState.Running
                ctlInfo.GameInfo = <span class="str">&quot;&quot;</span>
                StartWave()
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
            <span class="kwrd">Case</span> GameState.GameOver
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
            <span class="kwrd">Case</span> <span class="kwrd">Else</span>
                <span class="kwrd">Exit</span> <span class="kwrd">Select</span>
        <span class="kwrd">End</span> <span class="kwrd">Select</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>
    PlayerShip.Update(elapsed)

    BombLoop(elapsed)
    MissleLoop(elapsed)
    AlienLoop(elapsed)

    <span class="kwrd">For</span> <span class="kwrd">Each</span> alien <span class="kwrd">As</span> Alien <span class="kwrd">In</span> aliensRemove
        aliens.Remove(alien)
        gameRoot.Children.Remove(alien.SpriteCanvas)
        AlienShot(alien)
    <span class="kwrd">Next</span>
    aliensRemove.Clear()

    <span class="kwrd">For</span> <span class="kwrd">Each</span> missle <span class="kwrd">As</span> Missle <span class="kwrd">In</span> misslesRemove
        missles.Remove(missle)
        gameRoot.Children.Remove(missle.SpriteCanvas)
    <span class="kwrd">Next</span>
    misslesRemove.Clear()

    <span class="kwrd">If</span> nextShot &lt;= DateTime.Now <span class="kwrd">Then</span>
        nextShot = DateTime.Now.AddMilliseconds(enemyShootMilliseonds).AddMilliseconds(elapsed.Milliseconds * -1)

        shotsThisPass = shotsAtOnce
        <span class="kwrd">If</span> shotsThisPass &gt; aliens.Count <span class="kwrd">Then</span>
            shotsThisPass = aliens.Count
        <span class="kwrd">End</span> <span class="kwrd">If</span>

        <span class="kwrd">If</span> aliens.Count &gt; 0 <span class="kwrd">Then</span>
            <span class="kwrd">For</span> <span class="kwrd">Each</span> alien <span class="kwrd">As</span> Alien <span class="kwrd">In</span> aliens
                alienShooters.Add(alien)
            <span class="kwrd">Next</span>
        <span class="kwrd">End</span> <span class="kwrd">If</span>

        <span class="kwrd">While</span> alienShooters.Count &gt; shotsThisPass
            alienShooters.RemoveAt(GetRandInt(0, alienShooters.Count - 1))
        <span class="kwrd">End</span> <span class="kwrd">While</span>

        <span class="kwrd">For</span> <span class="kwrd">Each</span> alien <span class="kwrd">As</span> Alien <span class="kwrd">In</span> alienShooters
            EntityFired(alien)
        <span class="kwrd">Next</span>

        alienShooters.Clear()
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> <span class="kwrd">Sub</span></pre>
<p>Now we can almost call it a game:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_8.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_thumb_3.png" width="500" height="402"></a>
</p>
<p>Taking it one step further, I jumped into Expression Blend to create a bit more interesting XAML that our sprites are loading into their SpriteCanvas. This XAML can be found in the full download of the source code. The results make our game just a tad bit
 more interesting:</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_10.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9658490/image_thumb_4.png" width="500" height="400"></a>
</p>
<h3>Conclusion</h3>
<p>Silverlight provides a number of capabilities to enable robust game development. It should be noted that in this game, we are only scratching the surface. The core of this example used a game loop to position sprites on a canvas. Additional capabilities
 within Silverlight such as <a href="http://blogs.msdn.com/silverlight_sdk/archive/2008/03/21/silverlight-animations-a-walkthrough.aspx">
animations</a>, <a href="http://silverlight.net/blogs/msnow/archive/2008/10/02/silverlight-tip-of-the-day-55-how-to-apply-styles-in-silverlight-part-i.aspx">
styling</a>, <a href="http://timheuer.com/blog/archive/2008/10/06/silverlight-control-template-gallery-styles.aspx">
templating</a>, and <a href="http://timheuer.com/blog/archive/2008/06/04/silverlight-introduces-visual-state-manager-vsm.aspx">
visual states</a> provide even more ways to push the limits of browser based games. If you are at all like me, dabbling with game development is a great way to get your feet wet with Silverlight and learn some basics. Happy coding!</p>
<p>If you want to try this out, the download link for the source code is at the top of the article!</p>
<h3>About The Author</h3>
<p>Roger Guess is the Director of IT for The Wedge Group where he works with technologies such as Silverlight and WPF. He writes games in his spare time, and blogs at
<a href="http://silverlightaddict.com/blogs/">SilverlightAddict.com</a>. He can be reached via email at
<a href="mailto:email@rogerguess.net">email@rogerguess.net</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:f629d3120e354487b9a29e7600cbbe75">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Creating-Games-with-Silverlight-A-Simple-Shooter</comments>
      <itunes:summary>
This
 article will take you through some of the steps to creating the basics for writing games with Silverlight. This is a simple shooter style game that contains some of the building blocks for games that require abilities such as vectors, collision detection,
 a game loop, movement, and keyboard input. Please refer to the full source code for this project for any areas of the code that are not covered in detail in this article. 

Inspiration
There are a number of examples and tutorials out there to help get started creating games. You will find the basics of this game to be very similar to a Visual C# Coding4Fun article
here. This article will show you how to create a shooter style game in Silverlight. My first Silverlight game experience was playing with a Asteroids style game by Bill Reiss. My
 usage of vectors and how to do a game loop came from great examples like his and others. There are a number of sites and blogs where you can get good info on game development with Silverlight. Here are just a few. 

BlueRoseGames.com Farseer Games Cameron Albert Mike Snow 
Basic Layout
To begin, Open Visual Studio and create a new Silverlight Application in either C# or VB.net. First, we will start with the layout of the screen. First, I added a canvas to the grid inside the Page.xaml that is created for you. I set it&#39;s background to black,
 and named it &#39;gameRoot&#39;.  
&amp;lt;UserControl x:Class=&amp;quot;SimpleShooter.Page&amp;quot;
    xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot; 
    xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot; 
    Width=&amp;quot;400&amp;quot; Height=&amp;quot;300&amp;quot;&amp;gt;
   &amp;lt;Grid x:Name=&amp;quot;LayoutRoot&amp;quot;&amp;gt;
        &amp;lt;Canvas x:Name=&amp;quot;gameRoot&amp;quot; Width=&amp;quot;500&amp;quot; Height=&amp;quot;400&amp;quot; Background=&amp;quot;Black&amp;quot; &amp;gt;
        &amp;lt;/Canvas&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/UserControl&amp;gt;



Next we will start adding controls to our project for things like game entities, and information displays. In this ex</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Creating-Games-with-Silverlight-A-Simple-Shooter</link>
      <pubDate>Tue, 21 Jul 2009 14:19:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Creating-Games-with-Silverlight-A-Simple-Shooter</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9658490_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9658490_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Roger Guess </dc:creator>
      <itunes:author>Roger Guess </itunes:author>
      <slash:comments>13</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Creating-Games-with-Silverlight-A-Simple-Shooter/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Gaming</category>
      <category>Silverlight</category>
      <category>Web</category>
    </item>
  <item>
      <title>This Week C9: Speech Recognition, Army of 1, TweetCraft and more</title>
      <description><![CDATA[This week on Channel 9, Dan and&nbsp;Brian discuss the week's top developer news, including:<br>
<br>
&nbsp;- Joel Bennett - Control <a shape="rect" href="http://huddledmasses.org/control-your-pc-with-your-voice-and-powershell/" shape="rect">
your PC with your voice and PowerShell</a>, via <a shape="rect" href="http://www.alvinashcraft.com/2009/06/25/dew-drop-june-25-2009/" shape="rect">
Alvin Ashcraft</a><br>
- Frank La Vigne - <a shape="rect" href="http://franksworld.com/blog/archive/2009/06/30/11617.aspx" shape="rect">
Speech Recognition in WPF</a><br>
- Dan Waters - Great <a shape="rect" href="http://blogs.msdn.com/dawate/archive/2009/06/22/intro-to-audio-programming-part-1-how-audio-data-is-represented.aspx" shape="rect">
4-part series on Audio Programming</a><br>
- Andrew Woodward - <a shape="rect" href="http://www.21apps.com/agile/doing-agile-in-a-team-of-one-day2/" shape="rect">
Doing Agile in a Team of One</a><br>
- Leah Budley - <a shape="rect" href="http://franksworld.com/blog/archive/2009/06/29/11615.aspx" shape="rect">
UX Team of One</a>, via Frank La Vigne<br>
- Aaron Marten - <a shape="rect" href="http://code.msdn.microsoft.com/VS2010UX/Release/ProjectReleases.aspx?ReleaseId=2743" shape="rect">
Visual Studio 2010 User Interface Guidelines</a><br>
- Corey Schuman - <a shape="rect" href="http://www.85turns.com/2009/06/28/youtube-video-in-silverlight-3/" shape="rect">
YouTube video in Silverlight 3</a>, via Alvin Ashcraft<br>
- Tina Wood - <a shape="rect" href="http://channel9.msdn.com/shows/History/The-History-of-Microsoft-1995/" shape="rect">
The History of Microsoft 1995</a><br>
- Jaime Rodriguez&nbsp;- Best questions/answers in the&nbsp;<a shape="rect" href="http://blogs.msdn.com/jaimer/archive/2009/06/29/wpf-discussions-090626.aspx" shape="rect">WPF Discussions email</a> alias<br>
- <a shape="rect" href="http://ajaxian.com/archives/myspace-open-sources-advanced-browser-performance-tool-for-ie" shape="rect">
MySpace Releases MSFast</a>, a browser plugin for measuring CPU, memory, screenshost, HTML rendering, and more (<a shape="rect" href="http://msfast.myspace.com/" shape="rect">download</a>)<br>
- Registering Preview Pane types using <a shape="rect" href="http://www.winhelponline.com/blog/previewconfig-tool-registers-file-types-for-the-preview-pane-in-windows-vista/" shape="rect">
PreviewConfig</a>, via <a shape="rect" href="http://coolthingoftheday.blogspot.com/2009/06/easily-add-files-to-vistas-and-win7s.html" shape="rect">
Greg Duncan</a><br>
- Alois Kraus - The <a shape="rect" href="http://geekswithblogs.net/akraus1/archive/2009/06/21/132968.aspx" shape="rect">
differences between Logging and Tracing</a><br>
<br>
<strong>Picks of the week</strong><br>
Brian's pick of the week:&nbsp;Habib Heydarian - <a shape="rect" href="http://blogs.msdn.com/habibh/archive/2009/06/18/an-in-depth-look-at-the-historical-debugger-in-visual-studio-2010-part-v.aspx" shape="rect">
Debugging a Unit Test Failure with the Historical Debugger</a><br>
Dan's pick of the week:&nbsp;<a shape="rect" href="http://ch9.ms/tweetcraft" shape="rect">TweetCraft</a> an in-game World of Warcraft Twitter client, including a gratuitous video trailer<br>
<br>
PS - Happy fourth of July to our American viewers  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:dfd3b70bee574d2aa5d59dea00c49f70">]]></description>
      <comments>http://channel9.msdn.com/Shows/This+Week+On+Channel+9/This-Week-C9-Speech-Recognition-Army-of-1-TweetCraft-and-more</comments>
      <itunes:summary>This week on Channel 9, Dan and&amp;nbsp;Brian discuss the week&#39;s top developer news, including:

&amp;nbsp;- Joel Bennett - Control 
your PC with your voice and PowerShell, via 
Alvin Ashcraft
- Frank La Vigne - 
Speech Recognition in WPF
- Dan Waters - Great 
4-part series on Audio Programming
- Andrew Woodward - 
Doing Agile in a Team of One
- Leah Budley - 
UX Team of One, via Frank La Vigne
- Aaron Marten - 
Visual Studio 2010 User Interface Guidelines
- Corey Schuman - 
YouTube video in Silverlight 3, via Alvin Ashcraft
- Tina Wood - 
The History of Microsoft 1995
- Jaime Rodriguez&amp;nbsp;- Best questions/answers in the&amp;nbsp;WPF Discussions email alias
- 
MySpace Releases MSFast, a browser plugin for measuring CPU, memory, screenshost, HTML rendering, and more (download)
- Registering Preview Pane types using 
PreviewConfig, via 
Greg Duncan
- Alois Kraus - The 
differences between Logging and Tracing

Picks of the week
Brian&#39;s pick of the week:&amp;nbsp;Habib Heydarian - 
Debugging a Unit Test Failure with the Historical Debugger
Dan&#39;s pick of the week:&amp;nbsp;TweetCraft an in-game World of Warcraft Twitter client, including a gratuitous video trailer

PS - Happy fourth of July to our American viewers </itunes:summary>
      <itunes:duration>1217</itunes:duration>
      <link>http://channel9.msdn.com/Shows/This+Week+On+Channel+9/This-Week-C9-Speech-Recognition-Army-of-1-TweetCraft-and-more</link>
      <pubDate>Fri, 03 Jul 2009 21:26:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/This+Week+On+Channel+9/This-Week-C9-Speech-Recognition-Army-of-1-TweetCraft-and-more</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/476365_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/476365_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_large_ch9.png" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_small_ch9.png" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_2MB_ch9.wmv" expression="full" duration="1217" fileSize="369046320" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_ch9.mp3" expression="full" duration="1217" fileSize="9744829" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_ch9.mp4" expression="full" duration="1217" fileSize="90647145" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_ch9.wma" expression="full" duration="1217" fileSize="19705221" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_ch9.wmv" expression="full" duration="1217" fileSize="172108745" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_Zune_ch9.wmv" expression="full" duration="1217" fileSize="123900725" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_s_ch9.wmv" expression="full" duration="1217" fileSize="211" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/5/6/3/6/7/4/ThisWeekC9July3_ch9.wmv" length="172108745" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Dan Fernandez</dc:creator>
      <itunes:author>Dan Fernandez</itunes:author>
      <slash:comments>8</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/This+Week+On+Channel+9/This-Week-C9-Speech-Recognition-Army-of-1-TweetCraft-and-more/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Coding4Fun</category>
      <category>Speech</category>
      <category>Speech API</category>
      <category>WPF</category>
    </item>
  <item>
      <title>Creating audio signals in .Net</title>
      <description><![CDATA[
<p><a href="http://blogs.msdn.com/dawate/"></a><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9807450/whiteNoise_2.png"><img title="whiteNoise" border="0" alt="whiteNoise" align="right" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9807450/whiteNoise_thumb.png" width="250" height="52"></a>Dan
 Waters has created a 4 part series on audio programming with .Net.&nbsp;&nbsp; Some point in the future, he'll be posting a full article with WPF on Coding4Fun as well!</p>
<ol>
<li><a href="http://blogs.msdn.com/dawate/archive/2009/06/22/intro-to-audio-programming-part-1-how-audio-data-is-represented.aspx">How Audio Data is Represented</a>
</li><li><a href="http://blogs.msdn.com/dawate/archive/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format.aspx">Demystifying the WAV Format</a>
</li><li><a href="http://blogs.msdn.com/dawate/archive/2009/06/24/intro-to-audio-programming-part-3-synthesizing-simple-wave-audio-using-c.aspx">Synthesizing Simple Wave Audio using C#</a>
</li><li><a href="http://blogs.msdn.com/dawate/archive/2009/06/25/intro-to-audio-programming-part-4-algorithms-for-different-sound-waves-in-c.aspx">Algorithms for Different Sound Waves in C#</a>
</li></ol>
<p>Dan goes into depth on how audio is represented, explains how the WAV format works then creates different audio waves like the sawtooth, square and sine wave.&nbsp; He gives the equation then an implementation with c#.&nbsp; With part 3 and 4, Dan provides full source
 code so you too can rock out with some audio dial tones.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e3371c64b26a49fa81f09e7600cc2465">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/Creating-audio-signals-in-Net</comments>
      <itunes:summary>
Dan
 Waters has created a 4 part series on audio programming with .Net.&amp;nbsp;&amp;nbsp; Some point in the future, he&#39;ll be posting a full article with WPF on Coding4Fun as well! 

How Audio Data is Represented
Demystifying the WAV Format
Synthesizing Simple Wave Audio using C#
Algorithms for Different Sound Waves in C#

Dan goes into depth on how audio is represented, explains how the WAV format works then creates different audio waves like the sawtooth, square and sine wave.&amp;nbsp; He gives the equation then an implementation with c#.&amp;nbsp; With part 3 and 4, Dan provides full source
 code so you too can rock out with some audio dial tones. 
</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/Creating-audio-signals-in-Net</link>
      <pubDate>Sun, 28 Jun 2009 12:19:41 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/Creating-audio-signals-in-Net</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9807450_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9807450_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/Creating-audio-signals-in-Net/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>C4FNews</category>
    </item>
  <item>
      <title>Adding Sidetone to Skype</title>
      <description><![CDATA[
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image001_2.jpg"><img title="clip_image001" border="0" alt="clip_image001" align="right" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image001_thumb.jpg" width="240" height="91"></a>Ever
 use a headset with Skype – and were frustrated that it was <i>too</i> quiet? This article shows how to add the sound of your own voice to the headset and not feel exhausted from shouting to be heard.</p>

<h3>Skype: I find your lack of feedback disturbing.</h3>
<p>This article will discuss how to build a software tool that makes it easier to talk into Skype with a headset.</p>
<p>Recently my family began experimenting with Skype, but we found that talking over Skype can be exhausting with headphones. After doing a little research, I learned that the problem was that we only heard the other party. You'd think that this is a good thing,
 but we have a social brain that works hard to gauge our behavior and adjust.</p>
<p>The answer is to feed a little bit of the microphone back into the earpiece, so that our brain knows how loud we're talking. This is called
<i>side tone</i> in the telecommunication industry. Without it, we talk louder and louder until we're sure that we'll be heard.</p>
<p>I couldn't find a Skype plug-in to do this… but I had just read a <a href="http://blogs.msdn.com/coding4fun/archive/2009/02/02/9391048.aspx">
Coding4Fun article, by Mark Heath, about adding audio effects to Skype</a>. I decided I was going to write a tool to add this feedback.</p>
<h4>How to use the tool</h4>
<p>First, let's take a look at how to use the application. Once it is running, there will be a microphone icon in the lower right hand corner of the screen:</p>
<p>Figure 1: Icon in the system notification tray</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image004_2.jpg"><img title="clip_image004" border="0" alt="clip_image004" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image004_thumb.jpg" width="160" height="53"></a></p>
<p>Clicking on it, will get the application control window:</p>
<p>Figure 2: The application's controls</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image006_2.jpg"><img title="clip_image006" border="0" alt="clip_image006" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9583391/clip_image006_thumb.jpg" width="447" height="333"></a></p>
<p>Let's look at the side tone controls:</p>
<ul>
<li>The “Side Tones” check box enables or disables the side tone. If you have headphones, you'll want this on; if you have loud speakers, you'll want it off.
</li><li>The slider controls the volume of the microphone in the headset. You can change it while talking. The volume will vary with microphone and headset.
</li></ul>
<p>You can do a “sound check” to see if the feedback is working by clicking on the Sound Check button, and adjusting the volume. I found that the volume setting that works best in a conversation is much, much lower than what works in a sound check.</p>
<p>Next, let's look at the AGC (“Automatic Gain Control”) section. When making a call, the software can automatically adjust how loud you sound to the other party:</p>
<ul>
<li>When “Low Pass” is checked, the headphone feedback is at 44100 samples/sec. The microphone sound is filtered to keep only the sounds below 8 Khz, converted to 16000/samples per second and sent to Skype. When it is not checked, headphone feedback is at 16000
 samples/sec, and sent to Skype without the low pass filter. </li><li>When &quot;Skype AutoGain&quot; is checked, it signals to Skype that Skype can use its own algorithm. When clear, Skype is told not to apply any adjustments.
</li><li>When &quot;AutoGain&quot; is checked, the custom Automatic Gain Control algorithm is used.
</li></ul>
<p>The Automatic Gain Control has three sliders:</p>
<ul>
<li>The “Cutoff” slider controls the distinction between background noise and conversation. Sound below this level is cutoff and silence is sent to Skype. This will vary with microphone – more sensitive (expensive) microphones will pick more background noise
 and be better with a higher setting. </li><li>The “Normal” slider controls the volume when you are talking normally. The Gain Control tries to raise the volume to this level.
</li><li>The “Loud” slider controls the volume when you talk exceptionally loud. This rarely happens, but when you
<i>do</i> talk louder than the Normal level, the Gain Control tries to adjust the volume to this level.
</li></ul>
<h3>How the Software Works</h3>
<p>I originally started this project by creating an effect for the <a href="http://blogs.msdn.com/coding4fun/archive/2009/02/02/9391048.aspx">
Skype Voice Changer</a>. My plan was to open a WaveStream, begin playing it on the headphones and copy the microphone stream to it.</p>
<p>I quickly found that this was not the way to add feedback. The underlying “WaveOut” system had a huge latency: Everything I heard in the headphones was at least a second or more behind what I was saying. This made it even harder to talk than before, and
 I had to abandon it.</p>
<p>While researching the problem I found a DirectSound code sample that I could modify into doing what I wanted. (This initial prototype didn't coordinate with Skype – it attached to the microphone and copied the sounds to the output, at a lower volume. But
 it was on <i>always on.</i>) The sound in the headphones is still slightly behind (the microphone) but is barely perceptible, and we'll muffle it a bit more to make it less distinguishable.</p>
<p>From here on I shall describe the major – or technically interesting – components of the program. We'll look at:</p>
<ol>
<li>DirectSound and Circular buffers </li><li>Sample Window and Sizing the buffers </li><li>Using WaitHandle's to Synchronize with DirectSound </li><li>IIR Filters </li><li>Automatic Gain Control </li><li>Estimating loudness </li></ol>
<p>Note: I won't be describing how to connect to Skype. Mark Heath's description is very good.</p>
<h4>DirectSound and Circular Buffers</h4>
<p>The DirectSound code is in AudioLoop.cs. The module sets DirectSound to capture sound from the default recording device at 16bits / sample at either 16000 or 44100 samples per second. The capture and playback buffers are configured in “looping” mode to act
 as circular buffers. The capture buffer eventually overwrites samples, and we'll lose them if we don't act fast enough; if we don't update the playback buffer, it will repeat the same sound over and over.</p>
<p>The <strong>StartMicrophone() </strong>procedure sets up the capture and playback buffers. Then it creates a thread to do the work. The thread is at a high priority so that if the OS has a choice between (say) email or processing sound, it does the sound.</p>
<p>The <strong>StopMicrophone() </strong>procedure stops the worker thread and cleans up the resources.</p>
<p>The software processes a fixed number of samples at a time, called the “sample window.” The buffers are several times the size of sample window, so that the system can keep capturing and playing while the software is processing them. The sound processing
 loop is the heart of the application:</p>
<ol>
<li>Wait for the next sample window to be ready </li><li>Copy the samples from the capture buffer </li><li>Process the samples and send the results to the playback buffer </li><li>Process the samples and sends the results to Skype </li></ol>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">while</span> (Runnable)
{
    <span class="kwrd">for</span> (<span class="kwrd">int</span> I = 0, offset = 0; Runnable &amp;&amp; I &lt; _bufferPositions; I&#43;&#43;, offset &#43;= bufferSize)
    {
        <span class="rem">// Wait for the sample areas to be ready</span>
        notificationEvent[I].WaitOne(Timeout.Infinite, <span class="kwrd">true</span>);

        <span class="rem">// Get the sound samples</span>
        <span class="kwrd">byte</span>[] buffer = (<span class="kwrd">byte</span>[]) captureBuffer.Read(offset, <span class="kwrd">typeof</span> (<span class="kwrd">byte</span>), LockFlag.None, bufferSize);

        <span class="rem">// Convert samples to 16bit PCM </span>
        <span class="kwrd">for</span> (<span class="kwrd">int</span> L = buffer.Length, J = 10, K = 0; K &lt; L; K &#43;= 2)
            PCM16Buffer[J&#43;&#43;] = (Int16) ((UInt16) buffer[K] | (((UInt16) buffer[K &#43; 1]) &lt;&lt; 8));

        <span class="rem">// Play them out to the ear, if applicable</span>
        <span class="kwrd">if</span> (<span class="kwrd">null</span> != playbackBuffer)
        {
            <span class="rem">// Perform a low pass filter to &quot;muffle&quot; the sound</span>
            Butterworth(PCM16Buffer, 10, LPSample, Coefs);

            <span class="rem">// put the muffled sample into the output buffer</span>
            <span class="rem">// -- The lock flag seems to work, but others may work too</span>
            playbackBuffer.Write(Idx, LPSample, LockFlag.None);
            Idx &#43;= buffer.Length;
            <span class="kwrd">if</span> (Idx &gt;= 4*bufferSize)
                Idx -= 4*bufferSize;
            <span class="kwrd">if</span> (!playing)
            {
                playbackBuffer.Volume = _Volume;
                playbackBuffer.Play(0, BufferPlayFlags.Looping);
                playing = <span class="kwrd">true</span>;
            }
        }

        <span class="rem">// Process the sound and deliver it to Skype</span>
        <span class="kwrd">if</span> (<span class="kwrd">null</span> != outStream)
        {
            <span class="kwrd">int</span> L = AGC.Process(PCM16Buffer, 10, buffer);
            <span class="kwrd">if</span> (0 != L)
                outStream.BeginSend(buffer, 0, L, SocketFlags.None, SendCallback, <span class="kwrd">null</span>);
            <span class="rem">// Note: could send out pink noise if L == 0</span>
        }

        <span class="rem">// Move the sliding window of the previous 10 samples into the start</span>
        <span class="rem">// of the PCM16Buffer</span>
        <span class="kwrd">for</span> (<span class="kwrd">int</span> K = 0, J = PCM16Buffer.Length - 10; K &lt; 10; K&#43;&#43;, J&#43;&#43;)
            PCM16Buffer[K] = PCM16Buffer[J];
    }
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note the “for” loop at the bottom of the code. This preserves the last 10 incoming samples at the start of the buffer. This is needed to make the sound processing smooth, and will be discussed a bit later.</p>
<h4>Sample Window and Sizing the Buffers</h4>
<p>How big should the sample window be? This is bit of a trade off in responsiveness and design complexity.</p>
<p>I chose a window big enough to hold 10 milliseconds of sound. Since the ear is sensitive sound to delays of even 30 milliseconds, I cut this done so that a delay wouldn't be perceptible. (When I tried a 50 millisecond window, my voice came out the headphone
 sounding like an echo... and I found myself talking slower and slower.) The sample window could be made smaller, but I am sure that there is a point where the OS won't schedule the audio loop to wake-n-run more frequently. And, as the sample window gets smaller,
 the processing may drop in quality, because it doesn't have enough to work with.</p>
<p>The capture buffer is 8 times the size of the sample window. This ratio is arbitrary, but I wanted the buffer to be about an order of magnitude larger. My rationale is that if the processing falls behind, the sound – for the Skype call – won't be dropped.
 I feel that it is more important to preserve sound quality for the other party than to preserve the quality of feedback.</p>
<p>The playback buffer is four times the sample window. I wanted it small, so that if the processing fell behind, the replaying of a sound will seem to be a continuation of a current sound.</p>
<p>When writing the sound to the playback buffer, we have to track where in the buffer to put the samples. I tried to use GetCurrentPosition() to find where to write to next into the playback buffer; this created terrible sound. Instead, the software uses a
 local variable to track where to write next.</p>
<h4>DirectSound and Notifications</h4>
<p>How do we keep in sync with the sound capture – how do we know when a sample buffer is ready?</p>
<p>The application gives a table of buffer indices and WaitHandle's to DirectSound. When the capture buffer's write index reaches one of those indices, it signals the corresponding WaitHandle. The worker thread cycles performs a WaitOne() one each of the WaitHandle's,
 one at a time. As a convenience, we use a specific kind of WaitHandle called AutoResetEvent. This type of WaitHandle sets itself back to a “wait” state once WaitOne() returns.</p>
<p>If the thread has gotten behind, the WaitOne will return immediately, the loop processes the sample, and begins to catch up with the work.</p>
<p>We must use a separate AutoResetEvent for each of the 8 capture windows. The AutoResetEvent doesn't tell us if it was signaled multiple times. If only one AutoResetEvent handle were used, it wouldn't know that two (or more) sample windows were ready. Instead,
 it would process just one, falling further behind, adding latency. This would happen randomly overtime, and be hard to test consistently.</p>
<h4>IIR: Infinite Impulse Response Filters</h4>
<p>This project came together so quickly, so easy – once I found the right approach – that I couldn't resist getting fancy. I added a low-pass filter to muffle the feedback a little. And I added automatic gain control, as an experimental option.</p>
<p>For both of these I used a filtering algorithm called “IIR” (this stands for Infinite Impulse Response – but that term is a confusing mouthful, so let's just call it IIR). IIR is a special purpose virtual machine. Low-pass filters, high-pass filters, combinations
 of those filters, and even equalizers, can be specified, and use very specific techniques (like a compiler) to convert them into an IIR implementation.</p>
<p>(You could, instead, “compile” the filters to be the resistor values to use in a hardware circuit.
<i>That's programming in solder!)</i></p>
<p>The machine code for these IIR virtual machines is just two list of coefficients, called A &amp; B. The software emulator is code that
<i>looks</i> like the following bit of code:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode">Out[0] = Sample[0];
Out[1] = Sample[1];
<span class="kwrd">for</span> (<span class="kwrd">int</span> Idx = 2; Idx &lt; N; Idx&#43;&#43;)
{
    Out[Idx] =
    B0 * Sample[Idx]
 &#43; B1 * Sample[Idx - 1]
 &#43; B2 * Sample[Idx - 2]
        <span class="rem">// … more like this …</span>
        <span class="rem">// Next, the feed back</span>
 - A1 * Out[Idx - 1]
 - A2 * Out[Idx - 2]
        <span class="rem">// … more like this …</span>
 ;
}</pre>
<p>IIRs are easy to implement - and take less CPU power than other methods. But sometimes they sound poor; if they sound too bad, you'll want to use a different technique. I found that the low-pass filters in this project work will for some microphones, and
 add a slight crackle to others.</p>
<h4>Example Low Pass Filter</h4>
<p>For the low pass filter to create the muffling, I used a Butterworth filter, using the code below. It takes a buffer of signed, 16-bit samples, and then converts the 16-bit values into a byte array suitable for the sound buffer.</p>
<p>The filter code is a bit different than the example code in the previous section. Most of the differences are for speed.</p>
<ul>
<li>This code doesn't use a buffer for the old values, instead uses separate variables for the elements of the buffer.&nbsp; It uses I_0,I_1,I_2 instead of Sample[Idx], Sample[Idx-1], and Sample[Idx-2]. It also uses O_1, and O_2 instead of Out[Idx-1] and Out[Idx-2].
</li><li>The A and B coefficients are put into a single array. It also <i>adds</i> two of the sample input values, and is missing a coefficient; this is because the B0 and B2 coefficients are always the same for this kind of filter.
</li></ul>
<p>There is one difference that is not for speed. These are tricks done to make the filter smooth, and needed because the sample window is so small. They preserve the state of filter. If we didn't preserve them, the filter would be starting and stopping so
 frequently that it would add distracting clicks to the output sound. The filters performance would be weakened, because the sample window isn't big enough to hold sounds lower than (about) 200 Hz. Preserving these values, the filter isn't starting and stopping,
 and doesn't really know about the sample window. All of the IIR filters in this program use similar techniques.</p>
<ul>
<li>O_1, O_2 are explicitly preserved across calls by being stored in class variables
</li><li>I_1 and I_2 are preserved by the audio loop (remember the warning about preserving 10 samples at the bottom of the loop?) The audio loop preserves the last 10 samples at the start of InBuffer. When this procedure is called, it retrieves the last two samples.
</li></ul>
<p><b>C#</b></p>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">double</span> O_1 = 0.0, O_2=0.0;

<span class="kwrd">static</span> <span class="kwrd">void</span> Butterworth(Int16[] InBuffer, <span class="kwrd">int</span> Ofs, <span class="kwrd">byte</span>[] OutBuffer, <span class="kwrd">double</span>[] Coefs)
{
  <span class="kwrd">double</span> C0=Coefs[0], C1=Coefs[1], C2 = Coefs[2], C3=Coefs[3];
  <span class="kwrd">double</span> I_1=InBuffer[Ofs-1], I_2= InBuffer[Ofs-2];
  <span class="kwrd">for</span> (<span class="kwrd">int</span> L = InBuffer . Length, J=0, I = Ofs; I &lt; L; I&#43;&#43;)
  {
     <span class="kwrd">double</span> I_0 = InBuffer[I];

     <span class="rem">// Filter the samples</span>
     <span class="kwrd">double</span> A = (I_0 &#43; I_2) * C0 &#43; I_1 * C1;
     I_2 = I_1;
     I_1 = I_0;

     A = A - O_1 * C2 - O_2 * C3;
     O_2 = O_1;
     O_1 = A;

     <span class="rem">// Convert it back to 16 bit</span>
     Int16 S;
     <span class="kwrd">if</span> (A &lt; -32767) S = -32767;
     <span class="kwrd">if</span> (A &gt; 32767)  S = 32767;
     <span class="kwrd">else</span> S = (Int16) A;

     <span class="rem">// Store it</span>
     OutBuffer[J&#43;&#43;] = (<span class="kwrd">byte</span>)(S &amp; 0xFF);
     OutBuffer[J&#43;&#43;] = (<span class="kwrd">byte</span>)(((UInt16)S &gt;&gt; 8) &amp; 0xFF);
  }
}</pre>
<p>Automatic Gain Control</p>
<p>I decided next to tackle a problem where my wife's voice did not carry well on calls. This happens a lot to her with cell phones – and answering machines. I was pretty sure that the problem was poor automatic-gain-control (AGC). The typical amplifier in
 a headset (and in Skype) estimates how loud our voice is, then increases – or decreases – the volume to a reasonable level. It was deciding that my wife's voice was background noise, and cutting her off.</p>
<p>I chose to write an alternate gain control that amplified the sound and passed it to Skype. That way we'd have four to choose from: The one built into the Microphone, the Soundcard's, Mine, and Skype's. (To be fair, these automatic gain controls work well
 in most cases).</p>
<p>The main portion of the gain control is implemented in the file GainControl.cs. The control algorithm is:</p>
<ol>
<li>Calculate (or estimate) how loud we are currently talking (using the Analyze() procedure)
</li><li>If the loudness is very low, no one is talking… so set the output to zero. (Without this step, the volume of noise and hum would be cranked up)
</li><li>Otherwise, compute the guess-gain by dividing how loud the sound of our voice should be by how loud it currently is
</li><li>Compute the gain (called MaxGain) at which the sound will start clipping. If the guess-gain is louder than this, reduce it to MaxGain.
</li><li>The software adjusts the gain for a gentle transition – especially in the case when we go from absolute quiet, to the start of talking. It does this by tracking the gain (called PrevGain) used in previous sample and the current one.
</li><li>Multiple all the samples by this gain value. </li><li>If the sample rate is greater than 16000 samples/sec
<ol>
<li>Do a low pass filter at 8 khz (again in IIR form). This helps prevent artifacts from down sampling
</li><li>Resample the sound to 16000 </li></ol>
</li></ol>
<p>The portion of code that calculates the gain looks like (CutOff_dB, LowGain_dB, and TgtGain_dB are the three slider values):</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">if</span> (!AutoGain)
    Gain = 1.0;
<span class="kwrd">else</span>
{
    <span class="kwrd">double</span> MaxGain;
    <span class="kwrd">double</span> dB = Analyze(InBuffer, Ofs, <span class="kwrd">out</span> MaxGain);

    <span class="kwrd">if</span> (dB &lt; CutOff_dB)
        Gain = 0.0;
    <span class="kwrd">else</span> <span class="kwrd">if</span> (dB &lt; LowGain_dB &#43; 4.0)
    {
        Gain = Math.Exp((LowGain_dB - dB) * db2log);
    }
    <span class="kwrd">else</span>
    {
        Gain = Math.Exp((TgtGain_dB - dB) * db2log);
    }
    Gain = (0.4 * Gain &#43; 0.6 * PrevGain);
    <span class="kwrd">if</span> (Gain &gt; MaxGain)
        Gain = MaxGain;
    PrevGain = Gain;
}

<span class="rem">// Skip further process if there is silence</span>
<span class="kwrd">if</span> (0.0 == Gain)
{
    <span class="kwrd">return</span> 0;
}</pre>
<p>If you look at the code, you'll see that we don't compare directly with LowGain_db; rather we compare the estimate volume with LowGain_db&#43;4. This gives a little “hysteresis” – if we raise our voice momentarily, the software won't suddenly make it the highest
 possible volume. Instead, the software lowers the volume a little bit.</p>
<p>When the software changes the sample rate, it basically needs to know how many input samples to skip. At the start of a call, the software computes this, calling it InInc:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="rem">// Calculate how we resample to 16Khz</span>
InInc = (<span class="kwrd">int</span>)(1024.0 * SampleRate / 16000.0);</pre>
<p>The process of applying the gain adjustment, performing a low pass filter and re-sampling is below:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">int</span> NumSamples = InBuffer.Length;
<span class="kwrd">int</span> End = OutBuffer.Length;
<span class="kwrd">int</span> NextIdxForOut = -InInc;
<span class="kwrd">int</span> OutIdx = 0;
<span class="kwrd">for</span> (<span class="kwrd">int</span> I = Ofs; OutIdx &lt; End &amp;&amp; I &lt; NumSamples; I&#43;&#43;)
{
    <span class="rem">// Retrieve the sample</span>
    Int16 S = InBuffer[I];
    <span class="kwrd">double</span> I_0 = S;

    <span class="rem">// Apply Gain</span>
    I_0 *= Gain;

    <span class="rem">// 8khz low pass filter </span>
    <span class="kwrd">if</span> (DoLP)
    {
        <span class="rem">// Simple Butterworth 8KHz low-pass filter</span>
        <span class="kwrd">double</span> A = (I_0 &#43; DS_I_2) * LP[0] &#43; DS_I_1 * LP[1];
        DS_I_2 = DS_I_1;
        DS_I_1 = I_0;
        I_0 = A - DS_O_1 * LP[2] - DS_O_2 * LP[3];
        DS_O_2 = DS_O_1;
        DS_O_1 = I_0;

        <span class="rem">// Change sample rate</span>
        <span class="kwrd">int</span> Tmp = NextIdxForOut / 1024;
        <span class="kwrd">if</span> (I &lt; Tmp)
            <span class="kwrd">continue</span>;
        NextIdxForOut &#43;= InInc;
    }

    <span class="rem">// Convert it back to 16 bit</span>
    S = (Int16)I_0;

    <span class="rem">// Store it</span>
    OutBuffer[OutIdx&#43;&#43;] = (<span class="kwrd">byte</span>)(S &amp; 0xFF);
    OutBuffer[OutIdx&#43;&#43;] = (<span class="kwrd">byte</span>)(((UInt16)S &gt;&gt; 8) &amp; 0xFF);
}</pre>
<p>Estimating Volume</p>
<p>How loud “it should be” is controlled by a slider on the screen. The software estimates how loud the sound is by using
<a href="http://replaygain.hydrogenaudio.org/equal_loudness.html">an algorithm devised by David Robinson</a> that takes into account how it sounds
<i>to a person</i>. This way we can increase the gain on hard to hear sounds, and reduce the gain on sounds that a person is very sensitive to.</p>
<p>The loudness estimator, implemented in the Analysis procedure in GainAnalysis.cs, uses the following algorithm:</p>
<ol>
<li>Uses a combination of two (IIR) filters to make the sound to reflect how our ears hear it.
</li><li>Compute the Mean-Square value of the filtered sound (called MS) </li><li>Track the last 750 ms of these values. </li><li>Make a sorted copy of these. </li><li>Retrieve the first non-zero value at least 95% of the way into the buffer. This is so that we don't take the loudest sample and assume that is how the person is talking.
</li><li>If MS (the value computed in step 2) is much quieter, use that one instead </li><li>Convert this value into dB scale by performing a logarithm on it. </li></ol>
<p>The code to “normalize” the sound into how a person hears it is below. Along the way it computes the square of the samples (used in step 2). Like the earlier IIR filters, these preserves their variables across the calls. The first IIR is a yulewalk filter,
 but it preserves it old intermediary values in an array. Like the trick in AudioLoop, where we copy the last 10 samples into the start of the current buffer, the analysis procedure copies the last 10 immediate values into the start of YuleTmp array.</p>
<p>The output of the yulewalk filter is feed into a 150Hz high pass filter. It is essentially the same as the low-pass filter described earlier.</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">for</span> (<span class="kwrd">int</span> L = Samples.Length, N = Ofs; N &lt; L; N&#43;&#43;)
{
    <span class="kwrd">int</span> _V = Samples[N];
    <span class="kwrd">double</span> V = _V;
    <span class="kwrd">if</span> (_V &gt; MaxSample) MaxSample = _V;
    <span class="kwrd">if</span> (-_V &gt; MaxSample) MaxSample = -_V;

    <span class="rem">// Perform yulewalk filter</span>
    <span class="kwrd">double</span> S = V * YuleCoefs[0];
    <span class="kwrd">for</span> (<span class="kwrd">int</span> J = N - 1, I = 1; I &lt; 11; I&#43;&#43;, J--)
        S &#43;= Samples[J] * YuleCoefs[I];
    <span class="kwrd">for</span> (<span class="kwrd">int</span> J = N - 1, I = 11; I &lt; 21; I&#43;&#43;, J--)
        S -= YuleTmp[J] * YuleCoefs[I];

    <span class="rem">// Store for the feedback into the next stage of the yule walk</span>
    YuleTmp[N] = S;


    <span class="rem">// Perform butterworth high-pass filter stage, using S as an input</span>
    <span class="kwrd">double</span> Accum =
       (S &#43; GA_I_2) * HPCoefs[0]
       &#43; GA_I_1 * HPCoefs[1];
    GA_I_2 = GA_I_1;
    GA_I_1 = S;
    Accum = Accum - GA_O_1 * HPCoefs[2] - GA_O_2 * HPCoefs[3];

    GA_O_2 = GA_O_1;
    GA_O_1 = Accum;

    <span class="rem">// The square of the filtered results</span>
    Sum &#43;= Accum * Accum;
}

<span class="rem">// Copy the intermediate yulewalk state for the next</span>
<span class="rem">// (this is needed since we are looking at a fairly small time window)</span>
<span class="kwrd">for</span> (<span class="kwrd">int</span> I = 0, J = YuleTmp.Length - 10; I &lt; 10; I&#43;&#43;)
    YuleTmp[I] = YuleTmp[J];</pre>
<p>The mean-squared is computed:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="rem">// The mean square of the filtered results</span>
<span class="kwrd">double</span> MS = Sum / NumSamples;</pre>
<p>Tracking the last 750ms of samples is a simple matter of putting it into a circular queue:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode">MSQueue[QIdx&#43;&#43;] = MS;
<span class="kwrd">if</span> (QIdx &gt;= MSQueue . Length)
   QIdx = 0;</pre>
<p>Next, is the code to finding the first non-zero value 95% of the way into the buffer. It is a straightforward copy-the-array, sort it, and fetch:</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode">Array.Copy(MSQueue, SortedQ, MSQueue.Length);
Array.Sort(SortedQ);

<span class="rem">// Return the 95% </span>
<span class="kwrd">double</span> X = SortedQ[Q95Idx]; 
<span class="kwrd">for</span> (<span class="kwrd">int</span> I = Q95Idx &#43;1; X &lt; 400.0 &amp;&amp; I &lt; SortedQ . Length; I&#43;&#43;)
      X = SortedQ[I];</pre>
<p>Next, override this value if the current sample window is very, very quiet – that is, the user stopped talking. (If we don't do this, we'll amplify background noise between words)</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">if</span> (MS &lt; X * 0.40 &amp;&amp; MS &lt; 12800.0)
   X = MS;</pre>
<p>Finally, convert the result into decibels (or a reasonable approximation of a decibel)</p>
<p><b>C# <br>
</b></p>
<pre class="csharpcode"><span class="kwrd">return</span> 10.0 * Math . Log10 (X * 0.5 &#43; <span class="kwrd">double</span> . Epsilon);</pre>
<p>Note: The logarithm function takes a positive, non-zero floating point number. However, the value we pass to it can be zero; if we pass a zero, though, the Logarithm function would return a bad value. The simplest thing to do is check to see if the value
 we are passing is “zero” and not call Logarithm. However, I learned a long time ago to just add “epsilon” to the value to whatever we pass. This can really improve performance on number crunching.</p>
<h3>Conclusion</h3>
<p>This concludes how to add a little bit feedback and fancy amplification to you Skype phone calls.</p>
<p>If you want to try this out, the download link for the source code is at the top of the article!</p>
<p>If you'd like to experiment further, here are ideas of what can be done:</p>
<ol>
<li>DirectSound has echo cancellation and noise suppression. These seem desirable, esp. if you wanted to try making your own speakerphone. I was not able to get them to work and I would love to learn how.
</li><li>I'm sure it is possible to trim even more latency off of the side-tone playback, and I would be interested in learning better techniques to do so.
</li><li>Another would be to create the ideal equalizer from Robinson's Equal Loudness model, and use that filter and amplify the sound.
</li><li>It might be useful for the other party to control the settings, so that they decide when your voice has the right volume.
</li></ol>
<h4>Resources and References</h4>
<ul>
<li>David Robinson (while doing his PhD at University of Essex on human hearing).
<a href="http://replaygain.hydrogenaudio.org/equal_loudness.html">His algorithm</a> is intended to find the overall loudness of an album. He includes
<a href="http://replaygain.hydrogenaudio.org/mfiles/equalloudfilt.m">MATLAB scripts to compute coefficients</a> at custom sample rates, as well as some
<a href="http://replaygain.hydrogenaudio.org/equal_loud_coef.txt">pre-computed coefficients</a>.
</li><li>Mark Heath's <a href="http://blogs.msdn.com/coding4fun/archive/2009/02/02/9391048.aspx">
Skype Voice Changer</a> </li><li>Derek Pierson's <a href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">
DirectX tutorial</a> </li></ul>
<h3>About The Author</h3>
<p>Randall Maas writes firmware for medical devices, and consults in embedded software. Before that he did a lot of other things… like everyone else in the software industry. You can contact him at
<a href="mailto:randym@acm.org">randym@acm.org</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:3f2741667204495887219e7600cc49b6">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Adding-Sidetone-to-Skype</comments>
      <itunes:summary>
Ever
 use a headset with Skype – and were frustrated that it was too quiet? This article shows how to add the sound of your own voice to the headset and not feel exhausted from shouting to be heard. 

Skype: I find your lack of feedback disturbing.
This article will discuss how to build a software tool that makes it easier to talk into Skype with a headset. 
Recently my family began experimenting with Skype, but we found that talking over Skype can be exhausting with headphones. After doing a little research, I learned that the problem was that we only heard the other party. You&#39;d think that this is a good thing,
 but we have a social brain that works hard to gauge our behavior and adjust. 
The answer is to feed a little bit of the microphone back into the earpiece, so that our brain knows how loud we&#39;re talking. This is called
side tone in the telecommunication industry. Without it, we talk louder and louder until we&#39;re sure that we&#39;ll be heard. 
I couldn&#39;t find a Skype plug-in to do this… but I had just read a 
Coding4Fun article, by Mark Heath, about adding audio effects to Skype. I decided I was going to write a tool to add this feedback. 
How to use the tool
First, let&#39;s take a look at how to use the application. Once it is running, there will be a microphone icon in the lower right hand corner of the screen: 
Figure 1: Icon in the system notification tray 
 
Clicking on it, will get the application control window: 
Figure 2: The application&#39;s controls 
 
Let&#39;s look at the side tone controls: 

The “Side Tones” check box enables or disables the side tone. If you have headphones, you&#39;ll want this on; if you have loud speakers, you&#39;ll want it off.
The slider controls the volume of the microphone in the headset. You can change it while talking. The volume will vary with microphone and headset.

You can do a “sound check” to see if the feedback is working by clicking on the Sound Check button, and adjusting the volume. I found that the volume setting that works be</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Adding-Sidetone-to-Skype</link>
      <pubDate>Tue, 09 Jun 2009 18:44:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Adding-Sidetone-to-Skype</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9583391_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9583391_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Randall Maas</dc:creator>
      <itunes:author>Randall Maas</itunes:author>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Adding-Sidetone-to-Skype/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>utility</category>
      <category>Windows</category>
      <category>web miscellaneous</category>
    </item>
  <item>
      <title>Computer, Hello Computer, I need some transparent aluminum</title>
      <description><![CDATA[
<p><a href="http://blogs.microsoft.co.il/blogs/kim">Kim Major</a> is working on a rather neat item for Visual Studio.&nbsp; He is working on using speech recognition to program with Visual Studio!
</p>
<div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:1cde765d-4045-4544-b565-02c01dc97bbd" class="wlWriterEditableSmartContent">
<div id="362e554a-65bb-4151-b11c-eba4945b9aa1">
<div><a href="http://www.youtube.com/watch?v=x3Lm9nrFeMk&amp;hl=en&amp;fs=1&amp;" target="_new"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9708614/video65df5608ce7e.jpg" alt=""></a></div>
</div>
</div>
<p>They are looking for some feedback and if you want to, please <a href="http://weblogs.asp.net/jackieg/archive/2009/06/08/using-speech-recognition-to-program-in-microsoft-visual-studio.aspx">
post some over here</a>.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:d60eb6f953bd419b924f9e7600cc4e90">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/blog/Computer-Hello-Computer-I-need-some-transparent-aluminum</comments>
      <itunes:summary>
Kim Major is working on a rather neat item for Visual Studio.&amp;nbsp; He is working on using speech recognition to program with Visual Studio!
 





They are looking for some feedback and if you want to, please 
post some over here. 
</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/blog/Computer-Hello-Computer-I-need-some-transparent-aluminum</link>
      <pubDate>Mon, 08 Jun 2009 14:53:36 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/blog/Computer-Hello-Computer-I-need-some-transparent-aluminum</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9708614_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9708614_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Clint Rutkas</dc:creator>
      <itunes:author>Clint Rutkas</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/blog/Computer-Hello-Computer-I-need-some-transparent-aluminum/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>utility</category>
      <category>C4FNews</category>
      <category>Speech to Text</category>
    </item>
  <item>
      <title>Pete Brown, Silverlight Wizard in Action</title>
      <description><![CDATA[<a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/default.aspx" shape="rect">Pete Brown</a>&nbsp;brought along some fun toys to MIX09 written in the Silverlight 3 Beta which he demonstrates in this video.&nbsp; The first toy is a Commodore64
 emulator running print commands and the Dr. Who game.&nbsp; The second toy, or in this case maybe tool would be more applicable, is his audio synthesizer which generates sound dynamically within Silverlight.<br>
<br>
Since MIX09, Pete has been very busy posting tutorials on some of the newest features available in Silverlight 3:<br>
<ul>
<li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/23/Creating-Sound-using-MediaStreamSource-in-Silverlight-3-Beta.aspx" shape="rect">Creating Sound using MediaStreamSource in Silverlight 3 Beta</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/23/Using-Blur-to-make-Dialogs-Pop-in-Silverlight-3.aspx" shape="rect">Using Blur to make Dialogs Pop in Silverlight 3</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-Perspective-3d-Transforms-_1320_-PlaneProjection.aspx" shape="rect">Silverlight 3 – Perspective 3d Transforms – PlaneProjection</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-The-Bitmap-API-_2F00_-WriteableBitmap.aspx" shape="rect">Silverlight 3 – The Bitmap API / WriteableBitmap</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-BasedOn-Styles.aspx" shape="rect">Silverlight 3 – BasedOn Styles</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-Taking-Silverlight-Out-of-the-Browser.aspx" shape="rect">Silverlight 3 – Taking Silverlight Out of the Browser</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-UI-Element-to-Element-Binding.aspx" shape="rect">Silverlight 3 – UI Element to Element Binding</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-Creating-Video-from-Raw-Bits-using-a-MediaStreamSource.aspx" shape="rect">Silverlight 3 – Creating Video from Raw Bits using a MediaStreamSource</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-_1320_-Drop-Shadows-and-Glows-with-Pixel-Shaders.aspx" shape="rect">Silverlight 3 – Drop Shadows and Glows with Pixel Shaders</a>
</li><li><a shape="rect" href="http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Announcing-Silverlight-3_2100_-SL3-Post-Index.aspx" shape="rect">Announcing Silverlight 3! SL3 Post Index</a>
</li></ul>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:7b6c5d2be63c4fbbb81f9deb001c90e9">]]></description>
      <comments>http://channel9.msdn.com/Shows/Continuum/Pete-Brown-Silverlight-Wizard-in-Action</comments>
      <itunes:summary>Pete Brown&amp;nbsp;brought along some fun toys to MIX09 written in the Silverlight 3 Beta which he demonstrates in this video.&amp;nbsp; The first toy is a Commodore64
 emulator running print commands and the Dr. Who game.&amp;nbsp; The second toy, or in this case maybe tool would be more applicable, is his audio synthesizer which generates sound dynamically within Silverlight.

Since MIX09, Pete has been very busy posting tutorials on some of the newest features available in Silverlight 3:

Creating Sound using MediaStreamSource in Silverlight 3 Beta
Using Blur to make Dialogs Pop in Silverlight 3
Silverlight 3 – Perspective 3d Transforms – PlaneProjection
Silverlight 3 – The Bitmap API / WriteableBitmap
Silverlight 3 – BasedOn Styles
Silverlight 3 – Taking Silverlight Out of the Browser
Silverlight 3 – UI Element to Element Binding
Silverlight 3 – Creating Video from Raw Bits using a MediaStreamSource
Silverlight 3 – Drop Shadows and Glows with Pixel Shaders
Announcing Silverlight 3! SL3 Post Index

</itunes:summary>
      <itunes:duration>514</itunes:duration>
      <link>http://channel9.msdn.com/Shows/Continuum/Pete-Brown-Silverlight-Wizard-in-Action</link>
      <pubDate>Fri, 27 Mar 2009 18:48:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/Continuum/Pete-Brown-Silverlight-Wizard-in-Action</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/462669_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/462669_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_large_ch9.png" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_small_ch9.png" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_2MB_ch9.wmv" expression="full" duration="514" fileSize="151049031" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_ch9.mp3" expression="full" duration="514" fileSize="4118906" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_ch9.mp4" expression="full" duration="514" fileSize="35205555" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_ch9.wma" expression="full" duration="514" fileSize="8332077" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_ch9.wmv" expression="full" duration="514" fileSize="30648527" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_Zune_ch9.wmv" expression="full" duration="514" fileSize="38696507" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_s_ch9.wmv" expression="full" duration="514" fileSize="204" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/6/6/2/6/4/TCSPeteBrown_ch9.wmv" length="30648527" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Adam Kinney</dc:creator>
      <itunes:author>Adam Kinney</itunes:author>
      <slash:comments>5</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/Continuum/Pete-Brown-Silverlight-Wizard-in-Action/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Graphics</category>
      <category>Silverlight</category>
    </item>
  <item>
      <title>Coding4Fun Demo - How to mask your voice using the Skype Voice Changer</title>
      <description><![CDATA[<a shape="rect" href="http://mark-dot-net.blogspot.com/" shape="rect">Mark Heath</a>&nbsp;(of&nbsp;<a shape="rect" href="http://www.codeplex.com/naudio" shape="rect">NAudio</a> fame) recently published a&nbsp;<a shape="rect" href="http://blogs.msdn.com/coding4fun/archive/2009/02/02/9391048.aspx" shape="rect">how-to
 article for Coding4Fun</a> that shows how he plugged into Skype's audio APIs to dynamically apply different sound effects to the audio stream to mask your voice.
<br>
<br>
To see it in action, we setup a Skype connection between me and Clint Rutkas. Clint screen captured&nbsp;his PC so you can see the Skype Voice Changer application, while I recorded Clint's voice with the sound effects applied.
<br>
<br>
Coding is fun <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-1.gif' alt='Smiley' /><br>
<br>
<br>
<br>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:4ccf89f403124c21b2db9deb000cf9b9">]]></description>
      <comments>http://channel9.msdn.com/Blogs/Dan/Coding4Fun-Demo-How-to-mask-your-voice-using-the-Skype-Voice-Changer</comments>
      <itunes:summary>Mark Heath&amp;nbsp;(of&amp;nbsp;NAudio fame) recently published a&amp;nbsp;how-to
 article for Coding4Fun that shows how he plugged into Skype&#39;s audio APIs to dynamically apply different sound effects to the audio stream to mask your voice.


To see it in action, we setup a Skype connection between me and Clint Rutkas. Clint screen captured&amp;nbsp;his PC so you can see the Skype Voice Changer application, while I recorded Clint&#39;s voice with the sound effects applied.


Coding is fun 



</itunes:summary>
      <itunes:duration>200</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/Dan/Coding4Fun-Demo-How-to-mask-your-voice-using-the-Skype-Voice-Changer</link>
      <pubDate>Sat, 14 Feb 2009 17:05:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/Dan/Coding4Fun-Demo-How-to-mask-your-voice-using-the-Skype-Voice-Changer</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/457379_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/457379_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_large_ch9.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_small_ch9.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_2MB_ch9.wmv" expression="full" duration="200" fileSize="6093893" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_ch9.mp3" expression="full" duration="200" fileSize="1604255" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_ch9.mp4" expression="full" duration="200" fileSize="6429275" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_ch9.wma" expression="full" duration="200" fileSize="3258319" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_ch9.wmv" expression="full" duration="200" fileSize="7462641" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_Zune_ch9.wmv" expression="full" duration="200" fileSize="7734621" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_s_ch9.wmv" expression="full" duration="200" fileSize="222" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/9/7/3/7/5/4/SkypeVoiceChangerDemo_ch9.wmv" length="7462641" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Dan Fernandez</dc:creator>
      <itunes:author>Dan Fernandez</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/Dan/Coding4Fun-Demo-How-to-mask-your-voice-using-the-Skype-Voice-Changer/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Coding4Fun</category>
    </item>
  <item>
      <title>Skype Voice Changer</title>
      <description><![CDATA[
<p>In this article I demonstrate how you can create your own audio effects in .NET to manipulate digital audio at the sample level. These effects are used to process MP3 files while they are being played back, and to process the real-time microphone input allowing
 you to change your voice during a Skype conversation.</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="157">
<p>Mark Heath, <a href="http://mark-dot-net.blogspot.com">blog</a> <br>
</p>
</td>
<td valign="top" width="481">
<p><b>Source Code:</b> <a href="http://www.codeplex.com/skypefx">Download</a></p>
<p><b>Difficulty:</b> Intermediate <br>
<b>Time Required:</b> 8 hours <br>
<b>Cost:</b> Free <br>
<b>Software Needed:</b> <a href="http://www.microsoft.com/express/download/">Visual Basic or Visual C# Express 2008</a><b>
<br>
</b><b>Libraries:</b> <a href="http://www.codeplex.com/naudio">NAudio</a>, <a href="https://developer.skype.com/Docs/Skype4COM">
Skype4COM</a>, <a href="http://www.codeplex.com/MEF">MEF</a></p>
</td>
</tr>
</tbody>
</table>
<h3><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_15.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_12.png" width="500" height="204"></a>
</h3>
<h3>Audio and the .NET Framework</h3>
<p>Playing back audio in a .NET application is not quite as easy as you might hope it would be. The .NET 2.0 Framework introduced the
<a href="http://msdn.microsoft.com/en-us/library/system.media.soundplayer.aspx">SoundPlayer</a> component, which allows you to play back an existing WAV file. While this may be fine for many scenarios, as soon as you want to do things even slightly more advanced,
 such as changing the volume, or playing back from a different file-format, or pausing and repositioning, you must resort to writing P/Invoke wrappers for various Windows APIs.</p>
<p>Back in 2002, as I was getting started learning .NET, I create some audio-related classes of my own to compensate for the lack of audio support in the .NET Framework. I focused initially on reading and writing WAV and MIDI files, as well as playing back
 audio in a way that allowed real-time mixing and manipulation of the audio at a sample level. As time went by, I made this growing collection of audio classes available as an open source project, called
<a href="http://www.codeplex.com/naudio">NAudio</a>, now hosted at CodePlex.</p>
<h4>Audio Playback in NAudio</h4>
<p>NAudio works by constructing an audio playback graph. Audio comes in “streams” which can be connected together and modified before eventually they go to a renderer. This might be your soundcard if you are listening to the audio, or it might be to a file
 on the hard disk.</p>
<p>In NAudio, all streams derive from <b>WaveStream</b>. NAudio comes with a collection of useful
<b>WaveStream</b> derived classes such as <b>WaveFileReader</b> to read from WAV files or
<b>WaveStreamMixer</b> to sum together multiple audio streams. </p>
<p>Audio mixing and effects are almost always performed with floating point numbers (32 bit is most common), so one of the first steps after reading audio out of a WAV file is to convert it from 16 bit to 32 bit. NAudio includes the
<b>Wave16To32ConversionStream </b>class to do this. If the audio wasn't in PCM in the first place, for example it is MP3, then we make use of a combination of the
<b>Mp3FileReaderStream</b>, <b>WaveFormatConversionStream</b> and <b>BlockAlignmentReductionStream</b> to read the audio out and get it into just the format we want. Here's an example showing how to create a
<b>WaveStream</b> ready for playback.</p>
<pre class="csharpcode">WaveStream outStream;
<span class="kwrd">if</span> (fileName.EndsWith(<span class="str">&quot;.mp3&quot;</span>))
{
   outStream = <span class="kwrd">new</span> Mp3FileReader(fileName);
}
<span class="kwrd">else</span> <span class="kwrd">if</span>(fileName.EndsWith(<span class="str">&quot;.wav&quot;</span>))
{
   outStream = <span class="kwrd">new</span> WaveFileReader(fileName);
}
<span class="kwrd">else</span>
{
   <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException(<span class="str">&quot;Can't open this type of file&quot;</span>);
}                
<span class="kwrd">if</span> (outStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
{
   outStream = WaveFormatConversionStream.CreatePcmStream(outStream);
   outStream = <span class="kwrd">new</span> BlockAlignReductionStream(outStream); <span class="rem">// reduces choppiness</span>
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>If we simply want to play back the audio without any extra processing, we would use one of the audio output classes provided by NAudio to create an object that implements
<b>IWavePlayer</b>. The options are <b>WaveOut</b>, <b>DirectSoundOut</b>, <b>AsioOut</b> and
<b>WasapiOut</b>, each representing a different technology for audio playback in Windows. We will use
<b>WaveOut</b>, which is the most universally supported. Here we are opening the default output device with a latency of 300ms, and instructing it to use windowed callbacks.</p>
<pre class="csharpcode">IWavePlayer player = <span class="kwrd">new</span> WaveOut(0, 300, <span class="kwrd">true</span>);
player.Init(outStream);
player.Play();</pre>
<p><b>WaveOut</b> will now repeatedly call the <b>Read</b> method of the output stream to get the next batch of audio samples to play. All we need to do now is to insert our audio effects into the playback chain.</p>
<h4>An Audio Effects Framework</h4>
<p>To allow us to process sample level audio more simply, I have create a new <b>
WaveStream</b> derived class called <b>EffectStream</b>. <b>EffectStream</b> will simply pass each audio sample to one or more audio effects before returning the modified audio in its
<b>Read</b> method. The reason I have chosen to host all the effects in a single <b>
EffectSteam</b> rather than creating one <b>WaveStream</b> derived class is that I want to avoid the performance penalty of converting between arrays of bytes and arrays of floating point numbers at every step. Some types of effect, particularly those involving
 Fourier transforms can be processor intensive, so anything we can do to speed up performance will help.</p>
<p>As well as the <b>EffectStream </b>class, we need a base <b>Effect</b> class, from which all of our effects can derive. Here's a simplified version of the base Effect class (minus a whole load of helper mathematical functions):</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> Effect
{
    <span class="kwrd">private</span> List&lt;Slider&gt; sliders;
    <span class="kwrd">public</span> <span class="kwrd">float</span> SampleRate { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">float</span> Tempo { get; set; }
    <span class="kwrd">public</span> <span class="kwrd">bool</span> Enabled { get; set; }

    <span class="kwrd">public</span> Effect()
    {
        sliders = <span class="kwrd">new</span> List&lt;Slider&gt;();
        Enabled = <span class="kwrd">true</span>;
        Tempo = 120;
        SampleRate = 44100;
    }

    <span class="kwrd">public</span> IList&lt;Slider&gt; Sliders { get { <span class="kwrd">return</span> sliders; } }

    <span class="kwrd">public</span> Slider AddSlider(<span class="kwrd">float</span> defaultValue, <span class="kwrd">float</span> minimum, 
            <span class="kwrd">float</span> maximum, <span class="kwrd">float</span> increment, <span class="kwrd">string</span> description)
    {
        Slider slider = <span class="kwrd">new</span> Slider(defaultValue, minimum, 
            maximum, increment, description);
        sliders.Add(slider);
        <span class="kwrd">return</span> slider;
    }

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// Should be called on effect load, </span>
    <span class="rem">/// sample rate changes, and start of playback</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Init()
    {}

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// will be called when a slider value has been changed</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    <span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">void</span> Slider();

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// called before each block is processed</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Block()
    { }

    <span class="rem">/// &lt;summary&gt;</span>
    <span class="rem">/// called for each sample</span>
    <span class="rem">/// &lt;/summary&gt;</span>
    <span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">void</span> Sample(<span class="kwrd">ref</span> <span class="kwrd">float</span> spl0, <span class="kwrd">ref</span> <span class="kwrd">float</span> spl1);
}</pre>
<p>The bulk of the work of the effect should be done in the overridden <b>Sample</b> method. The
<b>spl0</b> and <b>spl1</b> parameters contain the current sample values to be modified for the left and right channels respectively. For example, to lower the volume we could halve the amplitude of every sample with the following code:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Sample(<span class="kwrd">ref</span> <span class="kwrd">float</span> spl0, <span class="kwrd">ref</span> <span class="kwrd">float</span> spl1)
{
    spl0 *= 0.5f;
    spl1 *= 0.5f;
}</pre>
<p>The <b>Effect</b> class contains <b>Tempo</b> and <b>SampleRate</b> values which are useful for certain types of effect. It also contains a concept of ‘Sliders' for each effect. These are the effect parameters, which allow real-time modification of the effect.
 So if we wanted to control the volume using a slider, we could write the following code (although bear in mind that normally volume sliders should be logarithmic not linear – see the
<b>Volume</b> effect in the sample code for an example of how to do this):</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Sample(<span class="kwrd">ref</span> <span class="kwrd">float</span> spl0, <span class="kwrd">ref</span> <span class="kwrd">float</span> spl1)
{
    spl0 *= slider1;
    spl1 *= slider1;
}</pre>
<p>To simplify the task of adding, removing and re-ordering effects, I created an
<b>EffectChain</b> class, which is a simple wrapper around a <b>List&lt;Effect&gt;</b>. The
<b>EffectStream</b> class has an <b>EffectChain</b> that contains all the effects it needs to run. Here is the code for the
<b>EffectStream</b>:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> EffectStream : WaveStream
{
    <span class="kwrd">private</span> EffectChain effects;
    <span class="kwrd">public</span> WaveStream source;
    <span class="kwrd">private</span> <span class="kwrd">object</span> effectLock = <span class="kwrd">new</span> <span class="kwrd">object</span>();
    <span class="kwrd">private</span> <span class="kwrd">object</span> sourceLock = <span class="kwrd">new</span> <span class="kwrd">object</span>();

    <span class="kwrd">public</span> EffectStream(EffectChain effects, WaveStream sourceStream)
    {
        <span class="kwrd">this</span>.effects = effects;
        <span class="kwrd">this</span>.source = sourceStream;
        <span class="kwrd">foreach</span> (Effect effect <span class="kwrd">in</span> effects)
        {
            InitialiseEffect(effect);
        }

    }

    <span class="kwrd">public</span> EffectStream(WaveStream sourceStream)
        : <span class="kwrd">this</span>(<span class="kwrd">new</span> EffectChain(), sourceStream)
    {        
    }

    <span class="kwrd">public</span> EffectStream(Effect effect, WaveStream sourceStream)
        : <span class="kwrd">this</span>(sourceStream)
    {
        AddEffect(effect);
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> WaveFormat WaveFormat
    {
        get { <span class="kwrd">return</span> source.WaveFormat; }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Length
    {
        get { <span class="kwrd">return</span> source.Length; }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Position
    {
        get { <span class="kwrd">return</span> source.Position; }
        set { <span class="kwrd">lock</span> (sourceLock) { source.Position = <span class="kwrd">value</span>; } }
    }        

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">int</span> Read(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
    {
        <span class="kwrd">int</span> read;
        <span class="kwrd">lock</span>(sourceLock)
        {
            read = source.Read(buffer, offset, count);
        }
        <span class="kwrd">if</span> (WaveFormat.BitsPerSample == 16)
        {
            <span class="kwrd">lock</span> (effectLock)
            {
                Process16Bit(buffer, offset, read);
            }
        }
        <span class="kwrd">return</span> read;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> Process16Bit(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
    {
        <span class="kwrd">foreach</span> (Effect effect <span class="kwrd">in</span> effects)
        {
            <span class="kwrd">if</span> (effect.Enabled)
            {
                effect.Block();
            }
        }

        <span class="kwrd">for</span>(<span class="kwrd">int</span> sample = 0; sample &lt; count/2; sample&#43;&#43;)
        {
            <span class="rem">// get the sample(s)</span>
            <span class="kwrd">int</span> x = offset &#43; sample * 2;
            <span class="kwrd">short</span> sample16Left = BitConverter.ToInt16(buffer, x);
            <span class="kwrd">short</span> sample16Right = sample16Left;
            <span class="kwrd">if</span>(WaveFormat.Channels == 2)
            {                    
                sample16Right = BitConverter.ToInt16(buffer, x &#43; 2);
                sample&#43;&#43;;
            }
           
            <span class="rem">// run these samples through the effects</span>
            <span class="kwrd">float</span> sample64Left = sample16Left / 32768.0f;
            <span class="kwrd">float</span> sample64Right = sample16Right / 32768.0f;
            <span class="kwrd">foreach</span> (Effect effect <span class="kwrd">in</span> effects)
            {
                <span class="kwrd">if</span> (effect.Enabled)
                {
                    effect.Sample(<span class="kwrd">ref</span> sample64Left, <span class="kwrd">ref</span> sample64Right);
                }
            }

            sample16Left = (<span class="kwrd">short</span>)(sample64Left * 32768.0f);
            sample16Right = (<span class="kwrd">short</span>)(sample64Right * 32768.0f);

            <span class="rem">// put them back</span>
            buffer[x] = (<span class="kwrd">byte</span>)(sample16Left &amp; 0xFF);
            buffer[x &#43; 1] = (<span class="kwrd">byte</span>)((sample16Left &gt;&gt; 8) &amp; 0xFF); 

            <span class="kwrd">if</span>(WaveFormat.Channels == 2)    
            {
                buffer[x &#43; 2] = (<span class="kwrd">byte</span>)(sample16Right &amp; 0xFF);
                buffer[x &#43; 3] = (<span class="kwrd">byte</span>)((sample16Right &gt;&gt; 8) &amp; 0xFF);
            }
        }
    }


    <span class="kwrd">public</span> <span class="kwrd">bool</span> MoveUp(Effect effect)
    {
        <span class="kwrd">lock</span> (effectLock)
        {
            <span class="kwrd">return</span> effects.MoveUp(effect);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">bool</span> MoveDown(Effect effect)
    {
        <span class="kwrd">lock</span> (effectLock)
        {
            <span class="kwrd">return</span> effects.MoveDown(effect);
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> AddEffect(Effect effect)
    {
        InitialiseEffect(effect);
        <span class="kwrd">lock</span> (effectLock)
        {
            <span class="kwrd">this</span>.effects.Add(effect);
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> InitialiseEffect(Effect effect)
    {
        effect.SampleRate = WaveFormat.SampleRate;
        effect.Init();
        effect.Slider();
    }

    <span class="kwrd">public</span> <span class="kwrd">bool</span> RemoveEffect(Effect effect)
    {
        <span class="kwrd">lock</span> (effectLock)
        {
            <span class="kwrd">return</span> <span class="kwrd">this</span>.effects.Remove(effect);
        }
    }
}</pre>
<p>When the <b>Read</b> method on <b>EffectStream</b> is called, we first read the requested number of bytes from our source
<b>WaveStream</b>. This might be from a WAV or MP3 file, or from a microphone. Then, we convert it from 16 bit to 32 bit floating point audio. 16 bit audio is stored as integers going from -32,768 to 32,767, and 32 bit audio uses the range -1.0 to 1.0 to represent
 this range. This means we have plenty of headroom to mix together multiple signals without distorting. It is important though to remember that no samples should be greater than 1.0 before converting back to 16 bit.</p>
<h3>Porting Effects to .NET</h3>
<p>Now we have a basic effect framework, it is time to create some real effects to use. There are many sources of algorithms for digital signal processing (DSP) (try
<a href="http://www.musicdsp.org/">musicdsp.org</a> for a good starting point), but I have chosen to base my effects model on that provided by the
<a href="http://www.reaper.fm/">REAPER digital audio workstation</a> (DAW). This impressive application, masterminded by legendary software developer
<a href="http://en.wikipedia.org/wiki/Justin_Frankel">Justin Frankel</a>, includes a text-based effects framework. These effects, known as
<a href="http://www.reaper.fm/sdk/js/">JS effects</a>, allow the use of a C-like syntax to quickly write your own effects. I have modelled my
<b>Effect</b> class on the JS syntax, allowing me to quickly port effects across.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Tremolo : Effect
{
    <span class="kwrd">public</span> Tremolo()
    {
        AddSlider(4,0,100,1,<span class="str">&quot;frequency (Hz)&quot;</span>);
        AddSlider(-6,-60,0,1,<span class="str">&quot;amount (dB)&quot;</span>);
        AddSlider(0, 0, 1, 0.1f, <span class="str">&quot;stereo separation (0..1)&quot;</span>);
    }

    <span class="kwrd">float</span> adv, sep, amount, sc, pos;

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Slider()
    {
        adv=PI*2*slider1/SampleRate;
        sep=slider3*PI;
        amount=pow(2,slider2/6);
        sc=0.5f*amount; amount=1-amount;
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Sample(<span class="kwrd">ref</span> <span class="kwrd">float</span> spl0, <span class="kwrd">ref</span> <span class="kwrd">float</span> spl1)
    {
        spl0 = spl0 * ((cos(pos) &#43; 1) * sc &#43; amount);
        spl1 = spl1 * ((cos(pos &#43; sep) &#43; 1) * sc &#43; amount);
        pos &#43;= adv;
    }
}</pre>
<p>Some members in the <b>Effect</b> base class such as <b>cos</b> and <b>slider1</b> allow me to keep the ported syntax as similar to the original JS script as possible.</p>
<p>REAPER ships with well over 100 of these JS Effects, so I chose about 15 of them and ported them to .NET. They are available in the download that accompanies this article. With some of them, for example pitch shifting effects, you will immediately notice
 the effect on the sound, while others, such as compressors, require some knowledge of how to adjust the parameters to get good results.</p>
<h4>The Test Harness</h4>
<p>Obviously we need a way to pass audio through our effects, so our next task is to create a test harness that will allow us to load in audio files and listen to them with the effects applied. For this purpose I created a simple Windows Forms application that
 allows you to select a WAV or MP3 file to play back. After being converted into PCM using various classes from the NAudio library, the resulting
<b>WaveStream</b> is passed through an <b>EffectStream </b>before being passed to the soundcard for playback. The use of an
<b>EffectChain </b>allows us to modify the effects loaded, and their order during playback.</p>
<p>To make the loading of effects simpler, I used the <a></a><a href="http://www.codeplex.com/MEF">Managed Extensibility Framework</a> (MEF), to
<a href="#_msocom_1" name="_msoanchor_1">[DF1]</a> make each effect a “plugin” to the test harness. Each effect is decorated with an
<b>Export</b> attribute to indicate that it is a plugin:</p>
<pre class="csharpcode">[Export(<span class="kwrd">typeof</span>(Effect))]
<span class="kwrd">public</span> <span class="kwrd">class</span> SuperPitch : Effect</pre>
<p>Then I can request that MEF auto-populates a property with all the exported effects it can find:</p>
<pre class="csharpcode">[Import]
<span class="kwrd">public</span> ICollection&lt;Effect&gt; Effects { get; set; }</pre>
<p>When the user selects an effect from the list of available effects, we create a new instance of it. This is because you might want to put the same effect into the effect chain more than once:</p>
<pre class="csharpcode">EffectSelectorForm effectSelectorForm = <span class="kwrd">new</span> EffectSelectorForm(Effects);
<span class="kwrd">if</span> (effectSelectorForm.ShowDialog(<span class="kwrd">this</span>) == DialogResult.OK)
{
    <span class="rem">// create a new instance of the selected effect </span>
    <span class="rem">// as we may want multiple copies of one effect</span>
    Effect effect = (Effect)Activator.CreateInstance(
       effectSelectorForm.SelectedEffect.GetType());
    audioGraph.AddEffect(effect);
    checkedListBox1.Items.Add(effect, <span class="kwrd">true</span>);
}</pre>
<p>To allow real-time modification of the effect parameters, I created two user controls. The first,
<b>EffectSliderPanel</b> allows you to hook up a Windows Forms <b>TrackBar</b> to one of our effect's sliders and manages the minimum, maximum and granularity settings. The second user control,
<b>EffectPanel</b> takes an <b>Effect</b> and creates one <b>EffectSliderPanel</b> for each slider in that effect. It also is responsible for calling the
<b>Slider</b> method on the <b>Effect</b> whenever the user moves one of the sliders. Here's an example of what it looks like:</p>
<p><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image.png" width="488" height="164">
</p>
<p>Now we are able to test our effects by listening to WAV files and playing them with real-time control over their parameters.</p>
<h3>Intercepting Skype Audio</h3>
<p>There are many interesting uses for audio effects, but it was suggested to me that I create a “voice changer” for Skype as the example program for this article. At first I didn't think that this would be possible, as you would need access to the audio samples
 from the microphone <i>before</i> Skype transmitted them over the network.</p>
<p>However, it turns out that Skype has a full featured SDK to allow all kinds of third-party add-ons and enhancements. The Skype API can be used in .NET via a COM object, called
<a href="https://developer.skype.com/">Skype4Com</a>. Skype plugins are not loaded directly by the Skype application but attach to it via network sockets. The Skype4Com COM object hides much of this complexity from the user.</p>
<p>Having added Skype4Com as a reference to our application, we then need to connect to Skype. This is achieved by using the following code:</p>
<pre class="csharpcode"><span class="kwrd">const</span> <span class="kwrd">int</span> Protocol = 8;
skype = <span class="kwrd">new</span> Skype();
_ISkypeEvents_Event events = (_ISkypeEvents_Event)skype;
events.AttachmentStatus &#43;= OnSkypeAttachmentStatus;            
skype.CallStatus &#43;= OnSkypeCallStatus;
skype.Attach(Protocol, <span class="kwrd">false</span>);</pre>
<p>In the <b>CallStatus</b> event handler, we tell Skype that we wish to ‘capture' the microphone. This will cause it to send us the raw audio data from the microphone via a TCP socket. Then we tell it that we will send the audio to be transmitted using another
 TCP socket.</p>
<pre class="csharpcode"><span class="kwrd">void</span> OnSkypeCallStatus(Call call, TCallStatus status)
{
    log.Info(<span class="str">&quot;SkypeCallStatus: {0}&quot;</span>, status);
    <span class="kwrd">if</span> (status == TCallStatus.clsInProgress)
    {
        <span class="kwrd">this</span>.call = call;                  
        call.set_CaptureMicDevice(
        TCallIoDeviceType.callIoDeviceTypePort, MicPort.ToString());
        call.set_InputDevice(
        TCallIoDeviceType.callIoDeviceTypeSoundcard, <span class="str">&quot;&quot;</span>);
        call.set_InputDevice(
        TCallIoDeviceType.callIoDeviceTypePort, OutPort.ToString());
    }
    <span class="kwrd">else</span> <span class="kwrd">if</span> (status == TCallStatus.clsFinished)
    {
        call = <span class="kwrd">null</span>;
        packetSize = 0;
    }
}</pre>
<p>I found an example Delphi application on the Skype developer website which shows how to intercept the microphone signal to
<a href="https://developer.skype.com/Docs/Skype4COM/Example/MicBooster_pas">boost the signal level</a>. I used this sample as the starting point for creating my own application to intercept audio samples in Skype. The Delphi application made use of an object
 called <a href="http://www.indyproject.org/docsite/html/frames.html?frmname=topic&amp;frmfile=TIdTCPServer.html">
TIdTCPServer</a>, which is a multi-threaded socket server. I created a very simple .NET implementation of this class (without the multi-threading as we will only have one connection at a time):</p>
<pre class="csharpcode"><span class="kwrd">class</span> TcpServer : IDisposable
{
    TcpListener listener;
    <span class="kwrd">public</span> <span class="kwrd">event</span> EventHandler&lt;ConnectedEventArgs&gt; Connect;
    <span class="kwrd">public</span> <span class="kwrd">event</span> EventHandler Disconnect;
    <span class="kwrd">public</span> <span class="kwrd">event</span> EventHandler&lt;DataReceivedEventArgs&gt; DataReceived;
    
    <span class="kwrd">public</span> TcpServer(<span class="kwrd">int</span> port)
    {
        listener = <span class="kwrd">new</span> TcpListener(IPAddress.Loopback, port);
        listener.Start();
        ThreadPool.QueueUserWorkItem(Listen);
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> Listen(<span class="kwrd">object</span> state)
    {
        <span class="kwrd">while</span> (<span class="kwrd">true</span>)
        {
            <span class="kwrd">using</span> (TcpClient client = listener.AcceptTcpClient())
            {
                AcceptClient(client);
            }
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> AcceptClient(TcpClient client)
    {
        <span class="kwrd">using</span> (NetworkStream inStream = client.GetStream())
        {
            OnConnect(inStream);
            <span class="kwrd">while</span> (client.Connected)
            {
                <span class="kwrd">int</span> available = client.Available;
                <span class="kwrd">if</span> (available &gt; 0)
                {
                    <span class="kwrd">byte</span>[] buffer = <span class="kwrd">new</span> <span class="kwrd">byte</span>[available];
                    <span class="kwrd">int</span> read = inStream.Read(buffer, 0, available);
                    Debug.Assert(read == available);
                    OnDataReceived(buffer);
                }
                <span class="kwrd">else</span>
                {
                    Thread.Sleep(50);
                }
            }
        }
        OnDisconnect();
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> OnConnect(NetworkStream stream)
    {
        var connect = Connect;
        <span class="kwrd">if</span> (connect != <span class="kwrd">null</span>)
        {
            connect(<span class="kwrd">this</span>, <span class="kwrd">new</span> ConnectedEventArgs() { Stream = stream });
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> OnDisconnect()
    {
        var disconnect = Disconnect;
        <span class="kwrd">if</span> (disconnect != <span class="kwrd">null</span>)
        {
            disconnect(<span class="kwrd">this</span>, EventArgs.Empty);
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> OnDataReceived(<span class="kwrd">byte</span>[] buffer)
    {
        var execute = DataReceived;
        <span class="kwrd">if</span> (execute != <span class="kwrd">null</span>)
        {
            execute(<span class="kwrd">this</span>, <span class="kwrd">new</span> DataReceivedEventArgs() { Buffer = buffer });
        }
    }

    <span class="preproc">#region</span> IDisposable Members

    <span class="kwrd">public</span> <span class="kwrd">void</span> Dispose()
    {
        listener.Stop();
    }

    <span class="preproc">#endregion</span>
}

<span class="kwrd">public</span> <span class="kwrd">class</span> DataReceivedEventArgs : EventArgs
{
    <span class="kwrd">public</span> <span class="kwrd">byte</span>[] Buffer { get; set; }
}

<span class="kwrd">public</span> <span class="kwrd">class</span> ConnectedEventArgs : EventArgs
{
    <span class="kwrd">public</span> NetworkStream Stream { get; set; }
}</pre>
<p>Once Skype has been told the port numbers on which to connect, it will attempt to open sockets to our
<b>TcpListener</b> classes (one for audio in, and one for audio out). We now simply need to pass the audio through our effect chain. But
<b>EffectStream </b>needs a <b>WaveStream</b> derived class for its input, so I created
<b>SkypeBufferStream</b> to which we pass the raw data received on the microphone in socket, and it returns it in its
<b>Read</b> method. One difficulty I encountered was that Skype offers no way of querying what the sample rate of the incoming data is. On my PC it seems to be 44.1kHz, but I do not know if this is guaranteed on all computers.</p>
<pre class="csharpcode"><span class="kwrd">class</span> SkypeBufferStream : WaveStream
{
    <span class="kwrd">byte</span>[] latestInBuffer;
    WaveFormat waveFormat;

    <span class="kwrd">public</span> SkypeBufferStream(<span class="kwrd">int</span> sampleRate)
    {
        waveFormat = <span class="kwrd">new</span> WaveFormat(sampleRate, 16, 1);
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> WaveFormat WaveFormat
    {
        get { <span class="kwrd">return</span> waveFormat; }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Length
    {
        get { <span class="kwrd">return</span> 0; }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Position
    {
        get
        {
            <span class="kwrd">return</span> 0;
        }
        set
        {
            <span class="kwrd">throw</span> <span class="kwrd">new</span> NotImplementedException();
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> SetLatestInBuffer(<span class="kwrd">byte</span>[] buffer)
    {
        latestInBuffer = buffer;
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">int</span> Read(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
    {
        <span class="kwrd">if</span> (offset != 0)
            <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentOutOfRangeException(<span class="str">&quot;offset&quot;</span>);
        <span class="kwrd">if</span> (buffer != latestInBuffer)
            Array.Copy(latestInBuffer, buffer, count);
        <span class="kwrd">return</span> count;
    }
}</pre>
<p>Now when we receive any data from the microphone socket, we pass it through the
<b>SkypeBufferStream</b> which in turn passes it through the <b>EffectStream</b> and finally out on the output socket's data stream. Here's the relevant code (found in the
<b>MicInterceptor</b> class):</p>
<pre class="csharpcode">NetworkStream outStream;
SkypeBufferStream bufferStream;
WaveStream outputStream;

<span class="kwrd">void</span> OnOutServerConnect(<span class="kwrd">object</span> sender, ConnectedEventArgs e)
{
    log.Info(<span class="str">&quot;OutServer Connected&quot;</span>);
    outStream = e.Stream;
}

<span class="kwrd">void</span> OnMicServerExecute(<span class="kwrd">object</span> sender, DataReceivedEventArgs args)
{
    <span class="rem">// log.Info(&quot;Got {0} bytes&quot;, args.Buffer.Length);</span>
    <span class="kwrd">if</span> (outStream != <span class="kwrd">null</span>)
    {
        <span class="rem">// give the input audio to the beginning of our audio graph</span>
        bufferStream.SetLatestInBuffer(args.Buffer);
        <span class="rem">// process it out through the effects</span>
        outputStream.Read(args.Buffer, 0, args.Buffer.Length);
        <span class="rem">// play it back</span>
        outStream.Write(args.Buffer, 0, args.Buffer.Length);
    }
}</pre>
<p>When you run your application for the first time, you will need to grant it permission from within Skype:</p>
<p><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_3.png" width="203" height="133">
</p>
<p><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_4.png" width="500" height="371">
</p>
<p>To test that the effects are working in Skype is a little tricky as you will not hear the effected sound on your end of the conversation. One good way of checking the effects are working as expected is to use the Skype test call service. This is a number
 you can dial and it will record what you say and play it back to you. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_5.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb.png" width="240" height="20"></a>
</p>
<p>It is a good idea to test your effect first using a local audio file, as you will not easily be able to determine whether glitches and other audio artifacts were caused by your effect, or simply due to poor network conditions.</p>
<p>There are a few things you should be aware of when selecting effects for use with Skype. First, the audio is mono, so there is no point using any effects such as stereo delay. Second, the audio is almost certainly down-sampled to a much lower sample rate
 before being transmitted to save on network bandwidth. This means any high frequency components of your sound will be lost. Third, internet telephony applications often have built in echo-suppression, so using delay-based effects might not work quite as well
 as you were hoping. </p>
<p>For silly voice effects, the most effective is pitch shifting (try the <b>SuperPitch</b> effect and shift either up or down about five semitones).
<b>FlangeBaby</b> or <b>Chorus</b> can be used for more subtle voice changing effects. Or if you just want to be annoying, load up a
<b>Delay</b>. Feel free to experiment with the other included effects, but bear in mind that many of them are designed with more musical uses in mind, so may not be relevant for internet telephony.</p>
<h3>The Sample Code</h3>
<p>The source code for all the effects, the <b>EffectStream</b> and the Skype connection code described in this article is available in the provided download. It uses a recent unreleased build of NAudio, so you will also need to visit the NAudio CodePlex site
 if you want to get access to the full source code. The <b>EffectStream</b> and <b>
Effect</b> classes will eventually be made part of the NAudio framework, once I have refined their design a bit.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_6.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_3.png" width="500" height="227"></a>
</p>
<p><b></b></p>
<p>How to use Effect Tester sample app:
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_7.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_4.png" width="45" height="41"></a>
</td>
<td valign="top" width="559">
<p>Click this icon to attach to Skype and await a call. Click it again to disconnect, allowing you to test your effects using audio files instead. The textbox in the top right corner keeps you updated with the status of the connection to Skype</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_8.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_5.png" width="39" height="43"></a>
</td>
<td valign="top" width="559">
<p>Click this icon to load a WAV or MP3 file for playback. Files at 44.1kHz work best.</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_9.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_6.png" width="147" height="40"></a>
</td>
<td valign="top" width="559">
<p>Rewind, Play, Pause or Stop the current WAV or MP3 file.</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_10.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_7.png" width="38" height="42"></a>
</td>
<td valign="top" width="559">
<p>Brings up the effect selector dialog to add a new instance of an effect to the current Effect chain. Loaded effects appear in the CheckedListBox on the left.</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_11.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_8.png" width="42" height="41"></a>
</td>
<td valign="top" width="559">
<p>Removes the currently selected effect from the effect chain</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_12.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_9.png" width="74" height="40"></a>
</td>
<td valign="top" width="559">
<p>Move the currently selected effects up or down in the signal chain</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_13.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_10.png" width="96" height="42"></a>
</td>
<td valign="top" width="559">
<p>Use the checkboxes to enable or disable effects in the effect chain on the fly.</p>
</td>
</tr>
<tr>
<td valign="top" width="57"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_14.png"><img title="image" border="0" alt="image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9391048/image_thumb_11.png" width="228" height="44"></a>
</td>
<td valign="top" width="559">
<p>Use the sliders to adjust the effect parameters in real-time</p>
</td>
</tr>
</tbody>
</table>
</p>
<p><b></b></p>
<h3>About the Author</h3>
<p>Mark<b> </b>Heath is a .NET developer based in Southampton, UK. When he's not writing .NET audio applications for fun, he enjoys home studio recording, playing football, reading theology books and sword fighting with his four small children. His development
 blog can be found at <a href="http://mark-dot-net.blogspot.com">http://mark-dot-net.blogspot.com</a></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:b7d8e2fa4703498d85ec9e7600cd487a">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Skype-Voice-Changer</comments>
      <itunes:summary>
In this article I demonstrate how you can create your own audio effects in .NET to manipulate digital audio at the sample level. These effects are used to process MP3 files while they are being played back, and to process the real-time microphone input allowing
 you to change your voice during a Skype conversation. 




Mark Heath, blog 
 


Source Code: Download 
Difficulty: Intermediate 
Time Required: 8 hours 
Cost: Free 
Software Needed: Visual Basic or Visual C# Express 2008

Libraries: NAudio, 
Skype4COM, MEF 






Audio and the .NET Framework
Playing back audio in a .NET application is not quite as easy as you might hope it would be. The .NET 2.0 Framework introduced the
SoundPlayer component, which allows you to play back an existing WAV file. While this may be fine for many scenarios, as soon as you want to do things even slightly more advanced,
 such as changing the volume, or playing back from a different file-format, or pausing and repositioning, you must resort to writing P/Invoke wrappers for various Windows APIs. 
Back in 2002, as I was getting started learning .NET, I create some audio-related classes of my own to compensate for the lack of audio support in the .NET Framework. I focused initially on reading and writing WAV and MIDI files, as well as playing back
 audio in a way that allowed real-time mixing and manipulation of the audio at a sample level. As time went by, I made this growing collection of audio classes available as an open source project, called
NAudio, now hosted at CodePlex. 
Audio Playback in NAudio
NAudio works by constructing an audio playback graph. Audio comes in “streams” which can be connected together and modified before eventually they go to a renderer. This might be your soundcard if you are listening to the audio, or it might be to a file
 on the hard disk. 
In NAudio, all streams derive from WaveStream. NAudio comes with a collection of useful
WaveStream derived classes such as WaveFileReader to read from WAV files or</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Skype-Voice-Changer</link>
      <pubDate>Mon, 02 Feb 2009 15:19:20 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Skype-Voice-Changer</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9391048_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9391048_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Mark Heath</dc:creator>
      <itunes:author>Mark Heath</itunes:author>
      <slash:comments>51</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Skype-Voice-Changer/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Mash Up</category>
    </item>
  <item>
      <title>Larry Osterman: Windows 7 Audio - What&#39;s New</title>
      <description><![CDATA[The great&nbsp;<a shape="rect" target="_blank" href="http://blogs.msdn.com/LarryOsterman/">Larry Osterman</a> discusses what excites him most about Windows 7's new audio features. Of course, we talk about all things audio as Larry is a 24 year veteran of Microsoft
 and best known as the developer who makes Windows go ding.&nbsp; <a shape="rect" target="_blank" href="http://blogs.msdn.com/LarryOsterman/">
He's also an avid blogger</a>.  <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:d33cf662f5084fbb86649dea00cda24a">]]></description>
      <comments>http://channel9.msdn.com/Blogs/Charles/Inside-Windows-7-Larry-Osterman-on-new-audio-capabilities</comments>
      <itunes:summary>The great&amp;nbsp;Larry Osterman discusses what excites him most about Windows 7&#39;s new audio features. Of course, we talk about all things audio as Larry is a 24 year veteran of Microsoft
 and best known as the developer who makes Windows go ding.&amp;nbsp; 
He&#39;s also an avid blogger. </itunes:summary>
      <itunes:duration>3399</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/Charles/Inside-Windows-7-Larry-Osterman-on-new-audio-capabilities</link>
      <pubDate>Wed, 14 Jan 2009 19:41:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/Charles/Inside-Windows-7-Larry-Osterman-on-new-audio-capabilities</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/434917_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/434917_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_large_ch9.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_small_ch9.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_2MB_ch9.wmv" expression="full" duration="3399" fileSize="1064098339" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_ch9.mp3" expression="full" duration="3399" fileSize="27199239" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_ch9.mp4" expression="full" duration="3399" fileSize="192949302" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_ch9.wma" expression="full" duration="3399" fileSize="27500855" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_ch9.wmv" expression="full" duration="3399" fileSize="213641995" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_Zune_ch9.wmv" expression="full" duration="3399" fileSize="269450087" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_s_ch9.wmv" expression="full" duration="3399" fileSize="225" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/7/1/9/4/3/4/LarryOstermanWin7Audio_ch9.wmv" length="213641995" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Charles</dc:creator>
      <itunes:author>Charles</itunes:author>
      <slash:comments>34</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/Charles/Inside-Windows-7-Larry-Osterman-on-new-audio-capabilities/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Larry Osterman</category>
      <category>Windows 7</category>
    </item>
  <item>
      <title>ButtKicker low frequency audio transducer</title>
      <description><![CDATA[Don't let the name fool you,&nbsp;<a href="http://www.thebuttkicker.com/">ButtKicker</a> brand low frequency audio transducers are serious, award winning and patented. You haven't enjoyed your gaming or movie viewing experience until you've felt the powerful THUD of bass pounding beneath your tushy. The best part about the ButtKicker is that you can install it in your own chouch or chair- so you aren't required to re-style your living room. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:fb7a53b0fd704d188cda9e0f010021d3">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LauraFoy/ButtKicker-at-CES-2008</comments>
      <itunes:summary>Don&#39;t let the name fool you,&amp;nbsp;ButtKicker brand low frequency audio transducers are serious, award winning and patented. You haven&#39;t enjoyed your gaming or movie viewing experience until you&#39;ve felt the powerful THUD of bass pounding beneath your tushy. The best part about the ButtKicker is that you can install it in your own chouch or chair- so you aren&#39;t required to re-style your living room.</itunes:summary>
      <itunes:duration>197</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/LauraFoy/ButtKicker-at-CES-2008</link>
      <pubDate>Tue, 05 Feb 2008 19:44:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LauraFoy/ButtKicker-at-CES-2008</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/on10_19008ebf-ffb4-40b9-ae78-89ba62d40b97.jpg" height="0" width="0"></media:thumbnail>
      <media:thumbnail url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_small_on10.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_2MB_on10.wmv" expression="full" duration="197" fileSize="62102823" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_on10.mp3" expression="full" duration="197" fileSize="1583357" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_on10.mp4" expression="full" duration="197" fileSize="12151565" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_on10.wma" expression="full" duration="197" fileSize="1609237" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_on10.wmv" expression="full" duration="197" fileSize="12689601" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_Zune_on10.wmv" expression="full" duration="197" fileSize="15686733" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/on10/3/7/6/0/2/ButtKicker_s_on10.wmv" expression="full" duration="197" fileSize="201" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/on10/3/7/6/0/2/ButtKicker_on10.wmv" length="12689601" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Laura Foy</dc:creator>
      <itunes:author>Laura Foy</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LauraFoy/ButtKicker-at-CES-2008/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>CES</category>
      <category>speakers</category>
      <category>ButtKicker</category>
    </item>
  <item>
      <title>Surround Sound Capturing with Holophone</title>
      <description><![CDATA[Not only does <a href="http://www.holophone.com/home.html">Holophone</a>&nbsp;design sexy hardware devices that will make you look cool simply by association- they actually perform well. Holophone offers us surround sound audio capturing for everybody from the power user to the NFL. They make it easy and affordable for whatever your needs may be. Plu, like I said, the stuff looks mighty cool. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:3c1140e32cbb4bc9a7299e0f00ffd727">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LauraFoy/Holophone</comments>
      <itunes:summary>Not only does Holophone&amp;nbsp;design sexy hardware devices that will make you look cool simply by association- they actually perform well. Holophone offers us surround sound audio capturing for everybody from the power user to the NFL. They make it easy and affordable for whatever your needs may be. Plu, like I said, the stuff looks mighty cool.</itunes:summary>
      <itunes:duration>388</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/LauraFoy/Holophone</link>
      <pubDate>Fri, 21 Dec 2007 22:02:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LauraFoy/Holophone</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/preview/holophone_large_on10.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/previewsmall/holophone_small_on10.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_2MB_on10.wmv" expression="full" duration="388" fileSize="106015951" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_on10.mp3" expression="full" duration="388" fileSize="3110580" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_on10.mp4" expression="full" duration="388" fileSize="23700097" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_on10.wma" expression="full" duration="388" fileSize="3150263" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_on10.wmv" expression="full" duration="388" fileSize="22097569" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_Zune_on10.wmv" expression="full" duration="388" fileSize="30823853" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/on10/2/8/0/0/2/holophone_s_on10.wmv" expression="full" duration="388" fileSize="198" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/on10/2/8/0/0/2/holophone_on10.wmv" length="22097569" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Laura Foy</dc:creator>
      <itunes:author>Laura Foy</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LauraFoy/Holophone/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>sound</category>
      <category>speakers</category>
      <category>Recording</category>
      <category>holophone</category>
    </item>
  <item>
      <title>TechNet Radio:  A first look at Microsoft&#39;s Unified Communications solutions</title>
      <description><![CDATA[
<p class="MsoNormal"><span>Join Sukhvinder Singh Gulati, Sr. Lead Program Manager, for a first look at Microsoft's newest unified communications solutions. Sukhvinder will discuss products like Office Communications Server 2007, Office Communicator 2007, Office
 Live Meeting 2007, Exchange Server 2007 Unified Messaging, and devices like Microsoft Office RoundTable. He'll explain how Microsoft is integrating all your unified communication needs in one single portfolio of products, making it easier to manage and administer
 your communications.</span></p>
<p class="MsoNormal"><font face="Arial" size="2"></p>
<hr align="center" width="100%" size="2">
</font>
<p></p>
<p></p>
<span><font color="#000000"><span><span><span><span><span>
<p class="MsoNormal"><span>Eric Ostrowski - Your Show Host and <span>TechNet Radio Producer<br>
</span></span><span><span>Kevin Remde – IT Pro Evangelist<br>
</span><span>Sukhvinder Singh Gulati - Sr. Lead Program Manager</span></p>
<p class="MsoNormal"></span></p>
<p class="MsoNormal"></span><span></p>
</span>
<p></p>
</span></span></span></span></font></span> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:749b89c77fee476f8eb69dea00bec7df">]]></description>
      <comments>http://channel9.msdn.com/Shows/TechNet+Radio/TechNet-Radio-A-first-look-at-Microsofts-Unified-Communications-solutions</comments>
      <itunes:summary>
Join Sukhvinder Singh Gulati, Sr. Lead Program Manager, for a first look at Microsoft&#39;s newest unified communications solutions. Sukhvinder will discuss products like Office Communications Server 2007, Office Communicator 2007, Office
 Live Meeting 2007, Exchange Server 2007 Unified Messaging, and devices like Microsoft Office RoundTable. He&#39;ll explain how Microsoft is integrating all your unified communication needs in one single portfolio of products, making it easier to manage and administer
 your communications. 
 


 
 

Eric Ostrowski - Your Show Host and TechNet Radio Producer
Kevin Remde – IT Pro Evangelist
Sukhvinder Singh Gulati - Sr. Lead Program Manager 
 
 

 
</itunes:summary>
      <itunes:duration>1536</itunes:duration>
      <link>http://channel9.msdn.com/Shows/TechNet+Radio/TechNet-Radio-A-first-look-at-Microsofts-Unified-Communications-solutions</link>
      <pubDate>Tue, 06 Nov 2007 19:08:56 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/TechNet+Radio/TechNet-Radio-A-first-look-at-Microsofts-Unified-Communications-solutions</guid>
      <media:group>
        <media:content url="http://download.microsoft.com/download/2/b/c/2bc22e38-2421-4d6d-849c-678f96f62d07/TechNetRadio-071106-hi-web.mp3" expression="full" duration="1536" fileSize="9260846" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://download.microsoft.com/download/2/b/c/2bc22e38-2421-4d6d-849c-678f96f62d07/TechNetRadio-071106-web.wma" expression="full" duration="1536" fileSize="6370417" type="audio/x-ms-wma" medium="audio"></media:content>
      </media:group>      
      <enclosure url="http://download.microsoft.com/download/2/b/c/2bc22e38-2421-4d6d-849c-678f96f62d07/TechNetRadio-071106-web.wma" length="6370417" type="audio/x-ms-wma"></enclosure>
      <dc:creator>erickingfrog</dc:creator>
      <itunes:author>erickingfrog</itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/TechNet+Radio/TechNet-Radio-A-first-look-at-Microsofts-Unified-Communications-solutions/RSS</wfw:commentRss>
      <category>Application Compatibility</category>
      <category>Audio</category>
      <category>Collaboration</category>
      <category>MS Office</category>
      <category>Office</category>
    </item>
  <item>
      <title>Ultimate Ears: In Action</title>
      <description><![CDATA[<a href="http://www.ultimateears.com/_ultimateears/">Ultimate Ears</a> personal monitors brings you music the way it was meant to be heard. Used by musicians across the globe its unbelievable the superior sound quality that these tiny little devise can bring you. With so much technology packed into a tiny little punch I decided I had to see how it was done. Check out my visit to their lab to see the technicians in action, and then check out my <a href="http://on10.net/Blogs/laura/ultimate-ears-how-music-was-meant-to-be-heard/">first report</a>&nbsp;on Ultimate Ears to learn more. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:7158856a0213485ebfaf9e0f00fe31b6">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LauraFoy/pt2-Ultimate-Ears-In-Action</comments>
      <itunes:summary>Ultimate Ears personal monitors brings you music the way it was meant to be heard. Used by musicians across the globe its unbelievable the superior sound quality that these tiny little devise can bring you. With so much technology packed into a tiny little punch I decided I had to see how it was done. Check out my visit to their lab to see the technicians in action, and then check out my first report&amp;nbsp;on Ultimate Ears to learn more.</itunes:summary>
      <itunes:duration>629</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/LauraFoy/pt2-Ultimate-Ears-In-Action</link>
      <pubDate>Fri, 24 Aug 2007 17:07:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LauraFoy/pt2-Ultimate-Ears-In-Action</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/preview/earspart2_large_on10.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/previewsmall/earspart2_small_on10.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_2MB_on10.wmv" expression="full" duration="629" fileSize="196529409" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_on10.mp3" expression="full" duration="629" fileSize="5029221" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_on10.mp4" expression="full" duration="629" fileSize="37800906" type="video/mp4" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_on10.wma" expression="full" duration="629" fileSize="5090877" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_on10.wmv" expression="full" duration="629" fileSize="39900366" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_Zune_on10.wmv" expression="full" duration="629" fileSize="50473322" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/on10/3/0/5/8/1/EarsPart2_s_on10.wmv" expression="full" duration="629" fileSize="198" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/on10/3/0/5/8/1/EarsPart2_on10.wmv" length="39900366" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Laura Foy</dc:creator>
      <itunes:author>Laura Foy</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LauraFoy/pt2-Ultimate-Ears-In-Action/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Music</category>
      <category>sound</category>
      <category>Technology</category>
    </item>
  <item>
      <title>geekSpeak recording: Speech Server with Michael Dunn</title>
      <description><![CDATA[In this geekSpeak (or maybe we should say &quot;geekSpeech&quot;) we explore Microsoft Speech Server technologies, focusing on&nbsp;Microsoft Office Communications Server 2007.<br>
<br>
After covering how Speech Server is now incorporated into OCS 2007, we talk about how it now supports industry standards&nbsp;for building IVR applications like&nbsp;SALT and VoiceXML. Michael shows a cool demo of creating a voice response workflow using the new designers
 based on Windows Workflow Foundation, which is incredibly easy to use. <br>
<br>
It's pretty exciting to see how integrated this technology is with .NET so you can do things like utilize WCF, make web service calls, reuse a data access or business logic layer, program in C# or VB, etc.<br>
<br>
Some great quesitons came through on the geekSpeak including using Speech Server with robotics as well as&nbsp;how to manage grammar, keywords, and concept answers. Michael also helps us understand considerations for&nbsp; design your voice UI around speech recognition
 versus DTMF (touch-tones).<br>
<br>
We also touch on testing approaches as well as how to work with systems such as Skype and Vonage.<br>
<br>
For more resources on Speech Server technologies, go to <a href="http://www.microsoft.com/speech">
http://www.microsoft.com/speech</a> as well as Michael's blog <a href="http://gotspeech.net/blogs/michaeldunn">
http://gotspeech.net/blogs/michaeldunn</a> .<br>
<br>
Let us know through here and the <a href="http://blogs.msdn.com/geekSpeak"><font color="#a55506">geekSpeak blog</font></a>&nbsp;what you'd like to see geekSpeaks in the future cover.<br>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:dbc1bb1d97f34d7eb3c29dea00c2cd59">]]></description>
      <comments>http://channel9.msdn.com/Shows/geekSpeak/geekSpeak-recording-Speech-Server-with-Michael-Dunn</comments>
      <itunes:summary>In this geekSpeak (or maybe we should say &amp;quot;geekSpeech&amp;quot;) we explore Microsoft Speech Server technologies, focusing on&amp;nbsp;Microsoft Office Communications Server 2007.

After covering how Speech Server is now incorporated into OCS 2007, we talk about how it now supports industry standards&amp;nbsp;for building IVR applications like&amp;nbsp;SALT and VoiceXML. Michael shows a cool demo of creating a voice response workflow using the new designers
 based on Windows Workflow Foundation, which is incredibly easy to use. 

It&#39;s pretty exciting to see how integrated this technology is with .NET so you can do things like utilize WCF, make web service calls, reuse a data access or business logic layer, program in C# or VB, etc.

Some great quesitons came through on the geekSpeak including using Speech Server with robotics as well as&amp;nbsp;how to manage grammar, keywords, and concept answers. Michael also helps us understand considerations for&amp;nbsp; design your voice UI around speech recognition
 versus DTMF (touch-tones).

We also touch on testing approaches as well as how to work with systems such as Skype and Vonage.

For more resources on Speech Server technologies, go to 
http://www.microsoft.com/speech as well as Michael&#39;s blog 
http://gotspeech.net/blogs/michaeldunn .

Let us know through here and the geekSpeak blog&amp;nbsp;what you&#39;d like to see geekSpeaks in the future cover.
</itunes:summary>
      <itunes:duration>3598</itunes:duration>
      <link>http://channel9.msdn.com/Shows/geekSpeak/geekSpeak-recording-Speech-Server-with-Michael-Dunn</link>
      <pubDate>Fri, 27 Jul 2007 03:32:20 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/geekSpeak/geekSpeak-recording-Speech-Server-with-Michael-Dunn</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/256584_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/256584_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/ec451dc3-d908-4e9a-8268-9297d38f2e26.jpg" height="203" width="270"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/fd9f1cc0-91df-455e-b340-98bb02ddeb01.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/4/8/5/6/5/2/329523_geekSpeak_MichaelDunn_20070718.wmv" expression="full" duration="3598" fileSize="1" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/4/8/5/6/5/2/329523_geekSpeak_MichaelDunn_20070718.wmv" length="0" type="video/x-ms-wmv"></enclosure>
      <dc:creator>glengo</dc:creator>
      <itunes:author>glengo</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/geekSpeak/geekSpeak-recording-Speech-Server-with-Michael-Dunn/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Speech Server</category>
    </item>
  <item>
      <title>Cakewalk: Making Music with Sonar</title>
      <description><![CDATA[The guys at <a href="http://www.cakewalk.com">Cakewalk </a>are passionate about music and providing the technology that enables audio enthusiasts &amp; professionals to create great music. Noel Borthwick, Cakewalk CTO and Carl Jacobson, Woldwide Marketing
 Director, spend some time with Inside Out talking about their lessons learned as an early Vista adopter for their audio application Sonar, which also is the only application of its kind for the 64-bit platform.
<br>
<br>
They also talk candidly about the development process and experiences with managed code, certification documentation and virtualization.
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:fcd1734a3c7f49ea95939dea00bfbc0f">]]></description>
      <comments>http://channel9.msdn.com/Shows/Inside+Out/Cakewalk-Making-Music-with-Sonar</comments>
      <itunes:summary>The guys at Cakewalk are passionate about music and providing the technology that enables audio enthusiasts &amp;amp; professionals to create great music. Noel Borthwick, Cakewalk CTO and Carl Jacobson, Woldwide Marketing
 Director, spend some time with Inside Out talking about their lessons learned as an early Vista adopter for their audio application Sonar, which also is the only application of its kind for the 64-bit platform.


They also talk candidly about the development process and experiences with managed code, certification documentation and virtualization.
</itunes:summary>
      <itunes:duration>1860</itunes:duration>
      <link>http://channel9.msdn.com/Shows/Inside+Out/Cakewalk-Making-Music-with-Sonar</link>
      <pubDate>Thu, 05 Jul 2007 17:47:51 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/Inside+Out/Cakewalk-Making-Music-with-Sonar</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/100/249425_100x75.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/220/249425_220x165.jpg" height="165" width="220"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/320/8e0c3329-e62f-4839-9594-81dc85e48320.jpg" height="213" width="270"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/previewImages/85/276d9bea-78bd-4bf1-acc0-a137c803c931.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://download.microsoft.com/download/f/2/7/f27575dd-efec-4056-adad-70eab1ca5f0e/IO_Cakewalk_ch9.mp3" expression="full" duration="1860" fileSize="14887497" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/0/7/2/2/3/cakewalk.20070604.182700.wmv" expression="full" duration="1860" fileSize="1" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="mms://mschnlnine.wmod.llnwd.net/a1809/d1/ch9/0/0/7/2/2/3/IO_Cakewalk_s_ch9.wmv" expression="full" duration="1860" fileSize="1" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/0/7/2/2/3/cakewalk.20070604.182700.wmv" length="0" type="audio/x-ms-wma"></enclosure>
      <dc:creator>Charles</dc:creator>
      <itunes:author>Charles</itunes:author>
      <slash:comments>14</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/Inside+Out/Cakewalk-Making-Music-with-Sonar/RSS</wfw:commentRss>
      <category>64-bit</category>
      <category>Application Compatibility</category>
      <category>Audio</category>
      <category>Drivers</category>
      <category>Partner</category>
      <category>Windows Vista</category>
    </item>
  <item>
      <title>Ultimate Ears: How music was meant to be heard</title>
      <description><![CDATA[You've never listened to your Zune like <a href="http://www.ultimateears.com/">THIS </a>before. I used to think headphones are headphones are headphones - but now I know that's not the case. Musicians know their stuff and they need the highest quality, most precise audio in their ears and that's why most on-stage performers use Ultimate Ears. There's actually an insane amount of technology all crammed into that little tiny earpiece. I wish you could all experience what I heard but take a look at this clip and I'm sure you'll get a better understanding of how music was meant to be heard. <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:3b9bb4ad679442a6bcba9e0f00fdb4e7">]]></description>
      <comments>http://channel9.msdn.com/Blogs/LauraFoy/Ultimate-Ears-How-music-was-meant-to-be-heard</comments>
      <itunes:summary>You&#39;ve never listened to your Zune like THIS before. I used to think headphones are headphones are headphones - but now I know that&#39;s not the case. Musicians know their stuff and they need the highest quality, most precise audio in their ears and that&#39;s why most on-stage performers use Ultimate Ears. There&#39;s actually an insane amount of technology all crammed into that little tiny earpiece. I wish you could all experience what I heard but take a look at this clip and I&#39;m sure you&#39;ll get a better understanding of how music was meant to be heard.</itunes:summary>
      <itunes:duration>742</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/LauraFoy/Ultimate-Ears-How-music-was-meant-to-be-heard</link>
      <pubDate>Thu, 28 Jun 2007 17:20:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/LauraFoy/Ultimate-Ears-How-music-was-meant-to-be-heard</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/preview/ears_large_on10.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/previewsmall/ears_small_on10.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_2MB_on10.wmv" expression="full" duration="742" fileSize="226994089" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_on10.mp3" expression="full" duration="742" fileSize="5945179" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_on10.mp4" expression="full" duration="742" fileSize="45206830" type="video/mp4" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_on10.wma" expression="full" duration="742" fileSize="6016087" type="audio/x-ms-wma" medium="audio"></media:content>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_on10.wmv" expression="full" duration="742" fileSize="45880922" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_Zune_on10.wmv" expression="full" duration="742" fileSize="59657990" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://on10.net/videos/ears_on10.asx" expression="full" duration="742" fileSize="102" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://download.microsoft.com/download/7/0/2/7022be2e-7174-46ec-8ce5-e20d03080ce4/ears_on10.wmv" length="45880922" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Laura Foy</dc:creator>
      <itunes:author>Laura Foy</itunes:author>
      <slash:comments>10</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/LauraFoy/Ultimate-Ears-How-music-was-meant-to-be-heard/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Music</category>
      <category>sound</category>
      <category>ears</category>
    </item>
  <item>
      <title>Behringer rocks it out for channel 10</title>
      <description><![CDATA[So you want to be a rockstar?&nbsp; Well, <a>Behringer</a>...a global M.I. audio company wants to help you make that happen.&nbsp; They make audio products for just about everybody.&nbsp; From consumers to professional musicians.&nbsp; They have USB guitars which I didn't know much about but I'm completely impressed.&nbsp; They've got podcasting equipment as well.&nbsp; Check out some other Behringer products <a>here</a>.&nbsp; <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e05328a6f2284c86a9729e0f000f31a8">]]></description>
      <comments>http://channel9.msdn.com/Blogs/Tina/Behringer-rocks-it-out-for-channel-10</comments>
      <itunes:summary>So you want to be a rockstar?&amp;nbsp; Well, Behringer...a global M.I. audio company wants to help you make that happen.&amp;nbsp; They make audio products for just about everybody.&amp;nbsp; From consumers to professional musicians.&amp;nbsp; They have USB guitars which I didn&#39;t know much about but I&#39;m completely impressed.&amp;nbsp; They&#39;ve got podcasting equipment as well.&amp;nbsp; Check out some other Behringer products here.&amp;nbsp;</itunes:summary>
      <itunes:duration>224</itunes:duration>
      <link>http://channel9.msdn.com/Blogs/Tina/Behringer-rocks-it-out-for-channel-10</link>
      <pubDate>Wed, 27 Jun 2007 16:20:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Blogs/Tina/Behringer-rocks-it-out-for-channel-10</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/preview/behringer_large_on10.jpg" height="240" width="320"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/content/on10/entries/previewsmall/behringer_small_on10.jpg" height="64" width="85"></media:thumbnail>
      <media:group>
        <media:content url="http://download.microsoft.com/download/9/e/f/9efa03f0-4254-4abe-9c42-4725e5701a31/Behringer_2MB_on10.wmv" expression="full" duration="224" fileSize="32950874" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/9/e/f/9efa03f0-4254-4abe-9c42-4725e5701a31/Behringer_on10.mp4" expression="full" duration="224" fileSize="13784163" type="video/mp4" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/9/e/f/9efa03f0-4254-4abe-9c42-4725e5701a31/Behringer_on10.wmv" expression="full" duration="224" fileSize="9564648" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://download.microsoft.com/download/9/e/f/9efa03f0-4254-4abe-9c42-4725e5701a31/Behringer_Zune_on10.wmv" expression="full" duration="224" fileSize="17974916" type="video/x-ms-wmv" medium="video"></media:content>
        <media:content url="http://on10.net/videos/Behringer_on10.asx" expression="full" duration="224" fileSize="107" type="video/x-ms-wmv" medium="video"></media:content>
      </media:group>      
      <enclosure url="http://download.microsoft.com/download/9/e/f/9efa03f0-4254-4abe-9c42-4725e5701a31/Behringer_on10.wmv" length="9564648" type="video/x-ms-wmv"></enclosure>
      <dc:creator>Tina</dc:creator>
      <itunes:author>Tina</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Blogs/Tina/Behringer-rocks-it-out-for-channel-10/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Seattle</category>
      <category>Behringer</category>
      <category>musician</category>
    </item>
  <item>
      <title>The Voice of Support - Show 011: The Zune Support Experience</title>
      <description><![CDATA[
<p>Welcome to the Show #11 of <strong>The Voice of Support</strong>! <br>
<br>
In this session, we sat down with <strong>Nabil Pike</strong>, Lead Program Manager for Zune Supportability. Nabil talks about the day-to-day activities of the Zune support team, his history here @ Microsoft, and the history of building the support experience
 for the Zune from concept to market. This is a really cool device - and if you haven't checked it out yet, you really should. <img src='http://ecn.channel9.msdn.com/o9/content/images/emoticons/emotion-2.gif' alt='Big Smile' /><br>
<br>
While we certainly have a lot of support-related content ideas to bring you, we really hope to hear from you, our listeners, about the specific topics you'd like to hear about in future sessions! Please use our&nbsp;<strong><a href="http://support.microsoft.com/common/survey.aspx?scid=sw;en;1328" target="_blank">Ask
 for It</a> </strong>form to let us know what you think!<br>
<br>
<font color="#ffa500"><br>
<br>
<strong>LINKS<br>
<br>
</strong></font><a href="http://support.microsoft.com/webcasts">Support WebCasts</a><br>
<br>
<a href="http://www.zune.net/">Zune.net </p>
<p></a></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Tags/audio/RSS&WT.dl=0&WT.entryid=Entry:RSSView:db99936cde304ae3bcf99dea00bd9452">]]></description>
      <comments>http://channel9.msdn.com/Shows/The+Voice+of+Support/The-Voice-of-Support-Show-011-The-Zune-Support-Experience</comments>
      <itunes:summary>
Welcome to the Show #11 of The Voice of Support! 

In this session, we sat down with Nabil Pike, Lead Program Manager for Zune Supportability. Nabil talks about the day-to-day activities of the Zune support team, his history here @ Microsoft, and the history of building the support experience
 for the Zune from concept to market. This is a really cool device - and if you haven&#39;t checked it out yet, you really should. 

While we certainly have a lot of support-related content ideas to bring you, we really hope to hear from you, our listeners, about the specific topics you&#39;d like to hear about in future sessions! Please use our&amp;nbsp;Ask
 for It form to let us know what you think!



LINKS

Support WebCasts

Zune.net  
 
</itunes:summary>
      <itunes:duration>1422</itunes:duration>
      <link>http://channel9.msdn.com/Shows/The+Voice+of+Support/The-Voice-of-Support-Show-011-The-Zune-Support-Experience</link>
      <pubDate>Tue, 05 Jun 2007 19:12:24 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/Shows/The+Voice+of+Support/The-Voice-of-Support-Show-011-The-Zune-Support-Experience</guid>
      <media:group>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/7/2/5/5/2/313533_vos032007_zune.mp3" expression="full" duration="1422" fileSize="1" type="audio/mp3" medium="audio"></media:content>
        <media:content url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/7/2/5/5/2/313533_vos032007_zune.wma" expression="full" duration="1422" fileSize="1" type="audio/x-ms-wma" medium="audio"></media:content>
      </media:group>      
      <enclosure url="http://mschnlnine.vo.llnwd.net/d1/ch9/0/7/2/5/5/2/313533_vos032007_zune.wma" length="0" type="audio/x-ms-wma"></enclosure>
      <dc:creator>gsamedia</dc:creator>
      <itunes:author>gsamedia</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/Shows/The+Voice+of+Support/The-Voice-of-Support-Show-011-The-Zune-Support-Experience/RSS</wfw:commentRss>
      <category>Audio</category>
      <category>Community</category>
      <category>Customer Support</category>
      <category>Microsoft Personalities</category>
      <category>Startups</category>
    </item>    
</channel>
</rss>