/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* htk_hmm.h --- HMM structure for HTK format */

/* $Id: htk_hmm.h,v 1.6 2003/01/06 16:10:39 ri Exp $ */

#ifndef __SENT_HTK_HMM_2_H__
#define __SENT_HTK_HMM_2_H__

#include <sent/stddefs.h>
#include <sent/htk_defs.h>
#include <sent/ptree.h>

#define currentis(A)  (!strcasecmp(A, rdhmmdef_token))
#define NoTokErr(S)      if (!rdhmmdef_token) rderr(S)


#define MAX_STATE_NUM 65535	/* allowed maximum state id = unsigned short */

/* delimiters to access logical triphones */
#define HMM_RC_DLIM "+"		/* right-context delimiter */
#define HMM_LC_DLIM "-"		/* right-context delimiter */
#define HMM_RC_DLIM_C '+'		/* right-context delimiter */
#define HMM_LC_DLIM_C '-'		/* right-context delimiter */

#define SPMODEL_NAME_DEFAULT "sp"	/* default logical name of short pause model */


/* options info */

typedef struct {
  short num;			/* num of stream */
  short vsize[50];			/* vector size for each stream */
} HTK_HMM_StreamInfo;

typedef struct {
  HTK_HMM_StreamInfo stream_info;	/* stream information */
  short vec_size;		/* size of parameter vector */
  short cov_type;		/* type of covariance matrix */
  short dur_type;		/* type of duration */
  short param_type;		/* type of parameter */
} HTK_HMM_Options;


/* HMM transition table */
/* only 2 fanout is allowed */
typedef struct __HTK_HMM_trans__ {
  char *name;			/* macro name */
  short statenum;		/* num of state */
  PROB **a;			/* arc transition prob */
  struct __HTK_HMM_trans__ *next;
} HTK_HMM_Trans;

/* HMM variance data */
typedef struct __HTK_HMM_variance__ {
  char *name;			/* macro name */
  VECT *vec;			/* covariance matrix (diagonal vector) */
  short len;			/* length of above */
  struct __HTK_HMM_variance__ *next;
} HTK_HMM_Var;

/* HMM density (a mixture) data */
typedef struct __HTK_HMM_dens__ {
  char *name;			/* macro name */
  VECT *mean;			/* mean vector */
  short meanlen;		/* length of above */
  HTK_HMM_Var *var;		/* variance data */
  LOGPROB gconst;		/* const value for outprob (log scale)*/
				/* gconst = (2pi)^n |(sigma of covariance) */
  struct __HTK_HMM_dens__ *next;
} HTK_HMM_Dens;

/* HMM state */
/* for tmix models, only bweight[] is set and **b is treated as pointer to GCODEBOOK */
typedef struct __HTK_HMM_state__ {
  char *name;			/* macro name */
  short mix_num;		/* num of mixture */
  HTK_HMM_Dens **b;		/* density data for each mixture */
  PROB *bweight;		/* weight of above */
  unsigned short id;		/* uniq id (0-) for outprob cache*/
  struct __HTK_HMM_state__ *next;
} HTK_HMM_State;

/* total HMM structure */
typedef struct __HTK_HMM_data__ {
  char *name;			/* HMM name */
  short state_num;		/* num of state */
  HTK_HMM_State **s;		/* outprob info for each state */
  HTK_HMM_Trans *tr;		/* transition info */
  struct __HTK_HMM_data__ *next;
} HTK_HMM_Data;

/* Gaussian(mixture) codebook for tied-mixture model */
typedef struct {
  char *name;			/* codebook name */
  int num;			/* # of mixtures in the codebook */
  HTK_HMM_Dens **d;		/* pointer to each mixture info */
  unsigned short id;
} GCODEBOOK;

/* state sets for Gaussian(codebook) Selection (define HMM_GS)*/
typedef struct {
  HTK_HMM_State *state;		/* pointer to states in HMM_GS */
  /*  GCODEBOOK *book;*/		/* pointer to the corresponding codebook in hmminfo */
} GS_SET;



/* context-wise state set --- for (inter-word) triphone handling */
typedef struct {		/* HMM state set for same LC & state */
  HTK_HMM_State **s;		/* array of state */
  unsigned short num;		/* # of above */
  unsigned short maxnum;	/* allocated # of above */
} CD_State_Set;
typedef struct __cd_set__{	/* list of HMM state set for given LC */
  char *name;			/* HMM set logical name ("a-k", "e+b", "e", etc.) */
  CD_State_Set *stateset;	/* array of state set for n'th node */
  unsigned short state_num;	/* # of above */
  HTK_HMM_Trans *tr;		/* transition table */
  struct __cd_set__ *next;
} CD_Set;
typedef struct {		/* total LC_* info */
  CD_Set *cdroot;		/* sequencial list of LC_Set */
  APATNODE *cdtree;		/* LC_Set name index for lookup  */
} HMM_CDSET_INFO;


/* logical HMM structure */
typedef struct __HMM_logical__ {
  char *name;			/* logical HMM name  */
  boolean is_pseudo;
  union {
    HTK_HMM_Data *defined;	/* pointer to the mapped physical HMM */
    CD_Set *pseudo;		/* pointer to the pseudo HMM */
  } body;
  struct __HMM_logical__ *next;
} HMM_Logical;
/* list of base phone name */
typedef struct {
  char *name;			/* name of base phone */
  boolean bgnflag;		/* TRUE if it can exist on word beginning */
  boolean endflag;		/* TRUE if it can exist on word end */
} BASEPHONE;
typedef struct {
  int num;			/* total number of base phone */
  int bgnnum;			/* # of phones that can be a word beginning */
  int endnum;			/* # of phones that can be a word end */
  APATNODE *root;		/* index root for BASEPHONE */
} HMM_basephone;

/* global HMM structure */
typedef struct {
  /* HMM definitions from hmmdefs*/
  HTK_HMM_Options opt;		/* only global option is allowed */
  HTK_HMM_Trans *trstart;	/* transition data */
  HTK_HMM_Var *vrstart;		/* variance data */
  HTK_HMM_Dens *dnstart;	/* density (mixture) data */
  HTK_HMM_State *ststart;	/* state outprob data */
  HTK_HMM_Data *start;		/* total HMM data */

  /* logical HMMs from HMMList (physical added as secondary) */
  HMM_Logical *lgstart;	/* logical HMM entry */
  HMM_basephone basephone;	/* base phone names extracted from HMM_Logical */

  /* name index tree */
  APATNODE *tr_root;		/* for Trans */
  APATNODE *vr_root;		/* for Var */
  APATNODE *dn_root;		/* for Dens */
  APATNODE *st_root;		/* for State */
  APATNODE *physical_root;	/* root node of defined HMM name index tree */
  APATNODE *logical_root;	/* root node of logical HMM name index tree */

  /* below are generated from given data above */

  /* state list per context class for cross-word handling */
  HMM_CDSET_INFO cdset_info;	/* context-wise state set info */
				/* for inter-word triphone handling */
  
  /* codebook for TM models */
  APATNODE *codebook_root;	/* (tied mixture) gaussian codebook */
				/* name->pointer index tree */
  
  /* misc. model info */
  boolean is_triphone;		/* TRUE if this is triphone model */
  boolean is_tied_mixture;	/* TRUE if this is tied-mixture model */
  boolean prefer_cdset_avg;	/* compute average of lcdset instead of maximum */
  HMM_Logical *sp;		/* short pause model */
  LOGPROB iwsp_penalty;		/* transition penalty for interword sp */
  
  int totalmixnum;		/* total mixture num */
  int totalstatenum;		/* total state num */
  int totalhmmnum;		/* physical HMM num */
  int totallogicalnum;		/* logical HMM num */
  int totalpseudonum;		/* pseudo HMM num in logical */
  int codebooknum;		/* total num of codebook */
  int maxcodebooksize;		/* maximum size of codebook */
  int maxmixturenum;		/* maximum size of mixture */
  int maxstatenum;		/* maximum number of state per model */
} HTK_HMM_INFO;



/* init_phmm.c */
void htk_hmm_set_pause_model(HTK_HMM_INFO *hmminfo, char *spmodel_name);
/* rdhmmdef.c */
void rderr(char *str);
char *read_token(FILE *fp);
void init_hmm(HTK_HMM_INFO *);
boolean rdhmmdef(FILE *, HTK_HMM_INFO *);
/* rdhmmdef_options.c */
void set_global_opt(FILE *fp, HTK_HMM_INFO *hmm);
char *get_cov_str(short covtype);
char *get_dur_str(short durtype);
/* rdhmmdef_trans.c */
HTK_HMM_Trans *get_trans_data(FILE *, HTK_HMM_INFO *);
void def_trans_macro(char *, FILE *, HTK_HMM_INFO *);
/* rdhmmdef_state.c */
HTK_HMM_State *get_state_data(FILE *, HTK_HMM_INFO *);
void def_state_macro(char *, FILE *, HTK_HMM_INFO *);
HTK_HMM_State *state_lookup(HTK_HMM_INFO *hmm, char *keyname);
/* rdhmmdef_dens.c */
HTK_HMM_Dens *get_dens_data(FILE *, HTK_HMM_INFO *);
void def_dens_macro(char *, FILE *, HTK_HMM_INFO *);
HTK_HMM_Dens *dens_lookup(HTK_HMM_INFO *hmm, char *keyname);
/* rdhmmdef_var.c */
HTK_HMM_Var *get_var_data(FILE *, HTK_HMM_INFO *);
void def_var_macro(char *, FILE *, HTK_HMM_INFO *);
/* rdhmmdef_hmm.c */
void def_HMM(char *, FILE *, HTK_HMM_INFO *);
HTK_HMM_Data *htk_hmmdata_new();
/* rdhmmdef_tiedmix.c */
void tmix_read(FILE *fp, HTK_HMM_State *state, HTK_HMM_INFO *hmm);
/* rdhmmdef_regtree.c */
void def_regtree_macro(char *name, FILE *fp, HTK_HMM_INFO *hmm);
/* rdhmmdef_hmmlist.c */
boolean rdhmmlist(FILE *fp, HTK_HMM_INFO *hmminfo);
/* put_htkdata_info.c */
void put_htk_trans(HTK_HMM_Trans *t);
void put_htk_var(HTK_HMM_Var *v);
void put_htk_dens(HTK_HMM_Dens *d);
void put_htk_state(HTK_HMM_State *s);
void put_htk_hmm(HTK_HMM_Data *h);
void print_hmmdef_info(HTK_HMM_INFO *);
HTK_HMM_INFO *hmminfo_new();
void init_hmminfo(HTK_HMM_INFO *hmminfo, char *filename, char *mapfile);
HTK_HMM_Data *htk_hmmdata_lookup_physical(HTK_HMM_INFO *, char *);
HMM_Logical *htk_hmmdata_lookup_logical(HTK_HMM_INFO *, char *);
void hmm_add_physical_to_logical(HTK_HMM_INFO *);
void hmm_add_pseudo_phones(HTK_HMM_INFO *hmminfo);
/* chkhmmlist.c */
void make_hmm_basephone_list(HTK_HMM_INFO *hmminfo);

/* HMM type check functions */
boolean check_hmm_limit(HTK_HMM_Data *dt);
boolean check_all_hmm_limit(HTK_HMM_INFO *hmm);
boolean check_hmm_options(HTK_HMM_INFO *hmm);
boolean is_context_free_model(HTK_HMM_Data *d);

/* CCD related */
boolean guess_if_cd_hmm(HTK_HMM_INFO *hmm);
HMM_Logical *get_right_context_HMM(HMM_Logical *base, char *rc_name, HTK_HMM_INFO *hmminfo);
HMM_Logical *get_left_context_HMM(HMM_Logical *base, char *lc_name, HTK_HMM_INFO *hmminfo);
void add_right_context(char name[], char *rc);
void add_left_context(char name[], char *lc);
char *center_name(char *hmmname, char *buf);
char *leftcenter_name(char *hmmname, char *buf);
char *rightcenter_name(char *hmmname, char *buf);

/* CD_SET related */
boolean regist_cdset(HTK_HMM_INFO *hmminfo, HTK_HMM_Data *d, char *cdname);
boolean make_cdset(HTK_HMM_INFO *hmminfo);
void put_all_cdinfo(HTK_HMM_INFO *hmminfo);
CD_Set *cdset_lookup(HTK_HMM_INFO *hmminfo, char *cdstr);
CD_Set *lcdset_lookup_by_hmmname(HTK_HMM_INFO *hmminfo, char *hmmname);
CD_Set *rcdset_lookup_by_hmmname(HTK_HMM_INFO *hmminfo, char *hmmname);
int hmm_logical_state_num(HMM_Logical *lg);
HTK_HMM_Trans *hmm_logical_trans(HMM_Logical *lg);

#include <sent/htk_param.h>
boolean check_param_coherence(HTK_HMM_INFO *hmm, HTK_Param *pinfo);
boolean check_param_basetype(HTK_HMM_INFO *hmm, HTK_Param *pinfo);
HTK_Param *new_param_check_and_adjust(HTK_HMM_INFO *hmm, HTK_Param *pinfo, boolean vflag);


#endif /* __SENT_HTK_HMM_2_H__ */
