MP3 VB.NET (2)

Reproductor aleatorio de MP3 – Usando OCX de Windows Media Player 10 – Ejercicio para Visual Studio .NET

Anteriormente publiqué un artículo sobre un reproductor de archivos MP3 realizado en Visual Basic .NET 2003 utilizando el OCX de Windows Media Player 9. Continuando ese ejercicio, he añadido la funcionalidad de reproducir los archivos de forma aleatoria. El programa crea un Array con todas las canciones existentes en una determinada carpeta y, mediante las funciones Randomize() y Rnd(), genera un índice aleatorio que asigna al reproductor.

Requisito imprescindible: tener instalado Windows Media Player y añadir su control OCX al proyecto (explicado en el artículo anterior).

Variables globales

Se crean unas variables con visibilidad a nivel de clase para poder utilizarlas en cualquier procedimiento:

' VARIABLES GLOBALES
'
' para la ruta al directorio seleccionado
Private strPath As String
' el evento WMPLib.WMPPlayState.wmppsTransitioning se produce
' cuando Windows Media Player está preparando un nuevo ítem
' pero sólo ha de suceder cuando la variable blShuffle sea True
Private blShuffle As Boolean = False
' para el título y el autor d elas canciones
Private strTitulo, strAutor, strAlbum As String
' para el tiempo de reproducción transcurrido
Private dtTime As DateTime
' strArchivo = nombre del archivo MP3
' strArchivo_sin = nombre del archivo MP3 sin los 4 últimos caracteres (.mp3)
Private strArchivo, strArchivo_sin As String
' colección con los nombres de todos los archivos MP3 del directorio y subdirectorios
Private listaMp3 As ArrayList
' para el índice de las canciones
Private intCancion As Integer
' i = índice de la última aparición de  en la ruta al archivo MP3
' j = longitud de la cadena con el nombre del archivo MP3
Dim i, j As Integer

Procedimiento para abrir un archivo

El procedimiento abrirCarpeta() presenta al usuario un cuadro de diálogo para elegir una carpeta que contenga archivos MP3. El resultado de la elección se pasa al reproductor. La variable strPath guarda la ruta a la carpeta y la variable listaMp3 una matriz con los archivos contenidos en esa carpeta.

' PROCEDIMIENTO QUE SE ENCARGA DE ELEGIR EL DIRECTORIO
Private Sub abrirCarpeta()
Try
' limpiar variables y parar el reproductor
ocxPlayer.Ctlcontrols.stop()
ocxPlayer.URL = ""
strPath = ""
lbIndex.Text = ""
' cuadro de diálogo de selección de carpeta (FolderBrowserDialog)
If folderDlg.ShowDialog = DialogResult.OK Then
' strPath contiene la ruta al directorio seleccionado
strPath = folderDlg.SelectedPath
' limpiar listaMp3 de su contenido anterior
If listaMp3.Count > 0 Then
listaMp3.Clear()
End If
Else
' si no se elige carpeta o se pulsa Cancelar, salir sin hacer nada
Return
End If
'
' función recursiva que rellena listaMp3 con los archivos MP3 de carpetas y subcarpetas
' comienza listando archivos y carpetas de strPath (directorio raíz)
Call listarArchivos(strPath)
'
blShuffle = True
'comenzar a reproducir una canción al azar
Call Aleatorio()
'
Catch ex As Exception
MsgBox("Error en abrirCarpeta(): " + vbCrLf & ex.Message)
End Try
End Sub

Estado del reproductor

El procedimiento ocxPlayer_PlayStateChange() detecta los cambios en el estado del reproductor (reproduciendo, detenido…) para mostrar información de la canción al cambiar el estado del reproductor (PlayStateChange). Como el OCX tiene configurado su inicio automático, simplemente con elegir un archivo ya cambia el estado de reproducción y comienza a tocar.

De este procedimiento, existente en el artículo anterior, sólo comentaré la inclusión de un nuevo estado wmppsTransitioning que tiene lugar cada vez que el reproductor está preparando un nuevo ítem; pero en algunas ocasiones no debe ser detectado por lo que se crea una variable booleana blShuffle que dice al programa cuándo detectar wmppsTransitioning y cuándo no hacerlo.

Por otro lado, el programa puede leer metadatos de los archivos MP3 tales como el título de la canción(.currentMedia.getItemInfobyType(“title”, “”, 0))
o el nombre del autor
(.currentMedia.getItemInfobyType(“author”, “”, 0))
y mostrarlos en unas etiquetas de texto. Pero si el archivo MP3 carece de esos tags (particularmente del tag author ya que el tag title se rellena a partir del nombre de archivo) el programa no muestra correctamente información sobre la duración de la canción y el tiempo transcurrido y aparecen errores respecto a los controles de la aplicación que han de verse habilitados o deshabilitados, por ese motivo se captura la excepción al rellenar esas etiquetas informativas.

' MOSTRAR INFORMACIÓN DE LA CANCIÓN AL CAMBIAR EL ESTADO DEL REPRODUCTOR (PlayStateChange),
' EL CONTROL OCX TIENE CONFIGURADO EL INICIO AUTOMÁTICO POR LO QUE
' AL ELEGIR UN ARCHIVO CAMBIA EL ESTADO DE REPRODUCCIÓN
Private Sub ocxPlayer_PlayStateChange(ByVal sender As Object, ByVal e As AxWMPLib._WMPOCXEvents_PlayStateChangeEvent) Handles ocxPlayer.PlayStateChange
'
Try
dtTime = DateTime.Now ' para empezar a contar el tiempo
' vaciar la información de la canción anterior
lbTitulo.Text = ""
lbTituloa.Text = "Título:"
lbAutor.Text = ""
lbAutora.Text = "Intérprete:"
lbAlbum.Text = ""
lbAlbuma.Text = "Album:"
'
' dependiendo del estado del reproductor
Select Case e.newState
'
' REPRODUCIENDO
Case WMPLib.WMPPlayState.wmppsPlaying
Try
' evitar errores con archivos MP3 que no tengan metainformación sobre los ítem Author y Title
Try
' mostrar en la barra de título de la ventana:
'- el número de orden del archivo en la carpeta
'- el título de la canción
'If (intCancion >= 0) AndAlso intCancion < (listaMp3.Count-1) Then
Me.Text = CStr(intCancion) + ".- " + ocxPlayer.currentMedia.getItemInfobyType("title", "", 0) ' título
'End If
strAutor = ocxPlayer.currentMedia.getItemInfobyType("author", "", 0)
strTitulo = ocxPlayer.currentMedia.getItemInfobyType("title", "", 0)
strAlbum = ocxPlayer.currentMedia.getItemInfobyType("album", "", 0)
lbAutora.Text = "Intérprete:"
lbAutor.Text = strAutor ' autor
lbTituloa.Text = "Título:"
lbTitulo.Text = strTitulo ' título
lbAlbuma.Text = "Album:"
lbAlbum.Text = strAlbum 'álbum
Catch pollo As Exception
' ruta al archivo MP3 a partir de la última aparición de 
'(es el nombre de archivo sin la ruta)
i = strArchivo.LastIndexOf("")
strArchivo_sin = strArchivo.Substring(i + 1)
' nombre del archivo sin los 4 caracteres finales (".mp3")
j = strArchivo_sin.Length
strArchivo_sin = strArchivo_sin.Remove(j - 4, 4)
' mostrar en la barra de título de la ventana:
'- el número de orden del archivo en la carpeta
'- el título de la canción
'If (intCancion >= 0) AndAlso intCancion < (listaMp3.Count-1) Then
Me.Text = CStr(intCancion) + ".- " + strArchivo_sin ' título
'End If
lbAutora.Text = "Intérprete:"
lbAutor.Text = "----------" ' autor
lbTituloa.Text = "Reproducción en curso:"
lbTitulo.Text = strArchivo_sin ' título
lbAlbuma.Text = "Album:"
lbAlbum.Text = "----------"
End Try
' para mostrar la duración de la canción
Dim minutos As Integer
Dim segundos As Integer
minutos = ocxPlayer.currentMedia.duration  60 ' división entera entre la duración en segundos y 60
' resto entre la duración total y el resultado de la división entera anterior
segundos = ocxPlayer.currentMedia.duration - (minutos * 60)
lbTotal.Text = Format(minutos, "00") + ":" + Format(segundos, "00").ToString
Timer1.Enabled = True ' iniciar el temporizador para cronometrar la canción
Timer1.Start()
'
btAbrir.Enabled = False ' desactivar el botón Abrir
btStop.Enabled = True ' activar el botón Abrir
btPlay.Enabled = False ' desactivar el botón Play
btSaltar.Enabled = True ' activar el botón Saltar
'
Catch ex As Exception
MsgBox("Error en WMPLib.WMPPlayState.wmppsPlaying: " + vbCrLf + ex.Message)
End Try
'
' DETENIDO
Case WMPLib.WMPPlayState.wmppsStopped
btAbrir.Enabled = True ' activar el botón Abrir
btStop.Enabled = False ' desactivar botón Stop
btPlay.Enabled = True ' activar botón Play
btSaltar.Enabled = False ' desactivar botón Saltar
' barra de título de la ventana vacía
Me.Text = "emiPlayer"
Timer1.Stop() ' detener temporizador
Timer1.Enabled = False
lbTotal.Text = ""
lbTime.Text = ""
'lbIndex0.Text = ""
'lbIndex.Text = ""
'
' desactivar reproducción aleatoria
If blShuffle = True Then
blShuffle = False
End If
'
' PREPARANDO UN NUEVO ITEM
Case WMPLib.WMPPlayState.wmppsTransitioning
' actuar en el evento wmppsTransitioning sólo si blShuffle es True
If blShuffle = True Then
Call Aleatorio()
End If
End Select
'
Catch ex As Exception
MsgBox("Error en ocxPlayer.PlayStateChange: " + vbCrLf + ex.Message)
End Try
'
End Sub

Obtener los archivos que contiene la carpeta elegida y las subcarpetas

Se emplea función recursiva que rellena listaMp3 con los archivos mp3 de carpetas y subcarpetas, es una función sobrecargada que se ejecuta de 2 formas diferentes:

  • con un parámetro strpath(string): lista los archivos y carpetas del directorio raíz
  • con 2 parámetros odir(directoryinfo) y nivel(integer): lista los archivos y carpetas de las subcarpetas.
' FUNCIÓN RECURSIVA QUE RELLENA listaMp3 CON LOS ARCHIVOS MP3 DE CARPETAS Y SUBCARPETAS
' ES UNA FUNCIÓN SOBRECARGADA QUE SE EJECUTA DE 2 FORMAS DIFERENTES:
' - CON UN PARÁMETRO strPath(String): LISTA LOS ARCHIVOS Y CARPETAS DEL DIRECTORIO RAÍZ
' - CON 2 PARÁMETROS oDir(DirectoryInfo) nivel(Integer): LISTA LOS ARCHIVOS Y CARPETAS DE LAS SUBCARPETAS
Private Overloads Function listarArchivos(ByVal strPath As String) As ArrayList
Try
Dim oDir As New System.IO.DirectoryInfo(strPath) ' propiedades del directorio raíz
Dim oSubDir() As System.IO.DirectoryInfo ' propiedades de los subdirectorios
Dim oFiles() As System.IO.FileInfo ' propiedades de los archivos
Dim i As Integer ' para contar elementos en bucles
oFiles = oDir.GetFiles ' archivos del directorio raíz
'
' añadir al ArrayList cada uno de los archivos MP3 del directorio raíz
' se emplea la propiedad FullName pues contiene la ruta completa al archivo
' necesaria para que el reproductor pueda abrir el archivo mediante su propiedad URL
For i = 0 To oFiles.Length - 1
If Not oFiles(i).Name.StartsWith(".") Then
If oFiles(i).Name.EndsWith("mp3") OrElse oFiles(i).Name.EndsWith("MP3") Then
listaMp3.Add(oFiles(i).FullName)
End If
End If
Next
'
' obtener las subcarpetas del directorio raíz
oSubDir = oDir.GetDirectories
' en cada subcarpeta, se llama a la función recursiva con 2 parámetros:
' - la subcarpeta actual
' - la profundidad de la subcarpeta respecto al directorio raíz (se empieza por 1)
For i = 0 To oSubDir.Length - 1
Call listarArchivos(oSubDir(i), 1)
Next
'
lbIndex0.Text = "Nº de canciones:"
lbIndex.Text = " " & listaMp3.Count
Catch ex As Exception
MsgBox("Error en Recursive(strPath): " + vbCrLf + ex.Message)
End Try
End Function
Private Overloads Function listarArchivos(ByVal oDir As System.IO.DirectoryInfo, ByVal nivel As Integer) As ArrayList
Try
Dim oSubDir() As System.IO.DirectoryInfo ' propiedades de los subdirectorios
Dim oFiles() As System.IO.FileInfo ' propiedades de los archivos
Dim i As Integer ' para contar elementos en bucles
oFiles = oDir.GetFiles ' archivos que contiene el directorio en cada llamada recursiva
'
' añadir a listaMp3 cada uno de los archivos MP3 del subdirectorio
' se emplea la propiedad FullName pues contiene la ruta completa al archivo
For i = 0 To oFiles.Length - 1
If oFiles(i).Name.EndsWith("mp3") OrElse oFiles(i).Name.EndsWith("MP3") Then
listaMp3.Add(oFiles(i).FullName)
End If
Next
'
' obtener las subcarpetas del subdirectorio
oSubDir = oDir.GetDirectories()
' en cada subcarpeta, se llama a la función recursiva con 2 parámetros:
' - la carpeta actual
' - la profundidad de la carpeta respecto al directorio raíz (avanza 1 en cada pasada)
For i = 0 To oSubDir.Length - 1
Call listarArchivos(oSubDir(i), nivel + 1)
Next
Catch ex As Exception
MsgBox("Error en Recursive(oDir, nivel): " + vbCrLf + ex.Message)
End Try
End Function

Reproducción aleatoria

El procedimiento Aleatorio() se encarga de generar un número aleatorio entre 1 y el número de elementos que componen la matriz de canciones (es decir, entre 1 y el número total de canciones en la carpeta).

La función Randomize() sin argumento arranca el generador de números aleatorios con un valor de inicialización basado en el temporizador del sistema.

La función Rnd() devuelve un número aleatorio de tipo Single (devuelve un valor menor que 1 pero mayor o igual que cero). Para producir enteros aleatorios en un intervalo dado, se utiliza la siguiente fórmula:

aleatorio = CInt(Int((límite_superior - límite_inferior + 1) * Rnd() + límite_inferior))

En el siguiente ejemplo se genera un entero aleatorio en el intervalo entre 1 y 6:

Dim value As Integer = CInt(Int((6 * Rnd()) + 1))

El código de esta sección es así:

' PROCEDIMIENTO PARA LA REPRODUCCIÓN ALEATORIA
Private Sub Aleatorio()
Try
' ejecutar este método cuando blShuffle es True
If blShuffle = True Then
' para que no llame al método Aleatorio() en el evento wmppsTransitioning
' hasta que termine el propio método Aleatorio() hacemos blShuffle = False
blShuffle = False
Randomize()
' saber el número de archivos MP3 -> límite superior para usar con Rnd()
Dim n As Integer
n = listaMp3.Count
' obtener un índice aleatorio
' (se usa -1 porque el índice del ArrayList empieza en cero y listaMp3.Count empieza en 1)
intCancion = CInt(n * Rnd() + 1) - 1
'
' asignar el archivo al reproductor si el índice está dentro del rango adecuado
If intCancion >= 0 And intCancion < listaMp3.Count Then
strArchivo = listaMp3(intCancion)
ocxPlayer.URL = strArchivo
Else
' volver a generar un índice aleatorio
blShuffle = True ' para que se pueda ejecutar Aleatorio()
Call Aleatorio()
End If
'
' para poder llamar al método Aleatorio() en el evento wmppsTransitioning
blShuffle = True
End If
Catch ex As Exception
MsgBox("Error en Aleatorio(): " + vbCrLf + ex.Message)
End Try
End Sub
Anuncios