Reading ID3v2 tag from mp3 files

drloosi

Member
Licensed User
Longtime User
hi everybody!

I am experiencing big problems regarding the ID3v2 Tags in mp3 files. I tried Erels example which reads the old format from the last 128 bytes at the end of the file. But this won't help me when I want to display the album cover/art in my app.

So I've read specifications of the newer ID3v2 tag but I must admit that I'm a little overstrained with that. As the documentation describes it, I am reading the first ten bytes of the file which contains the ID3v2 header. The size of the whole ID3v2 tag is encoded with four bytes. But I do not know what to do with this information? How can I calculate how much bytes I have to read from the file to get all the information stored in the ID3v2 tag?

I am sure that there will appear a lot more questions - i am not used to manipulate files on such a level. But so far i would really appreciate if somebody could help me with some hints.

Thanks a lot,
drloosi
 
Last edited:

arthurya

New Member
Licensed User
Longtime User
I had a similar need, and came up with the following code. I pulled from a larger Sub, so I only cut the relevant pieces. Hopefully it is enough to provide someone else the starting point to make it bullet-proof.

I only look for certain tags (stored in the strTags array), so not sure if it will work 100% for every/all tags.

Hope this helps,
Arthur

B4X:
*SNIPPET*

    Dim raf As RandomAccessFile
    raf.Initialize2(Dir, FileName, True, True)
    Dim buffer(128) As Byte

   ' Get first 10 bytes, which holds the header tag, size and version.
   raf.ReadBytes(buffer, 0, 10,0)
   
   strTemp = ConvertBytesToString(buffer,3)
   
   If strTemp.ToUpperCase = "ID3" Then
      'it is a proper MP3
      
      ' Calculate the size of the ID3 tag from the last 4 bytes of data
      Try
         raf.ReadBytes(buffer,0,4,raf.CurrentPosition )
         Do While buffer(0) <> 0
            strTag = ConvertBytesToString(buffer,4)   
            'Make sure it is a Tag I care about
            For i= 1 To intNumTags
               If strTag.ToUpperCase = strTags(i-1).ToUpperCase Then
                  blnIsIrrelevant = False
                  Exit
               End If
            Next
            If blnIsIrrelevant Then Exit
            blnIsIrrelevant = True
            
            If buffer(0) <> 0 Then
               ' Get 4 bytes for frame size
               raf.ReadBytes(buffer, 0, 4, raf.CurrentPosition )
               size = (65536 * (buffer(0) * 256 + buffer(1))) + (buffer(2) * 256 + buffer(3))
         
               ' Skip padding
               raf.ReadBytes(buffer, 0, 3, raf.CurrentPosition )
         
               If size > 0 Then
                  raf.ReadBytes(bigBuffer, 0, (size-1), raf.CurrentPosition)
                  strTemp = ConvertBytesToString(bigBuffer,(size-1))
                  Select strTag.ToUpperCase 
                     Case "TIT2":   strTitle = strTemp
                     Case "TPE1":   strArtist = strTemp
                  End Select
               End If
            End If
            raf.ReadBytes(buffer,0,4,raf.CurrentPosition )
         Loop
         raf.Close 
      Catch
         raf.Close 
      End Try
      strTemp = strTitle & strTagSeparator & strArtist
      Return strTemp
   Else
      Return "FALSE"
   End If

* SNIPPET *


Sub ConvertBytesToString(Buffer() As Byte, MaxLength As Int) As String
    For i = 0 To MaxLength - 1
        If Buffer(i) = 0 Then Return BytesToString(Buffer, 0, i, "UTF8")
    Next
    Return BytesToString(Buffer, 0, MaxLength, "UTF8")
End Sub
 
Upvote 0

ericvanderhoeven

Member
Licensed User
Longtime User
Can you fill out the rest?

I had a similar need, and came up with the following code. I pulled from a larger Sub, so I only cut the relevant pieces. Hopefully it is enough to provide someone else the starting point to make it bullet-proof.

I only look for certain tags (stored in the strTags array), so not sure if it will work 100% for every/all tags.

Hope this helps,
Arthur

B4X:
*SNIPPET*

    Dim raf As RandomAccessFile
    raf.Initialize2(Dir, FileName, True, True)
    Dim buffer(128) As Byte

   ' Get first 10 bytes, which holds the header tag, size and version.
   raf.ReadBytes(buffer, 0, 10,0)
   
   strTemp = ConvertBytesToString(buffer,3)
   
   If strTemp.ToUpperCase = "ID3" Then
      'it is a proper MP3
      
      ' Calculate the size of the ID3 tag from the last 4 bytes of data
      Try
         raf.ReadBytes(buffer,0,4,raf.CurrentPosition )
         Do While buffer(0) <> 0
            strTag = ConvertBytesToString(buffer,4)   
            'Make sure it is a Tag I care about
            For i= 1 To intNumTags
               If strTag.ToUpperCase = strTags(i-1).ToUpperCase Then
                  blnIsIrrelevant = False
                  Exit
               End If
            Next
            If blnIsIrrelevant Then Exit
            blnIsIrrelevant = True
            
            If buffer(0) <> 0 Then
               ' Get 4 bytes for frame size
               raf.ReadBytes(buffer, 0, 4, raf.CurrentPosition )
               size = (65536 * (buffer(0) * 256 + buffer(1))) + (buffer(2) * 256 + buffer(3))
         
               ' Skip padding
               raf.ReadBytes(buffer, 0, 3, raf.CurrentPosition )
         
               If size > 0 Then
                  raf.ReadBytes(bigBuffer, 0, (size-1), raf.CurrentPosition)
                  strTemp = ConvertBytesToString(bigBuffer,(size-1))
                  Select strTag.ToUpperCase 
                     Case "TIT2":   strTitle = strTemp
                     Case "TPE1":   strArtist = strTemp
                  End Select
               End If
            End If
            raf.ReadBytes(buffer,0,4,raf.CurrentPosition )
         Loop
         raf.Close 
      Catch
         raf.Close 
      End Try
      strTemp = strTitle & strTagSeparator & strArtist
      Return strTemp
   Else
      Return "FALSE"
   End If

* SNIPPET *


Sub ConvertBytesToString(Buffer() As Byte, MaxLength As Int) As String
    For i = 0 To MaxLength - 1
        If Buffer(i) = 0 Then Return BytesToString(Buffer, 0, i, "UTF8")
    Next
    Return BytesToString(Buffer, 0, MaxLength, "UTF8")
End Sub

Hi Arthurya, I am looking to do the same thing [get Title and Artist] but I can not seem to duplicate your code :-( as your is missing the declarations of the variables used.. Care to help? Thx
 
Upvote 0
Top