---
title: "Trim an audio file in C#"
url: https://recursiveai.org/oneaudio/cookbook/trim-audio/
description: "Cut a section out of an MP3, WAV, FLAC or Ogg file by time in C# and save it as WAV, with short fades so the cut doesn’t click."
version: "1.4.0"
---

# Trim an audio file in C#

Open the file, `Seek` to the start of the part you want, `Read` until its end and write what you read with a `WavEncoder`. Seeking is sample-exact, so the cut lands where you ask. The file here is a three-second synthetic test file from the oneaudio repository; the program keeps 0.5 s to 2.0 s.

```shell
dotnet new console -o TrimAudio && cd TrimAudio
dotnet add package RecursiveAI.OneAudio --version 1.4.0
t=https://raw.githubusercontent.com/recursive-ai-oss/oneaudio-csharp/v1.4.0/testdata
curl -L -o song.flac $t/flac/stereo16_seektable.flac
```

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

```csharp
using OneAudio;

TimeSpan from = TimeSpan.FromSeconds(0.5), to = TimeSpan.FromSeconds(2.0);

using IAudioDecoder decoder = Audio.Open("song.flac");
AudioFormat f = decoder.Format;
long start = (long)(from.TotalSeconds * f.SampleRate);
long end = Math.Min((long)(to.TotalSeconds * f.SampleRate), decoder.LengthFrames);
long fade = f.SampleRate / 100;                 // 10 ms at each end

decoder.Seek(start);
// A lossless source keeps its bit depth; a lossy one is written as 16-bit.
using (var wav = new WavEncoder(File.Create("cut.wav"), f, new WavEncoderSettings(),
                                leaveOpen: false))
{
    float[] block = new float[4096 * f.Channels];
    long position = start;
    while (position < end)
    {
        int want = (int)Math.Min(4096, end - position);
        int read = decoder.Read(block.AsSpan(0, want * f.Channels));
        if (read == 0)
            break;
        for (int i = 0; i < read; i++)          // fade in and out
        {
            long fromStart = position + i - start, fromEnd = end - (position + i) - 1;
            float gain = Math.Min(1f, Math.Min(fromStart, fromEnd) / (float)fade);
            for (int c = 0; c < f.Channels; c++)
                block[i * f.Channels + c] *= gain;
        }
        wav.Write(block.AsSpan(0, read * f.Channels));
        position += read;
    }
}

using IAudioDecoder cut = Audio.Open("cut.wav");
Console.WriteLine($"song.flac: {decoder.LengthFrames / (double)f.SampleRate:F3} s");
Console.WriteLine($"cut.wav: {cut.LengthFrames} frames, " +
                  $"{cut.LengthFrames / (double)f.SampleRate:F3} s, " +
                  $"{cut.Format.NativeType}");
```

```text
song.flac: 2.993 s
cut.wav: 33075 frames, 1.500 s, PcmSigned16
```

The 10 ms fades stop the cut from clicking where it lands mid-waveform. Leave the loop out (and use `ReadInteger` with `WriteInteger`) for a bit-exact cut of a lossless file.

## Limits

- Works the same for MP3, Ogg Vorbis, Opus, FLAC, AAC, AMR and WAV inputs: only the input name changes. MP3 and AAC seeks are exact because the decoder rebuilds its state from frames before the target.
- The output is WAV here. To keep it compressed, write the WAV to FLAC or Opus with `Audio.Transcode` (see [Convert audio files](https://recursiveai.org/oneaudio/cookbook/convert-audio-files/)). A lossy file can’t be cut without decoding, so the result is re-encoded, never a byte-for-byte copy of the original frames.
- A stream that can’t seek (a pipe or an HTTP body) throws `NotSupportedException` from `Seek`; read and discard frames up to the start instead.

To join clips end to end, see [Join audio files](https://recursiveai.org/oneaudio/cookbook/join-audio/).
