/**
* @file read_binhmm.c
*
*
* @brief バイナリ形式の %HMM 定義ファイルを読み込む
*
* Julius は独自のバイナリ形式の %HMM 定義ファイルをサポートしています.
* HTKのアスキー形式の %HMM 定義ファイルからバイナリ形式への変換は,
* 附属のツール mkbinhmm で行ないます.このバイナリ形式は,HTK の
* バイナリ形式とは非互換ですので注意して下さい.
*
*
*
* @brief Read a binary %HMM definition file
*
* Julius supports a binary format of %HMM definition file.
* The tool "mkbinhmm" can convert the ascii format HTK %HMM definition
* file to this format. Please note that this binary format is
* not compatible with the HTK binary format.
*
*
* @author Akinobu LEE
* @date Wed Feb 16 05:23:59 2005
*
* $Revision: 1.9 $
*
*/
/*
* Copyright (c) 2003-2005 Shikano Lab., Nara Institute of Science and Technology
* Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology
* All rights reserved
*/
#include
#include
#include
#undef DMES /* define to enable debug message */
static boolean gzfile; ///< TRUE when opened by fopen_readfile
#define rdn(A,B,C,D) if (rdnfunc(A,B,C,D) == FALSE) return FALSE
#define rdn_str(A,B,C) if ((C = rdn_strfunc(A,B)) == NULL) return FALSE
/**
* Binary read function with byte swaping (assume file is BIG ENDIAN)
*
* @param fp [in] file pointer
* @param buf [out] read data
* @param unitbyte [in] size of a unit in bytes
* @param unitnum [in] number of unit to be read
*/
static boolean
rdnfunc(FILE *fp, void *buf, size_t unitbyte, int unitnum)
{
size_t tmp;
if (unitnum == 0) return TRUE;
if (gzfile) {
tmp = myfread(buf, unitbyte, unitnum, fp);
} else {
tmp = fread(buf, unitbyte, unitnum, fp);
}
if (tmp < (size_t)unitnum) {
jlog("Error: read_binhmm: failed to read %d bytes\n", unitbyte * unitnum);
return FALSE;
}
#ifndef WORDS_BIGENDIAN
if (unitbyte != 1) {
swap_bytes(buf, unitbyte, unitnum);
}
#endif
return TRUE;
}
static char buf[MAXLINELEN]; ///< Local work are for text handling
static char nostr = '\0';
/**
* Read a string till NULL.
*
* @param fp [in] file pointer
* @param hmm [out] pointer to %HMM definition data to store the values.
*
* @return pointer to a newly allocated buffer that contains the read string.
*/
static char *
rdn_strfunc(FILE *fp, HTK_HMM_INFO *hmm)
{
int c;
int len;
char *p;
len = 0;
while ((c = gzfile ? myfgetc(fp) : fgetc(fp)) != -1) {
if (len >= MAXLINELEN) {
jlog("Error: read_binhmm: string len exceeded %d bytes\n", MAXLINELEN);
jlog("Error: read_binhmm: please check the value of MAXLINELEN\n");
return NULL;
}
buf[len++] = c;
if (c == '\0') break;
}
if (len == 0) return NULL;
if (len == 1) {
p = &nostr;
} else {
p = (char *)mybmalloc2(len, &(hmm->mroot));
strcpy(p, buf);
}
return(p);
}
static char *binhmm_header = BINHMM_HEADER; ///< Header string
static char *binhmm_header_v2 = BINHMM_HEADER_V2; ///< Header string for V2
/**
* Read acoustic analysis configration parameters from header of binary HMM.
*
* @param fp [in] file pointer
* @param para [out] acoustic analysis configration parameters
*/
static boolean
rd_para(FILE *fp, Value *para)
{
short version;
float dummy;
/* read version */
rdn(fp, &version, sizeof(short), 1);
if (version > VALUE_VERSION) {
jlog("Error: read_binhmm: unknown embedded parameter format version: %d\n", version);
return FALSE;
}
jlog("Stat: rd_para: found embedded acoutic parameter (ver.%d)\n", version);
/* read parameters */
rdn(fp, &(para->smp_period), sizeof(int), 1);
rdn(fp, &(para->smp_freq), sizeof(int), 1);
rdn(fp, &(para->framesize), sizeof(int), 1);
rdn(fp, &(para->frameshift), sizeof(int), 1);
/* tweak to read 64bit binhmm with older version (smp_period, smp_freq = 8byte) */
if (para->smp_period == 0 && para->framesize == 0 &&
para->smp_freq != 0 && para->frameshift != 0) {
jlog("Warning: rd_para: smp_period=%d, smp_freq=%d, framesize=%d, frameshift=%d\n", para->smp_period, para->smp_freq, para->framesize, para->frameshift);
jlog("Warning: rd_para: wrong values, may be reading binhmm created at 64bit?\n");
jlog("Warning: rd_para: try to re-parse values from 64bit to 32bit...\n");
para->smp_period = para->smp_freq;
para->smp_freq = para->frameshift;
rdn(fp, &(para->framesize), sizeof(int), 1);
rdn(fp, &(para->frameshift), sizeof(int), 1);
jlog("Warning: rd_para: smp_period=%d, smp_freq=%d, framesize=%d, frameshift=%d\n", para->smp_period, para->smp_freq, para->framesize, para->frameshift);
}
rdn(fp, &(para->preEmph), sizeof(float), 1);
rdn(fp, &(para->lifter), sizeof(int), 1);
rdn(fp, &(para->fbank_num), sizeof(int), 1);
rdn(fp, &(para->delWin), sizeof(int), 1);
rdn(fp, &(para->accWin), sizeof(int), 1);
rdn(fp, &(para->silFloor), sizeof(float), 1);
rdn(fp, &(para->escale), sizeof(float), 1);
rdn(fp, &(para->hipass), sizeof(int), 1);
rdn(fp, &(para->lopass), sizeof(int), 1);
rdn(fp, &(para->enormal), sizeof(int), 1);
rdn(fp, &(para->raw_e), sizeof(int), 1);
if (version == 1) {
/* version 1 has ss related parameters, but version 2 and later not */
/* skip ss related parameters (ss_alpha and ss_floor) */
rdn(fp, &dummy, sizeof(float), 1);
rdn(fp, &dummy, sizeof(float), 1);
}
rdn(fp, &(para->zmeanframe), sizeof(int), 1);
if (version >= 3) {
rdn(fp, &(para->usepower), sizeof(int), 1);
}
return(TRUE);
}
/**
* Read header string of binary HMM file.
*
* @param fp [in] file pointer
* @param hmm [out] pointer to %HMM definition data to store the values.
* @param para [out] store embedded acoustic parameters if any (V2)
* @param mpdf_macro_ret [out] will be set to TRUE if the file contains mixture pdf macro defined by "~p"
*
* @return TRUE if a correct header was read, FALSE if header string does not
* match the current version.
*/
static boolean
rd_header(FILE *fp, HTK_HMM_INFO *hmm, Value *para, boolean *mpdf_macro_ret)
{
char *p, *q;
boolean emp, inv;
rdn_str(fp, hmm, p);
if (strmatch(p, binhmm_header)) {
/* version 1 */
hmm->variance_inversed = FALSE;
} else if (strmatch(p, binhmm_header_v2)) {
/* version 2 */
emp = inv = FALSE;
rdn_str(fp, hmm, q);
if (*q != '\0') {
while(*q == '_') {
q++;
switch (*q) {
case BINHMM_HEADER_V2_EMBEDPARA:
/* read in embedded acoutic condition parameters */
emp = TRUE;
jlog("Stat: binhmm-header: analysis parameter embedded\n");
break;
case BINHMM_HEADER_V2_VARINV:
inv = TRUE;
jlog("Stat: binhmm-header: variance inversed\n");
break;
case BINHMM_HEADER_V2_MPDFMACRO:
*mpdf_macro_ret = TRUE;
jlog("Stat: binhmm-header: mixture PDF macro used\n");
break;
default:
jlog("Error: unknown format qualifier in header: \"%c\"\n", *q);
return FALSE;
}
q++;
}
}
if (emp) {
para->loaded = 1;
if (rd_para(fp, para) == FALSE) {
jlog("Error: read_binhmm: failed to read embeded parameter\n");
return FALSE;
}
jlog("Stat: read_binhmm: has acoutic analysis configurations in its header\n");
}
if (inv) {
hmm->variance_inversed = TRUE;
jlog("Stat: read_binhmm: has inversed variances\n");
} else {
hmm->variance_inversed = FALSE;
}
} else {
/* failed to read header */
return FALSE;
}
return TRUE;
}
/**
* Read %HMM option specifications.
*
* @param fp [in] file pointer
* @param opt [out] pointer to the %HMM option structure to hold the read
* values.
*/
static boolean
rd_opt(FILE *fp, HTK_HMM_Options *opt)
{
rdn(fp, &(opt->stream_info.num), sizeof(short), 1);
rdn(fp, opt->stream_info.vsize, sizeof(short), MAXSTREAMNUM);
rdn(fp, &(opt->vec_size), sizeof(short), 1);
rdn(fp, &(opt->cov_type), sizeof(short), 1);
rdn(fp, &(opt->dur_type), sizeof(short), 1);
rdn(fp, &(opt->param_type), sizeof(short), 1);
return(TRUE);
}
/**
* Read %HMM type of mixture tying.
*
* @param fp [in] file pointer
* @param hmm [out] pointer to %HMM definition data to store the values.
*/
static boolean
rd_type(FILE *fp, HTK_HMM_INFO *hmm)
{
rdn(fp, &(hmm->is_tied_mixture), sizeof(boolean), 1);
rdn(fp, &(hmm->maxmixturenum), sizeof(int), 1);
return TRUE;
}
/* read transition data */
static HTK_HMM_Trans **tr_index; ///< Map transition matrix id to its pointer
static unsigned int tr_num; ///< Length of above
/**
* @brief Read a sequence of transition matrix data for @a tr_num.
*
* The transition matrixes are stored into @a hmm, and their pointers
* are also stored in @a tr_index for later data mapping operation
* from upper structure (state etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read transitions.
*/
static boolean
rd_trans(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_Trans *t;
unsigned int idx;
int i;
PROB *atmp;
char *p;
rdn(fp, &tr_num, sizeof(unsigned int), 1);
tr_index = (HTK_HMM_Trans **)mymalloc(sizeof(HTK_HMM_Trans *) * tr_num);
hmm->trstart = NULL;
hmm->tr_root = NULL;
for (idx = 0; idx < tr_num; idx++) {
t = (HTK_HMM_Trans *)mybmalloc2(sizeof(HTK_HMM_Trans), &(hmm->mroot));
rdn_str(fp, hmm, p);
t->name = (*p == '\0') ? NULL : p;
rdn(fp, &(t->statenum), sizeof(short), 1);
t->a = (PROB **)mybmalloc2(sizeof(PROB *) * t->statenum, &(hmm->mroot));
atmp = (PROB *)mybmalloc2(sizeof(PROB) * t->statenum * t->statenum, &(hmm->mroot));
for (i=0;istatenum;i++) {
t->a[i] = &(atmp[i*t->statenum]);
rdn(fp, t->a[i], sizeof(PROB), t->statenum);
}
trans_add(hmm, t);
tr_index[idx] = t;
}
#ifdef DMES
jlog("Stat: read_binhmm: %d transition maxtix read\n", tr_num);
#endif
return TRUE;
}
static HTK_HMM_Var **vr_index; ///< Map variance id to its pointer
static unsigned int vr_num; ///< Length of above
/**
* @brief Read a sequence of variance vector for @a vr_num.
*
* The variance vectors are stored into @a hmm, and their pointers
* are also stored in @a vr_index for later data mapping operation
* from upper structure (density etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read variance.
*/
static boolean
rd_var(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_Var *v;
unsigned int idx;
char *p;
rdn(fp, &vr_num, sizeof(unsigned int), 1);
vr_index = (HTK_HMM_Var **)mymalloc(sizeof(HTK_HMM_Var *) * vr_num);
hmm->vrstart = NULL;
hmm->vr_root = NULL;
for (idx = 0; idx < vr_num; idx++) {
v = (HTK_HMM_Var *)mybmalloc2(sizeof(HTK_HMM_Var), &(hmm->mroot));
rdn_str(fp, hmm, p);
v->name = (*p == '\0') ? NULL : p;
rdn(fp, &(v->len), sizeof(short), 1);
v->vec = (VECT *)mybmalloc2(sizeof(VECT) * v->len, &(hmm->mroot));
rdn(fp, v->vec, sizeof(VECT), v->len);
vr_index[idx] = v;
var_add(hmm, v);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d variance read\n", vr_num);
#endif
return TRUE;
}
/* read density data */
static HTK_HMM_Dens **dens_index; ///< Map density id to its pointer
static unsigned int dens_num; ///< Length of above
/**
* @brief Read a sequence of mixture densities for @a dens_num.
*
* The mixture densities are stored into @a hmm, and their references
* to lower structure (variance etc.) are recovered from the id-to-pointer
* index. Their pointers are also stored in @a dens_index for
* later data mapping operation from upper structure (state etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read densities.
*/
static boolean
rd_dens(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_Dens *d;
unsigned int idx;
unsigned int vid;
char *p;
rdn(fp, &dens_num, sizeof(unsigned int), 1);
hmm->totalmixnum = dens_num;
dens_index = (HTK_HMM_Dens **)mymalloc(sizeof(HTK_HMM_Dens *) * dens_num);
hmm->dnstart = NULL;
hmm->dn_root = NULL;
for (idx = 0; idx < dens_num; idx++) {
d = (HTK_HMM_Dens *)mybmalloc2(sizeof(HTK_HMM_Dens), &(hmm->mroot));
rdn_str(fp, hmm, p);
d->name = (*p == '\0') ? NULL : p;
rdn(fp, &(d->meanlen), sizeof(short), 1);
d->mean = (VECT *)mybmalloc2(sizeof(VECT) * d->meanlen, &(hmm->mroot));
rdn(fp, d->mean, sizeof(VECT), d->meanlen);
rdn(fp, &vid, sizeof(unsigned int), 1);
d->var = vr_index[vid];
rdn(fp, &(d->gconst), sizeof(LOGPROB), 1);
dens_index[idx] = d;
dens_add(hmm, d);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d gaussian densities read\n", dens_num);
#endif
return TRUE;
}
/* read stream weight data */
static HTK_HMM_StreamWeight **streamweight_index; ///< Map stream weights id to its pointer
static unsigned int streamweight_num; ///< Length of above
/**
* @brief Read a sequence of stream weights for @a streamweight_num.
*
* The stream weights are stored into @a hmm, and their references
* to lower structure (variance etc.) are recovered from the id-to-pointer
* index. Their pointers are also stored in @a dens_index for
* later data mapping operation from upper structure (state etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read stream weights.
*/
static boolean
rd_streamweight(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_StreamWeight *sw;
unsigned int idx;
char *p;
rdn(fp, &streamweight_num, sizeof(unsigned int), 1);
streamweight_index = (HTK_HMM_StreamWeight **)mymalloc(sizeof(HTK_HMM_StreamWeight *) * streamweight_num);
hmm->swstart = NULL;
hmm->sw_root = NULL;
for (idx = 0; idx < streamweight_num; idx++) {
sw = (HTK_HMM_StreamWeight *)mybmalloc2(sizeof(HTK_HMM_StreamWeight), &(hmm->mroot));
rdn_str(fp, hmm, p);
sw->name = (*p == '\0') ? NULL : p;
rdn(fp, &(sw->len), sizeof(short), 1);
sw->weight = (VECT *)mybmalloc2(sizeof(VECT) * sw->len, &(hmm->mroot));
rdn(fp, sw->weight, sizeof(VECT), sw->len);
streamweight_index[idx] = sw;
sw_add(hmm, sw);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d stream weights read\n", streamweight_num);
#endif
return TRUE;
}
/* read tmix data */
static GCODEBOOK **tm_index; ///< Map codebook id to its pointer
static unsigned int tm_num; ///< Length of above
/**
* @brief Read a sequence of mixture codebook for @a tm_num.
*
* The mixture codebook data are stored into @a hmm, and their references
* to lower structure (mixtures etc.) are recovered from the id-to-pointer
* index. Their pointers are also stored in @a tm_index for
* later data mapping operation from upper structure (state etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read codebooks.
*/
static boolean
rd_tmix(FILE *fp, HTK_HMM_INFO *hmm)
{
GCODEBOOK *tm;
unsigned int idx;
unsigned int did;
int i;
char *p;
rdn(fp, &tm_num, sizeof(unsigned int), 1);
hmm->codebooknum = tm_num;
tm_index = (GCODEBOOK **)mymalloc(sizeof(GCODEBOOK *) * tm_num);
hmm->maxcodebooksize = 0;
hmm->codebook_root = NULL;
for (idx = 0; idx < tm_num; idx++) {
tm = (GCODEBOOK *)mybmalloc2(sizeof(GCODEBOOK), &(hmm->mroot));
rdn_str(fp, hmm, p);
tm->name = (*p == '\0') ? NULL : p;
rdn(fp, &(tm->num), sizeof(int), 1);
if (hmm->maxcodebooksize < tm->num) hmm->maxcodebooksize = tm->num;
tm->d = (HTK_HMM_Dens **)mybmalloc2(sizeof(HTK_HMM_Dens *) * tm->num, &(hmm->mroot));
for(i=0;inum;i++) {
rdn(fp, &did, sizeof(unsigned int), 1);
if (did >= dens_num) {
tm->d[i] = NULL;
} else {
tm->d[i] = dens_index[did];
}
}
tm->id = idx;
tm_index[idx] = tm;
codebook_add(hmm, tm);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d tied-mixture codebooks read\n", tm_num);
#endif
return TRUE;
}
/* read mpdf data */
static HTK_HMM_PDF **mpdf_index; ///< Map mixture pdf id to its pointer
static unsigned int mpdf_num; ///< Length of above
/**
* Read a mixture PDF.
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read codebooks.
* @param m [out] pointer where to store the input mixture PDF.
*
* @return TRUE on success, FALSE on error.
*
*/
static boolean
rd_pdf_sub(FILE *fp, HTK_HMM_INFO *hmm, HTK_HMM_PDF *m)
{
int i;
unsigned int did;
rdn(fp, &(m->mix_num), sizeof(short), 1);
if (m->mix_num == -1) {
/* tmix */
rdn(fp, &did, sizeof(unsigned int), 1);
m->b = (HTK_HMM_Dens **)tm_index[did];
m->mix_num = (tm_index[did])->num;
m->tmix = TRUE;
} else {
/* mixture */
m->b = (HTK_HMM_Dens **)mybmalloc2(sizeof(HTK_HMM_Dens *) * m->mix_num, &(hmm->mroot));
for (i=0;imix_num;i++) {
rdn(fp, &did, sizeof(unsigned int), 1);
if (did >= dens_num) {
m->b[i] = NULL;
} else {
m->b[i] = dens_index[did];
}
}
m->tmix = FALSE;
}
m->bweight = (PROB *)mybmalloc2(sizeof(PROB) * m->mix_num, &(hmm->mroot));
rdn(fp, m->bweight, sizeof(PROB), m->mix_num);
return TRUE;
}
/**
* @brief Read a sequence of mixture pdf for @a mpdf_num.
*
* The mixture pdfs are stored into @a hmm, and their references
* to lower structure (variance etc.) are recovered from the id-to-pointer
* index. Their pointers are also stored in @a mpdf_index for
* later data mapping operation from upper structure (state etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read data.
*/
static boolean
rd_mpdf(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_PDF *m;
unsigned int idx;
char *p;
rdn(fp, &mpdf_num, sizeof(unsigned int), 1);
mpdf_index = (HTK_HMM_PDF **)mymalloc(sizeof(HTK_HMM_PDF *) * mpdf_num);
hmm->pdfstart = NULL;
hmm->pdf_root = NULL;
for (idx = 0; idx < mpdf_num; idx++) {
m = (HTK_HMM_PDF *)mybmalloc2(sizeof(HTK_HMM_PDF), &(hmm->mroot));
rdn_str(fp, hmm, p);
m->name = (*p == '\0') ? NULL : p;
rdn(fp, &(m->stream_id), sizeof(short), 1);
if (rd_pdf_sub(fp, hmm, m) == FALSE) return FALSE;
mpdf_index[idx] = m;
mpdf_add(hmm, m);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d mixture PDFs read\n", mpdf_num);
#endif
return TRUE;
}
/* read state data */
static HTK_HMM_State **st_index; ///< Map state id to its pointer
static unsigned int st_num; ///< Length of above
/**
* @brief Read a sequence of state data for @a st_num.
*
* The state data are stored into @a hmm, and their references
* to lower structure (mixture, codebook, etc.) are recovered
* from the id-to-pointer index. Their pointers are also stored
* in @a st_index for later data mapping operation from
* upper structure (models etc.).
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read states.
* @param mpdf_macro [in] TRUE if mixture pdfs are already read separatedly, or FALSE if they are all defined in-line
*/
static boolean
rd_state(FILE *fp, HTK_HMM_INFO *hmm, boolean mpdf_macro)
{
HTK_HMM_State *s;
unsigned int idx;
unsigned int mid, swid;
int m;
char *buf;
rdn(fp, &st_num, sizeof(unsigned int), 1);
hmm->totalstatenum = st_num;
st_index = (HTK_HMM_State **)mymalloc(sizeof(HTK_HMM_State *) * st_num);
hmm->ststart = NULL;
hmm->st_root = NULL;
for (idx = 0; idx < st_num; idx++) {
s = (HTK_HMM_State *)mybmalloc2(sizeof(HTK_HMM_State), &(hmm->mroot));
rdn_str(fp, hmm, buf);
s->name = (*buf == '\0') ? NULL : buf;
s->nstream = hmm->opt.stream_info.num;
s->pdf = (HTK_HMM_PDF **)mybmalloc2(sizeof(HTK_HMM_PDF *) * s->nstream, &(hmm->mroot));
if (mpdf_macro) {
/* mpdf are stored separatedly, so read index */
for(m=0;mnstream;m++) {
rdn(fp, &mid, sizeof(unsigned int), 1);
if (mid >= mpdf_num) {
s->pdf[m] = NULL;
} else {
s->pdf[m] = mpdf_index[mid];
}
}
} else {
/* mpdf are stored sequencially, so read the content here */
for(m=0;mnstream;m++) {
s->pdf[m] = (HTK_HMM_PDF *)mybmalloc2(sizeof(HTK_HMM_PDF), &(hmm->mroot));
s->pdf[m]->name = NULL;
if (rd_pdf_sub(fp, hmm, s->pdf[m]) == FALSE) return FALSE;
s->pdf[m]->stream_id = m;
mpdf_add(hmm, s->pdf[m]);
}
}
if (hmm->opt.stream_info.num > 1) {
/* read steam weight info */
rdn(fp, &swid, sizeof(unsigned int), 1);
if (swid >= streamweight_num) {
s->w = NULL;
} else {
s->w = streamweight_index[swid];
}
} else {
s->w = NULL;
}
s->id = idx;
st_index[idx] = s;
state_add(hmm, s);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d states read\n", st_num);
#endif
return TRUE;
}
/**
* @brief Read a sequence of %HMM models.
*
* The models are stored into @a hmm. Their references
* to lower structures (state, transition, etc.) are stored in schalar
* ID, and are recovered from the previously built id-to-pointer index.
* when reading the sub structures.
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read models.
*/
static boolean
rd_data(FILE *fp, HTK_HMM_INFO *hmm)
{
HTK_HMM_Data *d;
unsigned int md_num;
unsigned int sid, tid;
unsigned int idx;
int i;
char *p;
rdn(fp, &(md_num), sizeof(unsigned int), 1);
hmm->totalhmmnum = md_num;
hmm->start = NULL;
hmm->physical_root = NULL;
for (idx = 0; idx < md_num; idx++) {
d = (HTK_HMM_Data *)mybmalloc2(sizeof(HTK_HMM_Data), &(hmm->mroot));
rdn_str(fp, hmm, p);
d->name = (*p == '\0') ? NULL : p;
rdn(fp, &(d->state_num), sizeof(short), 1);
d->s = (HTK_HMM_State **)mybmalloc2(sizeof(HTK_HMM_State *) * d->state_num, &(hmm->mroot));
for (i=0;istate_num;i++) {
rdn(fp, &sid, sizeof(unsigned int), 1);
if (sid > (unsigned int)hmm->totalstatenum) {
d->s[i] = NULL;
} else {
d->s[i] = st_index[sid];
}
}
rdn(fp, &tid, sizeof(unsigned int), 1);
d->tr = tr_index[tid];
htk_hmmdata_add(hmm, d);
}
#ifdef DMES
jlog("Stat: read_binhmm: %d HMM model definition read\n", md_num);
#endif
return TRUE;
}
/**
* Top function to read a binary %HMM file from @a fp.
*
* @param fp [in] file pointer
* @param hmm [out] %HMM definition structure to hold the read models.
* @param gzfile_p [in] TRUE if the file pointer points to a gzip file
* @param para [out] store acoustic parameters if embedded in binhmm (V2)
*
* @return TRUE on success, FALSE on failure.
*/
boolean
read_binhmm(FILE *fp, HTK_HMM_INFO *hmm, boolean gzfile_p, Value *para)
{
boolean mpdf_macro = FALSE;
gzfile = gzfile_p;
/* read header */
if (rd_header(fp, hmm, para, &mpdf_macro) == FALSE) {
return FALSE;
}
jlog("Stat: read_binhmm: binary format HMM definition\n");
/* read option data */
if (rd_opt(fp, &(hmm->opt)) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM options\n");
return FALSE;
}
/* read type data */
if (rd_type(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM type of mixture tying\n");
return FALSE;
}
/* read transition data */
if (rd_trans(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM transition data\n");
return FALSE;
}
/* read variance data */
if (rd_var(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM variance data\n");
return FALSE;
}
/* read density data */
if (rd_dens(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM density data\n");
return FALSE;
}
/* read stream weight data */
if (hmm->opt.stream_info.num > 1) {
if (rd_streamweight(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read stream weights data\n");
return FALSE;
}
}
/* read tmix data */
if (hmm->is_tied_mixture) {
if (rd_tmix(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM tied-mixture codebook data\n");
return FALSE;
}
}
/* read mixture pdf data */
if (mpdf_macro) {
if (rd_mpdf(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read mixture PDF data\n");
return FALSE;
}
}
/* read state data */
if (rd_state(fp, hmm, mpdf_macro) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM state data\n");
return FALSE;
}
/* read model data */
if (rd_data(fp, hmm) == FALSE) {
jlog("Error: read_binhmm: failed to read HMM data\n");
return FALSE;
}
/* free pointer->index work area */
if (mpdf_macro) free(mpdf_index);
free(tr_index);
free(vr_index);
if (hmm->opt.stream_info.num > 1) free(streamweight_index);
free(dens_index);
if (hmm->is_tied_mixture) free(tm_index);
free(st_index);
/* count maximum state num (it is not stored in binhmm... */
{
HTK_HMM_Data *dtmp;
int maxlen = 0;
for (dtmp = hmm->start; dtmp; dtmp = dtmp->next) {
if (maxlen < dtmp->state_num) maxlen = dtmp->state_num;
}
hmm->maxstatenum = maxlen;
}
/* compute total number of mixture PDFs */
{
HTK_HMM_PDF *p;
int n = 0;
for (p = hmm->pdfstart; p; p = p->next) {
n++;
}
hmm->totalpdfnum = n;
}
/* re-number state id */
{
HTK_HMM_State *stmp;
int n = 0;
for (stmp = hmm->ststart; stmp; stmp = stmp->next) {
stmp->id = n++;
}
}
/* assign ID number for all HTK_HMM_Trans */
{
HTK_HMM_Trans *ttmp;
int n = 0;
for (ttmp = hmm->trstart; ttmp; ttmp = ttmp->next) {
ttmp->id = n++;
}
hmm->totaltransnum = n;
}
/* determine whether this model needs multi-path handling */
hmm->need_multipath = htk_hmm_has_several_arc_on_edge(hmm);
if (hmm->need_multipath) {
jlog("Stat: read_binhmm: this HMM requires multipath handling at decoding\n");
} else {
jlog("Stat: read_binhmm: this HMM does not need multipath handling\n");
}
if (! hmm->variance_inversed) {
/* inverse all variance values for faster computation */
htk_hmm_inverse_variances(hmm);
hmm->variance_inversed = TRUE;
}
#ifdef ENABLE_MSD
/* check if MSD-HMM */
htk_hmm_check_msd(hmm);
#endif
return (TRUE);
}