What's New
Q & A
Tip Jar
C# Helper...
Follow VBHelper on Twitter
MSDN Visual Basic Community
TitleSelect random files from a set of directories to build a MP3 player mix in VB.NET
DescriptionThis example shows how to select random files from a set of directories to build a MP3 player mix in VB.NET.
Keywordsmp3, mix, random, random files, browse, SaveSetting, GetSetting, DeleteSetting
CategoriesFiles and Directories, Software Engineering, Multimedia, VB.NET
My MP3 player only has 164 MB of memory so it cannot hold all of my music at once. This application randomly picks files from a set of directories and copies them into a new mix directory. My MP3 player looks like a directory in the file system so I can copy files directly onto it until it is full.

This application demonstrates several useful techniques including:

  • Loading and saving settings when the application starts and stops.
  • Tracking multiple selected directories.
  • Managing ListBox choices.
  • Quickly listing the files in a directory with API functions.
  • Converting long file names to short file names.
  • Letting the user browse to select a directory.
  • Randomizing an array.
  • Generating a list of random files picked from the selected directories.
  • Copying files.

When the program starts, it calls its LoadSettings routine. That routine uses GetSetting to loads saved settings. It loads source directory names and their selected state by looping through the setting values Source0, Source1, ... and Selected0, Selected1, ...

Private Sub LoadSettings()
    txtDestination.Text = GetSetting(APP_NAME, _
        "Settings", "DestinationDirectory", CurDir)
    txtNumFiles.Text = GetSetting(APP_NAME, _
        "Settings", "NumFiles", "1")

    Dim txt As String
    Dim new_index As Integer
    Dim is_selected As Boolean
    For i As Integer = 0 To 100
        txt = GetSetting(APP_NAME, "Settings", "Source" & _
            Format$(i), "")
        If Len(txt) < 1 Then Exit For
        new_index = lstSources.Items.Add(txt)
        is_selected = CBool(GetSetting(APP_NAME, _
            "Settings", "Selected" & Format$(i), "False"))
        lstSources.SetSelected(new_index, is_selected)
    Next i
End Sub
When the form is closing, it calls the SaveSettings routine. This routine uses DeleteSetting to remove any previously saved settings. This clears out the source data and is necessary if the new source list is smaller than the previous one.

Next the program uses SaveSetting to save the current settings.

Private Sub SaveSettings()
    On Error Resume Next
    On Error GoTo 0
    SaveSetting(APP_NAME, "Settings", _
        "DestinationDirectory", txtDestination.Text)
    SaveSetting(APP_NAME, "Settings", "NumFiles", _

    For i As Integer = 0 To lstSources.Items.Count - 1
        SaveSetting(APP_NAME, "Settings", "Source" & _
            Format$(i), lstSources.Items(i).ToString)
        SaveSetting(APP_NAME, "Settings", "Selected" & _
            Format$(i), lstSources.GetSelected(i).ToString)
    Next i
End Sub
When the user clicks the Add button, the program displays a dialog that lets the user select a new source directory. The dlgPickFolder form lets the user enter or select the directory. The main program calls subroutine CenterFormOnForm to center the dialog over the main program's form and then displays the dialog.

The main form checks the dialog's txtDir text box to see if the user made a selection. If txtDir is not blank, then the program uses ChDir to try to move to that directory. If it succeeds, the program adds the directory to the source list.

Private Sub btnAdd_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnAdd.Click
    Dim dlg As New dlgPickFolder
    dlg.txtDir.Text = CurDir()
    CenterFormOnForm(dlg, Me)

    If Len(dlg.txtDir.Text) > 0 Then
        On Error Resume Next
        If Err.Number <> 0 Then
            MessageBox.Show("Error moving to directory '" & _
                dlg.txtDir.Text & "'", _
                "Directory Error", _
                MessageBoxButtons.OK, _
        End If
        On Error GoTo 0
    End If
End Sub
Subroutine CenterFormOnForm centers a form above another form. It calculates the position the form needs and then adjusts it if necessary to make the form fit on the screen.
Public Sub CenterFormOnForm(ByVal frm_above As Form, ByVal _
    frm_below As Form)
    Dim working_area As Rectangle = _
        Screen.GetWorkingArea(New Point(0, 0))

    Dim x As Integer
    x = (frm_below.Left + frm_below.Right - _
        frm_above.Width) \ 2
    If x < 0 Then x = 0
    If x + frm_above.Width > working_area.Right Then
        x = working_area.Right - frm_above.Width
    End If

    Dim y As Integer
    y = (frm_below.Top + frm_below.Bottom - _
        frm_above.Height) \ 2
    If y < 0 Then y = 0
    If y + frm_above.Height > working_area.Bottom Then
        y = working_area.Bottom - frm_above.Height
    End If

    frm_above.SetBounds(x, y, frm_above.Width, _
End Sub
When the user clicks the Remove button, the program confirms that the user wants to remove the selected source directories from the list and then removes them.
Private Sub btnRemove_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnRemove.Click
    If lstSources.Items.Count < 1 Then
        MessageBox.Show("No sources selected to delete", _
            "No Sources Selected", MessageBoxButtons.OK, _
    ElseIf MessageBox.Show("Delete selected sources?", _
        "Delete Sources?", MessageBoxButtons.YesNo, _
        MessageBoxIcon.Question) = vbYes Then
        For Each source As Object In _
        Next source
    End If
End Sub
When the user clicks the Browse button, the program uses its FolderBrowserDialog control to let the user select a destination directory. (This is a lot easier than it is in Visual Basic 6.)
Private Sub btnBrowse_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnBrowse.Click
    dlgFolder.SelectedPath = CurDir()
    If dlgFolder.ShowDialog(Me) = DialogResult.OK Then
        txtDestination.Text = dlgFolder.SelectedPath
    End If
End Sub
When the user clicks the Load Files button, the program make a collection to hold the names of the files in the selected source directories. For each currently selected source, the program calls subroutine ListFiles to get the file and directory names.

It then makes an array containing the indexes of the files and uss subroutine RandomizeArray to randomize the indexes. Next it uses the indexes to access the files in random order and copies them to the destination directory.

Private Sub btnLoadFiles_Click(ByVal sender As _
    System.Object, ByVal e As System.EventArgs) Handles _
    Dim file_names As Collection
    Dim num_files As Integer
    Dim indexes() As Integer
    Dim dest_dir As String
    Dim files_to_copy As Integer

    ' Make a list of all of the files.
    file_names = New Collection
    For Each source As String In lstSources.SelectedItems
        ListFiles(source, file_names)
    Next source

    ' See how many files we found.
    num_files = file_names.Count
    If num_files < 1 Then
        MessageBox.Show("No files found", "No Files", _
            MessageBoxButtons.OK, _
        Exit Sub
    End If

    ' Make the indexes array.
    ReDim indexes(num_files - 1)
    For i As Integer = 0 To num_files - 1
        indexes(i) = i + 1
    Next i

    ' Randomize the indexes array.

    ' Grab the first files.
    files_to_copy = CInt(txtNumFiles.Text)
    If files_to_copy > num_files Then files_to_copy = _

    ' Start copying files.
    Me.Cursor = Cursors.WaitCursor

    dest_dir = txtDestination.Text
    Dim file_name, file_title As String
    Dim files_copied As Integer = 0
    On Error Resume Next
    For i As Integer = 0 To files_to_copy - 1
        Me.Text = APP_NAME & " (" & i + 1 & ")"

        file_name = DirectCast(file_names(indexes(i)), _
        file_title = _

        FileCopy(file_name, dest_dir & file_title)
        If Err.Number <> 0 Then
            MessageBox.Show("Error copying file '" & _
                file_name & "' to '" & _
                dest_dir & file_title & "'" & vbCrLf & _
                Err.Description, _
                "Copy Error", _
                MessageBoxButtons.OK, MessageBoxIcon.Error)
            Exit For
        End If

        files_copied += 1
        'Debug.WriteLine(i & ": FileCopy """ & _
        '    file_name & """, """ & _
        '    dest_dir & file_title & """")
    Next i
    On Error GoTo 0

    Me.Text = APP_NAME
    Me.Cursor = Cursors.Default

    MessageBox.Show("Copied " & files_copied & " files", _
        "Done", MessageBoxButtons.OK, _
End Sub
Subroutine ListFiles uses the Directory class's GetFiles method to list the files that match the pattern *.mp3. It adds the files' names to the file_names collection. (This is a lot easier than it is in Visual Basic 6.)
Public Sub ListFiles(ByVal start_dir As String, ByVal _
    file_names As Collection)
    Dim new_files As String() = _
        Directory.GetFiles(start_dir, "*.mp3")
    For Each file_name As String In new_files
    Next file_name
End Sub
Subroutine RandomizeArray randomizes an array. For each entry in the array, it selects a random item at that point or later and swaps it into this position. The result is a randomized array.
' Randomize an array of integers indexed from 0.
Public Sub RandomizeArray(ByVal indexes() As Integer)
    Dim num_items As Integer
    Dim j As Integer
    Dim tmp As Integer

    ' Randomize the array.
    num_items = indexes.GetUpperBound(0)
    For i As Integer = 0 To num_items - 2
        ' Pick a random entry.
        j = CInt(Int((num_items - i) * Rnd() + i))

        ' Swap the numbers.
        tmp = indexes(i)
        indexes(i) = indexes(j)
        indexes(j) = tmp
    Next i
End Sub
While this program is intended to be useful, it's still not perfect and doesn't handle every possible error condition. It also doesn't save every possible useful setting such as the program's size and position.
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.