PDA

View Full Version : VB.Net Class for reading ID3 And List INFO from WAV Files



simonf
09-05-2008, 05:06 PM
Hi all,

I am new to this forum So hello everyone,

I have a customer who is using dbpoweramp a lot to rip cds into there music library. He wanted me to write a program to take the data out of thw wave files he produced and update his database with the data. I initialy used a the following code to read the tags.



Dim db As New DMCSCRIPTINGLib.Converter
For i = 0 To 1000
Dim Element As String, Value As String
Element = ""
Value = ""
db.ReadIDTag(Filename, i, Element, Value)
If Element = "" Then Exit For
Results(i) = Element & "|" & Value
Next



But I found this method very slow It took over 1 minuite to read the tags for 10 albums.

So I decided to write my own managed class to do the same thing (It only works with LIST INFO Items and ID3 Text tags IE T???) But It Is extreamly Quick. I can now read 40000 Tracks a Minute.

This also has the the advantage of not needing dbpoweramp to be installed on the client machine and also you dont need to worry about which version of dbpoweramp is loaded.

I thought It may be usefull for some of you, It dosnt write tags but I could modify it to do that if needed.

This code reads the data from my class as per the example above.



Dim RiffRdr As New RIFFReader(Filename)
i = 0
If Not IsNothing(RiffRdr.ID3Items) Then
For Each item In RiffRdr.ID3Items
Results(i) = item.FriendlyName & "|" & item.Data
i += 1
Next
End If

If Not IsNothing(RiffRdr.InfoItems) Then
For Each item In RiffRdr.InfoItems
Results(i) = item.FriendlyName & "|" & item.Data
i += 1
Next
End If
RiffRdr.Dispose()




Here is the class



Public Class RIFFReader

Dim RIFFfile As System.IO.FileStream
Dim RIFFLength As Long
Dim RIFFType As String

Structure RiffFrame

Dim Name As String
Dim StartOfData As Long
Dim Length As Long

End Structure

Structure InfoItem

Dim TAGNAME As String
Dim FriendlyName As String
Dim Data As String

End Structure

Structure ID3Item

Dim TAGNAME As String
Dim FriendlyName As String
Dim Data As String

End Structure


'4.2.1 TALB [*TALB Album/Movie/Show title]
'4.2.1 TBPM [*TBPM BPM (beats per minute)]
'4.2.1 TCOM [*TCOM Composer]
'4.2.1 TCON [*TCON Content type]
'4.2.1 TCOP [*TCOP Copyright message]
'4.2.1 TDAT [*TDAT Date]
'4.2.1 TDLY [*TDLY Playlist delay]
'4.2.1 TENC [*TENC Encoded by]
'4.2.1 TEXT [*TEXT Lyricist/Text writer]
'4.2.1 TFLT [*TFLT File type]
'4.2.1 TIME [*TIME Time]
'4.2.1 TIT1 [*TIT1 Content group description]
'4.2.1 TIT2 [*TIT2 Title/songname/content description]
'4.2.1 TIT3 [*TIT3 Subtitle/Description refinement]
'4.2.1 TKEY [*TKEY Initial key]
'4.2.1 TLAN [*TLAN Language(s)]
'4.2.1 TLEN [*TLEN Length]
'4.2.1 TMED [*TMED Media type]
'4.2.1 TOAL [*TOAL Original album/movie/show title]
'4.2.1 TOFN [*TOFN Original filename]
'4.2.1 TOLY [*TOLY Original lyricist(s)/text writer(s)]
'4.2.1 TOPE [*TOPE Original artist(s)/performer(s)]
'4.2.1 TORY [*TORY Original release year]
'4.2.1 TOWN [*TOWN File owner/licensee]
'4.2.1 TPE1 [*TPE1 Lead performer(s)/Soloist(s)]
'4.2.1 TPE2 [*TPE2 Band/orchestra/accompaniment]
'4.2.1 TPE3 [*TPE3 Conductor/performer refinement]
'4.2.1 TPE4 [*TPE4 Interpreted, remixed, or otherwise modified by]
'4.2.1 TPOS [*TPOS Part of a set]
'4.2.1 TPUB [*TPUB Publisher]
'4.2.1 TRCK [*TRCK Track number/Position in set]
'4.2.1 TRDA [*TRDA Recording dates]
'4.2.1 TRSN [*TRSN Internet radio station name]
'4.2.1 TRSO [*TRSO Internet radio station owner]
'4.2.1 TSIZ [*TSIZ Size]
'4.2.1 TSRC [*TSRC ISRC (international standard recording code)]
'4.2.1 TSSE [*TSEE Software/Hardware and settings used for encoding]
'4.2.1 TYER [*TYER Year]

Dim ID3TagName() As String = {"TALB", "TBPM", "TCMP", "TCOM", "TCON", "TCOP", "TDAT", "TDLY", "TENC", "TEXT", "TFLT", "TIME", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", "TOAL", "TOFN", "TOLY", "TOPE", "TORY", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TRCK", "TRDA", "TRSN", "TRSO", "TSIZ", "TSRC", "TSSE", "TYER"}
Dim ID3TagFriendlyName() As String = {"Album", "BPM", "Compilation", "Composer", "Genre", "Copyright message", "Date", "Playlist delay", "Encoded by", "Lyricist", "File type", "Time", "Style", "Title", "Subtitle/Description", "Initial key", "Language", "Length", "Media type", "Original album", "Original filename", "Original lyricist", "Original artist", "Original release year", "File owner/licensee", "Artist", "Album Artist", "Conductor", "Remixed", "Part of a set", "Label", "Track", "Recording dates", "Internet radio station name", "Internet radio station owner", "Size", "ISRC", "Software/Hardware and settings used for encoding", "Year"}


Dim INFOTagName() As String = {"IART", "ICMT", "ICOP", "ICRD", "IGNR", "INAM", "ISRC", "IPRD", "TORG", "LOCA", "TVER", "TURL", "TLEN", "ITCH", "TRCK", "itrk", "ISRF", "ITRK"}
Dim INFOTagFriendlyName() As String = {"Artist", "Comment", "Copyright", "Year", "Genre", "Title", "ISRC", "Album", "Label", "Location", "Version", "URL", "Length", "Technician", "Track", "Track", "Source", "Track"}

Public RiffFrames() As RiffFrame = Nothing
Public InfoItems() As InfoItem = Nothing
Public ID3Items() As ID3Item = Nothing


Sub New(ByVal Filename As String)

If My.Computer.FileSystem.FileExists(Filename) Then

RIFFfile = IO.File.Open(Filename, IO.FileMode.Open, IO.FileAccess.ReadWrite)

RIFFfile.Seek(0, IO.SeekOrigin.Begin)

If ReadFourCC() = "RIFF" Then

'Looks like its a riff

Else

Throw New Exception("Not A Riff")

End If

RIFFLength = RIFFfile.ReadByte() + _
RIFFfile.ReadByte() * 2 ^ 8 + _
RIFFfile.ReadByte() * 2 ^ 16 + _
RIFFfile.ReadByte() * 2 ^ 24

Else

Throw New Exception("File Not Found")

End If

RIFFType = ReadFourCC()

While RIFFfile.Position < RIFFfile.Length
' make space for the frame data
If IsNothing(RiffFrames) Then
ReDim RiffFrames(0)
Else
ReDim Preserve RiffFrames(RiffFrames.Length)

End If
RiffFrames(RiffFrames.Length - 1).Name = ReadFourCC()
RiffFrames(RiffFrames.Length - 1).Length = ReadDWord()
RiffFrames(RiffFrames.Length - 1).StartOfData = RIFFfile.Position
'seek the begining of the next frame
'MsgBox(RIFFfile.Position)
RIFFfile.Seek(RiffFrames(RiffFrames.Length - 1).Length, IO.SeekOrigin.Current)

'MsgBox(RIFFfile.Position)
End While

For Each item In RiffFrames
' Process "LIST" Section
If item.Name = "LIST" Then
'We Have A List Tag
RIFFfile.Seek(item.StartOfData, IO.SeekOrigin.Begin)
If ReadFourCC() = "INFO" Then
'We Have An Info Tag
While RIFFfile.Position < (item.StartOfData + item.Length)
' make space for the frame data
If IsNothing(InfoItems) Then
ReDim InfoItems(0)
Else
ReDim Preserve InfoItems(InfoItems.Length)
End If
InfoItems(InfoItems.Length - 1).TAGNAME = ReadFourCC()
InfoItems(InfoItems.Length - 1).Data = ReadString(ReadDWord)
'Set The frendly name to tag name just in case its not found
InfoItems(InfoItems.Length - 1).FriendlyName = _
InfoItems(InfoItems.Length - 1).TAGNAME

For i As Integer = 0 To INFOTagName.Length - 1

If INFOTagName(i) = InfoItems(InfoItems.Length - 1).TAGNAME Then

InfoItems(InfoItems.Length - 1).FriendlyName = INFOTagFriendlyName(i)
Exit For
End If


Next
End While
End If
End If

If item.Name = "id3 " Then
'We Have A List Tag
RIFFfile.Seek(item.StartOfData, IO.SeekOrigin.Begin)
If ReadFourCC() = "ID3" + Chr(3) Then
'We Have An ID3 Tag
RIFFfile.Seek(6, IO.SeekOrigin.Current)
While RIFFfile.Position < (item.StartOfData + item.Length)
' make space for the frame data
Dim Tag As String = ReadFourCC() 'The Tag
Dim Length As Long = ReadDWordRevProtected() 'The Length
RIFFfile.ReadByte() ' Read Flags
RIFFfile.ReadByte() ' Read Flags
If Tag(0) = "T" Then
'Its a TextTag
If IsNothing(ID3Items) Then
ReDim ID3Items(0)
Else
ReDim Preserve ID3Items(ID3Items.Length)
End If

ID3Items(ID3Items.Length - 1).TAGNAME = Tag
Dim InnerTag As String = ReadStringTag(Length)

If Tag = "TXXX" Then

ID3Items(ID3Items.Length - 1).FriendlyName = _
InnerTag.Substring(0, InnerTag.IndexOf(Chr(0)))
ID3Items(ID3Items.Length - 1).Data = _
InnerTag.Substring(InnerTag.IndexOf(Chr(0)) + 1)

Else

ID3Items(ID3Items.Length - 1).Data = InnerTag
ID3Items(ID3Items.Length - 1).FriendlyName = _
ID3Items(ID3Items.Length - 1).TAGNAME
For i As Integer = 0 To ID3TagName.Length - 1

If ID3TagName(i) = ID3Items(ID3Items.Length - 1).TAGNAME Then

ID3Items(ID3Items.Length - 1).FriendlyName = ID3TagFriendlyName(i)
Exit For
End If


Next

End If


Else

'Its Not A Text Tag
If Tag = Chr(0) + Chr(0) + Chr(0) + Chr(0) Then Exit While

'Skip The Tag
RIFFfile.Seek(Length, IO.SeekOrigin.Current)

End If

End While
End If
End If
Next

End Sub

Sub Dispose()

RIFFfile.Close()
RIFFfile.Dispose()
ID3TagName = Nothing
ID3TagFriendlyName = Nothing

INFOTagName = Nothing
INFOTagFriendlyName = Nothing
RiffFrames = Nothing
InfoItems = Nothing
ID3Items = Nothing


End Sub

Function ReadStringTag(ByVal I As Long) As String

Dim Tmp As Byte = RIFFfile.ReadByte
Dim Result As String = ""
Dim Unicode As Boolean
Dim LowByteLast As Byte
I = I - 1

If Tmp = 0 Then
' its an ordinary tag
Unicode = False
Else
'its a Unicode String

Tmp = RIFFfile.ReadByte
Tmp = RIFFfile.ReadByte

Unicode = True
If Tmp = 254 Then
LowByteLast = True
Else
LowByteLast = False
End If
I = I - 2

End If


While I > 0
Tmp = RIFFfile.ReadByte
I -= 1
If Unicode Then
Dim SecondByte As Byte = RIFFfile.ReadByte
I -= 1

If LowByteLast Then

Result += ChrW(Tmp * 256 + SecondByte)

Else

Result += ChrW(Tmp + SecondByte * 256)

End If

Else
Result += Chr(Tmp)

End If


End While
Return Result

End Function

Function ReadString(ByVal I As Long) As String

Dim Tmp As Byte
Dim Result As String = ""
While I > 0
Tmp = RIFFfile.ReadByte
Result += IIf(Tmp = 0, "", Chr(Tmp))
I -= 1
End While
Return Result

End Function

Function ReadFourCC() As String

'read four bytes into a string
Dim Result As String = ""

Result = Chr(RIFFfile.ReadByte()) & Chr(RIFFfile.ReadByte()) & Chr(RIFFfile.ReadByte()) & Chr(RIFFfile.ReadByte())

Return Result

End Function

Function ReadDWord() As Long

'read four bytes into a string
Return RIFFfile.ReadByte() + _
RIFFfile.ReadByte() * 2 ^ 8 + _
RIFFfile.ReadByte() * 2 ^ 16 + _
RIFFfile.ReadByte() * 2 ^ 24



End Function

Function ReadDWordRevProtected() As Long

'read four bytes into a string
Return RIFFfile.ReadByte() * 2 ^ 21 + _
RIFFfile.ReadByte() * 2 ^ 14 + _
RIFFfile.ReadByte() * 2 ^ 7 + _
RIFFfile.ReadByte()



End Function


End Class