Julius 4.2
libjulius/src/m_fusion.c
説明を見る。
00001 
00026 /*
00027  * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University
00028  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00029  * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology
00030  * All rights reserved
00031  */
00032 
00033 #include <julius/julius.h>
00034 
00072 static HTK_HMM_INFO *
00073 initialize_HMM(JCONF_AM *amconf, Jconf *jconf)
00074 {
00075   HTK_HMM_INFO *hmminfo;
00076 
00077   /* at here, global variable "para" holds values specified by user or
00078      by user-specified HTK config file */
00079   if (amconf->analysis.para_hmm.loaded == 1) {
00080     jlog("Warning: you seems to read more than one acoustic model for recognition, but\n");
00081     jlog("Warning: previous one already has header-embedded acoustic parameters\n");
00082     jlog("Warning: if you have different parameters, result may be wrong!\n");
00083   }
00084   
00085   /* allocate new hmminfo */
00086   hmminfo = hmminfo_new();
00087   /* load hmmdefs */
00088   if (init_hmminfo(hmminfo, amconf->hmmfilename, amconf->mapfilename, &(amconf->analysis.para_hmm)) == FALSE) {
00089     hmminfo_free(hmminfo);
00090     return NULL;
00091   }
00092 
00093   /* set multipath mode flag */
00094   if (amconf->force_multipath) {
00095     jlog("STAT: m_fusion: force multipath HMM handling by user request\n");
00096     hmminfo->multipath = TRUE;
00097   } else {
00098     hmminfo->multipath = hmminfo->need_multipath;
00099   }
00100 
00101   /* only MFCC is supported for audio input */
00102   /* MFCC_{0|E}[_D][_A][_Z][_N] is supported */
00103   /* check parameter type of this acoustic HMM */
00104   if (jconf->input.type == INPUT_WAVEFORM) {
00105     /* Decode parameter extraction type according to the training
00106        parameter type in the header of the given acoustic HMM */
00107     if ((hmminfo->opt.param_type & F_BASEMASK) != F_MFCC) {
00108       jlog("ERROR: m_fusion: for direct speech input, only HMM trained by MFCC is supported\n");
00109       hmminfo_free(hmminfo);
00110       return NULL;
00111     }
00112     /* set acoustic analysis parameters from HMM header */
00113     calc_para_from_header(&(amconf->analysis.para), hmminfo->opt.param_type, hmminfo->opt.vec_size);
00114   }
00115   /* check if tied_mixture */
00116   if (hmminfo->is_tied_mixture && hmminfo->codebooknum <= 0) {
00117     jlog("ERROR: m_fusion: this tied-mixture model has no codebook!?\n");
00118     hmminfo_free(hmminfo);
00119     return NULL;
00120   }
00121 
00122 #ifdef PASS1_IWCD
00123   /* make state clusters of same context for inter-word triphone approx. */
00124   if (hmminfo->is_triphone) {
00125     if (hmminfo->cdset_root == NULL) {
00126       jlog("STAT: making pseudo bi/mono-phone for IW-triphone\n");
00127       if (make_cdset(hmminfo) == FALSE) {
00128         jlog("ERROR: m_fusion: failed to make context-dependent state set\n");
00129         hmminfo_free(hmminfo);
00130         return NULL;
00131       }
00132     } else {
00133       jlog("STAT: pseudo phones are loaded from binary hmmlist file\n");
00134     }
00135 
00136     /* add those `pseudo' biphone and monophone to the logical HMM names */
00137     /* they points not to the defined HMM, but to the CD_Set structure */
00138     hmm_add_pseudo_phones(hmminfo);
00139   }
00140 #endif
00141 
00142   /* find short pause model and set to hmminfo->sp */
00143   htk_hmm_set_pause_model(hmminfo, amconf->spmodel_name);
00144 
00145 
00146   hmminfo->cdset_method = amconf->iwcdmethod;
00147   hmminfo->cdmax_num = amconf->iwcdmaxn;
00148 
00149   if (amconf->analysis.para_htk.loaded == 1) apply_para(&(amconf->analysis.para), &(amconf->analysis.para_htk));
00150   if (amconf->analysis.para_hmm.loaded == 1) apply_para(&(amconf->analysis.para), &(amconf->analysis.para_hmm));
00151   apply_para(&(amconf->analysis.para), &(amconf->analysis.para_default));
00152 
00153   return(hmminfo);
00154   
00155 }
00156 
00170 static HTK_HMM_INFO *
00171 initialize_GSHMM(JCONF_AM *amconf)
00172 {
00173   HTK_HMM_INFO *hmm_gs;
00174   Value para_dummy;
00175 
00176   jlog("STAT: Reading GS HMMs:\n");
00177   hmm_gs = hmminfo_new();
00178   undef_para(&para_dummy);
00179   if (init_hmminfo(hmm_gs, amconf->hmm_gs_filename, NULL, &para_dummy) == FALSE) {
00180     hmminfo_free(hmm_gs);
00181     return NULL;
00182   }
00183   return(hmm_gs);
00184 }
00185 
00202 static HTK_HMM_INFO *
00203 initialize_GMM(Jconf *jconf)
00204 {
00205   HTK_HMM_INFO *gmm;
00206   
00207   jlog("STAT: reading GMM: %s\n", jconf->reject.gmm_filename);
00208 
00209   if (jconf->gmm == NULL) {
00210     /* no acoustic parameter setting was given for GMM using -AM_GMM, 
00211        copy the first AM setting */
00212     jlog("STAT: -AM_GMM not used, use parameter of the first AM\n");
00213     jconf->gmm = j_jconf_am_new();
00214     memcpy(jconf->gmm, jconf->am_root, sizeof(JCONF_AM));
00215     jconf->gmm->hmmfilename = NULL;
00216     jconf->gmm->mapfilename = NULL;
00217     jconf->gmm->spmodel_name = NULL;
00218     jconf->gmm->hmm_gs_filename = NULL;
00219     if (jconf->am_root->analysis.cmnload_filename) {
00220       jconf->gmm->analysis.cmnload_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->analysis.cmnload_filename)+ 1), jconf->am_root->analysis.cmnload_filename);
00221     }
00222     if (jconf->am_root->analysis.cmnsave_filename) {
00223       jconf->gmm->analysis.cmnsave_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->analysis.cmnsave_filename)+ 1), jconf->am_root->analysis.cmnsave_filename);
00224     }
00225     if (jconf->am_root->frontend.ssload_filename) {
00226       jconf->gmm->frontend.ssload_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->frontend.ssload_filename)+ 1), jconf->am_root->frontend.ssload_filename);
00227     }
00228   }
00229 
00230   gmm = hmminfo_new();
00231   if (init_hmminfo(gmm, jconf->reject.gmm_filename, NULL, &(jconf->gmm->analysis.para_hmm)) == FALSE) {
00232     hmminfo_free(gmm);
00233     return NULL;
00234   }
00235   /* check parameter type of this acoustic HMM */
00236   if (jconf->input.type == INPUT_WAVEFORM) {
00237     /* Decode parameter extraction type according to the training
00238        parameter type in the header of the given acoustic HMM */
00239     if ((gmm->opt.param_type & F_BASEMASK) != F_MFCC) {
00240       jlog("ERROR: m_fusion: for direct speech input, only GMM trained by MFCC is supported\n");
00241       hmminfo_free(gmm);
00242       return NULL;
00243     }
00244   }
00245 
00246   /* set acoustic analysis parameters from HMM header */
00247   calc_para_from_header(&(jconf->gmm->analysis.para), gmm->opt.param_type, gmm->opt.vec_size);
00248 
00249   if (jconf->gmm->analysis.para_htk.loaded == 1) apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_htk));
00250   if (jconf->gmm->analysis.para_hmm.loaded == 1) apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_hmm));
00251   apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_default));
00252 
00253   return(gmm);
00254 }
00255 
00289 static WORD_INFO *
00290 initialize_dict(JCONF_LM *lmconf, HTK_HMM_INFO *hmminfo)
00291 {
00292   WORD_INFO *winfo;
00293   JCONF_LM_NAMELIST *nl;
00294   char buf[MAXLINELEN];
00295   int n;
00296 
00297   /* allocate new word dictionary */
00298   winfo = word_info_new();
00299   /* read in dictinary from file */
00300   if ( ! 
00301 #ifdef MONOTREE
00302       /* leave winfo monophone for 1st pass lexicon tree */
00303        init_voca(winfo, lmconf->dictfilename, hmminfo, TRUE, lmconf->forcedict_flag)
00304 #else 
00305        init_voca(winfo, lmconf->dictfilename, hmminfo, FALSE, lmconf->forcedict_flag)
00306 #endif
00307        ) {
00308     jlog("ERROR: m_fusion: failed to read dictionary, terminated\n");
00309     word_info_free(winfo);
00310     return NULL;
00311   }
00312 
00313   /* load additional entries */
00314   for (nl = lmconf->additional_dict_files; nl; nl=nl->next) {
00315     FILE *fp;
00316     if ((fp = fopen(nl->name, "rb")) == NULL) {
00317       jlog("ERROR: m_fusion: failed to open %s\n",nl->name);
00318       word_info_free(winfo);
00319       return NULL;
00320     }
00321     n = winfo->num;
00322     while (getl_fp(buf, MAXLINELEN, fp) != NULL) {
00323       if (voca_load_line(buf, winfo, hmminfo) == FALSE) break;
00324     }
00325     if (voca_load_end(winfo) == FALSE) {
00326       jlog("ERROR: m_fusion: failed to read dictionary %s\n", nl->name);
00327       fclose(fp);
00328       word_info_free(winfo);
00329       return NULL;
00330     }
00331     if (fclose(fp) == -1) {
00332       jlog("ERROR: m_fusion: failed to close %s\n", nl->name);
00333       word_info_free(winfo);
00334       return NULL;
00335     }
00336     jlog("STAT: + additional dictionary: %s (%d words)\n", nl->name, winfo->num - n);
00337   }
00338   n = winfo->num;
00339   for (nl = lmconf->additional_dict_entries; nl; nl=nl->next) {
00340     if (voca_load_line(nl->name, winfo, hmminfo) == FALSE) {
00341       jlog("ERROR: m_fusion: failed to set entry: %s\n", nl->name);
00342     }
00343   }
00344   if (lmconf->additional_dict_entries) {
00345     if (voca_load_end(winfo) == FALSE) {
00346       jlog("ERROR: m_fusion: failed to read additinoal word entry\n");
00347       word_info_free(winfo);
00348       return NULL;
00349     }
00350     jlog("STAT: + additional entries: %d words\n", winfo->num - n);
00351   }
00352 
00353   if (lmconf->lmtype == LM_PROB) {
00354     /* if necessary, append a IW-sp word to the dict if "-iwspword" specified */
00355     if (lmconf->enable_iwspword) {
00356       if (
00357 #ifdef MONOTREE
00358           voca_append_htkdict(lmconf->iwspentry, winfo, hmminfo, TRUE)
00359 #else 
00360           voca_append_htkdict(lmconf->iwspentry, winfo, hmminfo, FALSE)
00361 #endif
00362           == FALSE) {
00363         jlog("ERROR: m_fusion: failed to make IW-sp word entry \"%s\"\n", lmconf->iwspentry);
00364         word_info_free(winfo);
00365         return NULL;
00366       } else {
00367         jlog("STAT: 1 IW-sp word entry added\n");
00368       }
00369     }
00370     /* set {head,tail}_silwid */
00371     winfo->head_silwid = voca_lookup_wid(lmconf->head_silname, winfo);
00372     if (winfo->head_silwid == WORD_INVALID) { /* not exist */
00373       jlog("ERROR: m_fusion: head sil word \"%s\" not exist in voca\n", lmconf->head_silname);
00374       word_info_free(winfo);
00375       return NULL;
00376     }
00377     winfo->tail_silwid = voca_lookup_wid(lmconf->tail_silname, winfo);
00378     if (winfo->tail_silwid == WORD_INVALID) { /* not exist */
00379       jlog("ERROR: m_fusion: tail sil word \"%s\" not exist in voca\n", lmconf->tail_silname);
00380       word_info_free(winfo);
00381       return NULL;
00382     }
00383   }
00384   
00385   return(winfo);
00386   
00387 }
00388 
00389 
00422 static NGRAM_INFO *
00423 initialize_ngram(JCONF_LM *lmconf, WORD_INFO *winfo)
00424 {
00425   NGRAM_INFO *ngram;
00426   boolean ret;
00427 
00428   /* allocate new */
00429   ngram = ngram_info_new();
00430   /* load LM */
00431   if (lmconf->ngram_filename != NULL) { /* binary format */
00432     ret = init_ngram_bin(ngram, lmconf->ngram_filename);
00433   } else {                      /* ARPA format */
00434     /* if either forward or backward N-gram is specified, read it */
00435     /* if both specified, use backward N-gram as main and
00436        use forward 2-gram only for 1st pass (this is an old behavior) */
00437     if (lmconf->ngram_filename_rl_arpa) {
00438       ret = init_ngram_arpa(ngram, lmconf->ngram_filename_rl_arpa, DIR_RL);
00439       if (ret == FALSE) {
00440         ngram_info_free(ngram);
00441         return NULL;
00442       }
00443       if (lmconf->ngram_filename_lr_arpa) {
00444         ret = init_ngram_arpa_additional(ngram, lmconf->ngram_filename_lr_arpa);
00445         if (ret == FALSE) {
00446           ngram_info_free(ngram);
00447           return NULL;
00448         }
00449       }
00450     } else if (lmconf->ngram_filename_lr_arpa) {
00451       ret = init_ngram_arpa(ngram, lmconf->ngram_filename_lr_arpa, DIR_LR);
00452     }
00453   }
00454   if (ret == FALSE) {
00455     ngram_info_free(ngram);
00456     return NULL;
00457   }
00458 
00459   /* set unknown (=OOV) word id */
00460   set_unknown_id(ngram, lmconf->unknown_name);
00461 
00462   /* map dict item to N-gram entry */
00463   if (make_voca_ref(ngram, winfo) == FALSE) {
00464     ngram_info_free(ngram);
00465     return NULL;
00466   }
00467 
00468   /* post-fix EOS / BOS uni prob for SRILM */
00469   fix_uniprob_srilm(ngram, winfo);
00470 
00471   return(ngram);
00472 }
00473 
00506 boolean
00507 j_load_am(Recog *recog, JCONF_AM *amconf)
00508 {
00509   PROCESS_AM *am;
00510 
00511   jlog("STAT: *** loading AM%02d %s\n", amconf->id, amconf->name);
00512 
00513   /* create AM process instance */
00514   am = j_process_am_new(recog, amconf);
00515   
00516   /* HMM */
00517   if ((am->hmminfo = initialize_HMM(amconf, recog->jconf)) == NULL) {
00518     jlog("ERROR: m_fusion: failed to initialize AM\n");
00519     return FALSE;
00520   }
00521   if (amconf->hmm_gs_filename != NULL) {
00522     if ((am->hmm_gs = initialize_GSHMM(amconf)) == NULL) {
00523       jlog("ERROR: m_fusion: failed to initialize GS HMM\n");
00524       return FALSE;
00525     }
00526   }
00527 
00528   /* fixate model-specific params */
00529   /* set params whose default will change by models and not specified in arg */
00530   /* select Gaussian pruning function */
00531   if (am->config->gprune_method == GPRUNE_SEL_UNDEF) {/* set default if not specified */
00532     if (am->hmminfo->is_tied_mixture) {
00533       /* enabled by default for tied-mixture models */
00534 #if defined(GPRUNE_DEFAULT_SAFE)
00535       am->config->gprune_method = GPRUNE_SEL_SAFE;
00536 #elif defined(GPRUNE_DEFAULT_HEURISTIC)
00537       am->config->gprune_method = GPRUNE_SEL_HEURISTIC;
00538 #elif defined(GPRUNE_DEFAULT_BEAM)
00539       am->config->gprune_method = GPRUNE_SEL_BEAM;
00540 #endif
00541     } else {
00542       /* disabled by default for non tied-mixture model */
00543       am->config->gprune_method = GPRUNE_SEL_NONE;
00544     }
00545   }
00546   
00547   /* fixated analysis.para not uses loaded flag any more, so
00548      reset it for binary matching */
00549   amconf->analysis.para.loaded = 0;
00550 
00551   jlog("STAT: *** AM%02d %s loaded\n", amconf->id, amconf->name);
00552 
00553   return TRUE;
00554 }
00555 
00595 boolean
00596 j_load_lm(Recog *recog, JCONF_LM *lmconf)
00597 {
00598   JCONF_SEARCH *sh;
00599   PROCESS_LM *lm;
00600   PROCESS_AM *am, *atmp;
00601 
00602   jlog("STAT: *** loading LM%02d %s\n", lmconf->id, lmconf->name);
00603 
00604   /* find which am process instance to assign to each LM */
00605   am = NULL;
00606   for(sh=recog->jconf->search_root;sh;sh=sh->next) {
00607     if (sh->lmconf == lmconf) {
00608       for(atmp=recog->amlist;atmp;atmp=atmp->next) {
00609         if (sh->amconf == atmp->config) {
00610           am = atmp;
00611         }
00612       }
00613     }
00614   }
00615   if (am == NULL) {
00616     jlog("ERROR: cannot find corresponding AM for LM%02d %s\n", lmconf->id, lmconf->name);
00617     jlog("ERROR: you should write all AM/LM combinations to be used for recognition with \"-SR\"\n");
00618     return FALSE;
00619   }
00620 
00621   /* create LM process instance */
00622   lm = j_process_lm_new(recog, lmconf);
00623 
00624   /* assign AM process instance to the LM instance */
00625   lm->am = am;
00626 
00627   /* load language model */
00628   if (lm->lmtype == LM_PROB) {
00629     /* LM (N-gram) */
00630     if ((lm->winfo = initialize_dict(lm->config, lm->am->hmminfo)) == NULL) {
00631       jlog("ERROR: m_fusion: failed to initialize dictionary\n");
00632       return FALSE;
00633     }
00634     if (lm->config->ngram_filename_lr_arpa || lm->config->ngram_filename_rl_arpa || lm->config->ngram_filename) {
00635       if ((lm->ngram = initialize_ngram(lm->config, lm->winfo)) == NULL) {
00636         jlog("ERROR: m_fusion: failed to initialize N-gram\n");
00637         return FALSE;
00638       }
00639     }
00640   }
00641   if (lm->lmtype == LM_DFA) {
00642     /* DFA */
00643     if (lm->config->dfa_filename != NULL && lm->config->dictfilename != NULL) {
00644       /* here add grammar specified by "-dfa" and "-v" to grammar list */
00645       multigram_add_gramlist(lm->config->dfa_filename, lm->config->dictfilename, lm->config, LM_DFA_GRAMMAR);
00646     }
00647     /* load all the specified grammars */
00648     if (multigram_load_all_gramlist(lm) == FALSE) {
00649       jlog("ERROR: m_fusion: some error occured in reading grammars\n");
00650       return FALSE;
00651     }
00652     /* setup for later wchmm building */
00653     multigram_update(lm);
00654     /* the whole lexicon will be forced to built in the boot sequence,
00655        so reset the global modification flag here */
00656     lm->global_modified = FALSE;
00657   }
00658   
00659   jlog("STAT: *** LM%02d %s loaded\n", lmconf->id, lmconf->name);
00660 
00661   return TRUE;
00662 }
00663 
00664 /**********************************************************************/
00693 boolean
00694 j_load_all(Recog *recog, Jconf *jconf)
00695 {
00696   JCONF_AM *amconf;
00697   JCONF_LM *lmconf;
00698 
00699   /* set global jconf */
00700   recog->jconf = jconf;
00701 
00702   /* load acoustic models */
00703   for(amconf=jconf->am_root;amconf;amconf=amconf->next) {
00704     if (j_load_am(recog, amconf) == FALSE) return FALSE;
00705   }
00706 
00707   /* load language models */
00708   for(lmconf=jconf->lm_root;lmconf;lmconf=lmconf->next) {
00709     if (j_load_lm(recog, lmconf) == FALSE) return FALSE;
00710   }
00711 
00712   /* GMM */
00713   if (jconf->reject.gmm_filename != NULL) {
00714     jlog("STAT: loading GMM\n");
00715     if ((recog->gmm = initialize_GMM(jconf)) == NULL) {
00716       jlog("ERROR: m_fusion: failed to initialize GMM\n");
00717       return FALSE;
00718     }
00719   }
00720 
00721   /* check sampling rate requirement on AMs and set it to global jconf */
00722   {
00723     boolean ok_p;
00724 
00725     /* set input sampling rate from an AM */
00726     jconf->input.sfreq = jconf->am_root->analysis.para.smp_freq;
00727     jconf->input.period = jconf->am_root->analysis.para.smp_period;
00728     jconf->input.frameshift = jconf->am_root->analysis.para.frameshift;
00729     jconf->input.framesize = jconf->am_root->analysis.para.framesize;
00730     /* check if the value is equal at all AMs */
00731     ok_p = TRUE;
00732     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00733       if (jconf->input.sfreq != amconf->analysis.para.smp_freq) ok_p = FALSE;
00734     }
00735     if (!ok_p) {
00736       jlog("ERROR: required sampling rate differs in AMs!\n");
00737       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00738         jlog("ERROR: AM%02d %s: %dHz\n", amconf->analysis.para.smp_freq);
00739       }
00740       return FALSE;
00741     }
00742     /* also check equality for GMM */
00743     if (recog->gmm) {
00744       if (jconf->input.sfreq != jconf->gmm->analysis.para.smp_freq) {
00745         jlog("ERROR: required sampling rate differs between AM and GMM!\n");
00746         jlog("ERROR: AM : %dHz\n", jconf->input.sfreq);
00747         jlog("ERROR: GMM: %dHz\n", jconf->gmm->analysis.para.smp_freq);
00748         return FALSE;
00749       }
00750     }
00751     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00752       if (jconf->input.frameshift != amconf->analysis.para.frameshift) ok_p = FALSE;
00753     }
00754     if (!ok_p) {
00755       jlog("ERROR: requested frame shift differs in AMs!\n");
00756       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00757         jlog("ERROR: AM%02d %s: %d samples\n", amconf->analysis.para.frameshift);
00758       }
00759       return FALSE;
00760     }
00761     /* also check equality for GMM */
00762     if (recog->gmm) {
00763       if (jconf->input.frameshift != jconf->gmm->analysis.para.frameshift) {
00764         jlog("ERROR: required frameshift differs between AM and GMM!\n");
00765         jlog("ERROR: AM : %d samples\n", jconf->input.frameshift);
00766         jlog("ERROR: GMM: %d samples\n", jconf->gmm->analysis.para.frameshift);
00767         return FALSE;
00768       }
00769     }
00770     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00771       if (jconf->input.framesize != amconf->analysis.para.framesize) ok_p = FALSE;
00772     }
00773     if (!ok_p) {
00774       jlog("ERROR: requested frame size (window length) differs in AMs!\n");
00775       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
00776         jlog("ERROR: AM%02d %s: %d samples\n", amconf->analysis.para.framesize);
00777       }
00778       return FALSE;
00779     }
00780     /* also check equality for GMM */
00781     if (recog->gmm) {
00782       if (jconf->input.framesize != jconf->gmm->analysis.para.framesize) {
00783         jlog("ERROR: requested frame size differs between AM and GMM!\n");
00784         jlog("ERROR: AM : %d samples\n", jconf->input.framesize);
00785         jlog("ERROR: GMM: %d samples\n", jconf->gmm->analysis.para.framesize);
00786         return FALSE;
00787       }
00788     }
00789   }
00790 
00791   return TRUE;
00792 }
00793 
00811 static boolean
00812 mfcc_config_is_same(JCONF_AM *amconf, MFCCCalc *mfcc)
00813 {
00814   char *s1, *s2;
00815 
00816   /* parameter extraction conditions are the same */
00817   /* check exact match in amconf->analysis.* */
00818   if (&(amconf->analysis.para) == mfcc->para || memcmp(&(amconf->analysis.para), mfcc->para, sizeof(Value)) == 0) {
00819     s1 = amconf->analysis.cmnload_filename;
00820     s2 = mfcc->cmn.load_filename;
00821     if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
00822       s1 = amconf->analysis.cmnsave_filename;
00823       s2 = mfcc->cmn.save_filename;
00824       if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
00825         if (amconf->analysis.cmn_update == mfcc->cmn.update
00826             && amconf->analysis.cmn_map_weight == mfcc->cmn.map_weight) {
00827           if (amconf->frontend.ss_alpha == mfcc->frontend.ss_alpha
00828               && amconf->frontend.ss_floor == mfcc->frontend.ss_floor
00829               && amconf->frontend.sscalc == mfcc->frontend.sscalc
00830               && amconf->frontend.sscalc_len == mfcc->frontend.sscalc_len) {
00831             s1 = amconf->frontend.ssload_filename;
00832             s2 = mfcc->frontend.ssload_filename;
00833             if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
00834               return TRUE;
00835             }
00836           }
00837         }
00838       }
00839     }
00840   }
00841 
00842   return FALSE;
00843 }
00844 
00845 /***************************************************/
00846 /* create MFCC calculation instance from AM config */
00847 /* according to the fixated parameter information  */
00848 /***************************************************/
00873 void
00874 create_mfcc_calc_instances(Recog *recog)
00875 {
00876   PROCESS_AM *am;
00877   MFCCCalc *mfcc;
00878   int count;
00879   
00880   jlog("STAT: *** create MFCC calculation modules from AM\n");
00881   count = 0;
00882   for(am=recog->amlist;am;am=am->next) {
00883     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
00884       if (mfcc_config_is_same(am->config, mfcc)) {
00885         /* the same */
00886         jlog("STAT: AM%02d %s: share MFCC%02d\n", am->config->id, am->config->name, mfcc->id);
00887         am->mfcc = mfcc;
00888         break;
00889       }
00890     }
00891     if (!mfcc) {                /* the same not found */
00892       /* initialize MFCC calculation work area */
00893       count++;
00894       /* create new mfcc instance */
00895       mfcc = j_mfcccalc_new(am->config);
00896       mfcc->id = count;
00897       /* assign to the am */
00898       am->mfcc = mfcc;
00899       /* add to the list of all MFCCCalc */
00900       mfcc->next = recog->mfcclist;
00901       recog->mfcclist = mfcc;
00902       jlog("STAT: AM%2d %s: create a new module MFCC%02d\n", am->config->id, am->config->name, mfcc->id);
00903     }
00904   }
00905 
00906   /* for GMM */
00907   if (recog->gmm) {
00908     /* if GMM calculation config found, make MFCC instance for that. */
00909     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
00910       if (mfcc_config_is_same(recog->jconf->gmm, mfcc)) {
00911         /* the same */
00912         jlog("STAT: GMM: share MFCC%02d\n", mfcc->id);
00913         recog->gmmmfcc = mfcc;
00914         break;
00915         }
00916     }
00917     if (!mfcc) {                /* the same not found */
00918       /* initialize MFCC calculation work area */
00919       count++;
00920       /* create new mfcc instance */
00921       mfcc = j_mfcccalc_new(recog->jconf->gmm);
00922       mfcc->id = count;
00923       /* assign to gmm */
00924       recog->gmmmfcc = mfcc;
00925       /* add to the list of all MFCCCalc */
00926       mfcc->next = recog->mfcclist;
00927       recog->mfcclist = mfcc;
00928       jlog("STAT: GMM: create a new module MFCC%02d\n", mfcc->id);
00929     }
00930   }
00931   
00932   jlog("STAT: %d MFCC modules created\n", count);
00933 }
00934 
00967 boolean
00968 j_launch_recognition_instance(Recog *recog, JCONF_SEARCH *sconf)
00969 {
00970   RecogProcess *p;
00971   PROCESS_AM *am;
00972   PROCESS_LM *lm;
00973 
00974   jlog("STAT: composing recognizer instance SR%02d %s (AM%02d %s, LM%02d %s)\n", sconf->id, sconf->name, sconf->amconf->id, sconf->amconf->name, sconf->lmconf->id, sconf->lmconf->name);
00975 
00976   /* allocate recognition instance */
00977   p = j_recogprocess_new(recog, sconf);
00978 
00979   /* assign corresponding AM instance and LM instance to use */
00980   for(lm=recog->lmlist;lm;lm=lm->next) {
00981     if (sconf->lmconf == lm->config) {
00982       for(am=recog->amlist;am;am=am->next) {
00983         if (sconf->amconf == am->config) {
00984           p->am = am;
00985           p->lm = lm;
00986         }
00987       }
00988     }
00989   }
00990 
00991   if (p->config->sw.triphone_check_flag && p->am->hmminfo->is_triphone) {
00992     /* go into interactive triphone HMM check mode */
00993     hmm_check(p);
00994   }
00995   
00996   /******************************************/
00997   /******** set work area and flags *********/
00998   /******************************************/
00999 
01000   /* copy values of sub instances for handly access during recognition */
01001   /* set lm type */
01002   p->lmtype = p->lm->lmtype;
01003   p->lmvar  = p->lm->lmvar;
01004   p->graphout = p->config->graph.enabled;
01005   
01006   /* set flag for context dependent handling */
01007   if (p->config->force_ccd_handling) {
01008     p->ccd_flag = p->config->ccd_handling;
01009   } else {
01010     if (p->am->hmminfo->is_triphone) {
01011       p->ccd_flag = TRUE;
01012     } else {
01013       p->ccd_flag = FALSE;
01014     }
01015   }
01016 
01017   /* iwsp prepare */
01018   if (p->lm->config->enable_iwsp) {
01019     if (p->am->hmminfo->multipath) {
01020       /* find short-pause model */
01021       if (p->am->hmminfo->sp == NULL) {
01022         jlog("ERROR: iwsp enabled but no short pause model \"%s\" in hmmdefs\n", p->am->config->spmodel_name);
01023         return FALSE;
01024       }
01025       p->am->hmminfo->iwsp_penalty = p->am->config->iwsp_penalty;
01026     } else {
01027       jlog("ERROR: \"-iwsp\" needs multi-path mode\n");
01028       jlog("ERROR: you should use multi-path AM, or specify \"-multipath\" with \"-iwsp\"\n");
01029       return FALSE;
01030     }
01031   }
01032 
01033   /* for short-pause segmentation  */
01034   if (p->config->successive.enabled) {
01035     if (p->config->successive.pausemodelname) {
01036       /* pause model name string specified, divide it and store to p */
01037       char *s;
01038       int n;
01039       p->pass1.pausemodelnames = (char*)mymalloc(strlen(p->config->successive.pausemodelname)+1);
01040       strcpy(p->pass1.pausemodelnames, p->config->successive.pausemodelname);
01041       n = 0;
01042       for (s = strtok(p->pass1.pausemodelnames, " ,"); s; s = strtok(NULL, " ,")) {
01043         n++;
01044       }
01045       p->pass1.pausemodelnum = n;
01046       p->pass1.pausemodel = (char **)mymalloc(sizeof(char *) * n);
01047       strcpy(p->pass1.pausemodelnames, p->config->successive.pausemodelname);
01048       n = 0;
01049       for (s = strtok(p->pass1.pausemodelnames, " ,"); s; s = strtok(NULL, " ,")) {
01050         p->pass1.pausemodel[n++] = s;
01051       }
01052     } else {
01053       p->pass1.pausemodel = NULL;
01054     }
01055     /* check if pause word exists on dictionary */
01056     {
01057       WORD_ID w;
01058       boolean ok_p;
01059       ok_p = FALSE;
01060       for(w=0;w<p->lm->winfo->num;w++) {
01061         if (is_sil(w, p)) {
01062           ok_p = TRUE;
01063           break;
01064         }
01065       }
01066       if (!ok_p) {
01067 #ifdef SPSEGMENT_NAIST
01068         jlog("Error: no pause word in dictionary needed for decoder-based VAD\n");
01069 #else
01070         jlog("Error: no pause word in dictionary needed for short-pause segmentation\n");
01071 #endif
01072         jlog("Error: you should have at least one pause word in dictionary\n");
01073         jlog("Error: you can specify pause model names by \"-pausemodels\"\n");
01074         return FALSE;
01075       }
01076     }
01077   }
01078 
01079   /**********************************************/
01080   /******** set model-specific defaults *********/
01081   /**********************************************/
01082   if (p->lmtype == LM_PROB) {
01083     /* set default lm parameter if not specified */
01084     if (!p->config->lmp.lmp_specified) {
01085       if (p->am->hmminfo->is_triphone) {
01086         p->config->lmp.lm_weight = DEFAULT_LM_WEIGHT_TRI_PASS1;
01087         p->config->lmp.lm_penalty = DEFAULT_LM_PENALTY_TRI_PASS1;
01088       } else {
01089         p->config->lmp.lm_weight = DEFAULT_LM_WEIGHT_MONO_PASS1;
01090         p->config->lmp.lm_penalty = DEFAULT_LM_PENALTY_MONO_PASS1;
01091       }
01092     }
01093     if (!p->config->lmp.lmp2_specified) {
01094       if (p->am->hmminfo->is_triphone) {
01095         p->config->lmp.lm_weight2 = DEFAULT_LM_WEIGHT_TRI_PASS2;
01096         p->config->lmp.lm_penalty2 = DEFAULT_LM_PENALTY_TRI_PASS2;
01097       } else {
01098         p->config->lmp.lm_weight2 = DEFAULT_LM_WEIGHT_MONO_PASS2;
01099         p->config->lmp.lm_penalty2 = DEFAULT_LM_PENALTY_MONO_PASS2;
01100       }
01101     }
01102     if (p->config->lmp.lmp_specified != p->config->lmp.lmp2_specified) {
01103       jlog("WARNING: m_fusion: only -lmp or -lmp2 specified, LM weights may be unbalanced\n");
01104     }
01105   }
01106 
01107   /****************************/
01108   /******* build wchmm ********/
01109   /****************************/
01110   if (p->lmtype == LM_DFA) {
01111     /* execute generation of global grammar and build of wchmm */
01112     multigram_build(p); /* some modification occured if return TRUE */
01113   }
01114 
01115   if (p->lmtype == LM_PROB) {
01116     /* build wchmm with N-gram */
01117     p->wchmm = wchmm_new();
01118     p->wchmm->lmtype = p->lmtype;
01119     p->wchmm->lmvar  = p->lmvar;
01120     p->wchmm->ccd_flag = p->ccd_flag;
01121     p->wchmm->category_tree = FALSE;
01122     p->wchmm->hmmwrk = &(p->am->hmmwrk);
01123     /* assign models */
01124     p->wchmm->ngram = p->lm->ngram;
01125     if (p->lmvar == LM_NGRAM_USER) {
01126       /* register LM functions for 1st pass here */
01127       p->wchmm->uni_prob_user = p->lm->lmfunc.uniprob;
01128       p->wchmm->bi_prob_user = p->lm->lmfunc.biprob;
01129     }
01130     p->wchmm->winfo = p->lm->winfo;
01131     p->wchmm->hmminfo = p->am->hmminfo;
01132     if (p->wchmm->category_tree) {
01133       if (p->config->pass1.old_tree_function_flag) {
01134         if (build_wchmm(p->wchmm, p->lm->config) == FALSE) {
01135           jlog("ERROR: m_fusion: error in bulding wchmm\n");
01136           return FALSE;
01137         }
01138       } else {
01139         if (build_wchmm2(p->wchmm, p->lm->config) == FALSE) {
01140           jlog("ERROR: m_fusion: error in bulding wchmm\n");
01141           return FALSE;
01142         }
01143       }
01144     } else {
01145       if (build_wchmm2(p->wchmm, p->lm->config) == FALSE) {
01146         jlog("ERROR: m_fusion: error in bulding wchmm\n");
01147         return FALSE;
01148       }
01149     }
01150 
01151     /* 起動時 -check でチェックモードへ */
01152     if (p->config->sw.wchmm_check_flag) {
01153       wchmm_check_interactive(p->wchmm);
01154     }
01155 
01156     /* set beam width */
01157     /* guess beam width from models, when not specified */
01158     p->trellis_beam_width = set_beam_width(p->wchmm, p->config->pass1.specified_trellis_beam_width);
01159 
01160     /* initialize cache for factoring */
01161     max_successor_cache_init(p->wchmm);
01162   }
01163 
01164   /* backtrellis initialization */
01165   p->backtrellis = (BACKTRELLIS *)mymalloc(sizeof(BACKTRELLIS));
01166   bt_init(p->backtrellis);
01167 
01168   /* prepare work area for 2nd pass */
01169   wchmm_fbs_prepare(p);
01170 
01171   jlog("STAT: SR%02d %s composed\n", sconf->id, sconf->name);
01172 
01173   if (sconf->sw.start_inactive) {
01174     /* start inactive */
01175     p->active = -1;
01176   } else {
01177     /* book activation for the recognition */
01178     p->active = 1;
01179   }
01180   if (p->lmtype == LM_DFA) {
01181     if (p->lm->winfo == NULL ||
01182         (p->lmvar == LM_DFA_GRAMMAR && p->lm->dfa == NULL)) {
01183       /* make this instance inactive */
01184       p->active = -1;
01185     }
01186   }
01187 
01188   return TRUE;
01189 }
01190 
01191 
01245 boolean
01246 j_final_fusion(Recog *recog)
01247 {
01248   MFCCCalc *mfcc;
01249   JCONF_SEARCH *sconf;
01250   PROCESS_AM *am;
01251 
01252   jlog("STAT: ------\n");
01253   jlog("STAT: All models are ready, go for final fusion\n");
01254   jlog("STAT: [1] create MFCC extraction instance(s)\n");
01255   if (recog->jconf->input.type == INPUT_WAVEFORM) {
01256     /***************************************************/
01257     /* create MFCC calculation instance from AM config */
01258     /* according to the fixated parameter information  */
01259     /***************************************************/
01260     create_mfcc_calc_instances(recog);
01261   }
01262 
01263   /****************************************/
01264   /* create recognition process instances */
01265   /****************************************/
01266   jlog("STAT: [2] create recognition processing instance(s) with AM and LM\n");
01267   for(sconf=recog->jconf->search_root;sconf;sconf=sconf->next) {
01268     if (j_launch_recognition_instance(recog, sconf) == FALSE) return FALSE;
01269   }
01270 
01271   /****************************/
01272   /****** initialize GMM ******/
01273   /****************************/
01274   if (recog->gmm != NULL) {
01275     jlog("STAT: [2.5] create GMM instance\n");
01276     if (gmm_init(recog) == FALSE) {
01277       jlog("ERROR: m_fusion: error in initializing GMM\n");
01278       return FALSE;
01279     }
01280   }
01281 
01282   /* stage 4: setup output probability function for each AM */
01283   jlog("STAT: [3] initialize for acoustic HMM calculation\n");
01284   for(am=recog->amlist;am;am=am->next) {
01285 #ifdef ENABLE_PLUGIN
01286     /* set plugin function if specified */
01287     if (am->config->gprune_method == GPRUNE_SEL_USER) {
01288       am->hmmwrk.compute_gaussset = (void (*)(HMMWork *, HTK_HMM_Dens **, int, int *, int)) plugin_get_func(am->config->gprune_plugin_source, "calcmix");
01289       if (am->hmmwrk.compute_gaussset == NULL) {
01290         jlog("ERROR: calcmix plugin has no function \"calcmix\"\n");
01291         return FALSE;
01292       }
01293       am->hmmwrk.compute_gaussset_init = (boolean (*)(HMMWork *)) plugin_get_func(am->config->gprune_plugin_source, "calcmix_init");
01294       if (am->hmmwrk.compute_gaussset_init == NULL) {
01295         jlog("ERROR: calcmix plugin has no function \"calcmix_init\"\n");
01296         return FALSE;
01297       }
01298       am->hmmwrk.compute_gaussset_free = (void (*)(HMMWork *)) plugin_get_func(am->config->gprune_plugin_source, "calcmix_free");
01299       if (am->hmmwrk.compute_gaussset_free == NULL) {
01300         jlog("ERROR: calcmix plugin has no function \"calcmix_free\"\n");
01301         return FALSE;
01302       }
01303     }
01304 #endif
01305     if (am->config->hmm_gs_filename != NULL) {/* with GMS */
01306       if (outprob_init(&(am->hmmwrk), am->hmminfo, am->hmm_gs, am->config->gs_statenum, am->config->gprune_method, am->config->mixnum_thres) == FALSE) {
01307         return FALSE;
01308       }
01309     } else {
01310       if (outprob_init(&(am->hmmwrk), am->hmminfo, NULL, 0, am->config->gprune_method, am->config->mixnum_thres) == FALSE) {
01311         return FALSE;
01312       }
01313     }
01314   }
01315 
01316   /* stage 5: initialize work area for input and realtime decoding */
01317 
01318   jlog("STAT: [4] prepare MFCC storage(s)\n");
01319   if (recog->jconf->input.type == INPUT_VECTOR) {
01320     /* create an MFCC instance for MFCC input */
01321     /* create new mfcc instance */
01322     recog->mfcclist = j_mfcccalc_new(NULL);
01323     recog->mfcclist->id = 1;
01324     /* assign to the am */
01325     for(am=recog->amlist;am;am=am->next) {
01326       am->mfcc = recog->mfcclist;
01327     }
01328     if (recog->gmm) recog->gmmmfcc = recog->mfcclist;
01329   }
01330   /* allocate parameter holders */
01331   for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
01332     mfcc->param = new_param();
01333   }
01334   
01335   /* initialize SS calculation work area */
01336   if (recog->jconf->input.type == INPUT_WAVEFORM) {
01337     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
01338       if (mfcc->frontend.sscalc) {
01339         mfcc->frontend.mfccwrk_ss = WMP_work_new(mfcc->para);
01340         if (mfcc->frontend.mfccwrk_ss == NULL) {
01341           jlog("ERROR: m_fusion: failed to initialize MFCC computation for SS\n");
01342           return FALSE;
01343         }
01344         if (mfcc->frontend.sscalc_len * recog->jconf->input.sfreq / 1000 < mfcc->para->framesize) {
01345           jlog("ERROR: m_fusion: head sil length for SS (%d msec) is shorter than a frame (%d msec)\n", mfcc->frontend.sscalc_len, mfcc->para->framesize * 1000 / recog->jconf->input.sfreq);
01346           return FALSE;
01347         }
01348       }
01349     }
01350   }
01351 
01352   if (recog->jconf->decodeopt.realtime_flag) {
01353     jlog("STAT: [5] prepare for real-time decoding\n");
01354     /* prepare for 1st pass pipeline processing */
01355     if (recog->jconf->input.type == INPUT_WAVEFORM) {
01356       if (RealTimeInit(recog) == FALSE) {
01357         jlog("ERROR: m_fusion: failed to initialize recognition process\n");
01358         return FALSE;
01359       }
01360     }
01361   }
01362 
01363   /* finished! */
01364   jlog("STAT: All init successfully done\n\n");
01365 
01366   /* set-up callback plugin if any */
01367 #ifdef ENABLE_PLUGIN
01368   if (plugin_exec_engine_startup(recog) == FALSE) {
01369     jlog("ERROR: m_fusion: failed to execute callback setup in plugin\n");
01370     return FALSE;
01371   }
01372 #endif
01373 
01374   return TRUE;
01375 }
01376 
01377 /* end of file */