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.

Code:
            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.

Code:
            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

Code:
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