---
title: "Write a WAV file in C#"
url: https://recursiveai.org/oneaudio/cookbook/write-wav/
description: "Generate a sine wave or save float samples as a 16-bit, 24-bit or 32-bit float WAV in C#, with dither, and RF64 for files over 4 GB."
version: "1.4.0"
---

# Write a WAV file in C#

Create a `WavEncoder` over a file, `Write` interleaved float samples, and dispose it: the encoder converts to the bit depth you choose and fills in the header. The program needs no input: it generates two seconds of a 440 Hz tone and writes it three ways.

```shell
dotnet new console -o WriteWav && cd WriteWav
dotnet add package RecursiveAI.OneAudio --version 1.4.0
```

Put this in `Program.cs` and run `dotnet run`:

```csharp
using OneAudio;

// Two seconds of a 440 Hz sine at half scale, 48 kHz stereo, interleaved:
// samples[frame * 2] is the left channel, samples[frame * 2 + 1] the right.
const int Rate = 48000, Channels = 2;
float[] samples = new float[Rate * 2 * Channels];
for (int frame = 0; frame < Rate * 2; frame++)
{
    float s = 0.5f * MathF.Sin(2 * MathF.PI * 440 * frame / Rate);
    samples[frame * 2] = s;
    samples[frame * 2 + 1] = s;
}

var format = new AudioFormat(Rate, Channels);
Write("tone-16.wav", NativeSampleType.PcmSigned16);
Write("tone-24.wav", NativeSampleType.PcmSigned24);
Write("tone-float.wav", NativeSampleType.IeeeFloat32);

void Write(string path, NativeSampleType type)
{
    var settings = new WavEncoderSettings { SampleType = type };
    using (var wav = new WavEncoder(File.Create(path), format, settings,
                                    leaveOpen: false))
    {
        wav.Write(samples);         // call as often as you like
    }                               // Dispose finishes the header

    using IAudioDecoder check = Audio.Open(path);
    long bytes = new FileInfo(path).Length;
    Console.WriteLine($"{path,-15}{check.Format.NativeType,-13}" +
                      $"{check.LengthFrames} frames, {bytes,9:N0} bytes");
}
```

```text
tone-16.wav    PcmSigned16  96000 frames,   384,080 bytes
tone-24.wav    PcmSigned24  96000 frames,   576,104 bytes
tone-float.wav IeeeFloat32  96000 frames,   768,116 bytes
```

Each file plays in any audio player and opens in any editor. To write audio you produce over time, a recording or a synthesizer, keep the encoder open and call `Write` with each block.

## Options

- `SampleType` picks the stored type: `PcmUnsigned8`, `PcmSigned16`, `PcmSigned24`, `PcmSigned32`, `IeeeFloat32` or `IeeeFloat64`. Without it the encoder uses the format’s own type.
- Floats are scaled, rounded to nearest and clipped to the integer range; NaN becomes 0. `Dither = true` adds one bit of triangular dither first, from a fixed seed (`DitherSeed`), so the same input gives the same file. Use it when you reduce 24-bit or float audio to 16 bits.
- `WriteInteger` writes integers exactly, for audio that is already 16 or 24-bit.
- `WAVE_FORMAT_EXTENSIBLE` with a channel mask is used for more than two channels or more than 16 bits. Float files get a `fact` chunk.
- To copy a whole file, `Audio.Transcode("in.mp3", "out.wav")` decodes and writes in one call; `TranscodeOptions.Wav` takes the same settings.

## Limits

- On a stream that can seek, disposing writes the final sizes, and a file that outgrows 4 GB becomes RF64 by itself. `ForceRf64` writes RF64 from the start.
- On a stream that can’t seek, such as a pipe or an HTTP response, the header can’t be patched afterwards. Give `TotalFrames` for exact sizes; otherwise the sizes are written as “unknown”, which oneaudio and most readers take to mean “to the end of the stream”.
- The encoder isn’t thread-safe: write from one thread.

In the project’s [published benchmarks](https://github.com/recursive-ai-oss/oneaudio-csharp/blob/v1.4.0/README.md#benchmarks), writing 60 seconds of 48 kHz stereo as 16-bit PCM took 2.8 ms. To read the files back, see [Read a WAV file](https://recursiveai.org/oneaudio/cookbook/read-wav/).
