---
title: "Decode Ogg Vorbis in C#"
url: https://recursiveai.org/oneaudio/articles/ogg-vorbis-csharp/
description: "Decode Ogg Vorbis in C# with managed code on any OS: stream floats, seek to an exact frame, play chained files, convert OGG to WAV, and compare with NVorbis."
date: 2026-10-27
author: OneAudio team
---

# Decode Ogg Vorbis in C#

Decode Ogg Vorbis in C# with managed code on any OS: stream floats, seek to an exact frame, play chained files, convert OGG to WAV, and compare with NVorbis.

October 27, 2026 · OneAudio team

To decode an Ogg Vorbis file in C#, add the `RecursiveAI.OneAudio` package and call `Audio.Open("music.ogg")`: you get a streaming decoder that fills a float buffer block by block, with sample-accurate `Seek`. `Audio.Load` decodes the whole file into memory, and `Audio.Transcode("music.ogg", "music.wav")` converts OGG to WAV. The decoder is managed C# checked against libvorbis on the Xiph test vectors, so the same code runs on Windows, Linux and macOS. Every sample below was compiled and run against OneAudio 1.2.1 on .NET 10.

## Before you start

*Terminal · NuGet*

```
dotnet new console -o OggVorbis
cd OggVorbis
dotnet add package RecursiveAI.OneAudio --version 1.2.1
```

OneAudio targets .NET 10 and is licensed MIT OR Apache-2.0. The samples use `music.ogg`, 30 seconds of stereo music at 44.1 kHz encoded with libvorbis at quality 5, and `chained.ogg`, that file followed by a second, 10-second Vorbis stream.

## Decode, seek and convert an OGG file

*Program.cs · OneAudio 1.2.1 · .NET 10*

```
using OneAudio;
 
// Stream an Ogg Vorbis file: interleaved floats, block by block.
using IAudioDecoder vorbis = Audio.Open("music.ogg");
Console.WriteLine($"{vorbis.Format.SampleRate} Hz, {vorbis.Format.Channels} ch, {vorbis.LengthFrames} frames " +
                  $"({vorbis.LengthFrames / (double)vorbis.Format.SampleRate:F3} s)");
 
float[] block = new float[4096 * vorbis.Format.Channels];
long frames = 0;
int n;
while ((n = vorbis.Read(block)) > 0)
    frames += n;
Console.WriteLine($"decoded {frames} frames");
 
// Seek to an exact frame, e.g. a loop point at 10 s.
vorbis.Seek(441000);
n = vorbis.Read(block);
Console.WriteLine($"after seek: position {vorbis.PositionFrames}");
 
// Two Ogg Vorbis streams joined end to end (a chained file, here 30 s + 10 s) play as one.
using IAudioDecoder chained = Audio.Open("chained.ogg");
Console.WriteLine($"chained.ogg: {chained.LengthFrames} frames");
 
// OGG to WAV, or to FLAC or Opus by changing the extension.
Audio.Transcode("music.ogg", "music-from-ogg.wav");
Console.WriteLine($"music-from-ogg.wav: {new FileInfo("music-from-ogg.wav").Length:N0} bytes");
```

*Output · Console*

```
44100 Hz, 2 ch, 1323000 frames (30.000 s)
decoded 1323000 frames
after seek: position 445096
chained.ogg: 1764000 frames
music-from-ogg.wav: 5,292,080 bytes
```

- `Read` fills the span you pass with interleaved floats and returns a count of frames (one sample per channel), which can be less than you asked for; 0 means the end. Samples are never clipped, so a loud Vorbis file can exceed ±1 slightly and nothing is lost.
- The length is exact before you decode: 1,323,000 frames is exactly 30 seconds, because the decoder applies the stream’s granule positions to trim the first and last packets.
- `Seek` lands on the frame you ask for. Reading a block of 4,096 frames from frame 441,000 leaves the position at 445,096. That makes music loops with a loop point in the middle of a file sample-exact.
- A chained file, two or more Vorbis streams one after another in one file, plays as one stream: 30 s + 10 s is 1,764,000 frames, and seeking works across the join.
- Decoding allocates nothing per read. For a game, play the file with `mixer.PlayStream("music.ogg", loop: true)` and it is decoded ahead on a background thread. See [the game audio mixer article](https://recursiveai.org/oneaudio/articles/game-audio-mixer-csharp/).

## NVorbis

[NVorbis](https://www.nuget.org/packages/NVorbis/0.10.5) is the managed Vorbis decoder most C# answers point to, MIT licensed. Its latest stable release is 0.10.5, from October 16, 2022; 1.0.0-rc.2 is a prerelease. Following its [README](https://github.com/NVorbis/NVorbis):

*Program.cs · NVorbis 0.10.5*

```
using NVorbis;
 
using (var vorbis = new VorbisReader("music.ogg"))
{
    var channels = vorbis.Channels;
    var sampleRate = vorbis.SampleRate;
    Console.WriteLine($"{sampleRate} Hz, {channels} ch, {vorbis.TotalTime}");
 
    var readBuffer = new float[channels * sampleRate / 5];   // 200 ms
    long samples = 0;
    int cnt;
    while ((cnt = vorbis.ReadSamples(readBuffer, 0, readBuffer.Length)) > 0)
        samples += cnt;                                       // samples, not frames
    Console.WriteLine($"decoded {samples / channels} frames");
}
```

*Output · Console*

```
44100 Hz, 2 ch, 00:00:30
decoded 1323000 frames
```

- Both decoders give the same 1,323,000 frames. NVorbis’s `ReadSamples` counts samples, OneAudio’s `Read` counts frames: divide or multiply by the channel count when you move code across.
- The NVorbis README says the “sample value range is -0.99999994f to 0.99999994f unless vorbis.ClipSamples == false”, so it clips by default. OneAudio never clips decoded samples.
- NVorbis decodes Vorbis only. OneAudio reads Vorbis, Opus, FLAC, MP3 and WAV through the same call, writes WAV, FLAC and Opus, and adds resampling, a mixer and loudness measurement.

In the project’s [published decode benchmark](https://github.com/recursive-ai-oss/oneaudio-csharp/blob/v1.2.1/README.md#decode), OneAudio decoded three Xiph test files 1.20 to 1.25 times as fast as NVorbis 0.10.5. On the 186-second stereo file it took 196 ms against 240 ms and allocated 686 KB against NVorbis’s 77.9 MB. Measured with BenchmarkDotNet 0.15.8 on an AMD Ryzen 9 7950X3D under Linux with .NET 10.0.13. The decoder’s accuracy is checked against libvorbis 1.3.7: the same frame counts on every test vector, and floor-1 streams within 2e-6 of libvorbis’s float output.

## Writing a compressed file

OneAudio decodes Vorbis; for lossy output it encodes Opus, which is also stored in Ogg files. `Audio.Transcode("music.wav", "music.opus")` writes an Ogg Opus file, covered in [encode and decode Opus in C#](https://recursiveai.org/oneaudio/articles/opus-csharp/). For lossless output, write FLAC ([read and write FLAC in C#](https://recursiveai.org/oneaudio/articles/flac-csharp/)).

## Where next

- [Decode Ogg Vorbis](https://recursiveai.org/oneaudio/cookbook/decode-ogg-vorbis/) and [streaming decode](https://recursiveai.org/oneaudio/cookbook/streaming-decode/), the cookbook recipes.
- [Play audio in C#](https://recursiveai.org/oneaudio/articles/play-audio-csharp/), to hear the file.
- The [decoding section](https://recursiveai.org/oneaudio/docs/api/#decoding) of the API overview: chained streams, seeking and limits.
