MP3 ID3v1 and ID3v2 Tag Reader Functions by TheOneRing2nd Sep 2003 11:54
|
---|
Summary An include file with functions to read MP3 ID3v1 and ID3v2 tags. This is useful for things like media players, etc... Description Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com `-------------------------------------------------------------------- ` FILE NAME: ID3TAGS.DBA ` CREATED BY: ADAM PRESLEY adam@it-storm.com ` CREATED DATE: 08.28.2003 ` ` DESCRIPTION: Functions for reading ID3v1, ID3v1.1, and ID3v2 ` tags in MP3 music files. ` ` All code is copyright (c) 2003 Mighty Atom Software. ` You may use this code in any project, free or commercial. If its ` commercial the only thing I would like is a copy of the program. :) `-------------------------------------------------------------------- `-------------------------------------------------------------------- ` SECTION: ID3v1 Functions `-------------------------------------------------------------------- `---------------------------------------------------------------- ` This function will read the ID3v1 tag into a memblock. It ` returns 0 (false) or 1 (true) for failure and success, ` respectivly.NOTE: The memblock must not exist, and the ` filenumber used for file manipulation is 32. `---------------------------------------------------------------- function Read_ID3v1_Into_Memblock(Filename$, MemblockNumber) Success = 0 Signature$ = "" `----------------------------------------- ` Get the file size and starting position. `----------------------------------------- FileSize = file size(Filename$) StartPos = FileSize - 128 `------------------------------------------- ` Read the last 128 bytes into our memblock. `------------------------------------------- make memblock MemblockNumber, 129 open to read 32, Filename$ skip bytes 32, StartPos for index = 1 to 128 read byte 32, value write memblock byte MemblockNumber, index, value next index close file 32 `---------------------- ` Is this an ID3v1 tag? `---------------------- for index = 1 to 3 value = memblock byte(MemblockNumber, index) Signature$ = Signature$ + chr$(value) next index if Signature$ = "TAG" Success = 1 else Success = 0 delete memblock MemblockNumber endif endfunction Success function Get_ID3v1_Title(MemblockNumber) Value$ = "" StartPos = 3 for index = 1 to 30 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index endfunction Value$ function Get_ID3v1_Artist(MemblockNumber) Value$ = "" StartPos = 33 for index = 1 to 30 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index endfunction Value$ function Get_ID3v1_Album(MemblockNumber) Value$ = "" StartPos = 63 for index = 1 to 30 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index endfunction Value$ function Get_ID3v1_Year(MemblockNumber) Value$ = "" StartPos = 93 for index = 1 to 4 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index endfunction Value$ function Get_ID3v1_Comment(MemblockNumber) Value$ = "" StartPos = 97 for index = 1 to 28 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index value = memblock byte(MemblockNumber, 29 + StartPos) if value <> 0 Value$ = Value$ + chr$(value) value = memblock byte(MemblockNumber, 30 + StartPos) Value$ = Value$ + chr$(value) endif endfunction Value$ function Get_ID3v1_Genre(MemblockNumber) Value$ = "" StartPos = 127 for index = 1 to 1 value = memblock byte(MemblockNumber, index + StartPos) Value$ = Value$ + chr$(value) next index endfunction Value$ function Get_ID3v1_Track(MemblockNumber) Value$ = "" StartPos = 126 value = memblock byte(MemblockNumber, StartPos) if value = 0 value = memblock byte(MemblockNumber, StartPos + 1) Value$ = Value$ + str$(value) endif endfunction Value$ `-------------------------------------------------------------------- ` SECTION: ID3v2 Functions `-------------------------------------------------------------------- `---------------------------------------------------------------- ` This function will read the ID3v2 frames into a memblock. It ` returns the subversion of the ID3v2 tag. Valid values are 2, 3, ` and 4. If 0 is returned, there was an error. NOTE: The ` memblock must not exist, and the filenumber used for file ` manipulation is 32. `---------------------------------------------------------------- function Read_ID3v2_Into_Memblock(Filename$, MemblockNumber) SubVersion$ = "0" Signature$ = "" TagSize = 0 `---------------- ` Load this file. `---------------- if file exist(Filename$) = 0 then exitfunction $SubVersion$ open to read 32, Filename$ `------------------------------------------------------------ ` Determine if there is an ID3v2 tag here. NOTE: ID3v2 tags ` are usually at the beginning of the MP3. They can, however, ` be technically anywhere in the file. This routine only ` supports ID3v2 tags at the beginning of the MP3. `------------------------------------------------------------- for index = 1 to 3 read byte 32, value Signature$ = Signature$ + chr$(value) next index if Signature$ <> "ID3" then exitfunction $SubVersion$ `---------------------------------------------------------------- ` Get the ID3v2 tag subversion number. Only tested with version 3 `---------------------------------------------------------------- read byte 32, value if value >= 3 SubVersion$ = str$(value) `-------------------------------- ` Read past the 2 reserved bytes. `-------------------------------- skip bytes 32, 2 `------------------------------------------------------------------------------------------- ` Now get the size of the ID3v2 tag. This is tricky becuase its stored in big-endian format. ` Got to re-order the bytes. `------------------------------------------------------------------------------------------- read long 32, value TagSize = LittleEndianToBigEndian(value) `----------------------- ` Allocate the memblock. `----------------------- make memblock MemblockNumber, TagSize + 1 `------------------------------------ ` Now read the tag into the memblock. `------------------------------------ for index = 1 to TagSize read byte 32, value write memblock byte MemblockNumber, index, value next index endif close file 32 endfunction SubVersion$ function Get_ID3v2_Title(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TIT2") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Track_Number(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TRCK") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Play_Counter(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "PCNT") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Encoded_By(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TENC") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Copyright(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TCOP") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Original_Artist(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TOPE") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Composer(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TCOM") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Genre(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TCON") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Comment(MemblockNumber) `------------------------------------------------------------- ` Comments are wierd. Most MP3s I've tested on have the values ` e, n, g, null before the actual comment. Lets remove it if ` its there. `------------------------------------------------------------- Value$ = "" StartPos = FindFrame(MemblockNumber, "COMM") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) if lower$(left$(Value$, 3)) = "eng" then Value$ = right$(Value$, len(Value$) - 3) endif endfunction Value$ function Get_ID3v2_Year(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TYER") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Artist(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TPE1") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Album(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "TALB") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ function Get_ID3v2_Lyrics(MemblockNumber) `------------------------------------------------------------- ` Lyrics are wierd. Most MP3s I've tested on have the values ` e, n, g, null before the actual comment. Lets remove it if ` its there. `------------------------------------------------------------- Value$ = "" StartPos = FindFrame(MemblockNumber, "USLT") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) if lower$(left$(Value$, 3)) = "eng" then Value$ = right$(Value$, len(Value$) - 3) endif endfunction Value$ function Get_ID3v2_Artist_URL(MemblockNumber) Value$ = "" StartPos = FindFrame(MemblockNumber, "WOAR") if StartPos <> 0 FrameSize = GetFrameSize(MemblockNumber, StartPos) Value$ = GetFrameData(MemblockNumber, StartPos, FrameSize) endif endfunction Value$ `------------------------------------------------------------ ` This function takes a little-endian (Intel) style value and ` turns it into a big-endian (Motorola) style value. This ` is needed because the byte-order for the size values in an ` MP3 are big-endian. `------------------------------------------------------------ function LittleEndianToBigEndian(Value) `--------------------------------------------------------------------------- ` For all you C programmers out there here are those decimal numbers in hex: ` ` 2130706432 = 0x7F000000 ` 16777216 = 0x1000000 ` 2147483648 = 0x80000000 ` 128 = 0x80 ` 16711680 = 0xFF0000 ` 65536 = 0x10000 ` 256 = 0x100 ` 65280 = 0xFF00 `--------------------------------------------------------------------------- NewValue = 0 NewValue = ((Value && 2130706432) / 16777216) if (Value && 2147483648) = 2147483648 then NewValue = (NewValue || 128) NewValue = (NewValue || ((Value && 16711680) / 65536) * 256) NewValue = (NewValue || ((Value && 65280) / 256) * 65536) NewValue = (NewValue || (Value && 127) * 16777216) if (Value && 128) = 128 then NewValue = (NewValue || 2147483648) endfunction NewValue `------------------------------------------------------------- ` This function will find and return the starting position in ` the memblock where a particular frame begins (if it exists.) `------------------------------------------------------------- function FindFrame(MemblockNumber, FrameName$) StartPos = 0 TagSize = get memblock size(MemblockNumber) Temp$ = "" for index = 1 to TagSize - 5 Temp$ = "" for inner = 0 to 3 value = memblock byte(MemblockNumber, index + inner) Temp$ = Temp$ + chr$(value) next inner if Temp$ = FrameName$ then StartPos = index next index endfunction StartPos `------------------------------------------------------- ` This function will get the size of a particular frame. `------------------------------------------------------- function GetFrameSize(MemblockNumber, FramePos) Size = memblock dword(MemblockNumber, FramePos + 4) Size = LittleEndianToBigEndian(Size) endfunction Size `----------------------------------------------------- ` This function will grab the data of a frame. Need to ` know the starting position and size of the frame. `----------------------------------------------------- function GetFrameData(MemblockNumber, FramePos, FrameSize) Result$ = "" flagBeginCopy = 0 `--------------------------------------------------------------- ` A frame consists of a 4-digit name, size of the frame (dword), ` 3 or more padding 0 bytes, then the data. `--------------------------------------------------------------- StartPos = FramePos + 11 `---------------------------- ` Check for any more zeros... `---------------------------- for index = StartPos to (FrameSize + StartPos) - 2 if flagBeginCopy = 0 value = memblock byte(MemblockNumber, index) if value <> 0 Result$ = Result$ + chr$(value) flagBeginCopy = 1 endif else value = memblock byte(MemblockNumber, index) Result$ = Result$ + chr$(value) endif next index endfunction Result$ |