1 /**
2  * @file   m_fusion.c
3  *
4  * <JA>
5  * @brief  ǧ���κǽ���������.
6  *
7  * ����˽�������ǥ���ɤ߹��ߡ��ڹ�¤������ʤɤΥǡ�����¤�ι��ۡ�
8  * ������ꥢ�γ��ݤʤɡ�ǧ�����Ϥ�ɬ�פʴĶ��ι��ۤ�Ԥʤ�.
9  * </JA>
10  *
11  * <EN>
12  * @brief  Final set up for recognition.
13  *
14  * These functions build everything needed for recognition: load
15  * models into memory, build data structures such as tree lexicon, and
16  * allocate work area for computation.
17  *
18  * </EN>
19  *
20  * @author Akinobu Lee
21  * @date   Thu May 12 13:31:47 2005
22  *
23  * $Revision: 1.13 $
24  *
25  */
26 /*
27  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
28  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
29  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
30  * All rights reserved
31  */
32 
33 #include <julius/julius.h>
34 
35 /**
36  * <JA>
37  * @brief  ����HMM��ե����뤫���ɤ߹��ߡ�ǧ���Ѥ˥��åȥ��åפ���.
38  *
39  * �ե����뤫���HMM������ɤ߹��ߡ�HMMList �ե�������ɤ߹��ߡ�
40  * �ѥ�᡼�����Υ����å����ޥ���ѥ������� on/off, �ݡ�����ǥ������ʤ�
41  * ���Ԥ�졤ǧ���Τ���ν������Ԥ���.
42  *
43  * ���β�����ǥ�����ϤȤʤ벻���ѥ�᡼���μ����ѥ�᡼���⤳����
44  * �ǽ����ꤵ���. ����ˤϡ�����HMM�Υإå����ʥХ��ʥ�HMM�ξ�硤¸
45  * �ߤ���С˥Х��ʥ�HMM�������ޤ줿��ħ�̾���jconf ������ʤФ��
46  * ��ˡ����뤤�� -htkconf ���ѻ��ˤʤɤξ����Ѥ�����.
47  * </JA>
48  * <EN>
49  * @brief  Read in an acoustic HMM from file and setup for recognition.
50  *
51  * This functions reads HMM definitions from file, reads also a
52  * HMMList file, makes logical-to-physical model mapping, determine
53  * required parameter type, determine whether multi-path handling is needed,
54  * and find pause model in the definitions.
55  *
56  * The feature vector extraction parameters are also finally
57  * determined in this function.  Informations used for the
58  * determination is (1) the header values in hmmdefs, (2) embedded
59  * parameters in binary HMM if you are reading a binary HMM made with
60  * recent mkbinhmm, (3) user-specified parameters in jconf
61  * configurations (either by separatedly specified or by -htkconf
62  * options).
63  *
64  * </EN>
65  *
66  * @param amconf [in] AM configuration variables
67  * @param jconf [i/o] global configuration variables
68  *
69  * @return the newly created HMM information structure, or NULL on failure.
70  *
71  */
72 static HTK_HMM_INFO *
initialize_HMM(JCONF_AM * amconf,Jconf * jconf)73 initialize_HMM(JCONF_AM *amconf, Jconf *jconf)
74 {
75   HTK_HMM_INFO *hmminfo;
76 
77   /* at here, global variable "para" holds values specified by user or
78      by user-specified HTK config file */
79   if (amconf->analysis.para_hmm.loaded == 1) {
80     jlog("Warning: you seems to read more than one acoustic model for recognition, but\n");
81     jlog("Warning: previous one already has header-embedded acoustic parameters\n");
82     jlog("Warning: if you have different parameters, result may be wrong!\n");
83   }
84 
85   /* allocate new hmminfo */
86   hmminfo = hmminfo_new();
87   /* load hmmdefs */
88   if (init_hmminfo(hmminfo, amconf->hmmfilename, amconf->mapfilename, &(amconf->analysis.para_hmm)) == FALSE) {
89     hmminfo_free(hmminfo);
90     return NULL;
91   }
92 
93   /* set multipath mode flag */
94   if (amconf->force_multipath) {
95     jlog("STAT: m_fusion: force multipath HMM handling by user request\n");
96     hmminfo->multipath = TRUE;
97   } else {
98     hmminfo->multipath = hmminfo->need_multipath;
99   }
100 
101   /* only MFCC is supported for audio input */
102   /* MFCC_{0|E}[_D][_A][_Z][_N] is supported */
103   /* check parameter type of this acoustic HMM */
104   if (jconf->input.type == INPUT_WAVEFORM) {
105     /* Decode parameter extraction type according to the training
106        parameter type in the header of the given acoustic HMM */
107     if ((hmminfo->opt.param_type & F_BASEMASK) != F_MFCC) {
108       jlog("ERROR: m_fusion: for direct speech input, only HMM trained by MFCC is supported\n");
109       hmminfo_free(hmminfo);
110       return NULL;
111     }
112     /* set acoustic analysis parameters from HMM header */
113     calc_para_from_header(&(amconf->analysis.para), hmminfo->opt.param_type, hmminfo->opt.vec_size);
114   }
115   /* check if tied_mixture */
116   if (hmminfo->is_tied_mixture && hmminfo->codebooknum <= 0) {
117     jlog("ERROR: m_fusion: this tied-mixture model has no codebook!?\n");
118     hmminfo_free(hmminfo);
119     return NULL;
120   }
121 
122 #ifdef PASS1_IWCD
123   /* make state clusters of same context for inter-word triphone approx. */
124   if (hmminfo->is_triphone) {
125     jlog("STAT: making pseudo bi/mono-phone for IW-triphone\n");
126     if (make_cdset(hmminfo) == FALSE) {
127       jlog("ERROR: m_fusion: failed to make context-dependent state set\n");
128       hmminfo_free(hmminfo);
129       return NULL;
130     }
131     /* add those `pseudo' biphone and monophone to the logical HMM names */
132     /* they points not to the defined HMM, but to the CD_Set structure */
133     hmm_add_pseudo_phones(hmminfo);
134   }
135 #endif
136 
137   /* find short pause model and set to hmminfo->sp */
138   htk_hmm_set_pause_model(hmminfo, amconf->spmodel_name);
139 
140 
141   hmminfo->cdset_method = amconf->iwcdmethod;
142   hmminfo->cdmax_num = amconf->iwcdmaxn;
143 
144   if (amconf->analysis.para_htk.loaded == 1) apply_para(&(amconf->analysis.para), &(amconf->analysis.para_htk));
145   if (amconf->analysis.para_hmm.loaded == 1) apply_para(&(amconf->analysis.para), &(amconf->analysis.para_hmm));
146   apply_para(&(amconf->analysis.para), &(amconf->analysis.para_default));
147 
148   return(hmminfo);
149 
150 }
151 
152 /**
153  * <JA>
154  * Gaussian Mixture Selection �Τ���ξ��������ѥ�Υե���HMM���ɤ߹���.
155  * </JA>
156  * <EN>
157  * Initialize context-independent HMM for state selection with Gaussian
158  * Mixture Selection.
159  * </EN>
160  *
161  * @param amconf [in] AM configuratino variables
162  *
163  * @return the newly created HMM information structure, or NULL on failure.
164  */
165 static HTK_HMM_INFO *
initialize_GSHMM(JCONF_AM * amconf)166 initialize_GSHMM(JCONF_AM *amconf)
167 {
168   HTK_HMM_INFO *hmm_gs;
169   Value para_dummy;
170 
171   jlog("STAT: Reading GS HMMs:\n");
172   hmm_gs = hmminfo_new();
173   undef_para(&para_dummy);
174   if (init_hmminfo(hmm_gs, amconf->hmm_gs_filename, NULL, &para_dummy) == FALSE) {
175     hmminfo_free(hmm_gs);
176     return NULL;
177   }
178   return(hmm_gs);
179 }
180 
181 /**
182  * <JA>
183  * ȯ�ø��ڡ������Ѥ�1���� GMM ���ɤ߹���ǽ��������.
184  *
185  * </JA>
186  * <EN>
187  * Read and initialize an 1-state GMM for utterance verification and
188  * rejection.
189  *
190  * </EN>
191  *
192  * @param jconf [in] global configuration variables
193  *
194  * @return the newly created GMM information structure in HMM format,
195  * or NULL on failure.
196  */
197 static HTK_HMM_INFO *
initialize_GMM(Jconf * jconf)198 initialize_GMM(Jconf *jconf)
199 {
200   HTK_HMM_INFO *gmm;
201 
202   jlog("STAT: reading GMM: %s\n", jconf->reject.gmm_filename);
203 
204   if (jconf->gmm == NULL) {
205     /* no acoustic parameter setting was given for GMM using -AM_GMM,
206        copy the first AM setting */
207     jlog("STAT: -AM_GMM not used, use parameter of the first AM\n");
208     jconf->gmm = j_jconf_am_new();
209     memcpy(jconf->gmm, jconf->am_root, sizeof(JCONF_AM));
210     jconf->gmm->hmmfilename = NULL;
211     jconf->gmm->mapfilename = NULL;
212     jconf->gmm->spmodel_name = NULL;
213     jconf->gmm->hmm_gs_filename = NULL;
214     if (jconf->am_root->analysis.cmnload_filename) {
215       jconf->gmm->analysis.cmnload_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->analysis.cmnload_filename)+ 1), jconf->am_root->analysis.cmnload_filename);
216     }
217     if (jconf->am_root->analysis.cmnsave_filename) {
218       jconf->gmm->analysis.cmnsave_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->analysis.cmnsave_filename)+ 1), jconf->am_root->analysis.cmnsave_filename);
219     }
220     if (jconf->am_root->frontend.ssload_filename) {
221       jconf->gmm->frontend.ssload_filename = strcpy((char *)mymalloc(strlen(jconf->am_root->frontend.ssload_filename)+ 1), jconf->am_root->frontend.ssload_filename);
222     }
223   }
224 
225   gmm = hmminfo_new();
226   if (init_hmminfo(gmm, jconf->reject.gmm_filename, NULL, &(jconf->gmm->analysis.para_hmm)) == FALSE) {
227     hmminfo_free(gmm);
228     return NULL;
229   }
230   /* check parameter type of this acoustic HMM */
231   if (jconf->input.type == INPUT_WAVEFORM) {
232     /* Decode parameter extraction type according to the training
233        parameter type in the header of the given acoustic HMM */
234     if ((gmm->opt.param_type & F_BASEMASK) != F_MFCC) {
235       jlog("ERROR: m_fusion: for direct speech input, only GMM trained by MFCC is supported\n");
236       hmminfo_free(gmm);
237       return NULL;
238     }
239   }
240 
241   /* set acoustic analysis parameters from HMM header */
242   calc_para_from_header(&(jconf->gmm->analysis.para), gmm->opt.param_type, gmm->opt.vec_size);
243 
244   if (jconf->gmm->analysis.para_htk.loaded == 1) apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_htk));
245   if (jconf->gmm->analysis.para_hmm.loaded == 1) apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_hmm));
246   apply_para(&(jconf->gmm->analysis.para), &(jconf->gmm->analysis.para_default));
247 
248   return(gmm);
249 }
250 
251 /**
252  * <JA>
253  * @brief  ñ�켭���ե����뤫���ɤ߹���ǥ��åȥ��åפ���.
254  *
255  * �����Υ�Υե���ɽ������ȥ饤�ե���ؤη׻��� init_voca() ��
256  * �ɤ߹��߻��˹Ԥ���. ���Τ��ᡤ�����ɤ߹��߻��ˤϡ�ǧ���ǻ��Ѥ���
257  * ͽ���HMM�����Ϳ����ɬ�פ�����.
258  *
259  * N-gram ���ѻ��ϡ�ʸƬ̵��ñ�줪���ʸ��̵��ñ����������ꤹ��.
260  * �ޤ���"-iwspword" ������ϡ��ݡ���ñ�����κǸ����������.
261  *
262  * </JA>
263  * <EN>
264  * @brief  Read in word dictionary from a file and setup for recognition.
265  *
266  * Monophone-to-triphone conversion will be performed inside init_voca().
267  * So, an HMM definition data that will be used with the LM should also be
268  * specified as an argument.
269  *
270  * When reading dictionary for N-gram, sentence head silence word and
271  * tail silence word will be determined in this function.  Also,
272  * when an option "-iwspword" is specified, this will insert a pause
273  * word at the last of the given dictionary.
274  *
275  * </EN>
276  *
277  * @param lmconf [in] LM configuration variables
278  * @param hmminfo [in] HMM definition of each phone in dictionary, for
279  * phone checking and monophone-to-triphone conversion.
280  *
281  * @return the newly created word dictionary structure, or NULL on failure.
282  *
283  */
284 static WORD_INFO *
initialize_dict(JCONF_LM * lmconf,HTK_HMM_INFO * hmminfo)285 initialize_dict(JCONF_LM *lmconf, HTK_HMM_INFO *hmminfo)
286 {
287   WORD_INFO *winfo;
288 
289   /* allocate new word dictionary */
290   winfo = word_info_new();
291   /* read in dictinary from file */
292   if ( !
293 #ifdef MONOTREE
294       /* leave winfo monophone for 1st pass lexicon tree */
295        init_voca(winfo, lmconf->dictfilename, hmminfo, TRUE, lmconf->forcedict_flag)
296 #else
297        init_voca(winfo, lmconf->dictfilename, hmminfo, FALSE, lmconf->forcedict_flag)
298 #endif
299        ) {
300     jlog("ERROR: m_fusion: failed to read dictionary, terminated\n");
301     word_info_free(winfo);
302     return NULL;
303   }
304 
305   if (lmconf->lmtype == LM_PROB) {
306     /* if necessary, append a IW-sp word to the dict if "-iwspword" specified */
307     if (lmconf->enable_iwspword) {
308       if (
309 #ifdef MONOTREE
310 	  voca_append_htkdict(lmconf->iwspentry, winfo, hmminfo, TRUE)
311 #else
312 	  voca_append_htkdict(lmconf->iwspentry, winfo, hmminfo, FALSE)
313 #endif
314 	  == FALSE) {
315 	jlog("ERROR: m_fusion: failed to make IW-sp word entry \"%s\"\n", lmconf->iwspentry);
316 	word_info_free(winfo);
317 	return NULL;
318       } else {
319 	jlog("STAT: 1 IW-sp word entry added\n");
320       }
321     }
322     /* set {head,tail}_silwid */
323     winfo->head_silwid = voca_lookup_wid(lmconf->head_silname, winfo);
324     if (winfo->head_silwid == WORD_INVALID) { /* not exist */
325       jlog("ERROR: m_fusion: head sil word \"%s\" not exist in voca\n", lmconf->head_silname);
326       word_info_free(winfo);
327       return NULL;
328     }
329     winfo->tail_silwid = voca_lookup_wid(lmconf->tail_silname, winfo);
330     if (winfo->tail_silwid == WORD_INVALID) { /* not exist */
331       jlog("ERROR: m_fusion: tail sil word \"%s\" not exist in voca\n", lmconf->tail_silname);
332       word_info_free(winfo);
333       return NULL;
334     }
335   }
336 
337   return(winfo);
338 
339 }
340 
341 
342 /**
343  * <JA>
344  * @brief  ñ��N-gram��ե����뤫���ɤ߹���ǥ��åȥ��åפ���.
345  *
346  * ARPA �ե����ޥåȤǻ�����ϡ�LR�ե������ RL �ե�������ȹ礻��
347  * ư��ۤʤ�. LR �Τߡ����뤤�� RL �Τ߻�����ϡ�������Τޤ��ɤ߹���.
348  * �����Ȥ���ꤵ��Ƥ�����ϡ�RL��ޤ����ǥ�Ȥ����ɤ߹�����塤
349  * LR �� 2-gram ��������1�ѥ��Ѥ˼��ǥ���ɲ��ɤ߹��ߤ���.
350  *
351  * �ޤ����ɤ߹��߽�λ�塤������N-gram����ȥ�ȤΥޥå�������.
352  *
353  * </JA>
354  * <EN>
355  * @brief  Read in word N-gram from file and setup for recognition.
356  *
357  * When N-gram is specified in ARPA format, the behavior relies on whether
358  * N-grams are specified in "-nlr" and "-nrl".  When either of them was
359  * solely specified,  this function simply read it.  If both are specified,
360  * it will read the RL model fully as a primary model, and additionally
361  * read only the 2-gram part or the LR model as the first pass LM.
362  *
363  * Also, this function create mapping from dictionary words to LM entry.
364  *
365  * </EN>
366  *
367  * @param lmconf [in] LM configuration variables
368  * @param winfo [i/o] word dictionary that will be used with this N-gram.
369  * each word in the dictionary will be assigned to an N-gram entry here.
370  *
371  * @return the newly created N-gram information data, or NULL on failure.
372  *
373  */
374 static NGRAM_INFO *
initialize_ngram(JCONF_LM * lmconf,WORD_INFO * winfo)375 initialize_ngram(JCONF_LM *lmconf, WORD_INFO *winfo)
376 {
377   NGRAM_INFO *ngram;
378   boolean ret;
379 
380   /* allocate new */
381   ngram = ngram_info_new();
382   /* load LM */
383   if (lmconf->ngram_filename != NULL) {	/* binary format */
384     ret = init_ngram_bin(ngram, lmconf->ngram_filename);
385   } else {			/* ARPA format */
386     /* if either forward or backward N-gram is specified, read it */
387     /* if both specified, use backward N-gram as main and
388        use forward 2-gram only for 1st pass (this is an old behavior) */
389     if (lmconf->ngram_filename_rl_arpa) {
390       ret = init_ngram_arpa(ngram, lmconf->ngram_filename_rl_arpa, DIR_RL);
391       if (ret == FALSE) {
392 	ngram_info_free(ngram);
393 	return NULL;
394       }
395       if (lmconf->ngram_filename_lr_arpa) {
396 	ret = init_ngram_arpa_additional(ngram, lmconf->ngram_filename_lr_arpa);
397 	if (ret == FALSE) {
398 	  ngram_info_free(ngram);
399 	  return NULL;
400 	}
401       }
402     } else if (lmconf->ngram_filename_lr_arpa) {
403       ret = init_ngram_arpa(ngram, lmconf->ngram_filename_lr_arpa, DIR_LR);
404     }
405   }
406   if (ret == FALSE) {
407     ngram_info_free(ngram);
408     return NULL;
409   }
410 
411   /* set unknown (=OOV) word id */
412   set_unknown_id(ngram, lmconf->unknown_name);
413 
414   /* map dict item to N-gram entry */
415   if (make_voca_ref(ngram, winfo) == FALSE) {
416     ngram_info_free(ngram);
417     return NULL;
418   }
419 
420   /* post-fix EOS / BOS uni prob for SRILM */
421   fix_uniprob_srilm(ngram, winfo);
422 
423   return(ngram);
424 }
425 
426 /**
427  * <EN>
428  * @brief  Load an acoustic model.
429  *
430  * This function will create an AM process instance using the given AM
431  * configuration, and load models specified in the configuration into
432  * the instance.  Then the created instance will be installed to the
433  * engine instance.  The amconf should be registered to the global
434  * jconf before calling this function.
435  *
436  * </EN>
437  *
438  * <JA>
439  * @brief ������ǥ���ɤ߹��ࡥ
440  *
441  * ���δؿ��ϡ�Ϳ����줿 AM ����˽��ä� AM ����������������������
442  * ������˲�����ǥ����ɤ��ޤ������θ塤����AM��������������
443  * �����˥���������������Ͽ����ޤ���AM����Ϥ��δؿ���
444  * �Ƥ����ˤ��餫������������recog->jconf����Ͽ����Ƥ���ɬ�פ�����ޤ���
445  *
446  * </JA>
447  *
448  * @param recog [i/o] engine instance
449  * @param amconf [in] AM configuration to load
450  *
451  * @return TRUE on success, or FALSE on error.
452  *
453  * @callgraph
454  * @callergraph
455  * @ingroup instance
456  *
457  */
458 boolean
j_load_am(Recog * recog,JCONF_AM * amconf)459 j_load_am(Recog *recog, JCONF_AM *amconf)
460 {
461   PROCESS_AM *am;
462 
463   jlog("STAT: *** loading AM%02d %s\n", amconf->id, amconf->name);
464 
465   /* create AM process instance */
466   am = j_process_am_new(recog, amconf);
467 
468   /* HMM */
469   if ((am->hmminfo = initialize_HMM(amconf, recog->jconf)) == NULL) {
470     jlog("ERROR: m_fusion: failed to initialize AM\n");
471     return FALSE;
472   }
473   if (amconf->hmm_gs_filename != NULL) {
474     if ((am->hmm_gs = initialize_GSHMM(amconf)) == NULL) {
475       jlog("ERROR: m_fusion: failed to initialize GS HMM\n");
476       return FALSE;
477     }
478   }
479 
480   /* fixate model-specific params */
481   /* set params whose default will change by models and not specified in arg */
482   /* select Gaussian pruning function */
483   if (am->config->gprune_method == GPRUNE_SEL_UNDEF) {/* set default if not specified */
484     if (am->hmminfo->is_tied_mixture) {
485       /* enabled by default for tied-mixture models */
486 #if defined(GPRUNE_DEFAULT_SAFE)
487       am->config->gprune_method = GPRUNE_SEL_SAFE;
488 #elif defined(GPRUNE_DEFAULT_HEURISTIC)
489       am->config->gprune_method = GPRUNE_SEL_HEURISTIC;
490 #elif defined(GPRUNE_DEFAULT_BEAM)
491       am->config->gprune_method = GPRUNE_SEL_BEAM;
492 #endif
493     } else {
494       /* disabled by default for non tied-mixture model */
495       am->config->gprune_method = GPRUNE_SEL_NONE;
496     }
497   }
498 
499   /* fixated analysis.para not uses loaded flag any more, so
500      reset it for binary matching */
501   amconf->analysis.para.loaded = 0;
502 
503   jlog("STAT: *** AM%02d %s loaded\n", amconf->id, amconf->name);
504 
505   return TRUE;
506 }
507 
508 /**
509  * <EN>
510  * @brief  Load a language model.
511  *
512  * This function will create an LM process instance using the given LM
513  * configuration, and load models specified in the configuration into
514  * the instance.  Then the created instance will be installed to the
515  * engine instance.  The lmconf should be registered to the
516  * recog->jconf before calling this function.
517  *
518  * To convert phoneme sequence to triphone at loading, you should
519  * specify which AM to use with this LM by the argument am.
520  *
521  * </EN>
522  *
523  * <JA>
524  * @brief �����ǥ���ɤ߹��ࡥ
525  *
526  * ���δؿ��ϡ�Ϳ����줿 LM ����˽��ä� LM ����������������������
527  * ������˸����ǥ����ɤ��ޤ������θ塤����LM��������������
528  * �����˥���������������Ͽ����ޤ���LM����Ϥ��δؿ���
529  * �Ƥ����ˤ��餫������������recog->jconf����Ͽ����Ƥ���ɬ�פ�����ޤ���
530  *
531  * ������ɤ߹��߻��˥ȥ饤�ե���ؤ��Ѵ�����Ӳ�����ǥ�ȤΥ����
532  * Ʊ���˹Ԥ��ޤ������Τ��ᡤ���θ����ǥ뤬���Ѥ��벻����ǥ��
533  * ������������� am �Ȥ��ƻ��ꤹ��ɬ�פ�����ޤ���
534  *
535  * </JA>
536  *
537  * @param recog [i/o] engine instance
538  * @param lmconf [in] LM configuration to load
539  *
540  * @return TRUE on success, or FALSE on error.
541  *
542  * @callgraph
543  * @callergraph
544  * @ingroup instance
545  *
546  */
547 boolean
j_load_lm(Recog * recog,JCONF_LM * lmconf)548 j_load_lm(Recog *recog, JCONF_LM *lmconf)
549 {
550   JCONF_SEARCH *sh;
551   PROCESS_LM *lm;
552   PROCESS_AM *am, *atmp;
553 
554   jlog("STAT: *** loading LM%02d %s\n", lmconf->id, lmconf->name);
555 
556   /* find which am process instance to assign to each LM */
557   am = NULL;
558   for(sh=recog->jconf->search_root;sh;sh=sh->next) {
559     if (sh->lmconf == lmconf) {
560       for(atmp=recog->amlist;atmp;atmp=atmp->next) {
561 	if (sh->amconf == atmp->config) {
562 	  am = atmp;
563 	}
564       }
565     }
566   }
567   if (am == NULL) {
568     jlog("ERROR: cannot find corresponding AM for LM%02d %s\n", lmconf->id, lmconf->name);
569     jlog("ERROR: you should write all AM/LM combinations to be used for recognition with \"-SR\"\n");
570     return FALSE;
571   }
572 
573   /* create LM process instance */
574   lm = j_process_lm_new(recog, lmconf);
575 
576   /* assign AM process instance to the LM instance */
577   lm->am = am;
578 
579   /* load language model */
580   if (lm->lmtype == LM_PROB) {
581     /* LM (N-gram) */
582     if ((lm->winfo = initialize_dict(lm->config, lm->am->hmminfo)) == NULL) {
583       jlog("ERROR: m_fusion: failed to initialize dictionary\n");
584       return FALSE;
585     }
586     if (lm->config->ngram_filename_lr_arpa || lm->config->ngram_filename_rl_arpa || lm->config->ngram_filename) {
587       if ((lm->ngram = initialize_ngram(lm->config, lm->winfo)) == NULL) {
588 	jlog("ERROR: m_fusion: failed to initialize N-gram\n");
589 	return FALSE;
590       }
591     }
592   }
593   if (lm->lmtype == LM_DFA) {
594     /* DFA */
595     if (lm->config->dfa_filename != NULL && lm->config->dictfilename != NULL) {
596       /* here add grammar specified by "-dfa" and "-v" to grammar list */
597       multigram_add_gramlist(lm->config->dfa_filename, lm->config->dictfilename, lm->config, LM_DFA_GRAMMAR);
598     }
599     /* load all the specified grammars */
600     if (multigram_load_all_gramlist(lm) == FALSE) {
601       jlog("ERROR: m_fusion: some error occured in reading grammars\n");
602       return FALSE;
603     }
604     /* setup for later wchmm building */
605     multigram_update(lm);
606     /* the whole lexicon will be forced to built in the boot sequence,
607        so reset the global modification flag here */
608     lm->global_modified = FALSE;
609   }
610 
611   jlog("STAT: *** LM%02d %s loaded\n", lmconf->id, lmconf->name);
612 
613   return TRUE;
614 }
615 
616 /**********************************************************************/
617 /**
618  * <JA>
619  * @brief  ���ƤΥ�ǥ���ɤ߹��ߡ�ǧ���ν�����Ԥʤ�.
620  *
621  * ���δؿ��Ǥϡ�jconf ��ˤ����ʣ���Ρ� AM ����ѥ�᡼����¤�Τ�LM
622  * ����ѥ�᡼����¤�ΤΤ��줾����Ф��ơ�AM/LM������������������
623  * ����. �����Ƥ��줾��Υ��������ˤĤ��Ƥ�����˥�ǥ���ɤ߹��ߡ�
624  * ǧ���Ѥ˥��åȥ��åפ���. GMM�⤳�����ɤ߹��ޤ��.
625  *
626  * </JA>
627  * <EN>
628  * @brief  Read in all models for recognition.
629  *
630  * This function create AM/LM processing instance for each AM/LM
631  * configurations in jconf.  Then the model for each instance will be loaded
632  * into memory and set up for recognition.  GMM will also be read here.
633  *
634  * </EN>
635  *
636  * @param recog [i/o] engine instance
637  * @param jconf [in] global configuration variables
638  *
639  * @return TRUE on success, FALSE on failure.
640  *
641  * @callgraph
642  * @callergraph
643  * @ingroup instance
644  */
645 boolean
j_load_all(Recog * recog,Jconf * jconf)646 j_load_all(Recog *recog, Jconf *jconf)
647 {
648   JCONF_AM *amconf;
649   JCONF_LM *lmconf;
650 
651   /* set global jconf */
652   recog->jconf = jconf;
653 
654   /* load acoustic models */
655   for(amconf=jconf->am_root;amconf;amconf=amconf->next) {
656     if (j_load_am(recog, amconf) == FALSE) return FALSE;
657   }
658 
659   /* load language models */
660   for(lmconf=jconf->lm_root;lmconf;lmconf=lmconf->next) {
661     if (j_load_lm(recog, lmconf) == FALSE) return FALSE;
662   }
663 
664   /* GMM */
665   if (jconf->reject.gmm_filename != NULL) {
666     jlog("STAT: loading GMM\n");
667     if ((recog->gmm = initialize_GMM(jconf)) == NULL) {
668       jlog("ERROR: m_fusion: failed to initialize GMM\n");
669       return FALSE;
670     }
671   }
672 
673   /* check sampling rate requirement on AMs and set it to global jconf */
674   {
675     boolean ok_p;
676 
677     /* set input sampling rate from an AM */
678     jconf->input.sfreq = jconf->am_root->analysis.para.smp_freq;
679     jconf->input.period = jconf->am_root->analysis.para.smp_period;
680     jconf->input.frameshift = jconf->am_root->analysis.para.frameshift;
681     jconf->input.framesize = jconf->am_root->analysis.para.framesize;
682     /* check if the value is equal at all AMs */
683     ok_p = TRUE;
684     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
685       if (jconf->input.sfreq != amconf->analysis.para.smp_freq) ok_p = FALSE;
686     }
687     if (!ok_p) {
688       jlog("ERROR: required sampling rate differs in AMs!\n");
689       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
690 	jlog("ERROR: AM%02d %s: %dHz\n", amconf->analysis.para.smp_freq);
691       }
692       return FALSE;
693     }
694     /* also check equality for GMM */
695     if (recog->gmm) {
696       if (jconf->input.sfreq != jconf->gmm->analysis.para.smp_freq) {
697 	jlog("ERROR: required sampling rate differs between AM and GMM!\n");
698 	jlog("ERROR: AM : %dHz\n", jconf->input.sfreq);
699 	jlog("ERROR: GMM: %dHz\n", jconf->gmm->analysis.para.smp_freq);
700 	return FALSE;
701       }
702     }
703     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
704       if (jconf->input.frameshift != amconf->analysis.para.frameshift) ok_p = FALSE;
705     }
706     if (!ok_p) {
707       jlog("ERROR: requested frame shift differs in AMs!\n");
708       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
709 	jlog("ERROR: AM%02d %s: %d samples\n", amconf->analysis.para.frameshift);
710       }
711       return FALSE;
712     }
713     /* also check equality for GMM */
714     if (recog->gmm) {
715       if (jconf->input.frameshift != jconf->gmm->analysis.para.frameshift) {
716 	jlog("ERROR: required frameshift differs between AM and GMM!\n");
717 	jlog("ERROR: AM : %d samples\n", jconf->input.frameshift);
718 	jlog("ERROR: GMM: %d samples\n", jconf->gmm->analysis.para.frameshift);
719 	return FALSE;
720       }
721     }
722     for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
723       if (jconf->input.framesize != amconf->analysis.para.framesize) ok_p = FALSE;
724     }
725     if (!ok_p) {
726       jlog("ERROR: requested frame size (window length) differs in AMs!\n");
727       for(amconf = jconf->am_root; amconf; amconf = amconf->next) {
728 	jlog("ERROR: AM%02d %s: %d samples\n", amconf->analysis.para.framesize);
729       }
730       return FALSE;
731     }
732     /* also check equality for GMM */
733     if (recog->gmm) {
734       if (jconf->input.framesize != jconf->gmm->analysis.para.framesize) {
735 	jlog("ERROR: requested frame size differs between AM and GMM!\n");
736 	jlog("ERROR: AM : %d samples\n", jconf->input.framesize);
737 	jlog("ERROR: GMM: %d samples\n", jconf->gmm->analysis.para.framesize);
738 	return FALSE;
739       }
740     }
741   }
742 
743   return TRUE;
744 }
745 
746 /**
747  * <EN>
748  * Check if parameter extraction configuration is the same between an AM
749  * configuration and a MFCC instance.
750  * </EN>
751  * <JA>
752  * AM����ѥ�᡼���ȴ��˺��줿MFCC�׻����������֤ǡ��ѥ�᡼����Ф�
753  * ���꤬Ʊ��Ǥ��뤫�ɤ���������å�����.
754  *
755  * </JA>
756  *
757  * @param amconf [in] AM configuration parameters
758  * @param mfcc [in] MFCC calculation instance.
759  *
760  * @return TRUE if exactly the same, or FALSE if not.
761  *
762  */
763 static boolean
mfcc_config_is_same(JCONF_AM * amconf,MFCCCalc * mfcc)764 mfcc_config_is_same(JCONF_AM *amconf, MFCCCalc *mfcc)
765 {
766   char *s1, *s2;
767 
768   /* parameter extraction conditions are the same */
769   /* check exact match in amconf->analysis.* */
770   if (&(amconf->analysis.para) == mfcc->para || memcmp(&(amconf->analysis.para), mfcc->para, sizeof(Value)) == 0) {
771     s1 = amconf->analysis.cmnload_filename;
772     s2 = mfcc->cmn.load_filename;
773     if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
774       s1 = amconf->analysis.cmnsave_filename;
775       s2 = mfcc->cmn.save_filename;
776       if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
777 	if (amconf->analysis.cmn_update == mfcc->cmn.update
778 	    && amconf->analysis.cmn_map_weight == mfcc->cmn.map_weight) {
779 	  if (amconf->frontend.ss_alpha == mfcc->frontend.ss_alpha
780 	      && amconf->frontend.ss_floor == mfcc->frontend.ss_floor
781 	      && amconf->frontend.sscalc == mfcc->frontend.sscalc
782 	      && amconf->frontend.sscalc_len == mfcc->frontend.sscalc_len) {
783 	    s1 = amconf->frontend.ssload_filename;
784 	    s2 = mfcc->frontend.ssload_filename;
785 	    if (s1 == s2 || (s1 && s2 && strmatch(s1, s2))) {
786 	      return TRUE;
787 	    }
788 	  }
789 	}
790       }
791     }
792   }
793 
794   return FALSE;
795 }
796 
797 /***************************************************/
798 /* create MFCC calculation instance from AM config */
799 /* according to the fixated parameter information  */
800 /***************************************************/
801 /**
802  * <EN>
803  *
804  * @brief  Create MFCC calculation instance for AM processing instances and GMM
805  *
806  * If more than one AM processing instance (or GMM) has the same configuration,
807  * the same MFCC calculation instance will be shared among them.
808  *
809  * </EN>
810  * <JA>
811  *
812  * @brief  ���Ƥ�AM�����������������GMM�Ѥˡ�MFCC�׻�������������������.
813  *
814  * ���İʾ��AM�������������ʤ����GMM�ˤ�Ʊ�����ħ�̷׻������
815  * �ľ�硤�����Υ��������ϤҤȤĤ� MFCC �׻�����������ͭ����.
816  *
817  * </JA>
818  *
819  * @param recog [i/o] engine instance
820  *
821  * @callgraph
822  * @callergraph
823  *
824  */
825 void
create_mfcc_calc_instances(Recog * recog)826 create_mfcc_calc_instances(Recog *recog)
827 {
828   PROCESS_AM *am;
829   MFCCCalc *mfcc;
830   int count;
831 
832   jlog("STAT: *** create MFCC calculation modules from AM\n");
833   count = 0;
834   for(am=recog->amlist;am;am=am->next) {
835     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
836       if (mfcc_config_is_same(am->config, mfcc)) {
837 	/* the same */
838 	jlog("STAT: AM%02d %s: share MFCC%02d\n", am->config->id, am->config->name, mfcc->id);
839 	am->mfcc = mfcc;
840 	break;
841       }
842     }
843     if (!mfcc) {		/* the same not found */
844       /* initialize MFCC calculation work area */
845       count++;
846       /* create new mfcc instance */
847       mfcc = j_mfcccalc_new(am->config);
848       mfcc->id = count;
849       /* assign to the am */
850       am->mfcc = mfcc;
851       /* add to the list of all MFCCCalc */
852       mfcc->next = recog->mfcclist;
853       recog->mfcclist = mfcc;
854       jlog("STAT: AM%2d %s: create a new module MFCC%02d\n", am->config->id, am->config->name, mfcc->id);
855     }
856   }
857 
858   /* for GMM */
859   if (recog->gmm) {
860     /* if GMM calculation config found, make MFCC instance for that. */
861     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
862       if (mfcc_config_is_same(recog->jconf->gmm, mfcc)) {
863 	/* the same */
864 	jlog("STAT: GMM: share MFCC%02d\n", mfcc->id);
865 	recog->gmmmfcc = mfcc;
866 	break;
867 	}
868     }
869     if (!mfcc) {		/* the same not found */
870       /* initialize MFCC calculation work area */
871       count++;
872       /* create new mfcc instance */
873       mfcc = j_mfcccalc_new(recog->jconf->gmm);
874       mfcc->id = count;
875       /* assign to gmm */
876       recog->gmmmfcc = mfcc;
877       /* add to the list of all MFCCCalc */
878       mfcc->next = recog->mfcclist;
879       recog->mfcclist = mfcc;
880       jlog("STAT: GMM: create a new module MFCC%02d\n", mfcc->id);
881     }
882   }
883 
884   jlog("STAT: %d MFCC modules created\n", count);
885 }
886 
887 /**
888  * <EN>
889  * @brief  Launch a recognition process instance.
890  *
891  * This function will create an recognition process instance
892  * using the given SEARCH configuration, and launch recognizer for
893  * the search.  Then the created instance will be installed to the
894  * engine instance.  The sconf should be registered to the global
895  * jconf before calling this function.
896  *
897  * </EN>
898  *
899  * <JA>
900  * @brief ǧ����������������Ω���夲�롥
901  *
902  * ���δؿ��ϡ�Ϳ����줿 SEARCH ����˽��ä� ǧ������������������������
903  * �б����벻��ǧ������ۤ��ޤ������θ塤�����������줿ǧ����������������
904  * �����˥���������������Ͽ����ޤ���SEARCH����Ϥ��δؿ���
905  * �Ƥ����ˤ��餫������������jconf����Ͽ����Ƥ���ɬ�פ�����ޤ���
906  *
907  * </JA>
908  *
909  * @param recog [i/o] engine instance
910  * @param sconf [in] SEARCH configuration to launch
911  *
912  * @return TRUE on success, or FALSE on error.
913  *
914  * @callgraph
915  * @callergraph
916  * @ingroup instance
917  *
918  */
919 boolean
j_launch_recognition_instance(Recog * recog,JCONF_SEARCH * sconf)920 j_launch_recognition_instance(Recog *recog, JCONF_SEARCH *sconf)
921 {
922   RecogProcess *p;
923   PROCESS_AM *am;
924   PROCESS_LM *lm;
925 
926   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);
927 
928   /* allocate recognition instance */
929   p = j_recogprocess_new(recog, sconf);
930 
931   /* assign corresponding AM instance and LM instance to use */
932   for(lm=recog->lmlist;lm;lm=lm->next) {
933     if (sconf->lmconf == lm->config) {
934       for(am=recog->amlist;am;am=am->next) {
935 	if (sconf->amconf == am->config) {
936 	  p->am = am;
937 	  p->lm = lm;
938 	}
939       }
940     }
941   }
942 
943   if (p->config->sw.triphone_check_flag && p->am->hmminfo->is_triphone) {
944     /* go into interactive triphone HMM check mode */
945     hmm_check(p);
946   }
947 
948   /******************************************/
949   /******** set work area and flags *********/
950   /******************************************/
951 
952   /* copy values of sub instances for handly access during recognition */
953   /* set lm type */
954   p->lmtype = p->lm->lmtype;
955   p->lmvar  = p->lm->lmvar;
956   p->graphout = p->config->graph.enabled;
957 
958   /* set flag for context dependent handling */
959   if (p->config->force_ccd_handling) {
960     p->ccd_flag = p->config->ccd_handling;
961   } else {
962     if (p->am->hmminfo->is_triphone) {
963       p->ccd_flag = TRUE;
964     } else {
965       p->ccd_flag = FALSE;
966     }
967   }
968 
969   /* iwsp prepare */
970   if (p->lm->config->enable_iwsp) {
971     if (p->am->hmminfo->multipath) {
972       /* find short-pause model */
973       if (p->am->hmminfo->sp == NULL) {
974 	jlog("ERROR: iwsp enabled but no short pause model \"%s\" in hmmdefs\n", p->am->config->spmodel_name);
975 	return FALSE;
976       }
977       p->am->hmminfo->iwsp_penalty = p->am->config->iwsp_penalty;
978     } else {
979       jlog("Warning: \"-iwsp\" is supported on multi-path mode, ignored\n");
980     }
981   }
982 
983   /* for short-pause segmentation  */
984   if (p->config->successive.enabled) {
985     if (p->config->successive.pausemodelname) {
986       /* pause model name string specified, divide it and store to p */
987       char *s;
988       int n;
989       p->pass1.pausemodelnames = (char*)mymalloc(strlen(p->config->successive.pausemodelname)+1);
990       strcpy(p->pass1.pausemodelnames, p->config->successive.pausemodelname);
991       n = 0;
992       for (s = strtok(p->pass1.pausemodelnames, " ,"); s; s = strtok(NULL, " ,")) {
993 	n++;
994       }
995       p->pass1.pausemodelnum = n;
996       p->pass1.pausemodel = (char **)mymalloc(sizeof(char *) * n);
997       strcpy(p->pass1.pausemodelnames, p->config->successive.pausemodelname);
998       n = 0;
999       for (s = strtok(p->pass1.pausemodelnames, " ,"); s; s = strtok(NULL, " ,")) {
1000 	p->pass1.pausemodel[n++] = s;
1001       }
1002     } else {
1003       p->pass1.pausemodel = NULL;
1004     }
1005     /* check if pause word exists on dictionary */
1006     {
1007       WORD_ID w;
1008       boolean ok_p;
1009       ok_p = FALSE;
1010       for(w=0;w<p->lm->winfo->num;w++) {
1011 	if (is_sil(w, p)) {
1012 	  ok_p = TRUE;
1013 	  break;
1014 	}
1015       }
1016       if (!ok_p) {
1017 #ifdef SPSEGMENT_NAIST
1018 	jlog("Error: no pause word in dictionary needed for decoder-based VAD\n");
1019 #else
1020 	jlog("Error: no pause word in dictionary needed for short-pause segmentation\n");
1021 #endif
1022 	jlog("Error: you should have at least one pause word in dictionary\n");
1023 	jlog("Error: you can specify pause model names by \"-pausemodels\"\n");
1024 	return FALSE;
1025       }
1026     }
1027   }
1028 
1029   /**********************************************/
1030   /******** set model-specific defaults *********/
1031   /**********************************************/
1032   if (p->lmtype == LM_PROB) {
1033     /* set default lm parameter if not specified */
1034     if (!p->config->lmp.lmp_specified) {
1035       if (p->am->hmminfo->is_triphone) {
1036 	p->config->lmp.lm_weight = DEFAULT_LM_WEIGHT_TRI_PASS1;
1037 	p->config->lmp.lm_penalty = DEFAULT_LM_PENALTY_TRI_PASS1;
1038       } else {
1039 	p->config->lmp.lm_weight = DEFAULT_LM_WEIGHT_MONO_PASS1;
1040 	p->config->lmp.lm_penalty = DEFAULT_LM_PENALTY_MONO_PASS1;
1041       }
1042     }
1043     if (!p->config->lmp.lmp2_specified) {
1044       if (p->am->hmminfo->is_triphone) {
1045 	p->config->lmp.lm_weight2 = DEFAULT_LM_WEIGHT_TRI_PASS2;
1046 	p->config->lmp.lm_penalty2 = DEFAULT_LM_PENALTY_TRI_PASS2;
1047       } else {
1048 	p->config->lmp.lm_weight2 = DEFAULT_LM_WEIGHT_MONO_PASS2;
1049 	p->config->lmp.lm_penalty2 = DEFAULT_LM_PENALTY_MONO_PASS2;
1050       }
1051     }
1052     if (p->config->lmp.lmp_specified != p->config->lmp.lmp2_specified) {
1053       jlog("WARNING: m_fusion: only -lmp or -lmp2 specified, LM weights may be unbalanced\n");
1054     }
1055   }
1056 
1057   /****************************/
1058   /******* build wchmm ********/
1059   /****************************/
1060   if (p->lmtype == LM_DFA) {
1061     /* execute generation of global grammar and build of wchmm */
1062     multigram_build(p); /* some modification occured if return TRUE */
1063   }
1064 
1065   if (p->lmtype == LM_PROB) {
1066     /* build wchmm with N-gram */
1067     p->wchmm = wchmm_new();
1068     p->wchmm->lmtype = p->lmtype;
1069     p->wchmm->lmvar  = p->lmvar;
1070     p->wchmm->ccd_flag = p->ccd_flag;
1071     p->wchmm->category_tree = FALSE;
1072     p->wchmm->hmmwrk = &(p->am->hmmwrk);
1073     /* assign models */
1074     p->wchmm->ngram = p->lm->ngram;
1075     if (p->lmvar == LM_NGRAM_USER) {
1076       /* register LM functions for 1st pass here */
1077       p->wchmm->uni_prob_user = p->lm->lmfunc.uniprob;
1078       p->wchmm->bi_prob_user = p->lm->lmfunc.biprob;
1079     }
1080     p->wchmm->winfo = p->lm->winfo;
1081     p->wchmm->hmminfo = p->am->hmminfo;
1082     if (p->wchmm->category_tree) {
1083       if (p->config->pass1.old_tree_function_flag) {
1084 	if (build_wchmm(p->wchmm, p->lm->config) == FALSE) {
1085 	  jlog("ERROR: m_fusion: error in bulding wchmm\n");
1086 	  return FALSE;
1087 	}
1088       } else {
1089 	if (build_wchmm2(p->wchmm, p->lm->config) == FALSE) {
1090 	  jlog("ERROR: m_fusion: error in bulding wchmm\n");
1091 	  return FALSE;
1092 	}
1093       }
1094     } else {
1095       if (build_wchmm2(p->wchmm, p->lm->config) == FALSE) {
1096 	jlog("ERROR: m_fusion: error in bulding wchmm\n");
1097 	return FALSE;
1098       }
1099     }
1100 
1101     /* ��ư�� -check �ǥ����å��⡼�ɤ� */
1102     if (p->config->sw.wchmm_check_flag) {
1103       wchmm_check_interactive(p->wchmm);
1104     }
1105 
1106     /* set beam width */
1107     /* guess beam width from models, when not specified */
1108     p->trellis_beam_width = set_beam_width(p->wchmm, p->config->pass1.specified_trellis_beam_width);
1109 
1110     /* initialize cache for factoring */
1111     max_successor_cache_init(p->wchmm);
1112   }
1113 
1114   /* backtrellis initialization */
1115   p->backtrellis = (BACKTRELLIS *)mymalloc(sizeof(BACKTRELLIS));
1116   bt_init(p->backtrellis);
1117 
1118   jlog("STAT: SR%02d %s composed\n", sconf->id, sconf->name);
1119 
1120   if (sconf->sw.start_inactive) {
1121     /* start inactive */
1122     p->active = -1;
1123   } else {
1124     /* book activation for the recognition */
1125     p->active = 1;
1126   }
1127   if (p->lmtype == LM_DFA) {
1128     if (p->lm->winfo == NULL ||
1129 	(p->lmvar == LM_DFA_GRAMMAR && p->lm->dfa == NULL)) {
1130       /* make this instance inactive */
1131       p->active = -1;
1132     }
1133   }
1134 
1135   return TRUE;
1136 }
1137 
1138 
1139 /**
1140  * <EN>
1141  * @brief  Combine all loaded models and settings into one engine instance.
1142  *
1143  * This function will finalize preparation of recognition:
1144  *
1145  *  - create required MFCC calculation instances,
1146  *  - create recognition process instance for specified LM/AM combination,
1147  *  - set model-specific recognition parameters,
1148  *  - build tree lexicon for each process instance for the 1st pass,
1149  *  - prepare work area and cache area for recognition,
1150  *  - initialize some values / work area for frontend processing.
1151  *
1152  * After this function, all recognition setup was done and we are ready for
1153  * start recognition.
1154  *
1155  * This should be called after j_jconf_finalize() and j_load_all() has been
1156  * completed.  You should put the jconf at recog->jconf before calling this
1157  * function.
1158 
1159  * </EN>
1160  * <JA>
1161  * @brief  ���ƤΥ��ɤ��줿��ǥ�����꤫�饨������������
1162  * �ǽ���������.
1163  *
1164  * ���δؿ��ϡ�ǧ�������Τ���κǽ�������Ԥ�. �����Ǥϡ�
1165  *
1166  *  - ɬ�פ� MFCC �׻���������������
1167  *  - ���ꤵ�줿 LM/AM ���Ȥ����ǧ������������������
1168  *  - ��ǥ�˰�¸����ǧ���ѥѥ�᡼��������
1169  *  - ��1�ѥ��Ѥ��ڹ�¤�������ǧ�����������������Ȥ˹���
1170  *  - ǧ�������ѥ�����ꥢ�ȥ���å��奨�ꥢ�����
1171  *  - �ե��ȥ���ɽ����Τ���Τ����Ĥ����ͤȥ�����ꥢ�γ���
1172  *
1173  *  ��Ԥ�. ���δؿ�����λ�塤������������������ƤΥ��åȥ��å�
1174  *  �Ͻ�λ����ǧ�������ϤǤ�����֤Ȥʤ�.
1175  *
1176  *  ���δؿ��ϡ�j_jconf_finalize() �� j_load_all() ������ä����֤�
1177  *  �ƤӽФ�ɬ�פ�����. �ƽФ����ˤϡ�recog->jconf �� (j_load_all �ǤȤ��
1178  *  ���Ѥ���) jconf ���Ǽ���Ƥ�������.
1179  *
1180  * </JA>
1181  *
1182  * @param recog [in] engine instance
1183  *
1184  * @return TRUE when all initialization successfully done, or FALSE if any
1185  * error has been occured.
1186  *
1187  * @callgraph
1188  * @callergraph
1189  * @ingroup instance
1190  *
1191  */
1192 boolean
j_final_fusion(Recog * recog)1193 j_final_fusion(Recog *recog)
1194 {
1195   MFCCCalc *mfcc;
1196   JCONF_SEARCH *sconf;
1197   PROCESS_AM *am;
1198 
1199   jlog("STAT: ------\n");
1200   jlog("STAT: All models are ready, go for final fusion\n");
1201   jlog("STAT: [1] create MFCC extraction instance(s)\n");
1202   if (recog->jconf->input.type == INPUT_WAVEFORM) {
1203     /***************************************************/
1204     /* create MFCC calculation instance from AM config */
1205     /* according to the fixated parameter information  */
1206     /***************************************************/
1207     create_mfcc_calc_instances(recog);
1208   }
1209 
1210   /****************************************/
1211   /* create recognition process instances */
1212   /****************************************/
1213   jlog("STAT: [2] create recognition processing instance(s) with AM and LM\n");
1214   for(sconf=recog->jconf->search_root;sconf;sconf=sconf->next) {
1215     if (j_launch_recognition_instance(recog, sconf) == FALSE) return FALSE;
1216   }
1217 
1218   /****************************/
1219   /****** initialize GMM ******/
1220   /****************************/
1221   if (recog->gmm != NULL) {
1222     jlog("STAT: [2.5] create GMM instance\n");
1223     if (gmm_init(recog) == FALSE) {
1224       jlog("ERROR: m_fusion: error in initializing GMM\n");
1225       return FALSE;
1226     }
1227   }
1228 
1229   /* stage 4: setup output probability function for each AM */
1230   jlog("STAT: [3] initialize for acoustic HMM calculation\n");
1231   for(am=recog->amlist;am;am=am->next) {
1232 #ifdef ENABLE_PLUGIN
1233     /* set plugin function if specified */
1234     if (am->config->gprune_method == GPRUNE_SEL_USER) {
1235       am->hmmwrk.compute_gaussset = (void (*)(HMMWork *, HTK_HMM_Dens **, int, int *, int)) plugin_get_func(am->config->gprune_plugin_source, "calcmix");
1236       if (am->hmmwrk.compute_gaussset == NULL) {
1237 	jlog("ERROR: calcmix plugin has no function \"calcmix\"\n");
1238 	return FALSE;
1239       }
1240       am->hmmwrk.compute_gaussset_init = (boolean (*)(HMMWork *)) plugin_get_func(am->config->gprune_plugin_source, "calcmix_init");
1241       if (am->hmmwrk.compute_gaussset_init == NULL) {
1242 	jlog("ERROR: calcmix plugin has no function \"calcmix_init\"\n");
1243 	return FALSE;
1244       }
1245       am->hmmwrk.compute_gaussset_free = (void (*)(HMMWork *)) plugin_get_func(am->config->gprune_plugin_source, "calcmix_free");
1246       if (am->hmmwrk.compute_gaussset_free == NULL) {
1247 	jlog("ERROR: calcmix plugin has no function \"calcmix_free\"\n");
1248 	return FALSE;
1249       }
1250     }
1251 #endif
1252     if (am->config->hmm_gs_filename != NULL) {/* with GMS */
1253       if (outprob_init(&(am->hmmwrk), am->hmminfo, am->hmm_gs, am->config->gs_statenum, am->config->gprune_method, am->config->mixnum_thres) == FALSE) {
1254 	return FALSE;
1255       }
1256     } else {
1257       if (outprob_init(&(am->hmmwrk), am->hmminfo, NULL, 0, am->config->gprune_method, am->config->mixnum_thres) == FALSE) {
1258 	return FALSE;
1259       }
1260     }
1261   }
1262 
1263   /* stage 5: initialize work area for input and realtime decoding */
1264 
1265   jlog("STAT: [4] prepare MFCC storage(s)\n");
1266   if (recog->jconf->input.type == INPUT_VECTOR) {
1267     /* create an MFCC instance for MFCC input */
1268     /* create new mfcc instance */
1269     recog->mfcclist = j_mfcccalc_new(NULL);
1270     recog->mfcclist->id = 1;
1271     /* assign to the am */
1272     for(am=recog->amlist;am;am=am->next) {
1273       am->mfcc = recog->mfcclist;
1274     }
1275     if (recog->gmm) recog->gmmmfcc = recog->mfcclist;
1276   }
1277   /* allocate parameter holders */
1278   for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
1279     mfcc->param = new_param();
1280   }
1281 
1282   /* initialize SS calculation work area */
1283   if (recog->jconf->input.type == INPUT_WAVEFORM) {
1284     for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
1285       if (mfcc->frontend.sscalc) {
1286 	mfcc->frontend.mfccwrk_ss = WMP_work_new(mfcc->para);
1287 	if (mfcc->frontend.mfccwrk_ss == NULL) {
1288 	  jlog("ERROR: m_fusion: failed to initialize MFCC computation for SS\n");
1289 	  return FALSE;
1290 	}
1291 	if (mfcc->frontend.sscalc_len * recog->jconf->input.sfreq / 1000 < mfcc->para->framesize) {
1292 	  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);
1293 	  return FALSE;
1294 	}
1295       }
1296     }
1297   }
1298 
1299   if (recog->jconf->decodeopt.realtime_flag) {
1300     jlog("STAT: [5] prepare for real-time decoding\n");
1301     /* prepare for 1st pass pipeline processing */
1302     if (recog->jconf->input.type == INPUT_WAVEFORM) {
1303       if (RealTimeInit(recog) == FALSE) {
1304 	jlog("ERROR: m_fusion: failed to initialize recognition process\n");
1305 	return FALSE;
1306       }
1307     }
1308   }
1309 
1310   /* finished! */
1311   jlog("STAT: All init successfully done\n\n");
1312 
1313   /* set-up callback plugin if any */
1314 #ifdef ENABLE_PLUGIN
1315   if (plugin_exec_engine_startup(recog) == FALSE) {
1316     jlog("ERROR: m_fusion: failed to execute callback setup in plugin\n");
1317     return FALSE;
1318   }
1319 #endif
1320 
1321   return TRUE;
1322 }
1323 
1324 /* end of file */
1325