audio-tag

audio-tag

Spec-exact tags for every audio container. Read and write them in the browser and in Node, and every byte you did not touch stays as it was.

MP3 · ID3M4A · MP4FLACOggAIFF · AIFF-CWAV
0 dependenciesbrowser · Node · Deno · Bunbyte-exact round trips104 ID3v2 frames
import { readFromBlob, writeToBlob } from 'audio-tag/browser'

const { format, metadata } = await readFromBlob(file)
// 'mpeg' | 'mp4' | 'flac' | 'ogg' | 'aiff' | 'riff'

const out = await writeToBlob(file, {
  metadata: { title: 'New title', genre: ['Rock'] },
})
// a File with the same name; the audio is never copied

How it works

Reading looks at the tag regions only. Writing is a plan of new tag bytes and ranges of the old file, carried out in place when the size stays the same.

How audio-tag works Reading: bytes, a Blob or a file path go to detectFormat, which picks the reader for ID3, MP4, FLAC, Ogg, AIFF or RIFF; every reader returns the same metadata object plus the format's own structures. Writing: a metadata update goes to the format's planner, which returns a plan of new bytes and unchanged ranges of the old file; the plan is written in place, as a new Blob of slices, or through a temporary file and an atomic rename. READ Your file Uint8Arrayaudio-tag Blob / File…/browser file path…/node detectFormat() looks at the first bytes: ID3 ftyp fLaC OggS FORM RIFF and skips leading ID3 tags Format readers ID3 MP4 FLAC Ogg AIFF RIFF read only the tag regions metadata { title, artist, album, track, pictures, … } the same shape for every format, plus each format's own view: frames, atoms, comments, chunks WRITE Your change { metadata: { title: 'New' } } undefined keeps a field, null removes it Planner builds only the tag bytes that change; unknown frames, atoms and chunks keep their exact bytes A plan of segments new old file range audio is referenced, not copied Carried out by write()new bytes, in place …ToBlob()a Blob of slices …ToFile()in place, or temp file + fsync + rename

Read

Write

Try it on your own files

Drop an audio file, edit its tags and download the result. Everything runs in your browser; nothing is uploaded. Open "For nerds" to see the file byte by byte.

Open a file

MP3, M4A, FLAC, Ogg, AIFF or WAV. It never leaves your browser.

Up to 30 seconds, saved as a WAV file. Click again to stop.

No file yet

Open an audio file to see its tags, change them and download a copy. Curious how it is built? The details for nerds show every byte.

Discard your changes?

You changed tags that are not saved yet.

Where the tags live

Each format keeps its tags somewhere else. audio-tag reads and writes all of them with the same metadata object.

Where the tags live Each supported file drawn as a bar from start to end, with the tag regions audio-tag reads and writes in color and the audio data in grey. MP3: ID3v2 at the start, Lyrics3 and ID3v1 at the end. M4A: the ilst item list inside moov, next to the chunk offsets. FLAC: VORBIS_COMMENT and PICTURE metadata blocks. Ogg: the comment header packet. AIFF: text chunks and an ID3 chunk after the sound data. WAV: the LIST INFO list and an id3 chunk after the data chunk. Each file from its first byte to its last. Color: tags audio-tag reads and writes. Grey: audio data. Not to scale. MP3 .mp3 ID3v2 header + frames pad MPEG audio frames Lyrics3 ID3v1 M4A · MP4 .m4a .m4b .mp4 .mov ftyp moov trak · stco udta › meta › ilst free mdat · audio samples FLAC .flac fLaC STREAMINFO VORBIS_COMMENT PICTURE PADDING audio frames Ogg .ogg .opus .oga page 0 · id header comment header + cover setup header audio pages AIFF .aif .aiff .aifc FORM AIFF COMM SSND · sound data NAME AUTH (c) ID3 chunk WAV .wav RIFF WAVE fmt data · sound data LIST · INFO id3 chunk tags, read and written headers the reader uses (length, codec) free space for in-place writes

Each file from its first byte (top) to its last. Color: tags audio-tag reads and writes. Hatched: audio data.

MP3 .mp3

  1. ID3v2 header + frames
  2. pad
  3. MPEG audio frames
  4. Lyrics3
  5. ID3v1

M4A · MP4 .m4a .m4b .mp4 .mov

  1. ftyp
  2. moov
    1. trak · stco
    2. udta › meta › ilst
  3. free
  4. mdat · audio samples

FLAC .flac

  1. fLaC
  2. STREAMINFO
  3. VORBIS_COMMENT
  4. PICTURE
  5. PADDING
  6. audio frames

Ogg .ogg .opus .oga

  1. page 0 · id header
  2. comment header + cover
  3. setup header
  4. audio pages

AIFF .aif .aiff .aifc

  1. FORM AIFF
  2. COMM
  3. SSND · sound data
  4. NAME AUTH (c)
  5. ID3 chunk

WAV .wav

  1. RIFF WAVE
  2. fmt
  3. data · sound data
  4. LIST · INFO
  5. id3 chunk

MP3 · ID3

ID3v1 and v1.1, ID3v2.2, 2.3 and 2.4, and Lyrics3 v1 and v2.00. 104 frame types, including the CHAP/CTOC chapters, and 148 genres. Unknown frames keep their bytes.

M4A · MP4

The iTunes item list in moov/udta/meta/ilst, QuickTime mdta keys and udta text. When the metadata grows, every chunk offset (stco/co64) moves with it.

FLAC

The VORBIS_COMMENT block and PICTURE blocks (RFC 9639). A write reuses the padding, so it is usually in place.

Ogg

Vorbis, Opus and FLAC in Ogg: the comment header, with covers as METADATA_BLOCK_PICTURE. Only the header pages are rewritten, with new CRCs.

AIFF · AIFF-C

An ID3 chunk for rich metadata, plus the spec's NAME, AUTH, (c), ANNO and COMT chunks, kept in step.

WAV

An id3 chunk for rich metadata and the RIFF LIST/INFO list (INAM, IART and others) as a fallback, kept in step.

Install

One package, three entry points: bytes (audio-tag), Blob and File (audio-tag/browser), files on disk (audio-tag/node). It also ships this website, to read offline.

npm install audio-tag