## File: README.md # NAudio [](https://github.com/naudio/NAudio/blob/main/LICENSE) [](https://www.nuget.org/packages/NAudio/) [](https://github.com/naudio/NAudio/actions/workflows/build.yml) NAudio is an open source .NET audio library written by [Mark Heath](https://markheath.net) 📖 **[Documentation site](https://naudio.github.io/NAudio/)** — tutorials and the full API reference. ## NAudio 3 NAudio 3 is a major release. The headlines: * **The single `NAudio` assembly is split into focused packages** — take only what you need. The `NAudio` meta-package still pulls the Windows stack together, so existing consumers see no change. * **The core is cross-platform and Native-AOT compatible.** `NAudio.Core`, `NAudio.Midi`, `NAudio.Effects`, `NAudio.Sampler` and `NAudio.SoundFile` run on Windows, Linux and macOS. * **Minimum target framework is `net9.0`** — legacy .NET Framework and .NET Standard 2.0 support is dropped. * **New subsystems:** an audio effects framework, a software sampler, VST 3 hosting, ALSA playback/capture on Linux, and cross-platform file I/O via libsndfile. * **Modernised WASAPI and ASIO** — the new `WasapiPlayer` / `WasapiRecorder` and `AsioDevice` APIs. Upgrading from NAudio 2? Start with **[Migrating from NAudio 2 to NAudio 3](Docs/MigratingFromNAudio2.md)**. The full list of changes is in [RELEASE_NOTES.md](RELEASE_NOTES.md). ## Packages Installing the [`NAudio`](https://www.nuget.org/packages/NAudio/) meta-package gets you the full Windows stack and is the right default. On a non-Windows target framework it resolves to the cross-platform pieces only. Reference the individual packages directly if you want a smaller surface. | Package | Platform | What it gives you | | --- | --- | --- | | [NAudio](https://www.nuget.org/packages/NAudio/) | any | Meta-package — the Windows stack plus `AudioFileReader` and `Mp3FileReader` | | [NAudio.Core](https://www.nuget.org/packages/NAudio.Core/) | cross-platform | `WaveStream` / `ISampleProvider` model, WAV & AIFF I/O, mixing, resampling, DSP, `NAudio.Effects`, sequencing | | [NAudio.Midi](https://www.nuget.org/packages/NAudio.Midi/) | cross-platform (+ WinRT MIDI on Windows) | MIDI event model, Standard MIDI File reading & writing | | [NAudio.Wasapi](https://www.nuget.org/packages/NAudio.Wasapi/) | Windows | WASAPI playback, capture and loopback; Media Foundation codecs | | [NAudio.WinMM](https://www.nuget.org/packages/NAudio.WinMM/) | Windows | `WaveOut` / `WaveIn`, classic MIDI I/O, ACM codecs, mixer controls | | [NAudio.Asio](https://www.nuget.org/packages/NAudio.Asio/) | Windows | Low-latency multichannel playback and capture through ASIO drivers | | [NAudio.Dmo](https://www.nuget.org/packages/NAudio.Dmo/) | Windows | DMO effects, DMO MP3 decoder and resampler, `DirectSoundOut` | | [NAudio.WinForms](https://www.nuget.org/packages/NAudio.WinForms/) | Windows | WinForms controls, and the window-callback `WaveOutWindow` / `WaveInWindow` | | [NAudio.Sampler](https://www.nuget.org/packages/NAudio.Sampler/) | cross-platform | Polyphonic software sampler — SoundFont (`.sf2`), SFZ and single-sample instruments | | [NAudio.SoundFile](https://www.nuget.org/packages/NAudio.SoundFile/) | cross-platform | Read *and write* WAV/AIFF/FLAC/Ogg-Vorbis/Opus/MP3 via libsndfile | | [NAudio.Alsa](https://www.nuget.org/packages/NAudio.Alsa/) | Linux | `AlsaOut` / `AlsaIn` playback and capture via libasound | | [NAudio.Vst3](https://www.nuget.org/packages/NAudio.Vst3/) | Windows | VST 3 plug-in hosting (preview) — effects and instruments | | [NAudio.Extras](https://www.nuget.org/packages/NAudio.Extras/) | cross-platform (+ Windows extras) | Opinionated helpers — playback engine, capture mixing, ID3 tags | `NAudio.Core`, `NAudio.Midi`, `NAudio.Wasapi`, `NAudio.Dmo`, `NAudio.Sampler`, `NAudio.SoundFile` and `NAudio.Alsa` are Native-AOT compatible. See [the assembly layout plan](Docs/Architecture/NAudio3AssemblyLayoutPlan.md) for the reasoning behind the split. ## Documentation * **[Documentation site](https://naudio.github.io/NAudio/)** — tutorials and the full API reference. * **[Tutorials](#tutorials)** — the task-focused how-to guides listed below, also in [Docs/](Docs/). * **[Migrating from NAudio 2](Docs/MigratingFromNAudio2.md)** — every breaking change, with before/after code. * **[NAudio articles on Mark Heath's blog](http://markheath.net/category/naudio)**. NAudio comes with several demo applications, which are the quickest way to see how the various features fit together: [NAudioDemo](samples/NAudioDemo) (WinForms), [NAudioWpfDemo](samples/NAudioWpfDemo), and the smaller [NAudioConsoleTest](samples/NAudioConsoleTest), [AudioFileInspector](samples/AudioFileInspector), [MidiFileConverter](samples/MidiFileConverter) and [MixDiff](samples/MixDiff) tools. They have the advantage of being kept up to date, whilst some of the tutorials you will find on the internet refer to old versions of NAudio. ## Features * Play back audio using a variety of APIs * WASAPI (`WasapiPlayer`, and the legacy `WasapiOut`) * WaveOut * ASIO * DirectSound * ALSA on Linux * Read audio from many standard file formats * WAV, AIFF and raw PCM * MP3 (using ACM, DMO or MFT) * G.711 mu-law and a-law * ADPCM, G.722, Opus (using Concentus) * WMA, AAC, MP4 and more with Media Foundation * FLAC, Ogg Vorbis, Opus and MP3 cross-platform with libsndfile * Convert between various forms of uncompressed audio * Change the number of channels — mono to stereo, stereo to mono, and arbitrary matrix routings * Modify bit depth (8, 16, 24, 32 integer or 32 bit IEEE float) * Resample audio using a choice of resampling algorithms * Encode audio using any ACM or Media Foundation codec installed on your computer * Create MP3s, AAC/MP4 audio and WMA files * Create WAV files containing G.711, ADPCM, G.722, etc. * Encode FLAC, Ogg Vorbis and Opus on any platform with `NAudio.SoundFile` * Mix and manipulate audio streams using a 32-bit floating point mixing engine * construct signal chains * examine sample levels for the purposes of metering or waveform rendering * pass blocks of samples through an FFT for metering or DSP * delay, loop, or fade audio in and out * Apply audio effects with the cross-platform `NAudio.Effects` framework * EQ and filtering, dynamics (compressor, limiter, gate, multiband), saturation and lo-fi * delay and modulation, reverb including FFT convolution, pitch shifting * click-free bypass, dry/wet mix and a parameter model for automation * Record audio using a variety of capture APIs * WASAPI (`WasapiRecorder`), including system audio and per-process loopback * WaveIn * ASIO * ALSA on Linux * Host VST 3 effects and instruments * Play SoundFont (`.sf2`) and SFZ instruments with the built-in software sampler * Work with soundcards * Enumerate devices * Access soundcard controls and metering information * Follow the default device automatically, and observe endpoint changes as events * Full MIDI event model * Read and write MIDI files * Respond to received MIDI events * Send MIDI events * Render a MIDI file to audio through the sampler or a hosted VST 3 instrument * An extensible programming model * All base classes easily inherited from for you to add your custom components ## Tutorials ### Upgrading * [Migrating from NAudio 2 to NAudio 3](Docs/MigratingFromNAudio2.md) * [Migrating from AsioOut to AsioDevice](Docs/AsioMigration.md) ### Playback * [Playing an Audio File from a WinForms application](Docs/PlayAudioFileWinForms.md) * [Playing an Audio File from a Console application](Docs/PlayAudioFileConsoleApp.md) * [Playing Audio from a URL](Docs/PlayAudioFromUrl.md) * [Choose an audio output device type](Docs/OutputDeviceTypes.md) * [Enumerate and select Output Devices](Docs/EnumerateOutputDevices.md) * [Playing audio with WasapiPlayer (recommended for WASAPI)](Docs/WasapiPlayer.md) * [Creating and configuring a WasapiOut device (legacy)](Docs/WasapiOut.md) * [Implement "Fire and Forget" Playback (e.g. game sound effects)](http://markheath.net/post/fire-and-forget-audio-playback-with) * [Play streaming MP3](http://markheath.net/post/how-to-play-back-streaming-mp3-using) * [Handling playback stopped](Docs/PlaybackStopped.md) * [Understanding WaveStream, IWavePlayer and ISampleProvider](Docs/WaveProviders.md) * [Playing Audio with ASIO](Docs/AsioPlayback.md) ### Working with Codecs * [Convert an MP3 to WAV](Docs/ConvertMp3ToWav.md) * [Encode to MP3 and other formats using MediaFoundationEncoder](Docs/MediaFoundationEncoder.md) * [More examples](http://markheath.net/post/naudio-mediafoundationencoder) * [Understand how to convert between any audio formats you have codecs for](http://www.codeproject.com/Articles/501521/How-to-convert-between-most-audio-formats-in-NET) * [Enumerate Media Foundation Transforms (MFTs)](Docs/EnumerateMediaFoundationTransforms.md) * [Enumerate ACM Codecs](Docs/EnumerateAcmDrivers.md) * [Fix the NoDriver calling acmFormatSuggest issue](http://markheath.net/post/nodriver-calling-acmformatsuggest) ### Working with audio files * [Mix Two Audio Files to WAV](Docs/MixTwoAudioFilesToWav.md) * [Cross-platform audio files with NAudio.SoundFile](Docs/CrossPlatformAudioFilesWithSoundFile.md) * [Trim a WAV File](http://markheath.net/post/trimming-wav-file-using-naudio) * [Merge MP3 Files](http://markheath.net/post/merging-mp3-files-with-naudio-in-c-and) * [Convert an AIFF file to WAV](http://markheath.net/post/how-to-convert-aiff-files-to-wav-using) * [Use the WavFileWriter class](http://markheath.net/post/how-to-use-wavefilewriter) ### Manipulating audio * [Convert between mono and stereo](Docs/ConvertBetweenStereoAndMono.md) * [Concatenating Audio](Docs/ConcatenatingAudio.md) * [Skip and Take Using OffsetSampleProvider](Docs/OffsetSampleProvider.md) * [Implement Looped Playback](http://markheath.net/post/looped-playback-in-net-with-naudio) * [Work with Multi-Channel Audio](http://markheath.net/post/handling-multi-channel-audio-in-naudio) * [Resample Audio](Docs/Resampling.md) * [Input driven Audio Resampling](http://markheath.net/post/input-driven-resampling-with-naudio-using-acm) * [Using RawSourceWaveStream](Docs/RawSourceWaveStream.md) * [Adjust the pitch of audio using SmbPitchShiftingSampleProvider](Docs/SmbPitchShiftingSampleProvider.md) * [Varispeed playback with NAudio using SoundTouch](http://markheath.net/post/varispeed-naudio-soundtouch) * [Fade audio in and out](Docs/FadeInOutSampleProvider.md) * [Apply audio effects with NAudio.Effects](Docs/AudioEffects.md) ### Generating audio * [Play Sine Waves and other signal types](Docs/PlaySineWave.md) * [Implement sine wave with portamento](http://markheath.net/post/naudio-sine-portamento) * [Play SoundFont, SFZ and single-sample instruments](Docs/Sampler.md) ### Recording * [Recording a WAV file from a WinForms application](Docs/RecordWavFileWinFormsWaveIn.md) * [Recording audio with WasapiRecorder (recommended for WASAPI)](Docs/WasapiRecorder.md) * [Capturing system audio with WasapiLoopbackCapture (legacy)](Docs/WasapiLoopbackCapture.md) * [Mix the microphone and system audio](Docs/MixMicrophoneAndSystemAudio.md) * [Play and Record audio at the same time](http://markheath.net/post/how-to-record-and-play-audio-at-same) * [Record Audio with ASIO](Docs/AsioRecording.md) * [Duplex Processing with ASIO](Docs/AsioDuplex.md) * [ASIO Channel Mapping](Docs/AsioChannelMapping.md) * [Handling ASIO Driver Resets](Docs/AsioDriverReset.md) ### Visualization * [WaveForm Rendering to PNG](Docs/WaveFormRendering.md) * [Implement a Recording Level Meter](Docs/RecordingLevelMeter.md) ### MIDI * [Sending and Receiving MIDI Events](Docs/MidiInAndOut.md) * [Exploring MIDI Files with MidiFile](Docs/MidiFile.md) * [MIDI Event types](Docs/MidiEvent.md) ### Networking * [Stream live audio over the network (Network Chat)](Docs/NetworkChatDemo.md) ### Cross-platform and Linux * [Cross-platform audio files with NAudio.SoundFile](Docs/CrossPlatformAudioFilesWithSoundFile.md) * [Playing an audio file on Linux with ALSA](Docs/PlayAudioFileLinuxAlsa.md) * [Recording an audio file on Linux with ALSA](Docs/RecordAudioFileLinuxAlsa.md) * [Validating ALSA on Linux](Docs/ValidatingAlsaOnLinux.md) ## NAudio Training Courses If you want to get up to speed as quickly as possible with NAudio programming, I recommend you watch these two Pluralsight courses. You will need to be a subscriber to access the content, but there is 10 hours of training material on NAudio, and it also will give you access to their vast training library on other programming topics. * [Digital Audio Fundamentals](http://pluralsight.com/training/Courses/TableOfContents/digital-audio-fundamentals) * [Audio Programming with NAudio](http://pluralsight.com/training/Courses/TableOfContents/audio-programming-naudio) To be successful developing applications that process digital audio, there are some key concepts that you need to understand. To help developers quickly get up to speed with what they need to know before trying to use NAudio, I have created the [Digital Audio Fundamentals](http://pluralsight.com/training/Courses/TableOfContents/digital-audio-fundamentals) course, which covers sample rates, bit depths, file formats, codecs, decibels, clipping, aliasing, synthesis, visualisations, effects and much more. In particular, the fourth module on signal chains is vital background information if you are to be effective with NAudio. [Audio Programming with NAudio](http://pluralsight.com/training/Courses/TableOfContents/audio-programming-naudio) is a follow-on course which contains seven hours of training material covering all the major features of NAudio. It is highly recommended that you take this course if you intend to create an application with NAudio. Please note that these courses were recorded against earlier versions of NAudio. The concepts all still apply, but some of the class names have changed — see [Migrating from NAudio 2 to NAudio 3](Docs/MigratingFromNAudio2.md). ## FAQ **What is NAudio?** NAudio is an open source audio API for .NET written in C# by Mark Heath, with contributions from many other developers. It is intended to provide a comprehensive set of useful utility classes from which you can construct your own audio application. **Why NAudio?** NAudio was created because the Framework Class Library that shipped with .NET 1.0 had no support for playing audio. The System.Media namespace introduced in .NET 2.0 provided a small amount of support, and the MediaElement in WPF and Silverlight took that a bit further. The vision behind NAudio is to provide a comprehensive set of audio related classes allowing easy development of utilities that play or record audio, or manipulate audio files in some way. **Does NAudio work on Linux and macOS?** Partly, and much more so in NAudio 3. `NAudio.Core`, `NAudio.Midi`, `NAudio.Effects`, `NAudio.Sampler` and `NAudio.SoundFile` are fully cross-platform, so signal chains, file I/O, DSP, effects and MIDI all work anywhere .NET runs. For output and capture, Linux has `NAudio.Alsa`; the WASAPI, WinMM, ASIO, DMO and WinForms packages remain Windows-only, and there is no macOS (CoreAudio) backend yet (although there is a work-in-progress implementation). **Which .NET versions are supported?** NAudio 3 requires `net9.0` or later. If you need .NET Framework or .NET Standard 2.0, stay on NAudio 2.x. **Can I Use NAudio in my Project?** NAudio is licensed under the MIT license which means that you can use it in whatever project you like including commercial projects. Of course we would love it if you share any bug-fixes or enhancements you made to the original NAudio project files. **Is .NET Performance Good Enough for Audio?** While .NET cannot compete with unmanaged languages for very low latency audio work, it still performs better than many people would expect. On a fairly modest PC, you can quite easily mix multiple WAV files together, including pass them through various effects and codecs, play back glitch free with a latency of around 50ms. **How can I get help?** There are three main ways to get help. First, you can raise an issue here on GitHub. This is the best option when you've written some code and want to ask why it's not working as you expect. I attempt to answer all questions, but since this is a spare time project, occasionally I get behind. You can also ask on StackOverflow and [tag your question with naudio](http://stackoverflow.com/questions/tagged/naudio), if your question is a "how do I..." sort of question. This gives you a better chance of getting a quick answer. Please try to search first to see if your question has already been answered elsewhere. Finally, I am occasionally able to offer paid support for situations where you need quick advice, bugfixes or new features. Please contact Mark Heath directly if you wish to pursue this option. **How do I submit a patch?** I welcome contributions to NAudio and have accepted many patches, but if you want your code to be included, please familiarise yourself with the following guidelines: * Your submission must be your own work, and able to be released under the MIT license. * You may use AI-assisted code generation, but ensure that your code is original and not copied from other sources. Note that I may choose to rewrite contributions rather than merge pull requests, so consider raising a feature request rather than a pull request first. * You will need to make sure your code conforms to the layout and naming conventions used elsewhere in NAudio. * Remember that there are many existing users of NAudio. A patch that changes the public interface is not likely to be accepted. * Try to write "clean code" - avoid long functions and long classes. Try to add a new feature by creating a new class rather than putting loads of extra code inside an existing one. * I don't usually accept contributions I can't test, so please write unit tests (using NUnit) if at all possible. If not, give a clear explanation of how your feature can be unit tested and provide test data if appropriate. Tell me what you did to test it yourself, including what operating systems and soundcards you used. * If you are adding a new feature, please consider writing a short tutorial on how to use it. * Unless your patch is a small bugfix, I will code review it and give you feedback. You will need to be willing to make the recommended changes before it can be integrated into the main code. * Patches should be provided using the Pull Request feature of GitHub. * Please also bear in mind that when you add a feature to NAudio, that feature will generate future support requests and bug reports. Are you willing to stick around on the forums and help out people using it? --- ## File: Docs/AsioPlayback.md # Playback with ASIO NAudio 3 introduces `AsioDevice`, a redesigned ASIO API that handles playback, recording, and duplex I/O through three explicit configuration modes. This article covers playback only — see [AsioRecording](AsioRecording.md) and [AsioDuplex](AsioDuplex.md) for the other modes, and [AsioMigration](AsioMigration.md) if you're moving from the legacy `AsioOut` class. ASIO is the low-latency driver format supported by most professional Windows audio interfaces and many DAW applications. To use it you need a soundcard with an ASIO driver installed. If your hardware doesn't ship one, [ASIO4ALL](http://asio4all.com/) is a free WDM-to-ASIO shim that works with most consumer soundcards. ## Open the device Enumerate the installed ASIO drivers and open one by name: ```c# foreach (var name in AsioDevice.GetDriverNames()) Console.WriteLine(name); using var device = AsioDevice.Open("Focusrite USB ASIO"); ``` `AsioDevice` implements `IDisposable`. Always wrap it in a `using` statement (or call `Dispose` explicitly) — the underlying COM driver doesn't release until you do. ## Configure for playback Pass an `IWaveProvider` (or wrap an `ISampleProvider` via `.ToWaveProvider()`) to `InitPlayback`: ```c# using var reader = new AudioFileReader("music.wav"); device.InitPlayback(new AsioPlaybackOptions { Source = reader }); ``` The source's sample rate must be one the driver supports — `device.IsSampleRateSupported(rate)` answers that. The source's channel count must equal the number of output channels you select (defaults to a contiguous range starting at channel 0). ## Select output channels `AsioPlaybackOptions.OutputChannels` is an `int[]` of physical channel indices. Source channel `n` is routed to physical output `OutputChannels[n]`. The array can be **non-contiguous** — there's no `ChannelOffset` style restriction. ```c# // Stereo source → physical outputs 4 and 5 (zero-based). device.InitPlayback(new AsioPlaybackOptions { Source = reader, OutputChannels = [4, 5] }); ``` To send to every available output: ```c# OutputChannels = device.Capabilities.AllOutputChannels ``` `device.Capabilities.NbOutputChannels` tells you how many physical outputs the driver exposes; `device.Capabilities.OutputChannelInfos[i].name` gives a human-readable name for each. See [AsioChannelMapping](AsioChannelMapping.md) for more channel-routing patterns. > Need to write each output channel independently — a different source per channel, rather than one interleaved `IWaveProvider` fanned out — for example to route separate channel pairs to separate speakers? Use [duplex mode with no input channels](AsioDuplex.md#output-only-no-input-channels). ## Start and stop ```c# device.Start(); // ... device.Stop(); ``` `Stop()` raises the `Stopped` event on the captured `SynchronizationContext` (the thread you constructed the device on, typically the UI thread). The handler may safely call `Dispose()` — the device is fully off the ASIO callback thread by the time `Stopped` fires. By default the device auto-stops when the source reaches end-of-stream. Set `AutoStopOnEndOfStream = false` in the options if you want the device to keep running on silent buffers after the source runs dry (e.g. so you can swap providers). ## Handle errors and end-of-stream ```c# device.Stopped += (sender, e) => { if (e.Exception is not null) Console.WriteLine($"ASIO faulted: {e.Exception.Message}"); else Console.WriteLine("Playback complete."); }; ``` `Stopped` fires exactly once per `Start`/`Stop` cycle, with `e.Exception` populated if the source threw or the driver reported an unrecoverable fault. ## Recover from driver settings changes If the user opens the driver's control panel and changes the sample rate (or any other setting), the driver fires a reset request. The recommended response: ```c# device.DriverResetRequest += (_, _) => { device.Stop(); device.Reinitialize(); device.Start(); }; ``` `Reinitialize()` re-applies the most recent `InitPlayback` options against the (possibly changed) driver state — see [AsioDriverReset](AsioDriverReset.md) for the full pattern. ## Buffer size and latency `AsioPlaybackOptions.BufferSize` accepts a frame count, or `null` to use the driver's preferred size. Smaller buffers mean lower latency but more callback overhead. The actual latencies in frames are reported by `device.OutputLatencySamples` after `InitPlayback` succeeds. The buffer-switch callback runs on the ASIO driver's real-time thread, so any `IWaveProvider` in your chain must produce samples within the buffer duration. Allocations and slow I/O on that thread cause glitches. ## Full example ```c# using NAudio.Wave; using var reader = new AudioFileReader("music.wav"); using var device = AsioDevice.Open(AsioDevice.GetDriverNames()[0]); device.InitPlayback(new AsioPlaybackOptions { Source = reader, OutputChannels = [0, 1] }); var done = new ManualResetEventSlim(); device.Stopped += (_, _) => done.Set(); device.Start(); done.Wait(); ``` --- ## File: Docs/AsioRecording.md # Recording with ASIO NAudio 3's `AsioDevice` exposes a clean recording mode that delivers per-channel `Span` to your event handler — no `IntPtr` arithmetic, no manual sample-format decoding, no interleaving math. This article covers recording only — see [AsioPlayback](AsioPlayback.md), [AsioDuplex](AsioDuplex.md), and [AsioMigration](AsioMigration.md) for related modes and migration guidance. You need a soundcard with an ASIO driver installed. [ASIO4ALL](http://asio4all.com/) is a free fallback for hardware that doesn't ship one. ## Open the device ```c# foreach (var name in AsioDevice.GetDriverNames()) Console.WriteLine(name); using var device = AsioDevice.Open("Focusrite USB ASIO"); ``` ## Pick input channels `AsioRecordingOptions.InputChannels` is an `int[]` of physical channel indices. Entries can be **non-contiguous** — record from channels `[0, 1, 4, 5]` directly without recording the channels in between. ```c# device.InitRecording(new AsioRecordingOptions { InputChannels = [0, 1, 4, 5], SampleRate = device.CurrentSampleRate }); ``` To record every available input: ```c# InputChannels = device.Capabilities.AllInputChannels ``` `device.Capabilities.NbInputChannels` reports how many physical inputs the driver exposes. `device.Capabilities.InputChannelInfos[i].name` gives the driver's name for each (e.g. "Mic 1", "Line 3"). If you don't pass `SampleRate`, the device runs at whatever rate the driver is currently set to — which `device.CurrentSampleRate` reports. If you pass a specific rate, the driver must support it; check first with `device.IsSampleRateSupported(rate)`. See [AsioChannelMapping](AsioChannelMapping.md) for the rationale and patterns around non-contiguous channel selection. ## Subscribe to AudioCaptured Each ASIO buffer-switch raises `AudioCaptured` on the real-time driver thread. The event args expose one `ReadOnlySpan` per selected input, in the same order as `InputChannels`. NAudio handles the native `AsioSampleType` → float conversion (`Int16LSB`, `Int24LSB`, `Int32LSB`, `Float32LSB` are all supported transparently). ```c# device.AudioCaptured += (sender, e) => { // e.GetChannel(i) returns a ReadOnlySpan for the i'th selected input. var ch0 = e.GetChannel(0); // physical input InputChannels[0] var ch1 = e.GetChannel(1); // physical input InputChannels[1] // Compute RMS, write to a file, push to a ring buffer — anything quick. // The spans are valid only for the duration of this handler. }; device.Start(); ``` The index passed to `GetChannel` is into the **selected-channels array**, not the physical channel number. If `InputChannels = [4, 5]`, then `GetChannel(0)` returns physical input 4 and `GetChannel(1)` returns physical input 5. This matches JUCE/PortAudio conventions and keeps your handler portable across channel selections. ## Real-time thread constraints The handler runs on the ASIO callback thread. To avoid glitches: - Don't allocate. Pre-allocate any buffers you need before calling `Start`. - Don't perform blocking I/O. Hand the data off to a worker thread or a lock-free queue. - Don't call `device.Stop`, `device.Dispose`, or `device.Reinitialize` from inside the handler — `Stop` actively throws `InvalidOperationException` if you try, because the same-thread call would self-deadlock waiting for the callback to return. The spans returned by `GetChannel` point into library-owned buffers that the device reuses across callbacks. Copy out anything you need to keep beyond the handler's return. ## Save each input to its own WAV file ```c# using var device = AsioDevice.Open(driverName); int[] channels = [0, 1, 4, 5]; int sampleRate = device.CurrentSampleRate; device.InitRecording(new AsioRecordingOptions { InputChannels = channels, SampleRate = sampleRate }); var writers = channels .Select(phys => new WaveFileWriter( $"input-{phys}.wav", WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, 1))) .ToArray(); device.AudioCaptured += (s, e) => { for (int i = 0; i < e.ChannelCount; i++) writers[i].WriteSamples(e.GetChannel(i)); }; device.Stopped += (s, e) => { foreach (var w in writers) w.Dispose(); }; device.Start(); Console.ReadLine(); device.Stop(); ``` ## Save selected inputs as a single multi-channel WAV If you want to interleave the selected inputs into one WAV file: ```c# using var writer = new WaveFileWriter( "multi.wav", WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels.Length)); device.AudioCaptured += (s, e) => { for (int frame = 0; frame < e.Frames; frame++) for (int ch = 0; ch < e.ChannelCount; ch++) writer.WriteSample(e.GetChannel(ch)[frame]); }; ``` ## The raw escape hatch If you genuinely need zero-copy access to the driver's native bytes — for example, to memcpy them into a fixed buffer for a downstream codec — `AsioAudioCapturedEventArgs.RawInput(i)` returns an `AsioRawInputBuffer`: ```c# device.AudioCaptured += (s, e) => { var raw = e.RawInput(0); // ref struct ReadOnlySpan bytes = raw.Bytes; AsioSampleType format = raw.Format; // Int16LSB / Int24LSB / Int32LSB / Float32LSB int frames = raw.Frames; // ... your zero-copy logic ... }; ``` The bytes span is valid only for the duration of the handler. ## Stop and dispose ```c# device.Stop(); device.Dispose(); // or wrap the device in `using` ``` The `Stopped` event fires on the captured `SynchronizationContext` after the callback thread has fully drained, so it's safe for handlers to dispose the device. --- ## File: Docs/ConcatenatingAudio.md # Concatenating Audio When you play audio or render audio to a file, you create a single `ISampleProvider` or `IWaveProvider` that represents the whole piece of audio to be played. So playback will continue until you reach the end, and then stop. But what if you have two pieces of audio you want to play back to back? The `ConcatenatingSampleProvider` enables you to schedule one or more pieces of audio to play one after the other. Here's a simple example where we have three audio files that are going to play back to back. Note that the three audio files must have exactly the same sample rate, channel count and bit depth, because it's not possible to change those during playback. ```c# var first = new AudioFileReader("first.mp3"); var second = new AudioFileReader("second.mp3"); var third = new AudioFileReader("third.mp3"); var playlist = new ConcatenatingSampleProvider(new[] { first, second, third }); // to play: outputDevice.Init(playlist); outputDevice.Play(); // ... OR ... to save to file WaveFileWriter.CreateWaveFile16("playlist.wav", playlist); ``` Note that the `ConcatenatingSampleProvider` does not provide repositioning. If you want that, you can quite simply copy the code for `ConcatenatingSampleProvider` and adjust it to allow you to rewind, or jump to the beginning of one of the inputs, depending on your specific requirements. # FollowedBy Extension Helpers There are some helpful extension methods you can make use of to simplify concatenating. For example, to append one `ISampleProvider` onto the end of another, use `FollowedBy`. Under the hood this simply creates a `ConcatenatingSampleProvider`: ```c# var first = new AudioFileReader("first.mp3"); var second = new AudioFileReader("second.mp3"); var playlist = first.FollowedBy(second); ``` You can also provide a duration of silence that you want after the first sound has finished and before the second begins: ```c# var first = new AudioFileReader("first.mp3"); var second = new AudioFileReader("second.mp3"); var playlist = first.FollowedBy(TimeSpan.FromSeconds(1), second); ``` This makes use of an `OffsetSampleProvider` in conjunction with a `ConcatenatingSampleProvider` --- ## File: Docs/ConvertBetweenStereoAndMono.md # Convert Between Stereo and Mono NAudio includes a number of utility classes that can help you to convert between mono and stereo audio. You can use these whether you are playing audio live, or whether you are simply converting from one file format to another. # Mono to Stereo If you have a mono input file, and want to convert to stereo, the `MonoToStereoSampleProvider` allows you to do this. It takes a `SampleProvider` as input, and has two floating point `LeftVolume` and `RightVolume` properties, which default to `1.0f`. This means that the mono input will be copied at 100% volume into both left and right channels. If you wanted to route it just to the left channel, you could set `LeftVolume` to `1.0f` and `RightVolume` to `0.0f`. And if you wanted it more to the right than the left you might set `LeftVolume` to `0.25f` and `RightVolume` to `1.0f`. ```c# using(var inputReader = new AudioFileReader(monoFilePath)) { // convert our mono ISampleProvider to stereo var stereo = new MonoToStereoSampleProvider(inputReader); stereo.LeftVolume = 0.0f; // silence in left channel stereo.RightVolume = 1.0f; // full volume in right channel // can either use this for playback: myOutputDevice.Init(stereo); myOutputDevice.Play(); // ... // ... OR ... could write the stereo audio out to a WAV file WaveFileWriter.CreateWaveFile16(outputFilePath, stereo); } ``` There's also a `MonoToStereoProvider16` that works with 16 bit PCM `IWaveProvider` inputs and outputs 16 bit PCM. It works very similarly to `MonoToStereoSampleProvider` otherwise. # Stereo to Mono If you have a stereo input file and want to collapse to mono, then the `StereoToMonoSampleProvider` is what you want. It takes a stereo `ISampleProvider` as input, and also has a `LeftVolume` and `RightVolume` property, although the defaults are `0.5f` for each. This means the left sample will be multiplied by `0.5f` and the right by `0.5f` and the two are then summed together. If you want to just keep the left channel and throw away the right, you'd set `LeftVolume` to 1.0f and `RightVolume` to 0.0f. You could even sort out an out of phase issue by setting `LeftVolume` to `0.5f` and `RightVolume` to -0.5f. Usage is almost exactly the same. Note that some output devices won't let you play a mono file directly, so this would be more common if you were creating a mono output file, or if the mono audio was going to be passed on as a mixer input to `MixingSampleProvider`. ```c# using(var inputReader = new AudioFileReader(stereoFilePath)) { // convert our stereo ISampleProvider to mono var mono = new StereoToMonoSampleProvider(inputReader); mono.LeftVolume = 0.0f; // discard the left channel mono.RightVolume = 1.0f; // keep the right channel // can either use this for playback: myOutputDevice.Init(mono); myOutputDevice.Play(); // ... // ... OR ... could write the mono audio out to a WAV file WaveFileWriter.CreateWaveFile16(outputFilePath, mono); } ``` There is also a `StereoToMonoProvider16` that works with 16 bit PCM stereo `IWaveProvider` inputs and emits 16 bit PCM. # Panning Mono to Stereo Finally, NAudio offers a `PanningSampleProvider` which allows you to use customisable panning laws to govern how a mono input signal is placed into a stereo output signal. It has a `Pan` property which can be configured between `-1.0f` (fully left) and `1.0f` (fully right), with `0.0f` being central. The `PanningStrategy` can be overridden. By default is uses the `SinPanStrategy`. There is also `SquareRootPanStrategy`, `LinearPanStrategy` and `StereoBalanceStrategy`, each one operating slightly differently with regards to how loud central panning is, and how the sound tapers off as it is panned to each side. You can experiment to discover which one fits your needs the best. Usage is very similar to the `MonoToStereoSampleProvider` ```c# using(var inputReader = new AudioFileReader(monoFilePath)) { // convert our mono ISampleProvider to stereo var panner = new PanningSampleProvider(inputReader); // override the default pan strategy panner.PanStrategy = new SquareRootPanStrategy(); panner.Pan = -0.5f; // pan 50% left // can either use this for playback: myOutputDevice.Init(panner); myOutputDevice.Play(); // ... // ... OR ... could write the stereo audio out to a WAV file WaveFileWriter.CreateWaveFile16(outputFilePath, panner); } ``` --- ## File: Docs/ConvertMp3ToWav.md # Convert an MP3 File to a WAV File In this article I will show a few ways you can convert an MP3 file into a WAV file with NAudio. To start with we'll need a couple of file paths, one to the input MP3 file, and one to where we want to put the converted WAV file. ```c# var infile = @"C:\Users\Mark\Desktop\example.mp3"; var outfile = @"C:\Users\Mark\Desktop\converted.wav"; ``` ## MediaFoundationReader (recommended) `MediaFoundationReader` is the recommended approach for reading MP3 files (and many other formats) in NAudio. It uses Media Foundation which is available on all supported versions of Windows. It can read MP3, WMA, AAC, FLAC, Opus and many other formats. ```c# using(var reader = new MediaFoundationReader(infile)) { WaveFileWriter.CreateWaveFile(outfile, reader); } ``` ## Mp3FileReader The `Mp3FileReader` class uses the ACM MP3 codec that is present on most versions of Windows. The conversion is straightforward. Open the MP3 file with `Mp3FileReader` and then pass it to `WaveFileWriter.CreateWaveFile` to write the converted PCM audio to a WAV file. This will usually be 44.1kHz 16 bit stereo, but uses whatever format the MP3 decoder emits. ```c# using(var reader = new Mp3FileReader(infile)) { WaveFileWriter.CreateWaveFile(outfile, reader); } ``` ## DirectX Media Object `Mp3FileReaderBase` allows us to plug in alternative MP3 frame decoders. One option that comes in the box with NAudio is the DirectX Media Object MP3 codec. Here's how to use the `DmoMp3FrameDecompressor` as a custom frame decompressor: ```c# using(var reader = new Mp3FileReaderBase(infile, wf => new DmoMp3FrameDecompressor(wf))) { WaveFileWriter.CreateWaveFile(outfile, reader); } ``` ## NLayer The final option is to use [NLayer](https://github.com/naudio/NLayer) as the decoder for `Mp3FileReader`. NLayer is a fully managed MP3 decoder, meaning it can run on any .NET platform including cross-platform scenarios where Windows codecs are not available. You'll need the [NLayer.NAudioSupport NuGet package](https://www.nuget.org/packages/NLayer.NAudioSupport/). Then you can plug in a fully managed MP3 frame decoder: ```c# using (var reader = new Mp3FileReaderBase(infile, wf => new Mp3FrameDecompressor(wf))) { WaveFileWriter.CreateWaveFile(outfile, reader); } ``` --- ## File: Docs/EnumerateAcmDrivers.md # Enumerate ACM Drivers ACM drivers are the old Windows API for dealing with compressed audio that predates Media Foundation. In one sense this means that this is no longer very important, but sometimes you find that some codecs are more readily available as ACM codecs instead of Media Foundation Transforms. The class in NAudio that makes use of ACM codecs is `WaveFormatConversionStream`. When you construct one you provide it with a source and a target `WaveFormat`. This will be either going from compressed audio to PCM (this is a decoder) or from PCM to compressed (this is an encoder). Its important to not that you can't just pick two random `WaveFormat` definitions and expect a conversion to be possible. You can only perform the supported transforms. That's why it's really useful to be able to enumerate the ACM codecs installed on your system. You can do that with `AcmDriver.EnumerateAcmDrivers`. Then you explore the `FormatTags` for each driver, and from there ask for each format matching that tag with `driver.GetFormats`. It is a little complex, but the information you get from doing this is invaluable in helping you to work out exactly what `WaveFormat` you need to use to successfully use a codec. This code sample enumerates through all ACM drivers and prints out details of their formats. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` The output will be quite verbose (especially if you've installed some additional codecs on your system.) Here's a snippet of the output from the GSM codec: ``` Long Name: Microsoft GSM 6.10 Audio CODEC Short Name: Microsoft GSM 6.10 Driver ID: 48141232 FormatTags: =========================================== Format Tag 0: PCM Standard Format Count: 8 Support Flags: Codec Format Tag: Pcm, Format Size: 16 Formats: =========================================== Format 0: 8.000 kHz, 8 Bit, Mono FormatTag: Pcm, Support Flags: Codec WaveFormat: Pcm 8000Hz Channels: 1 Bits: 8 Block Align: 1, AverageBytesPerSecond: 8000 (64.0 kbps), Extra Size: 0 =========================================== Format 1: 8.000 kHz, 16 Bit, Mono FormatTag: Pcm, Support Flags: Codec WaveFormat: Pcm 8000Hz Channels: 1 Bits: 16 Block Align: 2, AverageBytesPerSecond: 16000 (128.0 kbps), Extra Size: 0 =========================================== Format 2: 11.025 kHz, 8 Bit, Mono FormatTag: Pcm, Support Flags: Codec WaveFormat: Pcm 11025Hz Channels: 1 Bits: 8 Block Align: 1, AverageBytesPerSecond: 11025 (88.2 kbps), Extra Size: 0 ``` And here's an example showing a non-PCM format. Here we can see that for `DviAdpcm`, the `WaveFormat` structure needs two extra bytes with values 0xF9 and 0x01: ``` =========================================== Format 1: 8.000 kHz, 4 Bit, Stereo FormatTag: DviAdpcm, Support Flags: Codec WaveFormat: DviAdpcm 8000Hz Channels: 2 Bits: 4 Block Align: 512, AverageBytesPerSecond: 8110 (64.9 kbps), Extra Size: 2 Extra Bytes: F9 01 ``` --- ## File: Docs/EnumerateMediaFoundationTransforms.md # Enumerate Media Foundation Transforms The `MediaFoundationReader` and `MediaFoundationEncoder` classes in NAudio make use of any available Media Foundation Transforms (MFTs) installed on your computer. It can be useful to enumerate the available audio-related MFTs. There are three categories of audio MFT - effects, decoders and encoders. A decoder allows you to decode audio compressed in different formats to PCM. An encoder allows you to encode PCM audio into compressed formats. An effect modifies audio in some way (e.g. resampling). You can use `MediaFoundationApi.EnumerateTransforms` to explore what's available: ```c# MediaFoundationApi.Startup(); var effects = MediaFoundationApi.EnumerateTransforms(MediaFoundationTransformCategories.AudioEffect); var decoders = MediaFoundationApi.EnumerateTransforms(MediaFoundationTransformCategories.AudioDecoder); var encoders = MediaFoundationApi.EnumerateTransforms(MediaFoundationTransformCategories.AudioEncoder); ``` These return an `IEnumerable`. The `MfActivate` wrapper provides methods to explore the attributes of each transform: ``` /* Detailed source-code truncated for AI context efficiency. */ ``` Here's an example output for an MFT effect. In this case, the Resampler which is a very useful MFT for changing sample rates: ``` Audio Effect Name: Resampler MFT Input Types: 2 items: Audio-PCM Audio-IEEE floating-point Class identifier: f447b69e-1884-4a7e-8055-346f74d6edb3 Output Types: 2 items: Audio-PCM Audio-IEEE floating-point Transform Flags: 1 Transform Category: Audio Effect ``` Here's an example output for a decoder. Windows 10 and above includes an Opus audio decoder: ``` Audio Decoder Name: Microsoft Opus Audio Decoder MFT Input Types: 1 items: Audio-Opus Class identifier: 63e17c10-2d43-4c42-8fe3-8d8b63e46a6a Output Types: 1 items: Audio-IEEE floating-point Transform Flags: 1 Transform Category: Audio Decoder ``` And an encoder. Windows 10 and above includes a FLAC encoder: ``` Audio Encoder Name: Microsoft FLAC Audio Encoder MFT Input Types: 1 items: Audio-PCM Class identifier: 128509e9-c44e-45dc-95e9-c255b8f466a6 Output Types: 1 items: Audio-FLAC Transform Flags: 1 Transform Category: Audio Encoder ``` You can also activate a transform directly from the `MfActivate` object. For example, to create an `MfTransform` wrapper: ```c# using var transform = mft.ActivateTransform(); ``` --- ## File: Docs/EnumerateOutputDevices.md # Enumerating Audio Devices The technique you use to enumerate audio devices depends on what audio output (or input) driver type you are using. This article shows the technique for each supported output device. ## WaveOut To discover the number of output devices you can use `WaveOut.DeviceCount`. Then you can call `WaveOut.GetCapabilities` passing in the index of a device to find out its name (and some basic information about its capabilities). Note that you can also pass an index of -1 which is the "audio mapper". Use this if you want to keep playing audio even when a device is removed (such as USB headphones being unplugged). Also note that the `ProductName` retured is limited to 32 characters, resulting in it often being truncated. This is a limitation of the underlying Windows API and there is unfortunately no easy way to fix it in NAudio. ```c# for (int n = -1; n < WaveOut.DeviceCount; n++) { var caps = WaveOut.GetCapabilities(n); Console.WriteLine($"{n}: {caps.ProductName}"); } ``` Once you've selected the device you want, you can open it by creating an instance of `WaveOut` and specifying it as the `DeviceNumber`: ```c# var outputDevice = new WaveOut() { DeviceNumber = deviceNumber }; ``` ## WaveIn Getting details of audio capture devices for `WaveIn` is very similar to for `WaveOut`: ```c# for (int n = -1; n < WaveIn.DeviceCount; n++) { var caps = WaveIn.GetCapabilities(n); Console.WriteLine($"{n}: {caps.ProductName}"); } ``` Once you've selected the device you want, you can open it by creating an instance of `WaveIn` and specifying it as the `DeviceNumber`: ```c# var recordingDevice = new WaveIn() { DeviceNumber = deviceNumber }; ``` # DirectSoundOut `DirectSoundOut` exposes the `Devices` static method allowing you to enumerate through all the output devices. This has the benefit over `WaveOut` of not having truncated device names: ```c# foreach (var dev in DirectSoundOut.Devices) { Console.WriteLine($"{dev.Guid} {dev.ModuleName} {dev.Description}"); } ``` Each device has a Guid, and that can be used to open a specific device: ```c# var outputDevice = new DirectSoundOut(deviceGuid); ``` There are also a couple of special device GUIDs you can use to open the default playback device (`DirectSoundOut.DSDEVID_DefaultPlayback`) or default voice playback device (`DirectSoundOut.DSDEVID_DefaultVoicePlayback`) # WASAPI Devices WASAPI playback (render) and recording (capture) devices can both be accessed via the `MMDeviceEnumerator` class. This allows you to enumerate only the type of devices you want (`DataFlow.Render` or `DataFlow.Capture` or `DataFlow.All`). You can also choose whether you want to include devices that are active, or also include disabled, unplugged or otherwise not present devices with the `DeviceState` bitmask. Here we show them all: ```c# var enumerator = new MMDeviceEnumerator(); foreach (var wasapi in enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.All)) { Console.WriteLine($"{wasapi.DataFlow} {wasapi.FriendlyName} {wasapi.DeviceFriendlyName} {wasapi.State}"); } ``` To open the device you want, pass the device in to the appropriate WASAPI builder depending on whether you are playing back or recording... ```c# var outputDevice = new WasapiPlayerBuilder().WithDevice(mmDevice).Build(); var recordingDevice = new WasapiRecorderBuilder().WithDevice(captureDevice).Build(); var loopbackCapture = new WasapiRecorderBuilder().WithDevice(loopbackDevice).WithLoopbackCapture().Build(); ``` You can also use the MMEnumerator to request what the default device is for a number of different scenarios (playback or record, and voice, multimedia or 'console'): ```c# enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia); ``` # ASIO You can discover the registered ASIO drivers on your system with `AsioDevice.GetDriverNames`. There is no guarantee that the associated soundcard is currently connected to the system. ```c# foreach (var asio in AsioDevice.GetDriverNames()) { Console.WriteLine(asio); } ``` You can then use the driver name to open the device: ```c# using var device = AsioDevice.Open(driverName); ``` (`AsioDevice` is the NAudio 3 ASIO API. The legacy `AsioOut` class still works — see [Migrating from AsioOut to AsioDevice](AsioMigration.md).) # Management Objects Finally you can use Windows Management Objects to get hold of details of the sound devices installed. This doesn't map specifically to any of the NAudio output device types, but can be a source of useful information ```c# var objSearcher = new ManagementObjectSearcher( "SELECT * FROM Win32_SoundDevice"); var objCollection = objSearcher.Get(); foreach (var d in objCollection) { Console.WriteLine("=====DEVICE===="); foreach (var p in d.Properties) { Console.WriteLine($"{p.Name}:{p.Value}"); } } ``` --- ## File: Docs/FadeInOutSampleProvider.md # Fading Audio in and out with FadeInOutSampleProvider The `FadeInOutSampleProvider` offers a simple, basic way to fade audio in and out. It follows the decorator pattern common to many `ISampleProvider` implementations. You pass in the `ISampleProvider` that you want to fade in and out. In this example, we'll construct a `FadeInOutSampleProvider` taking its source from an `AudioFileReader`, and passing the `true` flag to specify that we want to start with silence, ready for a fade in. We'll also immediately trigger a fade in over 2 seconds (2000 milliseconds) by calling `BeginFadeIn`. ```c# var audio = new AudioFileReader("example.mp3"); var fade = new FadeInOutSampleProvider(audio, true); fade.BeginFadeIn(2000); ``` Now we can pass our `FadeInOutSampleProvider` to an output device and start playing. We'll hear the audio fading in over the first two seconds. ```c# var waveOutDevice = new WaveOut(); waveOutDevice.Init(fade); waveOutDevice.Play(); ``` At some point in the future, we might want to fade out, and we can trigger that with `BeginFadeOut`, again specifying a 2 second fadeout. ```c# fade.BeginFadeOut(2000); ``` Once the audio has faded out, the `FadeInOutSampleProvider` continues to read from its source but emits silence until it reaches its end, or until you call `BeginFadeIn` again. ### Taking it further The `FadeInOutSampleProvider` is a very basic fade provider, and you may want additional features like: - automatically fading out when you reach the end of the source - automatically stopping at the end of a fade out - cross-fading into another input. You can do this by taking the code for `FadeInOutSampleProvider` and adapting it. For example, to automatically fade out at the end of the source, you'd actually need to read ahead by the duration of the fade (or know in advance where you want the fade to begin) These features may be added in the future to NAudio, but don't be afraid to create your own custom `ISampleProvider` implementations that behave just how you want.