Reproductor de mp3
Creaci�n de una clase para la reproducci�n de archivos mp3.

29 de Junio de 2003 (08/Jul/2003)
Autor: Gonzalo Antonio sosa M. y [email protected]


Codificaci�n de la clase Reproductor.

En este punto mostraremos como se ha codificado la clase Reproductor, por supuesto que todo esto se muestra a manera de ejemplo, dado que todos tenemos nuestra propia manera de hacer las cosas, sobre todo en esto de la programaci�n.

Primero importamos los espacios de nombres que necesitaremos...

using System;        
using System.IO;     
using System.Text;     
using System.Runtime.InteropServices; 

Ahora declaramos a las funciones de la Api que se necesitar�n, cada una de ellas tiene un prop�sito espec�fico...

[DllImport("winmm.dll")]
public static extern int mciSendString(string lpstrCommand, 
StringBuilder lpstrReturnString, int uReturnLengh, int hwndCallback);

La funci�n mciSendString env�a una cadena de comando a un dispositivo MCI. El dispositivo al que va destinado se espec�fica en la cadena de comando. La funci�n recibe 4 par�metros: lpstrCommand, una cadena terminada en nulo, d�nde se especifica la cadena de comando MCI; lpstrReturnString, un puntero a un buffer que recibe la informaci�n de retorno, sino se espera dicha informaci�n, el par�metro puede ser nulo; uReturnLength, tama�o en caracteres del buffer especificado en el par�metro lpstrReturnString y, hwndCallback, manejador de retorno si la bandera de callback ha sido especificada en la cadena de comando. La funci�n retorna 0 si ha tenido �xito y diferente de 0, en cualquier otro caso.

Para codificar la funci�n necesitamos pasar como segundo par�metro un puntero a una cadena modificable, y c�mo probablemente conozcas, las cadenas de tipo string, son del tipo inmutable, esto es, cuando se modifican sus valores en realidad devuelven una string  nueva. No siendo as� con las creadas como instancia de StringBuilder, que siempre devuelven una referencia a la misma. Por ello hemos optado por utilizar la clase StringBuilder, del espacio de nombres System.Text. Dicha clase ha sido utilizada para todas la funciones que requieran un par�metro similar.

[DllImport("winmm.dll")]
public static extern string mciGetErrorString(int fwdError, StringBuilder lpszErrorText, 
int cchErrorText);

Esta funci�n devuelve una cadena  que describe el c�digo de error MCI especificado. Toma 3 par�metros: fwdError, el c�digo de error (diferente de 0), devuelto por la funci�n mciSendString; lpszErrorText, un puntero a un buffer que recibe la cadena terminada en nulo, d�nde se describe el c�digo de error y, cchErrorText, la longitud del buffer apuntado por el par�metro lpszTextError. La funci�n devuelve verdadero (un valor diferente de 0) s� ha tenido �xito, � falso (valor igual con 0), si ha fallado.

[DllImport("winmm.dll")]
public static extern int waveOutGetNumDevs();

Esta funci�n devuelve el n�mero de dispositivos de salida de audio presentes en el sistema. La funci�n no requiere par�metros y devuelve el n�mero de dispositivos o cero si no se ha encontrado ninguno.

[DllImport("kernel32.dll")]
public static extern int GetShortPathName(string lpszLongPath,
StringBuilder lpszShortPath, int cchBuffer);

Devuelve una cadena conteniendo la ruta en formato corto, de la ruta especificada como entrada. Requiere 3 par�metros: lpszLongPath, cadena terminada en nulo, conteniendo la ruta origen. En la versi�n ANSI de esta funci�n, este par�metro est� limitado a un n�mero constante (MAX_PATH) de caracteres, para extender este l�mite a 32, 767 caracteres, se requiere una llamada a la versi�n Unicode de la funci�n y anteponer "\\?\" a la ruta; lpShortPath, puntero a un buffer terminado en nulo, que almacenar� la ruta en formato corto; cchBuffer, tama�o del buffer apuntado en lpShortPath.


[DllImport("kernel32.dll")]
public static extern int GetLongPathName(string
lpszShortPath, StringBuilder lpszLongPath, int cchBuffer);

Convierte la ruta especificada a su formato largo. S� la cadena en formato largo no es encontrada, simplemente devuelve la cadena original. Igualmente requiere 3 par�metros: lpszShortPath, cadena terminada en nulo, conteniendo la ruta a convertir. En su formato ANSI, la longitud de este par�metro est� limitada a MAX_PATH caracteres, para extender dicho valor se requiere llamar a su versi�n Unicode; lpszLongPath, puntero a un buffer que almacenar� la cadena convertida; cchBuffer, Tama�o del buffer.

Ahora declaremos las variables y constantes que se requieren...

// Constante con la longitud m�xima de un nombre de archivo.     
const int MAX_PATH = 260;                                                
// Constante con el formato de archivo a reproducir.
const string Tipo = "MPEGVIDEO";                                          
// Alias asignado al archivo especificado.
const string sAlias = "ArchivoDeSonido"; 
private string fileName; //Nombre de archivo a reproducir

Necesitamos que la clase se  comunique con el usuario de la misma, para comunicarle el estado de las operaciones efectuadas; y para ello, haremos uso de un evento.

//Especificamos el delegado al que se va a asociar el evento.
public delegate void ReproductorMessage(string Msg); 
//Declaramos nuestro evento.
public event ReproductorMessage ReproductorEstado;

No haremos ninguna modificaci�n al constructor por defecto.

public Reproductor()
{
}

Ahora agregamos una propiedad de lectura / escritura, que nos permita establecer el nombre del archivo que deseamos reproducir...

public string NombreDeArchivo 
{
    get
    {
        return fileName; 
    }
    set
    {
        fileName = value;
    }
}

Ahora necesitamos algunos m�todos que nos permitan manejar la reproducci�n del archivo m�s detalladamente. Necesitamos m�todos para abrir, Reproducir, detener, cerrar,  pausar, buscar dentro, saber el estado de la reproducci�n. Para todos ellos la funci�n MciSendString realiza el trabajo, pasando como par�metros, la cadena de comando adecuada, el nombre de archivo y/o el alias con el que se maneja dicho archivo. 

Bien, este el c�digo de los m�todos citados para la clase Reproductor:

/// <summary>
/// M�todo para convertir un nombre de archivo largo en uno corto,
/// necesario para usarlo como par�metro de la funci�n MciSendString.
/// </summary>
/// <param name="nombreLargo">Nombre y ruta del archivo a convertir.</param>
/// <returns>Nombre corto del archivo especificado.</returns>
private string NombreCorto(string NombreLargo)
{
    // Creamos un buffer usando un constructor de la clase StringBuider.
    StringBuilder sBuffer = new StringBuilder(MAX_PATH);
    // intentamos la conversi�n del archivo.
    if (GetShortPathName(NombreLargo, sBuffer, MAX_PATH) > 0)
        // si la funci�n ha tenido �xito devolvemos el buffer formateado
        // a tipo string.
        return sBuffer.ToString();
    else // en caso contrario, devolvemos una cadena vac�a.
        return "";
}
/// <summary>
/// M�todo que convierte un nombre de archivo corto, en uno largo.
/// </summary>
/// <param name="NombreCorto">Nombre del archivo a convertir.</param>
/// <returns>Cadena con el nombre de archivo resultante.</returns>
public string NombreLargo(string NombreCorto)
{
    StringBuilder sbBuffer = new StringBuilder(MAX_PATH);
    if (GetLongPathName(NombreCorto, sbBuffer, MAX_PATH) > 0)
        return sbBuffer.ToString();
    else 
        return "";
}
/// <summary>
/// M�todo para convertir los mensajes de error num�ricos, generados por la
/// funci�n mciSendString, en su correspondiente cadena de caracteres.
/// </summary>
/// <param name="ErrorCode">C�digo de error devuelto por la funci�n 
/// mciSendString</param>
/// <returns>Cadena de tipo string, con el mensaje de error</returns>
private string MciMensajesDeError(int ErrorCode)
{
// Creamos un buffer, con suficiente espacio, para almacenar el mensaje
// devuelto por la funci�n.
    StringBuilder sbBuffer = new StringBuilder(MAX_PATH);
    // Obtenemos la cadena de mensaje.
    if (mciGetErrorString(ErrorCode, sbBuffer, MAX_PATH) != 0)
        // S� la funci�n ha tenido �xito, valor devuelto diferente de 0,
        // devolvemos el valor del buffer, formateado a string.
        return sbBuffer.ToString();
    else // si no, devolvemos una cadena vac�a.
        return "";
}
/// <summary>
/// Devuelve el n�mero de dispositivos de salida, 
/// instalados en nuestro sistema.
/// </summary>
/// <returns>N�mero de dispositivos.</returns>
public int DispositivosDeSonido()
{
    return waveOutGetNumDevs();
}
/// <summary>
/// Abre el archivo espec�ficado.
/// </summary>
/// <returns>Verdadero si se tuvo �xito al abrir el archivo
/// falso en caso contrario.</returns>
private bool Abrir()
{
    // verificamos que el archivo existe; si no, regresamos falso.
    if (!File.Exists(fileName)) return false;
    // obtenemos el nombre corto del archivo.
        string nombreCorto = NombreCorto(fileName);
        // intentamos abrir el archivo, utilizando su nombre corto
        // y asign�ndole un alias para trabajar con �l.
        if (mciSendString("open " + nombreCorto + " type " + Tipo + 
        " alias " + sAlias, null, 0, 0) == 0)
        // si el resultado es igual a 0, la funci�n tuvo �xito,
        // devolvemos verdadero.
            return true;
        else
            // en caso contrario, falso.
            return false;
}
/// <summary>
/// Inicia la reproducci�n del archivo especificado.
/// </summary>
public void Reproducir()
{
    // Nos cersioramos que hay un archivo que reproducir.
    if (fileName != "")
    {
        // intentamos iniciar la reproducci�n.
        if (Abrir())
        {
            int mciResul = mciSendString("play " + sAlias, null, 0, 0);
            if (mciResul == 0)
            // si se ha tenido �xito, devolvemos el mensaje adecuado,
                ReproductorEstado("Ok");
            else // en caso contrario, la cadena de mensaje de error.
                ReproductorEstado(MciMensajesDeError(mciResul));
        }
    else // s� el archivo no ha sido abierto, indicamos el mensaje de error.
    ReproductorEstado("No se ha logrado abrir el archivo especificado");
    }
    else // si no hay archivo especificado, devolvemos la cadena indicando
        // el evento.
        ReproductorEstado("No se ha especificado ning�n nombre de archivo");
}
/// <summary>
/// Inicia la reproducci�n desde una posici�n espec�fica.
/// </summary>
/// <param name="Desde">Nuevo valor de la posici�n a iniciar</param>
public void ReproducirDesde(long Desde)
{
    int mciResul = mciSendString("play " + sAlias + " from " +
    (Desde * 1000).ToString(), null, 0, 0);
    if (mciResul == 0)
        ReproductorEstado("Nueva Posici�n: " + Desde.ToString());
    else
        ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Modifica la velocidad actual de reproducci�n.
/// </summary>
/// <param name="Tramas">Nuevo valor de la velocidad.</param>
public void Velocidad(int Tramas)
{
    // Establecemos la nueva velocidad pasando como par�metro,
    // la cadena adecuada, incluyendo el nuevo valor de la velocidad,
    // medido en tramas por segundo.
    int mciResul = mciSendString("set " + sAlias + " tempo " +
    Tramas.ToString(), null, 0, 0);
    if (mciResul == 0)
        // informamos el evento de la modificaci�n �xitosa,
        ReproductorEstado("Velocidad modificada.");
    else // de lo contrario, enviamos el mensaje de error correspondiente.
        ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Mueve el apuntador del archivo a la posici�n especificada.
/// </summary>
/// <param name="NuevaPosicion">Nueva posici�n</param>
public void Reposicionar(int NuevaPosicion)
{
// Enviamos la cadena de comando adecuada a la funci�n mciSendString,
// pasando como parte del mismo, la cantidad a mover el apuntador de
// archivo.
    int mciResul = mciSendString("seek " + sAlias + " to " +
    (NuevaPosicion * 1000).ToString(), null, 0, 0);
    if (mciResul == 0)
        ReproductorEstado("Nueva Posici�n: " + NuevaPosicion.ToString());
    else 
        ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Mueve el apuntador de archivo al inicio del mismo.
/// </summary>
public void Principio()
{
// Establecemos la cadena de comando para mover el apuntador del archivo,
// al inicio de este.
int mciResul = mciSendString("seek " + sAlias + " to start", null, 0, 0);
if (mciResul == 0)
ReproductorEstado("Inicio de"+Path.GetFileNameWithoutExtension(fileName));
else 
ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Mueve el apuntador de archivo al final del mismo.
/// </summary>
public void Final()
{
// Establecemos la cadena de comando para mover el apuntador del archivo,
// al final de este.
int mciResul = mciSendString("seek " + sAlias + " to end", null, 0, 0);
if (mciResul == 0)
ReproductorEstado("Final de"+Path.GetFileNameWithoutExtension(fileName));
else 
ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Pausa la reproducci�n en proceso.
/// </summary>
public void Pausar()
{
    // Enviamos el comando de pausa mediante la funci�n mciSendString,
    int mciResul = mciSendString("pause " + sAlias, null, 0, 0);
    if (mciResul == 0)
        ReproductorEstado("Pausada");
    else 
        ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Contin�a con la reproducci�n actual.
/// </summary>
public void Continuar()
{
    // Enviamos el comando de pausa mediante la funci�n mciSendString,
    int mciResul = mciSendString("resume " + sAlias, null, 0, 0);
    if (mciResul == 0)
        // informamos del evento,
        ReproductorEstado("Continuar");
    else // si no, comunicamos el error.
        ReproductorEstado(MciMensajesDeError(mciResul));
}
/// <summary>
/// Detiene la reproducci�n actual y cierra el archivo de audio.
/// </summary>
public void Cerrar()
{
    // Establecemos los comando detener reproducci�n y cerrar archivo.
    mciSendString("stop " + sAlias, null, 0, 0);
    mciSendString("close " + sAlias, null, 0, 0);
}
/// <summary>
/// Detiene la reproducci�n del archivo de audio.
/// </summary>
public void Detener()
{
    // Detenemos la reproducci�n, mediante el comando adecuado.
    mciSendString("stop " + sAlias, null, 0, 0);
}
/// <summary>
/// Obtiene el estado de la reproducci�n en proceso.
/// </summary>
/// <returns>Cadena con la informaci�n requerida.</returns>
public string Estado()
{
    StringBuilder sbBuffer = new StringBuilder(MAX_PATH);
    // Obtenemos la informaci�n mediante el comando adecuado.
    mciSendString("status " + sAlias + " mode", sbBuffer, MAX_PATH, 0);

    // Devolvemos la informaci�n.
    return sbBuffer.ToString();
} 
/// <summary>
/// Obtiene un valor que indica si la reproducci�n est� en marcha.
/// </summary>
/// <returns>Verdadero si se encuentra en marcha, falso si no.</returns>
public bool EstadoReproduciendo()
{
    return Estado() == "playing" ? true : false;
}
/// <summary>
/// Obtiene un valor que indica si la reproducci�n est� pausada.
/// </summary>
/// <returns>Verdadero si se encuentra en marcha, falso si no.</returns>
public bool EstadoPausado()
{
    return Estado() == "paused" ? true : false;
}
/// <summary>
/// Obtiene un valor que indica si la reproducci�n est� detenida.
/// </summary>
/// <returns>Verdadero si se encuentra en marcha, falso si no.</returns>
public bool EstadoDetenido()
{
    return Estado() == "stopped" ? true : false;
}
/// <summary>
/// Obtiene un valor que indica si el archivo se encuentra abierto.
/// </summary>
/// <returns>Verdadero si se encuentra en marcha, falso si no.</returns>
public bool EstadoAbierto()
{
    return Estado() == "open" ? true : false;
}
/// <summary>
/// Calcula la posici�n actual del apuntador del archivo.
/// </summary>
/// <returns>Posici�n actual</returns>
public long CalcularPosicion()
{
StringBuilder sbBuffer = new StringBuilder(MAX_PATH);
// Establecemos el formato de tiempo.
mciSendString("set " + sAlias + " time format milliseconds", null, 0, 0);
// Enviamos el comando para conocer la posici�n del apuntador.
mciSendString("status " + sAlias + " position", sbBuffer, MAX_PATH, 0);

// S� hay informaci�n en el buffer,
if (sbBuffer.ToString() != "")
// la devolvemos, eliminando el formato de milisegundos
// y formateando la salida a entero largo;
return long.Parse(sbBuffer.ToString()) / 1000;
else // si no, devolvemos cero.
return 0L;
}
/// <summary>
/// Devuelve una cadena con la informaci�n de posici�n del apuntador del archivo.
/// </summary>
/// <returns>Cadena con la informaci�n.</returns>
public string Posicion()
{
    // obtenemos los segundos.
    long sec = CalcularPosicion();
    long mins;

    // Si la cantidad de segundos es menor que 60 (1 minuto),
    if (sec < 60)
        // devolvemos la cadena formateada a 0:Segundos.
        return "0:" + String.Format("{0:D2}", sec);
    // Si los segundos son mayores que 59 (60 o m�s),
    else if (sec > 59)
    {
        // calculamos la cantidad de minutos,
        mins = (int)(sec / 60);
        // restamos los segundos de la cantida de minutos obtenida,
        sec = sec - (mins * 60);
        // devolvemos la cadena formateada a Minustos:Segundos.
        return String.Format("{0:D2}", mins) + ":" + String.Format("{0:D2}", sec);
    }
    else // en caso de obtener un valor menos a 0, devolvemos una cadena vac�a.
        return "";
}
/// <summary>
/// C�lcula el tama�o del archivo abierto para reproducci�n.
/// </summary>
/// <returns>Tama�o en segundos del archivo.</returns>
public long CalcularTama�o()
{
StringBuilder sbBuffer = new StringBuilder(MAX_PATH);
mciSendString("set " + sAlias + " time format milliseconds", null, 0, 0);
// Obtenemos el largo del archivo, en millisegundos.
mciSendString("status " + sAlias + " length", sbBuffer, MAX_PATH, 0);

// S� el buffer contiene informaci�n,
if (sbBuffer.ToString() != "")
// la devolvemos, formateando la salida a entero largo;
return long.Parse(sbBuffer.ToString()) / 1000;
else // si no, devolvemos cero.
return 0L;
}
/// <summary>
/// Obtiene una cadena con la informaci�n sobre el tama�o (largo) del archivo.
/// </summary>
/// <returns>Largo del archivo de audio.</returns>
public string Tama�o()
{
    long sec = CalcularTama�o();
    long mins;

    // Si la cantidad de segundos es menor que 60 (1 minuto),
    if (sec < 60)
        // devolvemos la cadena formateada a 0:Segundos.
        return "0:" + String.Format("{0:D2}", sec);
        // Si los segundos son mayores que 59 (60 o m�s),
    else if (sec > 59)
    {
        mins = (int)(sec / 60);
        sec = sec - (mins * 60);
        // devolvemos la cadena formateada a Minustos:Segundos.
        return String.Format("{0:D2}", mins) + ":" + String.Format("{0:D2}", sec);
    }
    else 
        return "";
}

Anterior

Men�

Siguiente


ir al ndice