Wednesday, 4 June 2008

NAudio Wave Stream Architecture

This post explains the basic architecture for audio streaming with the NAudio .NET open source audio library. The most important concept to understand is a Wave Stream. This is simply a stream of audio data, in any format, that can be read from and repositioned. In NAudio, all Wave Streams inherit from WaveStream, which in turn inherits from System.IO.Stream. NAudio ships with a number of highly useful WaveStream derived classes, but there is nothing stopping you creating your own.

Many types of Wave Stream accept input from one or more other Wave Streams and process that data in some way. For example, the WaveChannel32 stream turns mono 16 bit WAV data into stereo 32 bit data, and allows you to adjust panning and volume at the same time. The WaveMixer32 stream can take any number of 32 bit input streams and mix them together to produce a single output. The WaveFormatConversionStream will attempt to find an ACM codec that performs the format conversion you wish. For example, you might have some ADPCM compressed audio that you wish to decompress to PCM. Another common use of WaveStreams is to apply audio effects such as EQ, reverb or compression to the signal.

Obviously, you need a starting point for your Wave data to come from. The most common options are the WaveFileReader which can read standard WAV files, and the WaveInStream which captures data from a soundcard. Other examples that you might want to create would be a software synthesizer, emitting sound according to the notes the user was playing on a MIDI keyboard.

Once you have processed your audio data, you will want to render it somewhere. The two main options are to an audio device or to a file. NAudio provides a variety of options here. The most common are WaveOut which allows playback of a WaveStream using the WinMM APIs and WaveFileWriter which can write standard WAV files.

The following example shows a very simple graph which reads from one WAV file and passes the data through the DMO Resampler Wave Stream before writing it out to another WAV file. This would be all you needed to create your own WAV file resampling utility:


Of course, you can do much more complicated things with Wave Streams. The next example shows three WaveFileReader objects as the inputs. Two of them go through some stages of format conversion before they are all converted into IEEE 32 bit audio. Then one of the streams goes through an audio compressor effect to adjust its dynamic range, before all three streams are mixed together by WaveMixer32. The output could be processed further, but in this example it is simply played out of the soundcard using WaveOut.


Hopefully this gives a good flavour of the type of things possible with WaveStreams in NAudio. In a future post, I will explain how to create your own custom WaveStream, and I will discuss in more depth the design decisions behind the WaveStream class.

Post a Comment