Una clase para un reproductor de CD. versión: 0.9

Por: Demian Panello.

En la librería multimedia de Windows, (winmm.dll), se encuentran las funciones para manipular video, CD de audio, midi, archivos de sonido, etc. En particular una sola función es necesaria para realizar un simple reproductor de CD, mciSendString(). Todas las acciones, (reproducir, detener, averiguar si hay un cd, cantidad de canciones, duración de cada una de ellas, etc.),  se encuentran disponibles por medio de cadenas de comandos. Por ejemplo para reproducir un CD, hay que abrir el medio, (cadena "Open ..."), y luego reproducir, (cadena "Play...").

MCIERROR errMci;

errMci=mciSendString("Open cdaudio alias micd", NULL, 0, NULL);

if (errMci!=0)

    ...error.

errMci=mciSendString("Play micd", NULL,0,NULL);

...

Como estas hay muchas otras cadenas que están compartidas por los diferentes medios y otras son exclusivas. En este ejemplo la reproducción comienza del primer tema y no se detiene hasta terminar el disco, pero hay variantes de "Play", por ejemplo indicándole que reproduzca entre dos posiciones, (tiempos comprendidos dentro del tiempo total del CD), e incluso se puede especificar el handle de una ventana, (último parámetro de mciSendString()), que será la que reciba alguno de los mensajes multimedia, (por ejemplo MM_MCINOTIFY).

La clase CAudioCD.

Para facilitar el uso de la lectora de cd's como reproductora de cd's de audio, he escrito una clase que precisamente "envuelve" algunas de estas acciones con las cadenas MCI.

En principio, esta clase que llamé CAudioCD, ofrece la funcionalidad más común de un reproductor de CD's, (reproducir, pasar al siguiente tema, pasar al tema anterior, detener, pausar, eject, obtener información de capacidades del dispositivo, reproducción aleatoria y algunos pocos más). Todavía le falta algo de depuración y agregarle mayor funcionalidad, pero para el simple hecho de aprender como construir objetos que faciliten la programación y de practicar con C++ es más que suficiente.

La clase está mayormente en inglés; porque, que se le va a hacer, uno está más acostumbrado a ver Play que Reproducir, o Next que siguiente, etc.

Definición de la clase CAudioCD:

//AudioCD.h: interface for the CAudioCD class.
//************************* ENCABEZADO **********************************
//Clase que envuelve las funciones MCI para la reproducción de
//discos compactos de audio.
//Versión: 0.9 (depuración no exhaustiva).
//Autor: Demian Panello.
//demianpanello@yahoo.com.ar
//Yerba Mate y Visual C++ -> www.dcp.com.ar
//Febrero 2003

//Este fuente es de libre distribución. Se solicita la mención del autor
// manteniendo esta sección sin alterar en la inclusión.
//
//
//
////////////////////////////////////////////////////////////////////////

#if !defined(AFX_AUDIOCD_H__C9BB50A1_3549_11D7_8547_9FEF7B38783F__INCLUDED_)
#define AFX_AUDIOCD_H__C9BB50A1_3549_11D7_8547_9FEF7B38783F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "stdlib.h"

//Estructura para almacenar los resultados del comando mci "info"
struct CD_INFO
{
    char identity[40];          //info identity
    char upc[40];             //info upc
    char product[40];    //info product.
};

//Estructura para almacenar los resultados del comando mci "capability"
struct CD_CAPABILITY
{
    char can_eject[6];      //"TRUE" si puede eject.
    char can_play[6];         //"TRUE" si puede reproducir.
    char can_record[6];    //"TRUE" si puede grabar.
    char can_save[6];         //"TRUE" si puede guardar datos.
    char compound[6];         //"TRUE" si soporta un archivo.
    char device_type[10];    //Devuelve "CDAUDIO".
    char has_audio[6];         //"TRUE" si soporta audio.
    char has_video[6];        //"TRUE" si soporta video.
    char uses_files[6];         //"TRUE" si la forma de guardar es en archivo, (compound también
                                            //es TRUE si este campo lo es).

};

//Constantes enumeradas para el formato del tiempo.
enum TIMEFORMAT
{
    STF_MS,
    STF_MSF,
    STF_TMSF,
};

//Definición de la clase.
class CAudioCD
{

public:
    //********* Funciones miembro públicas **************************
    CAudioCD(); //Constructor por defecto.
    virtual ~CAudioCD(); //Destructor por defecto.
    MCIERROR PlayCD(); //Inicia reproducción.
    MCIERROR PlayCD(char* posIni, char* posEnd); //Reproduce entre dos posiciones.
    MCIERROR PlayCD(int nTrack); //Reproduce un nro. de tema especifico.
    MCIERROR EjectCD(); //Abre o cierra la lectora de CDs.
    MCIERROR StopCD(); //Detiene la reproducción.
    MCIERROR PauseCD(); //Pausa la reproducción.
    MCIERROR NextTrack(); //Pasa a el siguiente tema (track).
    MCIERROR PreviousTrack(); //Pasa a el tema anterior.
    MCIERROR PlayRandomTrack(); //Reproduce un tema al azar, (lo reproduce y se detiene).
    void ShowMciError(MCIERROR nerr); //Devuelve un texto descriptivo de acuerdo al MCIERROR
    MCIERROR isPlaying(); //Devuelve 1 si se está reproduciendo un tema.
    MCIERROR isReady(); //Devuelve 1 si el dispositivo está listo para reproducir.
    MCIERROR isStopped(); //Devuelve 1 si el cd está detenido.
    MCIERROR isPaused(); //Devuelve 1 si el cd está en pausa.
    MCIERROR isCDInsert(); //Devuelve 1 si hay un cd en la lectora.
    MCIERROR GetTracks(int& nTracks); //Obtiene la cantidad total de temas.
    MCIERROR GetCurrentTrack(int& curTrack ); //Obtiene el número de tema actual.
    MCIERROR InitialStartTrack(); //Permite inicializar datos miembros protegidos.
    MCIERROR GetCurrentPosition(char* curPos); //Obtiene la posición del tema actual.
    MCIERROR GetCDStart(char* curStart); //Obtiene la posición de inicio del tema actual.
    MCIERROR GetCDLength(char* cd_length);    //Obtiene la duración total del CD.
    MCIERROR GetTrackLength(char* track_length); //Obtiene la duración del tema actual.
    MCIERROR GetTrackLength(int nTrack, char* track_length); //Obtiene la duración de un tema específico.
    MCIERROR GetTimeFormat(char* time_format); //Obtener el formato actual del tiempo.
    MCIERROR SetTimeFormat(int TimeFormat=STF_MSF);    //Establece formato a milliseconds.
    MCIERROR GetCDInfo(CD_INFO& pCDInfo); //Obtiene información sobre el dispositivo.
    MCIERROR GetCDCapability(CD_CAPABILITY& pCDCapability); //Obtiene capacidades del dispositivo.
    MCIERROR GetStartPosition(int nTrack, char* StartPos); //Obtiene la posición de inicio de un tema.
        BOOL AttachHandle(HWND handle); //Asigna el handle de ventana que recibirá el mensaje MM_MCINOTIFY.

                                                                                                       
    //Funciones miembro privadas
private:
    MCIERROR GetEndTrack(int nTrack, char* endPos); //Devuelve la posición final de un tema.   

    //Datos miembros protegidos
protected:
    MCIERROR m_mciError;         //Código de error MCI.
    int m_ncurrentTrack;                  //Nro. de track actual.   
    int m_nTracks;                             //Cantidad de tracks.
    char m_currentStart[80];          //Inicio del tema actual.
    char m_currentPosition[80];      //Posición del tema actual.
   HWND Parent;                      //Handle de la ventana que recibirá el mensaje MM_MCINOTIFY   
};

#endif  // !defined(AFX_AUDIOCD_H__C9BB50A1_3549_11D7_8547_9FEF7B38783F__INCLUDED_)

Esta es la definición de la clase. La implementación, (junto con esta definición), la pueden descargar pulsando un link al final del artículo:

Descripción de la clase CAudioCD:

Funciones públicas:

Este es el constructor. Se encarga de abrir el dispositivo de CDAudio.

Puede declarar una variable miembro en un diálogo como sigue:

CAudioCD m_cd;

Este es el destructor. Se encarga de enviar la cadena "close" que permite cerrar el dispositivo, (obviamente lo contrario que hace el constructor).

Esta función se encarga de verificar si hay un CD en la lectora y, en caso de haberlo, inicializa la variable miembro protegida m_currentPosition y m_currentStart. Puede usar esta función antes de mostrar el diálogo, (o ventana), así ya está posicionado en el primer corte del disco.

Simplemente comienza la reproducción. Se detiene unicamente con un llamado a CAudioCD::StopCD() o CAudioCD::PauseCD(). Ejemplo:

  
  if (!m_cd.isPlaying())
        m_cd.PlayCD ();   

 

Reproduce entre dos posiciones. Los dos parámetros son cadenas cuyo contenido puede ser, por ejemplo: mm:ss y mm:ss, dependiendo del formato del tiempo especificado con CAudioCD::SetTimeFormat(int TimeFormat=STF_MSF). Envía el mensaje MM_MCINOTIFY.

Reproduce el número de tema nTrack pasado como parámetro. Envía el mensaje MM_MCINOTIFY.

Abre o cierra la lectora.

Detiene la reproducción.

Detiene la reproducción. Pero "recuerda" la posición para continuar.

Pasar al siguiente tema y al anterior. Si se llega al último y se vuelve a llamar a NextTrack() pasa al primero, si se está en el primer corte y se llama a PreviousTrack() se pasa al último.

Reproduce una canción de forma aleatoria. Envía el mensaje MM_MCINOTIFY.  

Devuelven 1 en caso que se esté reproduciendo, ó esté detenido, ó en pausa, ó hay un cd en la lectora. Cero en caso que no, y otro valor es error.

Devuelve 1 en caso que el dispositivo esté listo para recibir una orden. Cero en caso que no y otro valor es error.

Coloca en nTracks la cantidad de temas del CD.

Coloca en curTrack el número de tema actual, (se esté reproducciendo o no).

Coloca en curPos la posición actual. Ejemplo si el CD dura 50:00 y se encuentra en reproducción, (o no), por la mitad, esta función almacenaría "25:00" en curPos. Esta función es útil, por ejemplo, en combinación con GetCurrentTrack(int* curTrack).

Coloca en curStart la posición de inicio del CD. La función InitialStartTrack() llama a esta función.

Coloca en cd_length la longitud, (en el formato de tiempo especificado por SetTimeFormat()), de todo el CD de audio.

Coloca en track_length la longitud, (duración), del tema actual, (en reproducción o no).

Coloca en track_length la longitud del corte especificado en nTrack.

Coloca en time_format el formato del tiempo actual: "msf", "ms" ó "tmsf".

Establece el formato del tiempo de acuerdo a la constante pasada como parámetro. Estas constantes pueden ser:

STF_MS: Para establecer el formato a milésimas de segundos.
STF_MSF:
Para establecer el formato a minutos/segundos/frames. Este es el valor por defecto que toma la función.
STF_TMSF:
Para establecer el formato a track/minutos/segundos/frame.

Carga una estructura de tipo CD_INFO con información del dispositivo. Ver CD_INFO.

Carga una estructura de tipo CD_CAPABILITY con las capacidades de la lectora. Ver CD_CAPABILITY.

Carga StartPos con la posición de inicio del número de tema especificado en nTrack.

Muestra un mensaje descriptivo sobre el error pasado como parámetro.

Funciones privadas:

Esta función, por el hecho de ser privada, (sólo está disponible para las funciones de la clase), no puede ser accedida por el programa. Es utilizada por la función CAudioCD::PlayCD(int nTrack).

Las función CAudioCD::PlayCD(char* posIni, char* posEnd) usa la función mciSendString() de la siguiente forma:

//Reproduce entre dos posiciones.
MCIERROR CAudioCD::PlayCD (char* posIni, char* posEnd)
{
    char mciCad[80];
   
    wsprintf(mciCad, "Play micd from %s to %s notify", posIni, posEnd);
       
    m_mciError=mciSendString(mciCad, NULL, 0, Parent);
   if (m_mciError!=0)
        return m_mciError;
    return 0;
}

Indica que reproduzca entre dos posiciones y que notifique cuando el comando se complete, (notify). Esto da lugar a que se "dispare" un mensaje a una ventana, que es precisamente el handle almacenado en HWND Parent.

Lo primero que hay que hacer cuando se carga una ventana, (por ejemplo en OnInitDialog()), es especificarle al objeto CAudioCD(), (dato miembro del diálogo), cuál es el handle del diálogo por medio de una sentencia como la siguiente, (supongamos que el objeto CAudioCD es m_cd):

m_cd.AttachHandle(m_hWnd);  //o this->m_hWnd

Y además agregar el mensaje MM_MCINOTIFY al diálogo.

Desde ya esto es optativo, si no se especifica el handle de la ventana al dato miembro de la clase y no se agrega el mensaje, la función CAudioCD::PlayCD(char* posIni, char* posEnd) igual funcionará, aunque obviamente no existirá ninguna notificación de terminación.

 

Cómo usar la clase:

Si quiere hacer un reproductor de CD usando esta clase, (al pié de la página puede descargar un demo de ejemplo),  es muy fácil, (supongo un proyecto Dialog Based ya creado, aunque la puede usar también en proyectos SDI):

1) Agregue al proyecto los archivos de CAudioCD.h y CAudioCD.cpp, (Recuerde: Project -> Add to project -> files).

2) Escriba en el archivo StdAfx.h la siguiente sentencia: #include "mmsystem.h".

3) Agregue la librería winmm.lib al proyecto.

4) Verifique que en el archivo de cabecera del diálogo se encuentre la sentencia: #include "AudioCD.h", (debería estar puesto que la coloca automáticamente el Class Wizard), si no está, escríbala.

5) Agregue una variable de tipo CAudioCD al diálogo, (ejemplo CAudioCD m_cd). Puede editar directamente la clase del diálogo.

6) Luego, en OnInitDialog(), llame a la función CAudioCD::InitialStartTrack(), de la siguiente forma:

err=m_cd.InitialStartTrack();

7) Optativamente, puede especificarle al objeto CAudioCD cuál es el handle del diálogo para poder recibir el mensaje MM_MCINOTIFY, (si hace esto debe además agregar este mensaje). 

8) Codifique los controles del diálogo, (ejemplo: botones, ListBox, ComboBox, etc.), con las funciones del objeto m_cd, (PlayCD(), StopCD(), PauseCD(), etc.).

Programa de ejemplo:   

El programa de ejemplo que pueden descargar más abajo es un reproductor de CD,s simple. Utiliza la mayoría de las funciones de la clase y además muestra como colocar ToolTips en controles e implementa una clase para manipular el volumen escrita por Alex Chmut, la cual agiliza bastante la tarea. 

Descargar archivo fuente de CAudioCD, (archivos caudiocd.h y caudiocd.cpp).

Descargar programa de ejemplo.

Volver a la página principal.