---
title: "Read MP3, FLAC and WAV tags and duration in C#"
url: https://recursiveai.org/onemedia/cookbook/get-audio-file-tags-duration/
description: "Read the title, artist and other tags, the duration, sample rate and bit rate of MP3, FLAC and WAV files in C#: ID3v1/v2, APE, Vorbis comments and RIFF INFO, with a common view over all of them. Also Ogg, AIFF, WMA and M4A."
version: "0.2.0-preview.1"
---

# Read MP3, FLAC and WAV tags and duration in C#

`Media.Open` reads an audio file’s tags and its duration with the same calls as a video: `media.Tags` gives the common fields (title, artist, album, copyright…) whichever tag system the file uses, and `media.Metadata.NativeTags` lists every tag as stored. The inputs are the soundtrack of the Sintel trailer (CC BY 3.0, © copyright Blender Foundation | durian.blender.org), converted with FFmpeg to MP3, FLAC and WAV; FFmpeg copies the trailer’s tags into each format’s own tag system.

```shell
dotnet new console -o AudioTags && cd AudioTags
dotnet add package RecursiveAI.OneMedia --version 0.2.0-preview.1
curl -L -o sintel.mp4 https://download.blender.org/durian/trailer/sintel_trailer-480p.mp4
x="-v error -i sintel.mp4 -vn -metadata major_brand= -metadata minor_version= -metadata compatible_brands="
ffmpeg $x -c:a libmp3lame -q:a 4 sintel.mp3
ffmpeg $x sintel.flac
ffmpeg $x sintel.wav
```

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

```csharp
using RecursiveAI.OneMedia;
using RecursiveAI.OneMedia.Tags;

foreach (string path in new[] { "sintel.mp3", "sintel.flac", "sintel.wav" })
{
    using MediaFile media = Media.Open(path);
    MediaTrack audio = media.Audio!;
    string rate = audio.BitRate > 0 ? $", {audio.BitRate / 1000} kbit/s" : "";
    Console.WriteLine($"{path}: {media.Format}, {media.Duration:mm\\:ss\\.fff}," +
                      $" {audio.Codec} {audio.Audio?.SampleRate} Hz" +
                      $" {audio.Audio?.Channels} ch{rate}");

    // The common view: the same fields for ID3, APE, Vorbis comments, RIFF INFO...
    CommonTags tags = media.Tags;
    Console.WriteLine($"  title {tags.Title}, artist {tags.Artist}");
    Console.WriteLine($"  copyright {tags.Copyright}");

    // Every native tag: its system, its key and its value as stored.
    foreach (NativeTag tag in media.Metadata.NativeTags)
        Console.WriteLine($"  {tag.System}:{tag.Key} = {tag.Text}");
}
```

```text
sintel.mp3: mpegaudio, 00:51.925, mp3 48000 Hz 2 ch, 136 kbit/s
  title Sintel Trailer, artist Durian Open Movie Team
  copyright (c) copyright Blender Foundation | durian.blender.org
  id3v2:TCOP = (c) copyright Blender Foundation | durian.blender.org
  id3v2:TIT2 = Sintel Trailer
  id3v2:TPE1 = Durian Open Movie Team
  id3v2:TXXX:description = Trailer for the Sintel open movie project
  id3v2:TSSE = Lavf62.3.100
sintel.flac: flac, 00:51.925, flac 48000 Hz 2 ch
  title Sintel Trailer, artist Durian Open Movie Team
  copyright (c) copyright Blender Foundation | durian.blender.org
  vorbis:copyright = (c) copyright Blender Foundation | durian.blender.org
  vorbis:title = Sintel Trailer
  vorbis:artist = Durian Open Movie Team
  vorbis:description = Trailer for the Sintel open movie project
  vorbis:encoder = Lavf62.3.100
sintel.wav: wav, 00:51.925, pcm 48000 Hz 2 ch, 1536 kbit/s
  title Sintel Trailer, artist Durian Open Movie Team
  copyright (c) copyright Blender Foundation | durian.blender.org
  riff-info:IART = Durian Open Movie Team
  riff-info:ICOP = (c) copyright Blender Foundation | durian.blender.org
  riff-info:INAM = Sintel Trailer
  riff-info:ISFT = Lavf62.3.100
```

Each format keeps its tags its own way: ID3v2 frames in the MP3 (`TIT2` is the title), Vorbis comments in the FLAC (`title`), RIFF `LIST INFO` chunks in the WAV (`INAM`). The common view maps all of them to `Title`, `Artist`, `Copyright` and the rest through a fixed [mapping table](https://recursiveai.org/onemedia/docs/tag-mapping/); when several tags map to one field, the property is the first and `media.Tags.Values(CommonField.Title)` lists them all. One native tag reads as `media.Native["id3v2", "TIT2"]`.

The duration is exact for all three: the FLAC and WAV state their length in samples, and FFmpeg’s MP3 has a Xing/LAME header with the frame count and the encoder delay and padding, which OneMedia takes off. The same code reads ID3v1, APE and Lyrics3 tags on MP3, Vorbis comments in Ogg Vorbis and Opus, AIFF and CAF text chunks, BWF `bext` and iXML in WAV, WMA attributes, and iTunes tags in M4A ([Read MP4 metadata](https://recursiveai.org/onemedia/cookbook/read-mp4-metadata/)). Pictures such as cover art are native tags of kind `Image`; their bytes are read only when you call `tag.ReadValue()`.

## Check it with ffprobe

```shell
ffprobe -v error -show_entries format=duration:format_tags=title,artist -of compact sintel.flac
```

```text
format|duration=51.925333|tag:title=Sintel Trailer|tag:artist=Durian Open Movie Team
```

## Limits

- **Reading only.** OneMedia 0.2 doesn’t write or edit tags. Tag editing is not in this release.
- **Estimated durations.** An MP3 or ADTS AAC file without a frame count (no Xing, Info or VBRI header) gets a duration estimated from its bit rate, as other tools do.
- **Not mapped.** A tag the mapping table doesn’t list stays on the native list only, such as the MP3’s `TXXX:description` here.
- **Decoding** is OneAudio’s job: `media.Decode()` from `RecursiveAI.OneMedia.Audio` plays MP3, FLAC, Vorbis, Opus and AAC, but not PCM, ADPCM, WMA, AC-3 or ALAC tracks. For WAV samples, read the packets or use OneAudio directly.
- **Known differences** from ExifTool, MediaInfo, TagLib# and ATL.NET are listed per format: [MP3, AAC, AC-3 and AMR files](https://recursiveai.org/onemedia/docs/audio-es/), [FLAC](https://recursiveai.org/onemedia/docs/flac/), [WAV, AIFF and CAF](https://recursiveai.org/onemedia/docs/pcm-files/).

For video files, the same calls work on MP4 ([Read MP4 metadata](https://recursiveai.org/onemedia/cookbook/read-mp4-metadata/)) and MKV ([Read MKV and WebM file info](https://recursiveai.org/onemedia/cookbook/read-mkv-webm-info/)).
