Monday, January 6, 2014

Getting Started with NAudio and WinRT C# (Windows 8 Store)

I’ve recently been experimenting with the Audio APIs available for Windows Store apps and I discovered there’s an early release of NAudio working for Windows 8 Store apps.
I wouldn’t recommend using it in a commercial app without thorough testing but its definitely worth taking a look as its sure to be updated in the coming months. As the time of writing the current release is 1.7.0 beta 01.

1. Get the NAudio nuget Package
If you’re not experienced with nuget you can open the package manger prompt by navigating to:
TOOLS –> Library Package Manager –> Package Manager Console in Visual Studio 2012/2013
And then type in “Install-Package NAudio” (without the quotes of course).  If you have multiple projects in your solution make sure you have the correct project selected in the Default Project dropdown.

2. Read Mark Heath’s excellent post on NAudio
This post goes all the way back to 2009 but we can use most of his example code verbatim.

3. Copy/Create Mark’s WaveProvider32 and SineWaveProvider32 classes

Both of this classes will work without modification.  You’ll just need to add the NAudio using:
using NAudio.Wave;

4. Create a Win8 WasapiOutRT

You’ll need to update Mark’s example to actually make some noise.
Now we’ll need an instance of WasapiOutRT instead WaveOut.  Make this a member variable not a local variable.
NAudio.Win8.Wave.WaveOutputs.WasapiOutRT waveOut;
And the final important notes, to use  the “StartStopSineWave” mthod you’ll need to mark it as async and await the Init call.  Otherwise you’ll get silence and no obvious error messages.  My edits look like this:
private async void StartStopSineWave()
    if (waveOut == null)
        var sineWaveProvider = new SineWaveProvider32();
        sineWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
        sineWaveProvider.Frequency = 440;
        sineWaveProvider.Amplitude = 0.8f;
        waveOut = new NAudio.Win8.Wave.WaveOutputs.WasapiOutRT(NAudio.CoreAudioApi.AudioClientShareMode.Shared, 100);
        await waveOut.Init(sineWaveProvider);
        waveOut = null;

One other quick note.  Moving forward, if you decide to change the WaveProvider32 class to use 2 channels rather than 1 you’ll want to edit the sample rate in the Read method in SineWaveProvider32:

int sampleRate = WaveFormat.SampleRate * WaveFormat.Channels;

For more information you’re best bet is the NAudio dissusions on CodePlex:

My next goal is to try capturing audio.  Happy Coding!