# id3v1 _(no submodules)_ ## Purpose Parses the 128-byte ID3v1 and ID3v1.1 tag that lives at the very end of an MP3 file. ID3v1 is the oldest and most widely supported tag format; while its fixed-length fields and limited character encoding make it inferior to ID3v2, it remains prevalent in older libraries and legacy rips. The parser returns a `Track` object with normalised fields and a `rawTags` map so callers can inspect the original values before transformation. ## Features - Detects presence of the "TAG" magic marker at `buffer.length - 128` - Reads title (30 bytes), artist (30 bytes), album (30 bytes), year (4 bytes), comment (28–30 bytes), and genre index (1 byte) - Implements the ID3v1.1 track-number extension: if comment byte 28 is `0x00` and byte 29 is non-zero, byte 29 is the track number - Maps the genre byte to the 192-entry Winamp-extended genre list - Strips trailing null bytes and ASCII whitespace from every field - Returns an empty `Track` when the tag is absent or the buffer is shorter than 128 bytes ## Usage: Basic Example ```ts import { parseId3v1 } from "@suaveplan/audio-metadata/parsers/id3v1"; const buf = new Uint8Array(256); // write "TAG" at offset 128 buf[128] = 0x54; buf[129] = 0x41; buf[130] = 0x47; // write title "My Song" const enc = new TextEncoder(); enc.encodeInto("My Song", buf.subarray(131)); const track = parseId3v1(buf); // { title: "My Song", format: "id3v1", ... } ``` ## Usage: Advanced Example ```ts import { parseId3v1 } from "@suaveplan/audio-metadata/parsers/id3v1"; // Build a minimal ID3v1.1 buffer with track number const buf = new Uint8Array(128); buf[0] = 0x54; buf[1] = 0x41; buf[2] = 0x47; // "TAG" new TextEncoder().encodeInto("Dark Side", buf.subarray(3, 33)); // title new TextEncoder().encodeInto("Pink Floyd", buf.subarray(33, 63)); // artist new TextEncoder().encodeInto("The Wall", buf.subarray(63, 93)); // album new TextEncoder().encodeInto("1979", buf.subarray(93, 97)); // year // comment bytes 28=0, 29=track number buf[125] = 0x00; buf[126] = 3; // track 3 buf[127] = 17; // Rock genre const track = parseId3v1(buf); console.log(track.artist); // "Pink Floyd" console.log(track.trackNumber); // 3 console.log(track.genre); // "Rock" ``` ## API Reference ### `parseId3v1(buffer)` ```ts function parseId3v1(buffer: Uint8Array): Track ``` | Parameter | Type | Description | |-----------|------|-------------| | `buffer` | `Uint8Array` | Full audio file buffer (must be ≥ 128 bytes for a tag to be present) | **Returns:** A `Track` object. All fields are optional; an empty `Track` (`{}`) is returned when no ID3v1 tag is found. **Does not throw.** Out-of-bounds buffers and missing tags produce an empty result. ## Implementation Notes Latin-1 encoding is used for all field reads because the ID3v1 specification predates UTF-8 adoption in audio tags; using `TextDecoder("utf-8")` would corrupt characters in the 0x80–0xFF range. The ID3v1.1 track-number detection checks byte offsets 28 and 29 of the comment region (absolute offsets 125 and 126 from the tag start), consistent with the de-facto standard introduced by Michael Mutschler in 1997. Null-termination stripping uses a regex to remove all trailing `\0` characters before trimming whitespace, because some encoders pad fields with spaces rather than nulls.