/*      K L A T T  . C                                 */
/*      program to drive Klatt's PARWAVE routine       */
/*      adapted to SPARCSTATION.                       */
/*      10 April 1991                                  */
/*                                                     */
/*      Aaron Smith                                    */
/*      Brown University                               */
/*      Adapted from a version by                      */
/*      L. Goldstein, S. Levy                          */

/****************************************************************************/


#include "klsyn.h"
#include <stdio.h>
#include <curses.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <ctype.h>

#include "/usr/demo/SOUND/multimedia/libaudio.h"
#include "/usr/demo/SOUND/multimedia/audio_filehdr.h"
#include "/usr/demo/SOUND/multimedia/ulaw2linear.h"

#define NUM_SET_PARS 20

#define SAMP_RATE 8000

#define NMSPF_DEF 10
#define NF_DEF 20
#define MAX_SAM 10000
#define NFRAMES 20
#define NFRAMES_PER_PAGE 20
#define NSAMP_PER_BLOCK 256
#define MIDSCALE 2048
#define BOOLEAN int
#define MAX_PLA 100000
#define NCHANGE 20
#define SWITCH 5
#define BADVAL 99
#define CR 13
#define ZERO 48
#define NINE 57
#define BACKSPACE 8
#define NPARTOT 47

/****************************************************************************/

/* default values for pars array from .doc file */
        long def_pars[NPAR] = {
                1000,    60,
                500,     60,
                1500,    90,
                2800,    150,
                3250,    200,
                3700,    200,
                4990,    500,
                280,     90,
                280,     90,
                0,       30,
                0,       0,
                0,       0,
                0,       80,
                0,       200,
                0,       350,
                0,       500,
                0,       600,
                0,       800,
                0,       0,
                0,       66
        };

/****************************************************************************/

/*  index array = pointers to items in def_pars sorted by order in con_file */

        static int  index[]= { 7, 8,14,22,15,23,16,24,17,25,
                              18,26,19,27,20,28,21,29, 9,11,
                              10,12,30,13,31,38,32,39,33,40,
                              34,41,35,42,36,43,45,37,44,46};


/****************************************************************************/ 

/* header for parameter listing */

char *par_header[] = {
  "#", 
  "F0",
  "F1",
  "F2",
  "F3",
  "B1",
  "B2",
  "B3",
  "FNZ",
  "FNP",
  "AV",
  "TL",
  "AH",
  "AF",
  "A1",
  "A2",
  "A3",
  "A4",
  "A5",
  "A6",
  "AB"};
/****************************************************************************/


/*    Speaker Definition */
        long spkrdef[] = {
                   0,   /* OUTSELECT (Select which output waveform to save)  */
                SAMP_RATE,   /* SAMRAT                                       */
                80,   /* NSAMP_PER_FRAME (= SAMRAT * N_MSEC_FRAME) / 1000) */
/* Not used */   900,   /* FLPHZ dwnsampling low-pass filter, glottal source */
/* Not used */   600,   /* BLPHZ dwnsampling low-pass filter, glottal source */
                   1,   /* RANSEED (Initial value for variable "nrand")      */
                   5,   /* NFCASC (Number formants in cascade vocal tract)   */
                   1,   /* SOURCE_SELECT (1->impulse, 2-> natural            */
        };

/****************************************************************************/

/* globals */

        FILE *par_file, *ascii_file, *ascii_file2, *t_file;
        int file, mode, length, status;
        long sigmx;
        short iwave[MAX_SAM];
        int nsamtot, isam, totsam;
        int icount, par_count;   
        short header[NSAMP_PER_BLOCK];
        char *bufp;
        int ibuf;
        char name[12]; 
        short par_array[NPAR] [MAX_FRAMES];    /* parameter buffer */
        short inflect[MAX_FRAMES];             /* needed for interpolation */
        char choice;
        int data_exist = 0;
        unsigned char plabuf[MAX_PLA];
static int change[NUM_SET_PARS]={0,2,4,6,3,5,7,14,16,1,21,18,22,24,26,28,30,32,34,37};
        char string[3], nstring[5];
        long pars[NPAR];
        long initsw, warnsw, dispt, disptcum;
        int nframes, dur_of_stim, nmsec_per_frame;
        static int con_file[NPARTOT];
char   *Info = NULL;
int     Ilen = 0;

int  bDebug=0;
FILE *debug1,*debug2;

/****************************************************************************/

main(argc,argv)
int argc;
char *argv[];  
{
  short temp;

  if (argc == 2) {
    if (!strcmp(argv[1],"-d"))
      bDebug = 1;
  }

  if (bDebug) {
    debug1 = fopen("d1.dat","w+");
    debug2 = fopen("d2.dat","w+");
  }

  initscr();
  cbreak(); 
  noecho();

  if (bDebug) 
    if ((ascii_file = fopen ("test_data", "w+")) == NULL) {
      perror("Error: ");
      printf("Ascii file not saved\n");
      return;
    }

  system ("clear");
  printf("\nHello, Welcome to the KLATT synthesizer\n");
  nframes = NF_DEF;
  nmsec_per_frame = NMSPF_DEF;
  dur_of_stim = nframes*nmsec_per_frame - nmsec_per_frame;
  init_par_array();

  do {
    printf("\n\n\n\nYour options are:");
    printf("\n  C   Compute waveform");
    printf("\n  L   List parameters");
    printf("\n  P   Play speech"); 
    printf("\n  R   Read parameter file");
    printf("\n  S   Save waveform and parameter files"); 
    printf("\n  F   read config File and reset parameters to new defaults");
    printf("\n  V   show Values of current configuration");
    printf("\n  D   reset parameters to current Defaults"); 
    printf("\n  N   Change number of msec per frame");
    printf("\n  X   Exit");
    printf("\n\n==>");
    choice = getch();
    printf("%c\n",choice);
    choice = toupper(choice);

    if (choice == 'S')
      save_files();  

    if (choice == 'C') {
      ibuf = 0;
      nsamtot = 0;
      initsw = 0; 
      warnsw = 0;
      dispt = 0;
      disptcum =0;

      for (icount=0; icount< nframes; icount++) {
        for (par_count = 0; par_count < NPAR; ++par_count)
          pars[par_count] = par_array[par_count] [icount];
        nsamtot = 0; 
        parwav (&iwave[nsamtot]); 
        for (isam = 0; isam < NSAMP_PER_FRAME; ++ isam) {  
          temp = iwave[isam];
          if (temp == 0)
            temp = 1;
          if (bDebug) 
            fprintf(ascii_file,"%hd\n",temp);
          plabuf[ibuf] = audio_s2u(iwave[isam]); 
          ibuf++;
        }

        data_exist = 1;
        totsam = ibuf;
      }
      fclose(ascii_file);
    }
    if (choice == 'P') {
      printf("Play: %d samples\n",totsam);
      hplay(totsam,0);
      echo();
      printf("Press any key to continue\n");
      noecho();
      getch();
    }

    if (choice == 'L') list();
    if (choice == 'R') read_pars();
    if (choice == 'D') init_par_array();
    if (choice == 'F') con_read();
    if (choice == 'V') { 
        pr_pars();
        printf ("\n HIT ANY KEY TO CONTINUE.");
        getchar();
    }
    if (choice == 'N') change_nmspf();
    if (choice == 'X') {
      printf("\n \nQuit KLATT ? ");
      choice = getch();
      choice = toupper(choice);
      if (choice == 'Y') choice = 'X';
      else choice = ')';
    }
    system ("clear");
  } while (choice != 'X');
}

/****************************************************************************/ 

/* open waveform file for output. prompts user for file name, and opens it for
   output, returning file pointer.  prints error message and returns NULL
   if file could not be opened */

w_open_output() 
{    int pmode; 

     printf("\n enter name of output file >");
     echo();
     scanf("%s", name);
     noecho();
     mode = O_WRONLY | O_CREAT;
     pmode = S_IREAD | S_IWRITE;
     file = open (name, mode, pmode);
}

/****************************************************************************/


/* open file for input. prompts user for file name, and opens it for
   input, returning file pointer.  prints error message and returns NULL
   if file could not be opened */

open_input() 
{ int pmode; 

     printf("\n enter name of input file >");
     echo();
     scanf("%s", name);
     noecho();
     mode = O_RDONLY ;
     pmode = S_IREAD | S_IWRITE;
     file = open (name, mode, pmode);
}

/****************************************************************************/

p_buf ()        /* write a buffer of parameters to a file  */
{
     int i, j;
     FILE *p_file;

     strcat(name,".par");
     p_file = fopen(name,"w");
     for (i=0; i<nframes; i++) {    
       for (j=0; j<NUM_SET_PARS; j++) {
         fprintf (p_file," %4d", par_array [change[j]] [i]);
       }
       fprintf(p_file,"\n");
     }
     fclose(p_file);
}

/****************************************************************************/

/* initialize the array of user-modified parameters to the defaults in
   the parameter buffer */

init_par_array()

{
    int i, j; 

     
    for (i = 0; i < NPAR; ++i) {
       pars[i] = def_pars[i];
       for (j = 0; j < MAX_FRAMES; ++j) 
          par_array[i] [j] = pars[i];
    }      
}
/* list parameter values  */

list ()
{
   int i, j, npages, start, finish = 0;
   char quit = ' ';

   npages = nframes/NFRAMES_PER_PAGE;
   for (i=1; (i<=npages && quit != 'Q'); ++i) {
     clear();
     start = finish;
     finish = i*NFRAMES_PER_PAGE;
     list_page(start,finish);
     if (nframes > finish) 
       printf ("\n Type Q to quit, any other key to continue listing");
     else 
       printf ("\n Type any key to return to menu");
     quit = getch();
     quit = toupper(quit);
   }
   if (nframes > finish && quit != 'Q') {
     clear();
     start = finish;
     finish = nframes;
     list_page(start,finish);
     printf("\n Type any key to return to menu");
     getch();
   }
}
/****************************************************************************/

/* list one page of parameter values */

list_page(start,finish)
int start, finish;
{
   int i, j;

   if (start*nmsec_per_frame < 1000) printf("\n mS");   /* display header */
   else printf("\n  mS");
   for (j=0; j<SWITCH; j++) {
     printf (" %4s", par_header[j+1]);
   }
   for (j=SWITCH; j<SWITCH+3; j++) {
     printf ("%3s ", par_header[j+1]);
   }
   for (j=SWITCH+3; j<NCHANGE; j++) {
     printf ("%2s ", par_header[j+1]);
   }
   
   for (i=start; i<finish; i++) {                     /* display parameters */
      printf ("\n%3d",i*nmsec_per_frame);
      for (j=0; j<SWITCH; j++) {
        printf (" %4d", par_array [change[j]] [i]);
      }
      for (j=SWITCH; j<NCHANGE; j++) {
        printf (" %2d", par_array [change[j]] [i]);
      }
   }
}
/****************************************************************************/

/* input a string from keyboard until user hits <CR> */

_getstr(){

  int i = 0;
  do {
    string[i] = getchar();
    string[i] = toupper(string[i]);
    if (string[i] == BACKSPACE) i -= 2;
    ++i;} while (string[i-1] != CR);
  string[i-1] = '\0';
}
/****************************************************************************/

/* same as above, but convert string to integer */

getnum(){

  int i = 0;
  do {
    nstring[i] = getchar(nstring[i]);
    if ((nstring[i] >= ZERO && nstring[i] <= NINE) || (nstring[i] == CR) || (nstring[i] == BACKSPACE)) { 
      if (nstring[i] == BACKSPACE) i -= 2;
      ++i;
     } 
   }  while (nstring[i-1] != CR);
  nstring[i-1] = '\0';
}
/****************************************************************************/

/* save waveform and parameter files */

save_files()

{
  int pmode,i=0;
  Audio_hdr header;
  char buf[20];

  get_string_data("\n enter name of output file >",name);
  sprintf(buf,"%s.dat",name);
  if ((ascii_file = fopen (buf, "w+")) == NULL) {
    perror("Error: ");
    printf("Ascii file not saved\n");
    return;
  }
  while (i++ < totsam-1) {
    fprintf(ascii_file,"%d\n",audio_u2s(plabuf[i])/2); 
  }
  fclose(ascii_file);

  sprintf(buf,"%s.xgr",name);
  if ((ascii_file = fopen (buf, "w+")) == NULL) {
    perror("Error: ");
    printf("Ascii file not saved\n");
    return;
  }
  i=0;
  while (i++ < totsam-1) {
    fprintf(ascii_file,"%d %d\n",i,audio_u2s(plabuf[i])/2); 
  }
  fclose(ascii_file);

#if FALSE
  sprintf(buf,"%s.au",name);
  mode = O_WRONLY | O_CREAT;
  pmode = S_IWRITE | S_IREAD;
  if ((file = open (buf, mode, pmode)) == -1) {
    perror("Error: ");
    printf("File not saved\n");
    return;
  }
  header.sample_rate = SAMP_RATE;
  header.samples_per_unit = 1;
  header.bytes_per_unit = 1;
  header.channels = 1;
  header.encoding = AUDIO_ENCODING_ULAW;
  header.data_size = totsam;
  if ((status = audio_write_filehdr(file,&header, Info, Ilen)) != AUDIO_SUCCESS){
    printf("error in writing audio file header\n");
    return;
  }

  status = write(file,plabuf,totsam);
  if (status < 0) 
    perror ("\n Error in writing file: ");

  status = close(file); 
#endif
  p_buf();
}

/****************************************************************************/
get_string_data(text,store)
char *text;
char *store;
{
  nocbreak();
  echo();
  printf(text);
  scanf("%s",store);
  noecho();
  cbreak();
}
/****************************************************************************/

/* read parameter values from a file into the parameter array */

read_pars()
{
     int i = 0, j, numread, dummy;
     FILE *p_file;
     char *out_name;

     get_string_data("Name of Parameter file: ",name);
     strcat(name,".par");
     out_name = &name[0];

     if ((p_file = fopen(name,"r")) == NULL) {
       printf("\n COULDN'T OPEN %s",out_name);
       printf("\n Hit any key to return to menu");
       getch();
     }

     else {
       do {
         for (j=0; j<NUM_SET_PARS && numread != EOF; j++) {
           numread = fscanf (p_file,"%d", (int *) &dummy);
           par_array [change[j]] [i] = dummy;
         }
         ++i;
       } while (numread != EOF);
       nframes = i - 1;
       dur_of_stim = nframes*nmsec_per_frame - nmsec_per_frame;
       fclose(p_file);
       printf("\n\n NEW # OF FRAMES:        %d",nframes);
       printf("\n Hit any key to return to menu ");
       getch();
     }
} 

/****************************************************************************/

/* read a configuration file */

con_read () {

     int i,j;
     FILE *p_file;
     char junk[30];
     char *out_name;

     get_string_data("\n Enter name of configuration file to read > ",name);
     strcat(name,".con");
     out_name = &name[0];
     if ((p_file = fopen(name,"r")) == NULL) {
       printf("\n COULDN'T OPEN %s",out_name);
       printf("\n Hit any key to return to menu");
       getch();
     }
     else {
         for (i=0; i<NPARTOT; i++) {
           fscanf (p_file, "%s %d", junk, &con_file[i]); 
         }
         SAMRAT = con_file[0];
         nmsec_per_frame = con_file[2];
         NSAMP_PER_FRAME  = SAMRAT * nmsec_per_frame / 1000;
         dur_of_stim = con_file[1];
         nframes = dur_of_stim / nmsec_per_frame;
         OUTSELECT = con_file[6];
         RANSEED = con_file[5];
         NFCASC = con_file[3];
         SOURCE_SELECT = con_file[4];
      
         for (i=0; i<NPAR; i++) {
           def_pars[i] = con_file[index[i]];
         }
         init_par_array();
         pr_pars();

         printf ("\n\n HIT ANY KEY TO CONTINUE.");
         getch();
     }
}

/****************************************************************************/

/* graph a single parameter or F0 through F5 over time */


int length_flag = 0;   

toggle_length()   {

     if (length_flag == 0) {
       spkrdef[6] = 4;
       def_pars[8]= 3700;
       init_par_array();
       printf ("\n vocal tract is now short (nf=4, F4=3700).");
       printf ("\n press any Key to continue");
       getch();
       length_flag = 1;
       return;
    }
     else {
       spkrdef[6] = 5;
       def_pars[8]= 3200;
       init_par_array();
       printf ("\n vocal tract is now long (nf=5, F4=3200).");
       printf ("\n press any Key to continue");
       getch();
       length_flag = 0;
    }


}


change_nmspf()
{
    int val;

    system("clear");
    printf("\n\n\n\n\n CURRENT # OF FRAMES:        %d",nframes);
    printf("\n CURRENT MSEC PER FRAME:     %d",nmsec_per_frame);
    printf("\n CURRENT TOTAL TIME IN MSEC: %d",nframes*nmsec_per_frame);
    printf("\n Enter new msec per frame > ");
    getnum();
    if (strlen(nstring) != 0) {
      val = atoi(nstring);
      nmsec_per_frame = val;
    }
    spkrdef[2] = (spkrdef[1]*nmsec_per_frame)/1000;
    dur_of_stim = nframes*nmsec_per_frame - nmsec_per_frame;
    printf("\n NEW MSEC PER FRAME:     %d",nmsec_per_frame);
    printf("\n NEW TOTAL TIME IN MSEC: %d",nframes*nmsec_per_frame);
    printf("\n\n Okay? ");
    choice = getch();
    choice = toupper(choice);
    if (choice != 'Y') change_nmspf();
}
