TGC Codebase Backup



MP3 ID3v1 and ID3v2 Tag Reader Functions by TheOneRing

2nd 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$