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(¶_dummy);
174 if (init_hmminfo(hmm_gs, amconf->hmm_gs_filename, NULL, ¶_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