/* Copyright (c) 2000-2003                             */
/*   Takao Kobayashi, Takashi Masuko, Masatsune Tamura */
/*   Tokyo Institute of Technology                     */
/*   Keiichi Tokuda, Takayoshi Yoshimura, Heiga Zen    */
/*   Nagoya Institute of Technology                    */
/*   All rights reserved                               */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "synthesis.h"
#include "confpara.h"
#include "defaults.h"
#include "misc.h"
#include "model.h"
#include "mlpg.h"
#include "vocoder.h"
#include "tree.h"
#include "hmmsynth.h"

int TmpMsg(char *,...);
int ErrMsg(char *,...);
void restart(int);

void init_hmmsynth()
{
  FILE *fp;
  int sid;

/* read tree file */
  for (sid = 0;sid < n_speaker; sid++)
    {
      fp = getfp (speaker[sid].dur_tree_file ,"r");
      ReadTreeFile (fp, DURATION, sid);
      fclose(fp);
      fp = getfp (speaker[sid].pit_tree_file ,"r");
      ReadTreeFile (fp, PITCH, sid);
      fclose(fp);
      fp = getfp (speaker[sid].mcep_tree_file ,"r");
      ReadTreeFile (fp, MCEP, sid);
      fclose(fp);

/* read model file */
      durmodel = getfp (speaker[sid].dur_model_file, "rb");
      pitchmodel = getfp (speaker[sid].pit_model_file, "rb");
      mcepmodel = getfp (speaker[sid].mcep_model_file, "rb");
      ReadModelFile (sid);
      fclose(durmodel);
      fclose(pitchmodel);
      fclose(mcepmodel);
    }

/* set delta window for mlpg */
  if ((pitchpst.dw.fn = (char **) calloc (sizeof (char *), 3)) == NULL)
    {
      ErrMsg("Memory allocation erorr !  (in init_hmmsynth)\n");
      exit(1);
    }

  pitchpst.dw.fn[1] = strdup (DELTAWIN);
  pitchpst.dw.fn[2] = strdup (ACCWIN);
  pitchpst.dw.num = 3;
  pitchpst.dw.calccoef = 0;
  pitchpst.vSize = pitchstream;
  InitDWin (&pitchpst);

  if ((mceppst.dw.fn = (char **) calloc (sizeof (char *), 3)) == NULL)
    {
       ErrMsg("Memory allocation error !  (in init_hmmsynth)\n");
       exit(1);
    }

  mceppst.dw.fn[1] = strdup (DELTAWIN);
  mceppst.dw.fn[2] = strdup (ACCWIN);
  mceppst.dw.num = 3;
  mceppst.dw.calccoef = 0;
  mceppst.vSize = mcepvsize;
  
  InitDWin (&mceppst);

  mceppst.order = mceppst.vSize / mceppst.dw.num - 1;
/* vocoder */
  init_vocoder (mceppst.order);
}

void refresh_hmmsynth()
{
  int i;
  Model *m,*next;

  if(f0.data == NULL)return;
  free (f0.data);
  free (power.data);
  free (alpha.data);
  free (wave.data);
  for (i = 0; i <= totalframe; i++)
    {
      free (mcep[i]);
      free (coeff[i]);
    }
  free(mcep);
  free(coeff);
  free(voiced);

  m = mhead;
  while (m)
    {
      next = m->next;
      free (m->name);
      free (m->durpdf);
      free (m->duration + 2);
      for ( i = 2; i<= nstate + 1; i++)
        {
           free (m->pitchmean[i] + 1);
           free (m->pitchvariance[i] + 1);
        }
      free (m->pitchpdf + 2);
      free (m->pitchmean + 2);
      free (m->pitchvariance + 2);
      free (m->voiced + 2);
      free (m->mceppdf + 2);
      free (m->mcepmean + 2);
      free (m->mcepvariance + 2);
      free (m);
      m = next;
    }
    mhead = mtail = NULL;
    refresh_vocoder();
}

char *id2str(int i)
{
  static char buff[5];

  if(i<0)
    return("x");
  else {
    sprintf(buff,"%d",i);
    return buff;
  }
}

void make_context_label (PHONEME *p,char *buff)
{
  MORA *mr;
  MORPH *mp;
  APHRASE *a;
  BREATH *b;
  SENTENCE *s;

  mr = p->parent;
  mp = mr->parent;
  a = mp->parent;
  b = a->parent;
  s = b->parent;

		/* phoneme-previous */
  if (mr->silence != SILB)
    sprintf (buff, "%s-", p->prev->phoneme);
  else 
    sprintf (buff, "x-");

		/* phoneme-center */
  sprintf (buff, "%s%s", buff, p->phoneme);

		/* phoneme-next */
  if (mr->silence != SILE)
    sprintf (buff, "%s+%s", buff, p->next->phoneme);
  else 
    sprintf (buff, "%s+x",buff);

		/* mora */
  sprintf (buff, "%s/A:", buff);
  if (mr->silence == NON)
    sprintf (buff, "%s%d_", buff, mr->position);
  else
    sprintf (buff, "%sx_", buff);
  if (mr->silence == NON)
    sprintf (buff, "%s%d", buff, mr->acdist);
  else
    sprintf (buff, "%sx", buff);

		/* morph-previous */
  sprintf (buff, "%s/B:", buff);
  if (mp->silence == SILB || mp->prev->silence == SILB)
    sprintf (buff, "%sx_x_x",buff);
  else if (mp->prev->silence == PAU) {
    sprintf (buff, "%s%s", buff, id2str(mp->prev->prev->hinshiID));
    sprintf (buff, "%s_%s", buff, id2str(mp->prev->prev->katsuyogataID));
    sprintf (buff, "%s_%s", buff, id2str(mp->prev->prev->katsuyokeiID));
  } else {
    sprintf (buff, "%s%s", buff, id2str(mp->prev->hinshiID));
    sprintf (buff, "%s_%s", buff, id2str(mp->prev->katsuyogataID));
    sprintf (buff, "%s_%s", buff, id2str(mp->prev->katsuyokeiID));
  }

		/* morph-center */
  sprintf (buff, "%s-", buff);
  if ( mp->silence == NON) {
    sprintf (buff, "%s%s", buff, id2str(mp->hinshiID));
    sprintf (buff, "%s_%s", buff, id2str(mp->katsuyogataID));
    sprintf (buff, "%s_%s", buff, id2str(mp->katsuyokeiID));
  } else
    sprintf(buff, "%sx_x_x", buff);

		/* morph-next */
  sprintf(buff, "%s+", buff);
  if (mp->silence == SILE || mp->next->silence == SILE)
    sprintf (buff, "%sx_x_x", buff);
  else if (mp->next->silence == PAU) {
    sprintf (buff, "%s%s", buff, id2str(mp->next->next->hinshiID));
    sprintf (buff, "%s_%s", buff, id2str(mp->next->next->katsuyogataID));
    sprintf (buff, "%s_%s", buff, id2str(mp->next->next->katsuyokeiID));
  } else {
    sprintf (buff, "%s%s", buff, id2str(mp->next->hinshiID));
    sprintf (buff, "%s_%s", buff, id2str(mp->next->katsuyogataID));
    sprintf (buff, "%s_%s", buff, id2str(mp->next->katsuyokeiID));
  }

		/* aphrase-previous */
  sprintf (buff, "%s/C:", buff);
  if (a->silence == SILB || a->prev->silence == SILB)
    sprintf (buff, "%sx_x", buff);
  else if (a->prev->silence == PAU)
    sprintf (buff, "%s%d_%d", buff, a->prev->prev->nmora,
             a->prev->prev->accentType);
  else
    sprintf (buff, "%s%d_%d", buff, a->prev->nmora, a->prev->accentType);
  sprintf (buff, "%s_x", buff);
  if ( a->silence == NON)
    {
      if (a->prev->silence == PAU)
        sprintf (buff, "%s_1", buff);
      else
        sprintf (buff, "%s_0", buff);
    }
  else
    sprintf (buff, "%s_x", buff);

		/* aphrase-center */
  sprintf (buff, "%s-", buff);
  if ( a->silence == NON)
    sprintf (buff, "%s%d_%d_x_%d_%d", buff, a->nmora, a->accentType, a->position, a->interrogative);
  else
    sprintf(buff, "%sx_x_x_x_x", buff);
  sprintf(buff, "%s+", buff);

		/* aphrase-next */
  if (a->silence == SILE || a->next->silence == SILE)
    sprintf (buff, "%sx_x", buff);
  else if (a->next->silence == PAU)
    sprintf (buff, "%s%d_%d", buff, a->next->next->nmora, a->next->next->accentType);
  else
    sprintf (buff, "%s%d_%d", buff, a->next->nmora, a->next->accentType);
  sprintf (buff, "%s_x", buff);
  if ( a->silence == NON)
    {
      if (a->next->silence == PAU)
        sprintf (buff, "%s_1", buff);
      else
        sprintf (buff, "%s_0", buff);
    }
  else
    sprintf (buff, "%s_x", buff);

		/* breath-prev */
  sprintf (buff, "%s/D:", buff);
  if (b->silence == SILB || b->prev->silence == SILB)
    sprintf (buff, "%sx", buff);
  else if (b->prev->silence == PAU)
    sprintf (buff, "%s%d", buff, b->prev->prev->nmora);
  else
    sprintf (buff, "%s%d", buff, b->prev->nmora);

		/* breath-center */
  sprintf (buff, "%s-", buff);
  if (b->silence == NON)
    sprintf (buff, "%s%d_%d", buff, b->nmora, b->position);
  else if (b->silence == PAU)
    sprintf (buff, "%sx_%d", buff, b->prev->position);
  else 
    sprintf (buff, "%sx_x", buff);
  sprintf (buff, "%s+", buff);

		/* breath-next */
  if (b->silence == SILE || b->next->silence == SILE)
    sprintf (buff, "%sx", buff);
  else if (b->next->silence == PAU)
    sprintf (buff, "%s%d", buff, b->next->next->nmora);
  else
    sprintf (buff, "%s%d", buff, b->next->nmora);

		/* sentence */
  sprintf (buff, "%s/E:", buff);
  sprintf (buff, "%s%d", buff, s->nmora);

#ifdef PRINTDATA
  TmpMsg("%s\n",buff);
#endif
}

void init_parameter(){
  PHONEME *ph;
  char label[1024];
  if((mhead = (Model *) calloc (1, sizeof (Model))) == NULL)
    {
      ErrMsg("Memory allocation error !  (in init_parameter)\n");
      restart(1);
    }
  mtail = mhead;
  ph = phhead;
  for (;;)
    {
      make_context_label(ph,label);
      mtail->name = strdup (label);
      mtail->phoneme = ph;

      if (ph == phtail) break;
      ph = ph->next;
      if ((mtail->next = (Model *) calloc (1, sizeof (Model))) == NULL)
        {
          ErrMsg("Memory allocation error !  (in init_parameter)\n");
          restart(1);
        }

      mtail = mtail->next;
    }
}
