Table of Contents

Cross-platform audio file reading and writing with NAudio.SoundFile

The NAudio.SoundFile package wraps libsndfile to read and write a wide range of audio formats — WAV, AIFF, FLAC, Ogg/Vorbis, Opus and MP3 — on Linux, macOS and Windows. It is the cross-platform counterpart to MediaFoundationReader / MediaFoundationEncoder (which are Windows-only), and provides the first cross-platform FLAC/Vorbis/Opus encoder in NAudio.

SoundFileReader is a WaveStream and an ISampleProvider, so it drops straight into any NAudio pipeline. SoundFileWriter is a Stream sink with the same static helpers as WaveFileWriter.

Installing

NAudio.SoundFile is not part of the NAudio meta-package — reference it explicitly:

dotnet add package NAudio.SoundFile

It P/Invokes a system libsndfile (no binary is shipped). Install the runtime library for your platform:

sudo apt install libsndfile1     # Debian/Ubuntu
brew install libsndfile          # macOS
vcpkg install libsndfile         # Windows (or the official libsndfile release binaries)

Which codecs are available depends on how that libsndfile was built; see Checking codec availability below.

Reading any audio file

SoundFileReader decodes to 32-bit float. Because it is a WaveStream, you can play it through any output device or feed it into any sample pipeline — exactly where you would otherwise reach for MediaFoundationReader or AudioFileReader on Windows:

using NAudio.SoundFile;
using NAudio.Wave;

using var reader = new SoundFileReader("song.flac");
Console.WriteLine($"{reader.WaveFormat} {reader.TotalTime}");

using var output = new WasapiPlayerBuilder().Build();   // or AlsaOut on Linux
output.Init(reader);
output.Play();
while (output.PlaybackState == PlaybackState.Playing)
    Thread.Sleep(200);

Encoding to FLAC, Ogg-Vorbis, Opus and MP3

Let's create a 20-second test WAV with SignalGenerator, then encode it. SoundFileWriter mirrors WaveFileWriter's static helpers — CreateSoundFile for an IWaveProvider and CreateSoundFile16 for an ISampleProvider:

var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NAudio");
Directory.CreateDirectory(dir);
var wavPath = Path.Combine(dir, "test.wav");

WaveFileWriter.CreateWaveFile16(wavPath, new SignalGenerator(44100, 2)
{
    Type = SignalGeneratorType.Sweep,
    Frequency = 500,
    FrequencyEnd = 3000,
    Gain = 0.2f,
    SweepLengthSecs = 20
}.Take(TimeSpan.FromSeconds(20)));

FLAC is lossless — there is no bitrate, but you can trade encode speed for size with CompressionLevel (0.0 fastest … 1.0 smallest):

using (var reader = new SoundFileReader(wavPath))
{
    SoundFileWriter.CreateSoundFile(Path.Combine(dir, "test.flac"), reader,
        SoundFileMajorFormat.Flac,
        new SoundFileWriterOptions { CompressionLevel = 0.8 });
}

Ogg-Vorbis and Opus are lossy — set VbrQuality (0.0 … 1.0):

using (var reader = new SoundFileReader(wavPath))
{
    SoundFileWriter.CreateSoundFile(Path.Combine(dir, "test.ogg"), reader,
        SoundFileMajorFormat.OggVorbis,
        new SoundFileWriterOptions { VbrQuality = 0.6 });
}

using (var reader = new SoundFileReader(wavPath))
{
    // Opus only supports 8/12/16/24/48 kHz; the writer throws a clear
    // ArgumentException for other rates so resample first if needed.
    SoundFileWriter.CreateSoundFile(Path.Combine(dir, "test.opus"), reader,
        SoundFileMajorFormat.Opus,
        new SoundFileWriterOptions { VbrQuality = 0.7 });
}

The output format is also inferred from the file extension, so for the common case you don't even need to name it:

using (var reader = new SoundFileReader(wavPath))
    SoundFileWriter.CreateSoundFile(Path.Combine(dir, "test.flac"), reader); // → FLAC

Converting between formats

Because the reader decodes anything and the writer encodes anything, conversion is just "read one, write another" — e.g. MP3 → FLAC:

using (var reader = new SoundFileReader("podcast.mp3"))
{
    SoundFileWriter.CreateSoundFile("podcast.flac", reader, SoundFileMajorFormat.Flac, null);
}

The writer accepts 16-bit PCM or 32-bit IEEE float input — the two formats NAudio pipelines naturally produce. For anything else, convert with SampleToWaveProvider16 or .ToSampleProvider() first.

Reading and writing streams

Both ends work over a System.IO.Stream (via libsndfile's virtual I/O), so you can encode into a MemoryStream or decode from a network/HTTP stream. The stream is not disposed by the reader/writer — the caller owns it:

using var ms = new MemoryStream();
using (var reader = new SoundFileReader("in.wav"))
{
    SoundFileWriter.WriteSoundFileToStream(ms, reader, SoundFileMajorFormat.OggVorbis, null);
}

ms.Position = 0;
using (var back = new SoundFileReader(ms))
{
    // ... decode the in-memory Ogg
}

FLAC/Ogg/Opus/MP3 stream fine to a forward-only target; WAV and AIFF back-patch their header at close, so the writer throws early if you pair a non-seekable stream with those.

Reading and writing tags

Title/artist/album and friends are read on open and can be written via SoundFileWriterOptions.Tags (Vorbis comments for FLAC/Ogg/Opus, a limited LIST/INFO set for WAV/AIFF — unsupported fields are simply ignored):

SoundFileWriter.CreateSoundFile("tagged.flac", source, SoundFileMajorFormat.Flac,
    new SoundFileWriterOptions
    {
        Tags = new SoundFileTags { Title = "Demo", Artist = "NAudio", Album = "Examples" }
    });

using var reader = new SoundFileReader("tagged.flac");
Console.WriteLine($"{reader.Tags.Artist} – {reader.Tags.Title}");

Checking codec availability

FLAC, Vorbis, Opus and MP3 are optional libsndfile build features, so a given install may not have them. Query before encoding rather than catching an exception:

Console.WriteLine(SoundFileCapabilities.LibraryVersion);   // e.g. "libsndfile-1.2.2"

if (SoundFileCapabilities.IsFormatSupported(SoundFileMajorFormat.Opus))
{
    // safe to encode Opus
}

foreach (var f in SoundFileCapabilities.GetSupportedMajorFormats())
    Console.WriteLine(f);

The Debian/Ubuntu libsndfile1, Homebrew libsndfile, vcpkg libsndfile, and the official libsndfile Windows release binaries are all built with the full FLAC/Vorbis/Opus/MP3 set.

What's out of scope

AAC, M4A, ALAC and WMA are not covered — that is the MPEG-4 / FFmpeg family. On Windows those are handled by MediaFoundationReader / MediaFoundationEncoder (see Encode to MP3, WMA, AAC and more with MediaFoundationEncoder); there is no cross-platform decoder for them in NAudio.

See also