---
title: "Decode AAC and M4A in C#"
url: https://recursiveai.org/oneaudio/cookbook/decode-aac/
description: "Read .m4a, .mp4, .3gp and raw .aac files as float samples or convert them to WAV in C#, with no Media Foundation or FFmpeg."
version: "1.4.0"
---

# Decode AAC and M4A in C#

`Audio.Load` decodes AAC-LC from M4A, MP4, 3GP and raw ADTS (`.aac`) files to float samples, and `Audio.Transcode` converts them to WAV, in managed code with no Media Foundation or FFmpeg. The files here are 1.5-second synthetic test files from the oneaudio repository, one M4A and the same kind of audio as raw AAC.

```shell
dotnet new console -o DecodeAac && cd DecodeAac
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.m4a $t/containers/aac-itunes-gapless.m4a
curl -L -o song.aac $t/containers/aac.aac
```

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

```csharp
using OneAudio;
using OneAudio.Aac;

// AAC-LC in an M4A file decodes to float like any other format.
AudioClip clip = Audio.Load("song.m4a");
AudioFormat f = clip.Format;
Console.WriteLine($"song.m4a: {f.SampleRate} Hz, {f.Channels} ch, " +
                  $"{clip.Frames} frames " +
                  $"({clip.Frames / (double)f.SampleRate:F3} s)");

// Raw ADTS: nothing in the file records the encoder's priming and padding.
using (IAudioDecoder adts = Audio.Open("song.aac"))
    Console.WriteLine($"song.aac: {adts.GetType().Name}, {adts.LengthFrames} frames");

// The concrete decoder says what the stream is. Seeking is exact.
using (var aac = (AacDecoder)Audio.Open("song.m4a"))
{
    float[] block = new float[1024 * f.Channels];
    aac.Seek(44100);
    int frames = aac.Read(block);
    int at = 44100 * f.Channels, n = frames * f.Channels;
    bool same = block.AsSpan(0, n).SequenceEqual(clip.Samples.Span.Slice(at, n));
    Console.WriteLine($"object type {aac.Config.ObjectType} (AAC-LC), seek to 1 s, " +
                      $"same as a full decode: {same}");
}

// M4A to WAV, block by block.
TranscodeResult wav = Audio.Transcode("song.m4a", "song.wav");
Console.WriteLine($"song.wav: {wav.Frames} frames, " +
                  $"{new FileInfo("song.wav").Length:N0} bytes");
```

```text
song.m4a: 44100 Hz, 2 ch, 65000 frames (1.474 s)
song.aac: AacDecoder, 67584 frames
object type 2 (AAC-LC), seek to 1 s, same as a full decode: True
song.wav: 65000 frames, 260,080 bytes
```

## If Audio.Open says “No MPEG audio frame found”

In 1.4.0, `Audio` checks for MP3 before MP4 and AMR, and the MP3 check can claim some M4A, 3GP and AMR files. Opening one of those throws `AudioFormatException: No MPEG audio frame found.` An `AudioKit` that checks MP4, AMR and ADTS before MP3 opens them, and has the same `Open`, `Load`, `Transcode`, `Measure` and `Normalize` as `Audio`:

```csharp
using OneAudio;

var kit = new AudioKit(new AudioCodecRegistry()
    .AddWav().AddOgg().AddVorbis().AddOpus().AddFlac()
    .AddMp4().AddAmr().AddAdts().AddMp3().AddAac());
AudioClip clip = kit.Load("song.m4a");
Console.WriteLine($"{clip.Frames} frames");
```

```text
65000 frames
```

## Gapless length

An AAC encoder starts with 1,024 frames of priming and pads the end to a whole frame. An M4A file records both, in its edit list or in an iTunes `iTunSMPB` tag, and oneaudio trims them, so `song.m4a` decodes to the length that was encoded. A raw `.aac` file has nowhere to record them, so the whole decoded signal is kept.

## Limits

- AAC-LC, mono or stereo, 8 to 48 kHz, with every AAC-LC coding tool. A stream that carries SBR data without signalling it decodes as its AAC-LC core.
- HE-AAC signalled in the file (SBR or PS), more than two channels, rates above 48 kHz and the other AAC object types throw `UnsupportedAudioFormatException`. So does ALAC in an M4A.
- Fragmented MP4 files are rejected with a typed error. With several audio tracks, `Mp4PacketSource.Tracks` lists them and `SelectTrack` picks one.
- Title, artist and comments come from `Mp4PacketSource` (`OneAudio.Mp4`): `Mp4PacketSource.Open(File.OpenRead(path))`.
- oneaudio doesn’t write AAC. To compress, write [Ogg Opus](https://recursiveai.org/oneaudio/cookbook/encode-opus/).

The decoder matches all 72 exact AAC-LC mono and stereo ISO/IEC 14496-26 conformance streams within the full-accuracy limits. Speech in AMR and 3GP files: [Decode AMR](https://recursiveai.org/oneaudio/cookbook/decode-amr/).
