/* Adapted from code found here: * http://www.vbaccelerator.com/home/VB/Code/vbMedia/Audio/Reading_and_Writing_MP3_ID3v1_and_v2_Tags/article.asp * * By Penagate, 26 December 2005. * * Free to use/modify for any purpose, but please link to the original post: * http://www.vbforums.com/showthread.php?t=378193 * rather than distributing this source file itself. */ using System.IO; using System.Text; /// /// Holds ID3v1 tag information. /// Supports ID3 1.0-1.1. /// class ID3v1tag { private struct mp3ID3v1tag { public byte[] tag; public byte[] title; public byte[] artist; public byte[] album; public byte[] year; public byte[] comment; // [version 1.1] public byte filler; public int track; // [/version 1.1] public int genre; public mp3ID3v1tag (bool useThisCtor) { tag = new byte[3]; title = new byte[30]; artist = new byte[30]; album = new byte[30]; year = new byte[4]; comment = new byte[28]; filler = 0; track = 0; genre = 0; } } private string _sMp3File; private bool _bHasID3v1Tag; public string Title, Artist, Album, Year, Comment; public int Genre, Track; public string MP3File { get { return _sMp3File; } set { _sMp3File = value; pLoadTag(); } } public bool HasID3v1Tag { get { return _bHasID3v1Tag; } } /// /// Creates a new ID3v1 tag reader class and reads a tag from the specified file. /// /// public ID3v1tag (string Filename) { MP3File = Filename; } public void Update () { pUpdateTag(); } public string GenreName (byte Genre) { switch (Genre) { case 34: return "Acid"; case 74: return "Acid Jazz"; case 73: return "Acid Punk"; case 99: return "Acoustic"; case 40: return "Alt. Rock"; case 20: return "Alternative"; case 26: return "Ambient"; case 145: return "Anime"; case 90: return "Avant Garde"; case 116: return "Ballad"; case 41: return "Bass"; case 135: return "Beat"; case 85: return "Bebob"; case 96: return "Big Band"; case 138: return "Black Metal"; case 89: return "Blue Grass"; case 0: return "Blues"; case 107: return "Booty Bass"; case 132: return "Brit Pop"; case 65: return "Cabaret"; case 88: return "Celtic"; case 104: return "Chamber Music"; case 102: return "Chanson"; case 97: return "Chorus"; case 136: return "Christian Gangsta Rap"; case 61: return "Christian Rap"; case 141: return "Christian Rock"; case 1: return "Classic Rock"; case 32: return "Classical"; case 112: return "Club"; case 128: return "Club - House"; case 57: return "Comedy"; case 140: return "Contemporary Christian"; case 2: return "Country"; case 139: return "Crossover"; case 58: return "Cult"; case 3: return "Dance"; case 125: return "Dance Hall"; case 50: return "Darkwave"; case 22: return "Death Metal"; case 4: return "Disco"; case 55: return "Dream"; case 127: return "Drum & Bass"; case 122: return "Drum Solo"; case 120: return "Duet"; case 98: return "Easy Listening"; case 52: return "Electronic"; case 48: return "Ethnic"; case 54: return "Eurodance"; case 124: return "Euro - House"; case 25: return "Euro - Techno"; case 84: return "Fast Fusion"; case 80: return "Folk"; case 81: return "Folk / Rock"; case 115: return "Folklore"; case 119: return "Freestyle"; case 5: return "Funk"; case 30: return "Fusion"; case 36: return "Game"; case 59: return "Gangsta Rap"; case 126: return "Goa"; case 38: return "Gospel"; case 49: return "Gothic"; case 91: return "Gothic Rock"; case 6: return "Grunge"; case 79: return "Hard Rock"; case 129: return "Hardcore"; case 137: return "Heavy Metal"; case 7: return "Hip Hop"; case 35: return "House"; case 100: return "Humour"; case 131: return "Indie"; case 19: return "Industrial"; case 33: return "Instrumental"; case 46: return "Instrumental Pop"; case 47: return "Instrumental Rock"; case 8: return "Jazz"; case 29: return "Jazz - Funk"; case 146: return "JPop"; case 63: return "Jungle"; case 86: return "Latin"; case 71: return "Lo - fi"; case 45: return "Meditative"; case 142: return "Merengue"; case 9: return "Metal"; case 77: return "Musical"; case 82: return "National Folk"; case 64: return "Native American"; case 133: return "Negerpunk"; case 10: return "New Age"; case 66: return "New Wave"; case 39: return "Noise"; case 11: return "Oldies"; case 103: return "Opera"; case 12: return "Other"; case 75: return "Polka"; case 134: return "Polsk Punk"; case 13: return "Pop"; case 62: return "Pop/Funk"; case 53: return "Pop/Folk"; case 109: return "Porn Groove"; case 117: return "Power Ballad"; case 23: return "Pranks"; case 108: return "Primus"; case 92: return "Progressive Rock"; case 67: return "Psychedelic"; case 93: return "Psychedelic Rock"; case 43: return "Punk"; case 121: return "Punk Rock"; case 14: return "R&B"; case 15: return "Rap"; case 68: return "Rave"; case 16: return "Reggae"; case 76: return "Retro"; case 87: return "Revival"; case 118: return "Rhythmic Soul"; case 17: return "Rock"; case 78: return "Rock'n'Roll"; case 143: return "Salsa"; case 114: return "Samba"; case 110: return "Satire"; case 69: return "Showtunes"; case 21: return "Ska"; case 111: return "Slow Jam"; case 95: return "Slow Rock"; case 105: return "Sonata"; case 42: return "Soul"; case 37: return "Sound Clip"; case 24: return "Soundtrack"; case 56: return "Southern Rock"; case 44: return "Space"; case 101: return "Speech"; case 83: return "Swing"; case 94: return "Symphonic Rock"; case 106: return "Symphony"; case 147: return "Synth Pop"; case 113: return "Tango"; case 18: return "Techno"; case 51: return "Techno - Industrial"; case 130: return "Terror"; case 144: return "Thrash Metal"; case 60: return "Top 40"; case 70: return "Trailer"; case 31: return "Trance"; case 72: return "Tribal"; case 27: return "Trip Hop"; case 28: return "Vocal"; } return "Unknown"; } private string trimAll (string text) { return text.Contains("\0") ? text.Substring(0, text.IndexOf('\0')) : text.Trim(); } private void pLoadTag () { _bHasID3v1Tag = false; Comment = string.Empty; Artist = string.Empty; Album = string.Empty; Year = string.Empty; Genre = 255; Title = string.Empty; Track = 0; if (File.Exists(_sMp3File)) { FileStream fs = new FileStream(_sMp3File, FileMode.Open); if (fs.Length > 128) { mp3ID3v1tag Tag = new mp3ID3v1tag(true); fs.Seek(-128, SeekOrigin.End); fs.Read(Tag.tag, 0, 3); ASCIIEncoding encoding = new ASCIIEncoding(); if (encoding.GetString(Tag.tag).ToUpper() == "TAG") { _bHasID3v1Tag = true; fs.Read(Tag.title, 0, 30); Title = trimAll(encoding.GetString(Tag.title)); fs.Read(Tag.artist, 0, 30); Artist = trimAll(encoding.GetString(Tag.artist)); fs.Read(Tag.album, 0, 30); Album = trimAll(encoding.GetString(Tag.album)); fs.Read(Tag.year, 0, 4); Year = trimAll(encoding.GetString(Tag.year)); fs.Read(Tag.comment, 0 , 28); Comment = trimAll(encoding.GetString(Tag.comment)); // [version 1.1] fs.ReadByte(); // Ignore the filler byte Tag.track = fs.ReadByte(); // [/version 1.1] Tag.genre = fs.ReadByte(); Genre = Tag.genre; } } fs.Close(); } } private byte[] strToByteArr (Encoding encoding, string text, int maxChars) { if (text.Length > maxChars) text = text.Substring(0, maxChars); else if (text.Length < maxChars) text = text.PadRight(maxChars, '\0'); return encoding.GetBytes(text); } private void pUpdateTag () { if (File.Exists(MP3File)) { FileStream fs = new FileStream(MP3File, FileMode.Open); mp3ID3v1tag tag = new mp3ID3v1tag(true); ASCIIEncoding encoding = new ASCIIEncoding(); if (fs.Length > 128) { fs.Seek(-127, SeekOrigin.End); fs.Read(tag.tag, 0, 3); if (!(tag.tag.ToString().ToUpper() == "TAG")) { /* no MP3 tag already, need to extend the file to add it */ fs.Seek(0, SeekOrigin.End); tag.tag = strToByteArr(encoding, "TAG", 3); fs.Write(tag.tag, 0, 3); } tag.title = strToByteArr(encoding, Title, 30); tag.artist = strToByteArr(encoding, Artist, 30); tag.album = strToByteArr(encoding, Album, 30); tag.year = strToByteArr(encoding, Year, 4); // [version 1.1] tag.track = Track; // [/version 1.1] tag.comment = strToByteArr(encoding, Comment, 28); tag.genre = Genre; fs.Write(tag.title, 0, 30); fs.Write(tag.artist, 0, 30); fs.Write(tag.album, 0, 30); fs.Write(tag.year, 0, 4); fs.Write(tag.comment, 0, 28); // [version 1.1] fs.WriteByte(0); fs.WriteByte((byte) tag.track); // [/version 1.1] fs.WriteByte((byte) tag.genre); } fs.Close(); } } }