// Programación en C++ para Ingenieros, Ed. Thomson Paraninfo, 2006 // Apéndice B: La Biblioteca CDAudioLib // Fichero AplicacionCDAudio.cpp // Implementación de la clase AplicacionCDAudio #include "AplicacionCDAudio.h" // Declaración de los atributos estáticos HWND AplicacionCDAudio::hDlg; std::vector<int> AplicacionCDAudio::vListaTracks; int AplicacionCDAudio::iTrackActual; bool AplicacionCDAudio::bPausa; bool AplicacionCDAudio::bRandom; bool AplicacionCDAudio::bPlaying; bool AplicacionCDAudio::bRepetir; bool AplicacionCDAudio::bResume; // Método constructor, crea la ventana de diálogo, inicializa los // atributos de estado y realiza un reset de la ventana de diálogo hDlg // y de la lista de reproducción vListaTracks. AplicacionCDAudio::AplicacionCDAudio(HINSTANCE hThisInstance) { hDlg = CreateDialog(hThisInstance,"diálogoCDAudio",NULL, DlgProc); bRandom = false; bRepetir = false; bResume = false; reset(); } // Método de ejecución de la aplicación. Muestra la ventana de diálogo y // procesa todos los mensajes mediante un bucle. Si no se puede abrir el // dispositivo muestra un mensaje de error y finaliza la aplicación. int AplicacionCDAudio::Ejecutar(void) { MSG messages; if(OpenCDAudio()) { MessageBox(hDlg, MensajeError(), NULL,MB_OK); return 1; } ShowWindow (hDlg,SW_SHOW); while(GetMessage (&messages, NULL, 0, 0)) { if(!IsDialogMessage(hDlg,&messages)) { /* Traduce los mensajes de las teclas virtuales en mensajes de caracteres */ TranslateMessage(&messages); /* Envia el mensaje a la función de atención de la ventana */ DispatchMessage(&messages); } } CloseCDAudio(); return messages.wParam; } // Función de atención a los mensajes de la ventana de diálogo hDlg. // Comprueba que botón o casilla de verificación ha pulsado el usuario // y llama al método correspondiente. BOOL CALLBACK AplicacionCDAudio::DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_BUTTON_ANTERIOR: botonAnterior(); break; case IDC_BUTTON_PLAY_PAUSA: botonPlayPausa(); break; case IDC_BUTTON_SIGUIENTE: botonSiguiente(); break; case IDC_BUTTON_EXPULSAR_CD: botonExpulsar(); break; case IDC_BUTTON_STOP: botonStop(); break; case IDC_CHECK_RANDOM: controlCheckRandom(); break; case IDC_CHECK_REPETIR: controlCheckRepetir(); break; case WM_DESTROY: PostQuitMessage (0); EndDialog(hDlg, FALSE); break; } return TRUE; } return FALSE; } // Método que se ejecuta cuando se pulsa el boton Play/Pause. Cambia el // estado de la aplicación de play a pause y viceversa. Actualiza los // botones de la ventana de diálogo hDlg. void AplicacionCDAudio::botonPlayPausa(void) { char wsPlayPause[30]; if(!IsPlaying()) { // Si no está reproduciendo se comprueba que haya un disco // a reproducir y que la lista de reproducción sea correcta. if(NumeroDeTracks() < 1 || NumeroDeTracks() != vListaTracks.size()) // Se actualiza la lista de reproducción vListaTracks y la // ventana de diálogo reset(); if(vListaTracks.size() != 0) { // Si hay algún track a reproducir cambia el estado a play. bPlaying = true; // Cuando está en reprodución el mismo botón sirve para la pausa. SetDlgItemText(hDlg,IDC_BUTTON_PLAY_PAUSA,"Pausa"); // Dependiendo de si estaba en pausa o no solicita al dispositivo // continuar la reproducción anterior o iniciar la reproducción // del track actual de la lista. if(bPausa) { bPausa = false; Resume(intProcedure); bResume = true; } else { PlayTrack(vListaTracks[iTrackActual],intProcedure); } } } else{ // Si está reproduciendo cambia el estado a pausa y solicita // la pausa al dispositivo. SetDlgItemText(hDlg,IDC_BUTTON_PLAY_PAUSA,"Play"); bPausa = true; bPlaying = false; Pause(); } } // Método que se ejecuta cuando se pulsa el botón Siguiente. // Actualiza el track actual al siguiente de la lista de // Tracks vListaTracks y si está reproduciendo se incia la // reproducción del nuevo track. Se comprueba que la lista de // reproducción es correcta y si no lo es actualiza la lista de // reproducción vListaTracks y la ventana de diálogo. void AplicacionCDAudio::botonSiguiente(void) { if(NumeroDeTracks() != vListaTracks.size()) { reset(); } if(vListaTracks.size() != 0) { iTrackActual = (iTrackActual+1) % vListaTracks.size(); char wsTrack[5]; // Se actualiza el valor del campo track actual de la ventana. wsprintf(wsTrack,"%i",vListaTracks[iTrackActual]); SetDlgItemText(hDlg,IDC_EDIT_TRACK_ACTUAL,wsTrack); if(bPlaying) { if(PlayTrack(vListaTracks[iTrackActual],intProcedure)) reset(); } } } // Método que se ejecuta cuando se pulsa el botón Anterior. // Actualiza el track actual al anterior de la lista de // tracks vListaTracks y si está reproduciendo se incia la // reproducción del nuevo track. Se comprueba que la lista de // reproducción es correcta y si no lo es actualiza la lista de // reproducción vListaTracks y la ventana de diálogo. void AplicacionCDAudio::botonAnterior(void) { if(NumeroDeTracks() != vListaTracks.size()) { reset(); } if(vListaTracks.size() != 0) { if(iTrackActual == 0) iTrackActual = vListaTracks.size()-1; else iTrackActual--; char wsTrack[5]; // Se actualiza el valor del campo track actual de la ventana. wsprintf(wsTrack,"%i",vListaTracks[iTrackActual]); SetDlgItemText(hDlg,IDC_EDIT_TRACK_ACTUAL,wsTrack); if(bPlaying) { if(PlayTrack(vListaTracks[iTrackActual],intProcedure)) reset(); } } } // Método que se ejecuta cuando se pulsa el botón Expulsar. // Abre la puerta del dispositivo, expulsa el CD y actualiza // la lista de reproducción y la ventana de diálogo. void AplicacionCDAudio::botonExpulsar(void) { OpenDoorCD(); reset(); } // Método que se ejecuta cuando se pulsa el botón Stop. // Si está reproduciendo detiene la reproducción. Si es // necesario actualiza la lista de reproducción y la ventana // de diálogo. void AplicacionCDAudio::botonStop(void) { Stop(); if(NumeroDeTracks() != vListaTracks.size()) { reset(); } else { bPlaying = false; bPausa = false; SetDlgItemText(hDlg,IDC_BUTTON_PLAY_PAUSA,"Play"); } } // Método que se ejecuta cuando se marca o desmarca la casilla // de verificación Orden aleatorio. Actualiza la lista de // reproducción vListaTracks según corresponda. void AplicacionCDAudio::controlCheckRandom(void) { bRandom = !bRandom; if(bRandom) generarListaAleatoriaTracks(); else generarListaTracks(); } // Método que se ejecuta cuando se marca o desmarca la casilla // de verificación Repetir. Actualiza el atributo de estado bRepetir // que indica si la casilla está marcada o no. void AplicacionCDAudio::controlCheckRepetir(void) { bRepetir = !bRepetir; } // Método que genera la lista de tracks a reproducir en el mismo orden // que se encuentran en el CD. void AplicacionCDAudio::generarListaTracks(void) { int auxTrackActual; // Se ha de almacenar el track actual para actualizar su posición // en la nueva lista de reproducción. if(iTrackActual < vListaTracks.size()) auxTrackActual = vListaTracks[iTrackActual]; else auxTrackActual = 0; vListaTracks = std::vector<int>(NumeroDeTracks()); for(int i = 0; i < vListaTracks.size() ; i++) { vListaTracks[i] = i+1; if (i+1 == auxTrackActual) iTrackActual = i; // Se actualiza la posición del track actual } } // Método que genera la lista de tracks a reproducir en un orden // aleatorio. void AplicacionCDAudio::generarListaAleatoriaTracks(void) { int auxTrackActual; // Se ha de almacenar el track actual para actualizar su posición // en la nueva lista de reproducción. if(iTrackActual < vListaTracks.size()) auxTrackActual = vListaTracks[iTrackActual]; else auxTrackActual = 0; vListaTracks = std::vector<int>(NumeroDeTracks()); int i = 0; // Se introducen los tracks en la lista en orden aleatorio while(i < vListaTracks.size()) { int aux = rand() % vListaTracks.size() + 1; // Se ha de comprovar que el track escogido aleatoriamente // no este ya en la lista de reproducción antes de añadirlo. bool bYaEsta = false; int j = 0; while (j < i && !bYaEsta) { bYaEsta = vListaTracks[j] == aux; j++; } if(!bYaEsta) { vListaTracks[i] = aux; if (aux == auxTrackActual) iTrackActual = i; i++; } } } // Método que actualiza la lista de reproducción vListaTracks y la // ventana de diálogo hDlg según el contenido del CD y las casillas // de verificación. void AplicacionCDAudio::reset(void) { bPausa = false; bPlaying = false; if(NumeroDeTracks() < 1) { iTrackActual = -1; SetDlgItemText(hDlg,IDC_EDIT_TRACK_ACTUAL,""); vListaTracks = std::vector<int>(); SetDlgItemText(hDlg,IDC_BUTTON_PLAY_PAUSA,"Play"); } else { if(bRandom) generarListaAleatoriaTracks(); else generarListaTracks(); iTrackActual = 0; char wsTrack[5]; wsprintf(wsTrack,"%i",vListaTracks[iTrackActual]); SetDlgItemText(hDlg,IDC_EDIT_TRACK_ACTUAL,wsTrack); SetDlgItemText(hDlg,IDC_BUTTON_PLAY_PAUSA,"Play"); } } // Función de atención a las interrupciones del dispositivo. void AplicacionCDAudio::intProcedure(int wParam) { // Si la petición de reproducción ha finalizado correctamente // y hay que reproducir más canciones reproduce la siguiente // utilizando el método botonSiguiente(). if(wParam == MCI_NOTIFY_SUCCESSFUL) { if(iTrackActual+1 < vListaTracks.size() || bRepetir) { if(bResume) bResume = false; else botonSiguiente(); } } // Si la petición no ha finalizado correctamente se comprueba // que no se haya quitado el CD (o sustituido) y si es así se // actualiza la lista de reproducción y la ventana de diálogo. else if(NumeroDeTracks() != vListaTracks.size()) { reset(); } }