---
title: "Read and write FLAC in C#"
url: https://recursiveai.org/oneaudio/cookbook/flac/
description: "Decode FLAC files bit-exact in C# with oneaudio, verify the MD5 signature, read the tags, and encode WAV to FLAC at compression levels 0 to 8 with your…"
version: "1.2.1"
---

# Read and write FLAC in C#

Decode FLAC files bit-exact in C# with oneaudio, verify the MD5 signature, read the tags, and encode WAV to FLAC at compression levels 0 to 8 with your own tags.

```csharp
using OneAudio;
using OneAudio.Flac;

// Read: FlacDecoder adds the true bit depth, the tags and the MD5 check.
using (var flac = (FlacDecoder)Audio.Open("music.flac"))
{
    Console.WriteLine($"music.flac: {flac.Format.SampleRate} Hz, {flac.Format.Channels} ch, " +
                      $"{flac.BitsPerSample}-bit, {flac.LengthFrames} frames");
    Console.WriteLine($"tags: {string.Join(", ", flac.Comments)}");

    // Decodes the whole file; the read position is restored afterwards.
    Console.WriteLine($"MD5 matches STREAMINFO: {flac.VerifyMd5()}");

    // Exact integer samples, for lossless work.
    int[] ints = new int[4096 * flac.Format.Channels];
    int frames = flac.ReadInteger(ints);
    int max = ints.Take(frames * 2).Max(Math.Abs);
    Console.WriteLine($"first {frames} frames as integers, max {max}");
}

// Write: WAV to FLAC at the highest compression level, with tags.
long written;
using (IAudioDecoder source = Audio.Open("music.wav"))
using (FileStream output = File.Create("music-level8.flac"))
{
    written = FlacEncoder.Encode(source, output, new FlacEncoderSettings
    {
        CompressionLevel = 8,           // 0 (fastest) to 8 (smallest), default 5
        Comments = ["TITLE=Four chords", "ARTIST=Test signal"],
    });
}
long flacBytes = new FileInfo("music-level8.flac").Length;
long wavBytes = new FileInfo("music.wav").Length;
Console.WriteLine($"music-level8.flac: {written} frames, {flacBytes:N0} bytes " +
                  $"(WAV: {wavBytes:N0})");

// Check the round trip: the decoded integers equal the WAV's.
using IAudioDecoder a = Audio.Open("music.wav"), b = Audio.Open("music-level8.flac");
int[] x = new int[8192], y = new int[8192];
bool same = true;
int n;
while ((n = a.ReadInteger(x)) > 0)
    same &= b.ReadInteger(y) == n && x.AsSpan(0, n * 2).SequenceEqual(y.AsSpan(0, n * 2));
Console.WriteLine($"bit-exact: {same}");
```

```text
music.flac: 44100 Hz, 2 ch, 16-bit, 1411200 frames
tags: DATE=2026, TITLE=Four chords, ARTIST=Test signal, encoder=Lavf62.3.100
MD5 matches STREAMINFO: True
first 4096 frames as integers, max 8423
music-level8.flac: 1411200 frames, 788,714 bytes (WAV: 5,644,878)
bit-exact: True
```

## Reading

- `ReadInteger` returns the stream’s exact samples. A depth that isn’t a whole number of bytes is shifted up to the container width in `Format.BitsPerSample`, so a 12-bit stream reads as 16-bit values. `FlacDecoder.BitsPerSample` is the true depth. `Read` returns floats scaled to the stream’s own depth.
- `VerifyMd5` decodes the whole file and compares it with the signature in STREAMINFO. It returns null when the encoder didn’t store one, and it puts the read position back where it was.
- Every frame is CRC-checked. A frame that contradicts STREAMINFO is rejected with `AudioFormatException`, after the frames before it have been delivered.
- Ogg FLAC opens the same way as native FLAC.

## Writing

- `CompressionLevel` runs from 0 (fastest) to 8 (smallest), and the default is 5. Output stays within FLAC’s streamable subset unless you set `Subset = false`.
- On a seekable stream, `Finish` (or `Dispose`) goes back and writes the length, the MD5 signature and a seek table. On a stream that can’t seek, give `TotalFrames` if you know it. There’s no MD5 or seek table.
- `BitsPerSample` 0, the default, keeps the integer depth of the input format, or writes 16 bits for float and lossy input. Float samples are rounded to that depth, and `Dither = true` adds triangular dither first.
- The encoder writes native FLAC only, not Ogg FLAC.
- The project tests the encoder’s output against the reference `flac -d`: it decodes bit-exact, and files are within 0.4% of the size `flac` produces at the same level.

To convert a whole folder or other formats, see [Convert audio files](https://recursiveai.org/oneaudio/cookbook/convert-audio-files/). Every encoder setting is in the [API overview](https://recursiveai.org/oneaudio/docs/api/#encoding).

Decoding, encoding, tags and the MD5 check: [Read and write FLAC in C#](https://recursiveai.org/oneaudio/articles/flac-csharp/).
