Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / DirectX

XML Writer for MP3 Tags, with XSD Validation Using LINQ to XML

4.38/5 (5 votes)
26 Nov 2008CPOL5 min read 30.3K   310  
Creates MP3 tag XML files and validates them

Image 1

Introduction

I have been using Notepad for sometime now, and use it for creating all types of files. I recently wanted to create an XML file for my MP3 collection and found that writing 5 to 8 tags for 350+ MP3s was going to be a task (for me, typing is a task). So, I decided to create a program that did just that, with validation as an added extra.

When I was in college (20 or so years ago), our professor always made us use some sort of pseudo-code to follow while we were creating our programs, which I totally forgot about until I decided to make this program.

Here is the Pseudo... Short Version

  • Design the UI (using the pseudo that follows)
  • Create a filename with the XML extension
  • Validate, then accept the filename if it is good
  • Select the MP3s and add them to a list box
  • Create and write the tags to the file
  • Display to the user what we have done so far (in a list box)
  • Validate the file using XSD (LINQ to XML)
  • After validating, open the file to see our handiwork
  • Finally... reset, and repeat if required

Starting Point

XMLWriter/xml2.jpg

The XML writer starts with all the buttons in the disabled state. You must complete the first task before continuing on to the next task. After creating the filename, validating it, selecting the MP3s, and writing tags, we are now at the validation part. We can now validate the file that we just created.

VB
Private Sub buttonValidate_Click(ByVal sender As System.Object, _
                                 ByVal e As System.EventArgs) _
                                 Handles buttonValidate.Click
    lstActions.Items.Add("Linking (LINQ to XML using XSD)")
    'XSD code was in ms-help
    'I re-edited it to fit the output in the xml file
    Dim xsdMarkup As XElement = _
    <schema xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" />
        <element name=""MP3Info"" />
            <complextype />
                <sequence maxoccurs=""unbounded"" />
                    <element name=""TrackTitle"" type=""xsd:string"" />
                    <element name=""Artist"" type=""xsd:string"" />
                    <element name=""Length"" type=""xsd:string"" />
                    <element name=""Title"" type=""xsd:string"" />
                    <element name=""Genre"" type=""xsd:string"" />
                </sequence />
            </complextype />
        </element />
    </schema />

    Dim schemas As XmlSchemaSet = New XmlSchemaSet()
    schemas.Add("", xsdMarkup.CreateReader)

    lstActions.Items.Add("Attempting to Validate")

    Dim myDoc As XDocument = XDocument.Load(path & Trim(txtFileXML.Text))

    errors = False
    myDoc.Validate(schemas, AddressOf XSDErrors)

    If errors = True Then
        isValid = False
        lstActions.Items.Add("File is InValid")
        lblStatus.Text = "Invalid..."
        buttonOpen.Enabled = True
        Exit Sub
    Else
        isValid = True
        lstActions.Items.Add("File is Valid")
        lblStatus.Text = "Valid..."
    End If
    buttonOpen.Enabled = True
End Sub

XMLWriter/xml3.jpg

I searched for code in MS-Help, and got nothing but old code that did not fare well with .NET v. 3.5. Most of the code was for .NET v. 1.1, which I later discovered due to errors in my code. I also found that errors were unacceptable when using XML. If you have errors, your program will crap out on you. So, you have to write error-free code, which I have finally accomplished through trial and error using all sorts of tidbits that I found in MS-Help.

VB
Private Sub loadFiles(ByVal mediaType As String)
    Dim supportedFiles As String

    Select Case mediaType
        Case "Audio"
            supportedFiles = audioFiles
        Case Else
            supportedFiles = audioFiles
    End Select

    lstActions.Items.Add("Please wait...Creating File")

    With ofd 'OpenFileDialog Control
        .InitialDirectory = strPath
        .Filter = supportedFiles
        .CheckFileExists = True
        .Multiselect = True
        .RestoreDirectory = True
    End With

    If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then

        Using sw As StreamWriter = File.CreateText(path & Trim(txtFileXML.Text))
            sw.WriteLine("")
            sw.WriteLine("<mp3info />") 'Opening Tag for MP3Info

            For Each Me.strFilePath In ofd.FileNames
                strFileShow = GetFileName(strFilePath)
                lstMP3.Items.Add(strFilePath)
                MMedia.LoadMedia(strFilePath)
                Dim fileInfo As New clsID3v1Reader(strFilePath)
                'sw.WriteLine("<mp3info />") 'Opening Tag for MP3Info
                sw.WriteLine("    <tracktitle />" & fileInfo.TrackTitle & _
                             "</tracktitle />")
                sw.WriteLine("    <artist />" & fileInfo.Artist & "</artist />")

                'Lets get the time length of the mp3 file.
                Dim secx, minx, mediaTotal As String
                Dim mediaTimes As String
                mediaTotal = CStr(Int(MMedia.MediaDuration))
                'If mediaTotal < 1 Then mediaTotal = 1
                secx = CStr(CDbl(mediaTotal) - (Int(CDbl(mediaTotal) / 60) * 60))
                minx = CStr(Int((CDbl(mediaTotal) - 
                            Int(CDbl(mediaTotal) / 3600) * 3600) / 60))
                mediaTimes = minx.ToString() & ":" & secx.ToString

                sw.WriteLine("    <length />" & mediaTimes & "</length />")
                MMedia.UnLoadMedia(strFilePath)
                sw.WriteLine("    ")
                sw.WriteLine("    <genre />" & GetGenre(currentMP3) & "</genre />")
                'sw.WriteLine("</mp3info />") 'Closing Tag for MP3Info
                sw.WriteLine()
            Next

            sw.WriteLine("</mp3info />") 'Closing Tag for MP3Info

            'Lets close the writer.
            sw.Close()

        End Using
    End If

    'Display again what we are doing for the user...
    lstActions.Items.Add("File created - " & Trim(txtFileXML.Text))
    lstActions.Items.Add("# of files selected..." & (lstMP3.Items.Count).ToString)
    lblStatus.Text = (lstMP3.Items.Count).ToString & " files selected"

    'Make unenabled, Enabled.
    buttonValidate.Enabled = True
End Sub

Next... we can open the new file that we just created to see the results of our handiwork. I used the Process class to open Notepad and display our file.

XMLWriter/xml4.jpg

XMLWriter/xml5.jpg

VB
Private Sub buttonOpen_Click(ByVal sender As System.Object, _
                             ByVal e As System.EventArgs) Handles buttonOpen.Click
    ProcessNotepad.StartInfo.FileName = path & Trim(txtFileXML.Text)
    ProcessNotepad.Start()
    ProcessNotepad.WaitForExit()
    buttonReset.Enabled = True
End Sub

Using the Code

The XML writer creates mp3tag.xml files that can be used in WPF or Blend as a data source or as a play list, or whatever else XML files are used for. I believe it to be a good utility, but that's just me wishing.

The classes that I used in this program are re-edited classes that were found on this site and MS-Help. clsDirectXAudio.vb is from MMPlayer which can be found on this site, and clsID3TagReader.vb I believe was in 'Managing a MP3 Collection" which was on MS-Help as an MS-Word doc file. One last thing, the program cannot be run inside the IDE, it throws a Managed Code Exception. Make a .exe file and run it outside the IDE, it works fine.

Points of Interest

When I first started this program, I knew nothing about LINQ, XSD, or XML, now I know more than what I started with (which was a thimble full of nothing).

Please do not download this until I fix some bugs. I totally forgot about the apostrophies, ampersand, and the less-than and greater-than signs. I do not know how to read a character in a string, and if I do find out, I do not know how to replace them using code, preferably VB.NET. Thank you for your patience on this matter. If someone could point me in the right direction on how to do this, I would greatly appreciate it!

XMLWriter/xml-start.jpg

Update

In the original, XMLWriter, there were design flaws that created some nasty exceptions. It would throw an exception when it came across an ampersand or an apostrophy. I fixed it with a few replace statements in the correct spots. I also re-did the psuedo which is in the program disguised as labels. See the picture below.

XMLWriter/xml-accept.jpg

Using the Code

After the program starts (intro picture), you will enter a filename with an XML extension and press the accept button (pictured above). Next...

XMLWriter/xml-Created.jpg

Enter any or all your mp3 files, the program will then create your XML file and display it to you in the listbox. Picture above. Next...

XMLWriter/xml-validate.jpg

We validate our newly created XML file. With the use of a few replace statements in the right area, this took care of the exceptions that would occur when you picked an mp3 file with ampersands or apostrophies in the tracktitle, title or artist (example: Brooks & Dunn - She's not the cheatin' Kind). This would make the program crap out on you. This has been fixed. Picture above. Next... just hit the reset button and you are ready to do it all over again. Doing this multiple times would be useful as playlists in WPF® or Blend®. Picture below.

XMLWriter/xml-reset.jpg

Apologies All Around

If you downloaded the original XMLWriter, please delete it and use this updated version. It works so much better and the results are better also. I apologize for any inconvienience that this little mental mistake of mine may have cost you. Once again...apologies all around.

To the Authors…

To all the authors of code that I used (all names are in comments throughout the program), I thank you all very much. Special thanks go to MS-Help for having such a vast library of knowledge.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)