Version:0.9 StartHTML:0000000105 EndHTML:0000045764 StartFragment:0000000152 EndFragment:0000045730
/******************************************************/
/*************** Isidro Pastor Jorda ******************/
/******************************************************/
/****************** Telematica ************************/
/******************** FPII ****************************/
/****************** Practica 5 ************************/
/******************************************************/

#include "Pasaje.h"
#include <fstream.h>
#include <string>
#include <windows.h>   // uso de la funcion beep para reproducir la musica

const float frec[2][13]={
{262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 0},
{523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 0} };

const float dura[5]={1.0, 2.0, 4.0, 0.5,0.25};
const int tiempobase = 1000 ; //Equivale a 1s como tiempo base

/*****************************************************************************
* Funcion: IntroNota
* Descripcion: Introduce una nota de tipo Valor en el objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*   n           E         Dato que queremos introducir en el pasaje
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

void Pasaje::IntroNota(Valor n)
{
    while ( !(lst.FinalLista()) ) // Solo introducimos nota en un pasaje luego siempre lo haremos al final
        lst.Avanzar();
    lst.Insertar(n);              // Una vez situados al final insertamos la nota
};

/*****************************************************************************
* Funcion: EliminarNota
* Descripcion: elimina una nota de tipo Valor en el objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
* idno          E         id de la nota que queremos eliminar del pasaje
*
*
*
* Valor devuelto:
*       True si se ha podido eliminar, false en caso contrario
*****************************************************************************/

bool Pasaje::EliminarNota(int idno)
{
    bool ok;

    ok = BuscarIdNota(idno);
    if (ok) // Posicionamos el punto de interes en la nota que queremos eliminar
        lst.Eliminar();    // y la eliminamos
    else
        cerr << " El identificador de nota introducido no se encuentra en el pasaje/melodia\n";
    return (ok);
};

/*****************************************************************************
* Funcion: Visualizar
* Descripcion: Muestra por pantalla los elementos del objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

void Pasaje::Visualizar()
{
    Valor aux;

    lst.IrAInicio();
    lst.Consulta(aux);
    cout << " IDNOTA    OCTAVA    NOTA     DURACION   \n" ;
    while ( !(lst.FinalLista()) )
    {
         cout << " " <<  aux.iden << " ";  // Mostramos primero el id de nota

         if (aux.nota == Tiponota(12) )    // Si la nota es un silencimo mostraremos una S
             cout << " S ";
         else
             cout << " " << int(aux.octava) + 1 << " " ;  // Si no es silencio entonces mostramos la octava

         switch ( int(aux.nota) ) // Para estar seguros de que tenemos un entero lo explicitamos aunque no es necesario
         {
             case 0:
                  cout << "Do   ";
                  break;
             case 1:
                  cout << "Do#  ";
                  break;
             case 2:
                  cout << "Re   ";
                  break;
             case 3:
                  cout << "Re#  ";
                  break;
             case 4:
                  cout << "Mi   ";
                  break;
             case 5:
                  cout << "Fa   ";
                  break;
             case 6:
                  cout << "Fa#  ";
                  break;
             case 7:
                  cout << "Sol  ";
                  break;
             case 8:
                  cout << "Sol# ";
                  break;
             case 9:
                  cout << "La   ";
                  break;
             case 10:
                  cout << "La#  ";
                  break;
             case 11:
                  cout << "Si   ";
                  break;
             case 12:
                  cout << "     ";
                  break;
             default:
                 cout << "     ";
                 break;

         };

         switch ( int(aux.duracion) ) // y despues de mostrar la nota mostramos la duracion de la misma
         {
             case 0:
                  cout << " ne ";
                  break;
             case 1:
                  cout << " bl ";
                  break;
             case 2:
                  cout << " re ";
                  break;
             case 3:
                  cout << " co ";
                  break;
             case 4:
                  cout << " sc ";
                  break;
             default:
                  cout << "    ";
                  break;
         };
         cout << endl;
         lst.Avanzar();      // Avanzamos el punto de interes una posicion en la lista
         lst.Consulta(aux);  // y volvemos a consultar el dato siguiente
    } // while
};

/*****************************************************************************
* Funcion: LimpiarPasaje
* Descripcion: Elimina todos los elementos del objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

void Pasaje::LimpiarPasaje()
{
    lst.IrAInicio();           // Vamos al inicio del pasaje
    while(!lst.ListaVacia())   // y empezamos a borrar todo hasta que tengamos una lista vacia
       lst.Eliminar();
};

/*****************************************************************************
* Funcion: Tocar
* Descripcion: Reproduce mediante el PCSpeaker los datos del objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

void Pasaje::Tocar()
{
    Valor aux;
    lst.IrAInicio();      // Reproduciremos empezando desde el principio
    while( !lst.FinalLista() )
    {
        lst.Consulta(aux); // consultamos el dato y llamamos a la funcion beep para reproducirlo por el pcspeaker
        Beep(int(frec[aux.octava][aux.nota]), int(tiempobase * dura[aux.duracion]));
        lst.Avanzar();    // despues de tocar la nota avanzamos a la siguiente el punto de interes
    }
};

/*****************************************************************************
* Funcion: TocarAlreves
* Descripcion: Reproduce en orden inverso mediante el PCSpeaker los datos del
*              objeto que hace la llamada
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

void Pasaje::TocarAlreves()
{
    Valor aux;
    if (!lst.ListaVacia())     // si la lista no esta vacia
    {
        lst.IrAFinal();        // nos situamos al final de la lista
        while ( !lst.PrincipioLista() )  // y hasta que no estemos en el principio
        {
            lst.Consulta(aux);   // consultaremos el dato, lo reproduciremos ....
            Beep(int(frec[aux.octava][aux.nota]), int(tiempobase * dura[aux.duracion]));
            lst.Retroceder();    // y situaremos el punto de interes en la nota anterior de la lista
        }
        lst.Consulta(aux);    // Consultamos y tocamos el primer elemento de la lista
        Beep(int(frec[aux.octava][aux.nota]), int(tiempobase * dura[aux.duracion]));
    }
};

/*****************************************************************************
* Funcion: IntroPasaje
* Descripcion: Introduce un objeto pasaje en otro delante de una determinada
*              posicion modificando el id de la nota introducida para evitar
*              repeticiones de id dentro de la nueva melodia
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*  pas         E          Objeto cuyos elementos queremos introducir
*  idno        E          Posicion de la nota delante de la que queremos introducir los datos
*  idnota      E/S        contador de id de notas del programa principal
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

bool Pasaje::IntroPasaje(Pasaje pas, int idno, int & idnota) //Añade en una cierta posición
{
    bool ok;
    Valor aux;
    if (idno == 0)  // Si pasamos idno = 0 queremos insertar al principio de la melodia
    {
         lst.IrAInicio();
         cout << " Insertando el pasaje al inicio de la melodia ... \n";
         ok = true;
    }
    else
    {
        if (idno == -1) // si le introducimos un -1 entendemos que queremos insertar al final
        {
            ok = true;
            while ( !(lst.FinalLista()))
                lst.Avanzar();
        }
        else           // en caso de no ser ni 0 ni -1 buscamos el id de nota correspondiente
        {

            if (!BuscarIdNota(idno))     // si no encontramos ese id de nota daremos un error
            {
                cerr << " Error, no se ha encontrado ese id de nota\n";
                ok = false;
            }
            else     // si se ha encontrado entonces tendremos ya situado nuestro punto de interes
                ok = true;

        }  // else
    } // else

    if (ok)    // si todo ha ido bien en la busqueda del id nota tendremos el pto de interes bien situado
    {
        pas.lst.IrAInicio();   // nos situamos en el principio de la lista que vamos a introducir
        while( !(pas.lst.FinalLista()) ) // y repetiremos la operacion hasta completar toda la lista
        {
            pas.lst.Consulta(aux);   // consultaremos un dato y lo almacenaremos en aux
            aux.iden = idnota;       // modificamos el id de nota de ese aux para asegurarnos que es UNICO
            lst.Insertar(aux);       // Insertamos la nota en la melodia, objeto que hace la llamada a la funcion
            pas.lst.Avanzar();       // Avanzamos una posicion en la lista para seguir introduciendo la siguiente nota
            idnota++;
        }
    }
    return (ok);                     // si todo ha ido bien devolveremos true, false en caso contrario
};

/*****************************************************************************
* Funcion: EliminarPasaje
* Descripcion: Elimina del objeto que hace la llamada, y a partir de una nota
*              pasada como dato a la funcion, un determinado numero de notas.
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*  n           E          Numero de notas a eliminar
*  idno        E          Posicion de la nota a partir de la cual queremos eliminar
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

bool Pasaje::EliminarPasaje(int idno, int n)
{
    int i;
    bool ok;

    ok = BuscarIdNota(idno);       // buscamos el id nota a partir del que queremos eliminar

    if (ok)                       // si lo encontramos empezaremos a borrar elementos
    {
        for( i=0; i<n; i++)       // empezando por ese id de nota y hasta un total de n elementos
            lst.Eliminar();
    };

    return (ok);
};

/*****************************************************************************
* Funcion: BuscarIdNota
* Descripcion: Posiciona el punto de interes sobre una determinada nota
*
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
*  idno        E          id de la nota donde queremos posicionar el punto de interes
*
*
*
* Valor devuelto:
*       No devuelve nada
*****************************************************************************/

bool Pasaje::BuscarIdNota(int idno)
{
    bool ok;
    Valor aux;

    if (idno == 0)
       cerr << " El id nota 0 esta reservado para indicar el principio de un pasaje/melodia\n";
    else        // si no es el idnota reservado para el inicio del pasaje
    {
        lst.Consulta(aux);        // Consultaremos el dato donde esta ahora el pto de interes por si fuera ese
        if(aux.iden == idno)      // si tenemos suerte y lo es entonces ya hemos terminado
            ok = true;
        else                      // en caso contrario debemos empezar a buscar desde el principio del pasaje
        {
            lst.IrAInicio();      // Nos situamos al principio del pasaje
            lst.Consulta(aux);    // y consultamos el primer dato
            while(aux.iden != idno && !lst.FinalLista() ) // repetiremos lo siguiente hasta encontrarlo o llegar al final
            {
                lst.Avanzar();         // Avanzaremos
                lst.Consulta(aux);     // y consultaremos el siguiente elemento que se compara en el while
            };

            if (lst.FinalLista())     // si hemos salido del while por llegar al final de la lista
                ok = false;           // entonces no habremos encontrado el elemento buscado
            else
                ok = true;            // en caso contrario hemos salido por haber encontrado el elemento
        }
   }
   return(ok);
};

/*****************************************************************************
* Funcion: GrabarMelodia
* Descripcion: Graba los datos del objeto que hace la llamada en un fichero de texto
*              cuyo nombre se pasa como un parametro a la funcion junto con el
*              titulo de ese pasaje que se incluira a titulo informativo dentro
*              del fichero de texto para una mejor distincion de la melodia.
*
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
* fichero       E          string con el nombre del fichero que queremos grabar
* titulo        E          Titulo de la melodia que vamos a grabar
*
*
* Valor devuelto:
*       True si se ha grabado con exito el fichero, false en caso contrario
*****************************************************************************/

bool Pasaje::GrabarMelodia(string fichero, string titulo)
{
    ofstream f;
    Valor aux;
    bool ok;
    ok = true;

    f.open(fichero.c_str());

    if (!f)
    {
        cerr << " Error creando el fichero " << fichero << endl;
        ok = false;
    }
    else
    {
        f << ".Titulo: " << titulo << " Fichero datos musicales by Isidro Pastor & Noemi Ruth Moya" << endl;
        lst.IrAInicio();                    // Si hemos abierto el fichero correctamente vamos al inicio del pasaje
        while ( !(lst.FinalLista()) )
        {
             lst.Consulta(aux);             // Consultamos el dato y lo almacenamos en aux

             f << aux.octava << " " ;       // grabamos en el fichero la octava correspondiente a la nota

             switch (aux.nota)               // y la nota de la que se trata en modo texto
             {
                 case 0:
                      f << "Do ";
                      break;
                 case 1:
                      f << "Do# ";
                      break;
                 case 2:
                      f << "Re ";
                      break;
                 case 3:
                      f << "Re# ";
                      break;
                 case 4:
                      f << "Mi ";
                      break;
                 case 5:
                      f << "Fa ";
                      break;
                 case 6:
                      f << "Fa# ";
                      break;
                 case 7:
                      f << "Sol ";
                      break;
                 case 8:
                      f << "Sol# ";
                      break;
                 case 9:
                      f << "La ";
                      break;
                 case 10:
                      f << "La# ";
                      break;
                 case 11:
                      f << "Si ";
                      break;
                 case 12:
                      f << ". ";
                      break;
                 default:
                      f << ". ";
                      break;

             };

             switch (aux.duracion)         // seguida de la duracion
             {
                 case 0:
                     f << "ne";
                     break;
                 case 1:
                     f << "bl";
                     break;
                 case 2:
                     f << "re";
                     break;
                 case 3:
                     f << "co";
                     break;
                 case 4:
                     f << "sc";
                     break;
                 default:
                     f << ".";
                     break;
             };
             f << endl;               // terminaremos la introduccion de cada nota con un salto de linea
             lst.Avanzar();           // y avanzaremos el punto de interes para leer el siguiente dato y grabarlo
        } // while
    } // else
    return (ok);
};

/*****************************************************************************
* Funcion: LeerMelodia
* Descripcion: Lee los datos de un fichero de texto con el formato reconocido
*              por el programa y carga esos datos en el objeto que hace la
*              llamada.
*
*
*
*
* Parametros:
*
* Nombre        E/S       Descripcion
* ------       -----      -----------
* fichero       E          string con el nombre del fichero que queremos cargar
* idnota        E/S        contador para el id de las notas
*
*
* Valor devuelto:
*       True si se ha podido cargar correctamente el fichero, false en caso contrario
*****************************************************************************/

bool Pasaje::LeerMelodia(string fichero,int & idnota)
{
    ifstream f;
    string aux, aux2;
    Valor notaaux;
    int leer;
    bool ok;
    ok = true;

    int total = 0; //numero total de notas cargadas desde el fichero
    int idaux = idnota; // idnota inicial antes de introducir cualquier otra nota del fichero

    lst.IrAFinal(); // Nos situamos siempre al final de la lista para introducir el pasaje
    lst.Avanzar(); // y avanzamos una vez para introducir despues del ultimo elemento

    f.open(fichero.c_str());

    if (!f)
    {
        cerr << " Error abriendo el fichero " << fichero << endl;
        ok = false;
    }
    else
    {
        getline(f, aux);

      /****************************************************************************
       * Definiremos como estructura de nuestro fichero que comience por un punto *
       * de esta forma podremos, al menos en un principio, determinar si el       *
       * fichero al que estamos intentando acceder tiene un formato inteligible   *
       * por nuestro programa, en caso contrario mostrara que el formato del      *
       * fichero no es interpretable por el programa y abortara la carga del      *
       * archivo                                                                  *
       ****************************************************************************/

        if ( aux[0] == '.')  // Comprobamos que el primer caracter leido del fichero es un punto
        {
            f >> leer >> aux >> aux2;
            while(!f.eof() && ok)
            {
                notaaux.octava = Tipooctava(leer);
                notaaux.iden = idnota;

                switch ( int(aux[0]) )             // Comprobaremos el indice entero que tiene la primera letra de la nota
                {
                    case 68:                       // caso en que la primera letra es una D
                        if ( aux.find('#') != -1)
                            notaaux.nota = do_s;
                        else
                            notaaux.nota = do_;
                        break;
                    case 70:                       // caso en que la primera letra es una F
                        if ( aux.find('#') != -1)
                            notaaux.nota = fa_s;
                        else
                            notaaux.nota = fa;
                        break;
                    case 76:                       // caso en que la primera letra es una L
                        if ( aux.find('#') != -1)
                            notaaux.nota = la_s;
                        else
                            notaaux.nota = la;
                        break;
                    case 77:                       // caso en que la primera letra es una M
                        notaaux.nota = mi;
                        break;
                    case 82:                       // caso en que la primera letra es una R
                        if ( aux.find('#') != -1)
                            notaaux.nota = re_s;
                        else
                            notaaux.nota = re;
                        break;
                    case 83:                       // caso en que la primera letra es una S
                        if (aux != "Si")
                        {
                            if ( aux.find('#') != -1)
                                notaaux.nota = sol_s;
                            else
                                notaaux.nota = sol;
                        }
                        else
                            notaaux.nota = si;
                        break;
                    case 46:                       // caso que la letra sea un punto tendremos una pausa
                        notaaux.nota = pausa;
                        break;
                    default:
                        cerr << " Error cargando nota, Formato irreconocible\n";
                        ok = false;
                        break;
                };// switch


                switch (int (aux2[0]))   // comprobamos la primera letra del string de duracion
                {
                    case 110:                              // si es una "n" sera una negra
                        notaaux.duracion = negra;
                        break;
                    case 98:                               // si es una "b" sera una blanca
                        notaaux.duracion = blanca;
                        break;
                    case 114:                              // si es una "r" sera una redonda
                        notaaux.duracion = redonda;
                        break;
                    case 99:                              // si es una "c" sera una corchea
                        notaaux.duracion = corchea;
                        break;
                    case 115:                             // si es una "s" sera una semicorchea
                        notaaux.duracion = semicorchea;
                        break;
                    default:                              // si no es ninguna de las anteriores letras hay error
                        cerr << " Error cargando duracion, Formato irreconocible\n";
                        ok = false;
                        break;
                };// switch

                if(ok)   // si todo ha ido bien podremos introducir en la lista y seguir adelante
                {
                    idnota++;        // aumentaremos el id nota si hemos introducido la nota bien
                    total++;         // incrementamos el contador total de notas introducidas desde fichero
                    lst.Insertar(notaaux); // y finalmente insertamos la nota en nuestro pasaje
                    f >> leer >> aux >> aux2; // leemos la siguiente linea del fichero fuente de datos
                }
            } // while

        } //if
        else
            cerr << " El formato del fichero de notas no es correcto, no se puede cargar la melodia\n";

    f.close();

    }// else

     /**********************************************************************
      * Si se produjeron errores durante la carga del fichero, tendremos   *
      * una carga parcial en memoria del fichero hasta el momento donde    *
      * se produjo el error, y logicamente no queremos que esto ocurra     *
      * por lo tanto borraremos del pasaje a partir del idnota inicial     *
      * con el que se entra en la funcion almacenado en idaux, tantas      *
      * notas como hayamos leido satisfactoriamente del fichero, dato que  *
      * hemos ido almacenando en la variable total, por lo que al final    *
      * si tenemos errores no se notara modificacion alguna en la melodia  *
      * donde ibamos a cargar el fichero en caso de tener esta melodia     *
      * otros elementos ya cargados y reestablecemos el idnota inicial del *
      * programa para no desperdiciar id's de notas no usados              *
      **********************************************************************/

    if (!ok)
    {
        EliminarPasaje(idaux, total); // eliminamos las notas cargadas desde fichero
        idnota = idaux;           // restauramos el indice de id al valor inicial antes de la llamada a la funcion
    }

    return (ok);
};