/* 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();
}
}
}