Un pantallazo

Orden de los procesos y el main

Primero trataremos de explicar, sin hablar como trabajan, las funciones más importantes usadas en textura y en que orden son llamadas.

La entrada principal, como es obvio, está en el main y las llamadas se harán desde aquí. A través de la línea de comandos obtenemos todos los datos necesarios para generar los eventos y crear el audio de salida.

Antes de hacer nada, inicializamos sndlib y preparamos el archivo de audio para la salida. Usamos la función AbrirAudioSalida. Si éste proceso sale bien, seguimos adelante, de otro modo salimos del main.

Una vez preparado el audio, creamos los eventos. LLamamos a ConstruirObra que toma los parámetros de eventos pasados por el usuario. Ésta función llama a GenComienzos, quien devuelve un arreglo de valores conteniendo los comienzos de cada evento en segundos desde el inicio de la obra, y un entero con la cantidad de eventos generados. Luego, aún dentro de ConstruirObra, llamamos a GenParametros varias veces para generar los restantes parámetros, usando los datos de usuario y la cantidad de eventos como argumentos. Dicha función siempre devuelve un arreglo de valores, en cada caso se interpretan como un parámetro específico de los eventos. ConstruirObra termina devolviendo un puntero a un arreglo de estructuras EVENTO con todos los eventos generados.

Ahora podemos saber la duración real del audio, así como la cantidad de muestras que tiene por canal. Estos datos los guardamos en una estructura DAUDIO y usamos para ello la función CompletarDatosAudio.

Teniendo la información de la cantidad de muestras, podremos crear un bufer de memoria cuya primera dimensión es la cantidad de canales que tiene el archivo de audio y la segunda, la cantidad de muestras por canal. Usamos para ello la función SndAsignarMemoria debido a que se usan funciones específicas de sndlib.

Con el audio abierto y los eventos generados llamamos a ProcesarEventos que guardará todos los eventos en el archivo de audio.

Todo el trabajo está hecho, sólo nos queda liberar la memoria creada en el bufer con SndLiberarMemoria, cerrar el audio, y liberar la memoria creada dinámicamente para los eventos.

Información al usuario

A medida que se completan ciertos procesos, daremos alguna información en pantalla al usuario para que verifique que todo va bien.

Código del main

int main(int argc, char **argv)
{
  /* en el futuro, se llena a partir de los datos del usuario */
  PARAMETROS  pars = {50, {.7, 1.7}, {1.5, 2.5}, {2, 9}, {100, 500}, {0.0, 1.0}}; 
  EVENTO *evs;                           /* una tabla de eventos sonoros */
  int cant;                              /* cantidad de eventos generados */
  mus_sample_t **sbuf;                   /* bufer de salida para el audio */

    /* 
    creo una estructura que será llenada con datos de la cabecera del audio
    algunos datos son iniciados a -1 porque no son necesarios todavía, y dependen de otros datos
    */
  DAUDIO au_sal = {-1, NUM_CANALES, FREC_MUES, -1, -1, -1, MUS_BSHORT, MUS_NEXT, "escrito por textura"};

  RotuloDeInicio();                             /* muestro el rotulo de la aplicación */

  mus_sound_initialize();                         /* inicializo sndlib */
  AbrirAudioSalida(argv[1], &au_sal);             /* abro el audio de salida */
  if(au_sal.na == -1)                             /* ¿todo bien? */
    return -1;

    /* GENERACIÓN DE EVENTOS  -----------------------*/
  srand((unsigned)time(NULL));
  evs = ConstruirObra(&pars, &cant);
    /* FIN GENERACIÓN DE EVENTOS  -------------------*/

    /* termino de llenar los datos de la estructura DAUDIO */
  CompletarDatosAudio(&au_sal, evs, cant);

    /* creo el bufer de audio */
  sbuf = SndAsignarMemoria(&au_sal);

    /* proceso los eventos y los guardo en el audio de salida */
  ProcesarEventos(&au_sal, evs, cant, sbuf);

    /* una vez terminado todo, imprimo la cabecera del audio */
  ImprDatosDeAudio(argv[1], &au_sal, "\nAUDIO DE SALIDA");
  printf("\nCantidad de eventos: %i\n", cant);

  SndLiberarMemoria(&au_sal, sbuf);
  close(au_sal.na);
  free(evs);
  return 0;
}

Función CompletarDatosAudio

Completa los datos que faltan en la estructura DAUDIO, los cuales son la duración total del audio, la cantidad de muestras por canal y el total de muestras.

Código

void CompletarDatosAudio(DAUDIO *au, EVENTO *evs, int tam)
{
  /* primero debo encontrar cual es el último valor */
  double temp, ultimo = 0.0;   /* el último lugar en segundos */
  int i;
  for(i = 0; i < tam; i++)
    {
    temp = evs[i].comienzo + evs[i].duracion;
    if(temp > ultimo)
      ultimo = temp;
    }
  au->mu_can =  ultimo * FREC_MUES;
  au->muestras = au->mu_can * au->canales;
  au->duracion = (double)au->mu_can / (float)au->frec_muestreo;
}

  Inicio  Siguiente
    Definiciones