Julius 4.2
|
00001 00054 /* 00055 * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University 00056 * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology 00057 * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology 00058 * All rights reserved 00059 */ 00060 00061 /* By "fast" setting (default), search_bestfirst_v1.c is used for faster 00062 decoding. Please specify option "--enable-setup=standard" or 00063 "--enable-strict-iwcd2" at "./configure" to activate this. */ 00064 00065 #include <julius/julius.h> 00066 00067 #ifdef PASS2_STRICT_IWCD 00068 00069 #undef TCD ///< Define if want triphone debug messages 00070 00071 00072 /**********************************************************************/ 00073 /************ 仮説ノードの基本操作 ************/ 00074 /************ Basic functions for hypothesis node handling ************/ 00075 /**********************************************************************/ 00076 00077 #undef STOCKER_DEBUG 00078 00079 #ifdef STOCKER_DEBUG 00080 static int stocked_num = 0; 00081 static int reused_num = 0; 00082 static int new_num = 0; 00083 static int request_num = 0; 00084 #endif 00085 00098 static void 00099 free_node_exec(NODE *node) 00100 { 00101 if (node == NULL) return; 00102 free(node->g); 00103 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00104 if (node->region->graphout) { 00105 free(node->wordend_frame); 00106 free(node->wordend_gscore); 00107 } 00108 #endif 00109 free(node); 00110 } 00111 00126 void 00127 free_node(NODE *node) 00128 { 00129 if (node == NULL) return; 00130 00131 if (node->region->graphout) { 00132 if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) { 00133 wordgraph_free(node->prevgraph); 00134 } 00135 } 00136 00137 /* save to stocker */ 00138 node->next = node->region->pass2.stocker_root; 00139 node->region->pass2.stocker_root = node; 00140 00141 #ifdef STOCKER_DEBUG 00142 stocked_num++; 00143 #endif 00144 } 00145 00162 void 00163 clear_stocker(StackDecode *s) 00164 { 00165 NODE *node, *tmp; 00166 node = s->stocker_root; 00167 while(node) { 00168 tmp = node->next; 00169 free_node_exec(node); 00170 node = tmp; 00171 } 00172 s->stocker_root = NULL; 00173 00174 #ifdef STOCKER_DEBUG 00175 jlog("DEBUG: %d times requested, %d times newly allocated, %d times reused\n", request_num, new_num, reused_num); 00176 stocked_num = 0; 00177 reused_num = 0; 00178 new_num = 0; 00179 request_num = 0; 00180 #endif 00181 } 00182 00203 NODE * 00204 cpy_node(NODE *dst, NODE *src) 00205 { 00206 int peseqlen; 00207 00208 peseqlen = src->region->peseqlen; 00209 00210 dst->next = src->next; 00211 dst->prev = src->prev; 00212 memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen); 00213 memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM); 00214 #ifdef CM_SEARCH 00215 #ifdef CM_MULTIPLE_ALPHA 00216 { 00217 int w; 00218 for(w=0;w<src->seqnum;w++) { 00219 memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * src->region->config->annotate.cm_alpha_num); 00220 } 00221 } 00222 #else 00223 memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM); 00224 #endif 00225 #endif /* CM_SEARCH */ 00226 dst->seqnum = src->seqnum; 00227 dst->score = src->score; 00228 dst->bestt = src->bestt; 00229 dst->estimated_next_t = src->estimated_next_t; 00230 dst->endflag = src->endflag; 00231 dst->state = src->state; 00232 dst->tre = src->tre; 00233 if (src->region->ccd_flag) { 00234 dst->last_ph = src->last_ph; 00235 dst->last_ph_sp_attached = src->last_ph_sp_attached; 00236 } 00237 dst->totallscore = src->totallscore; 00238 dst->final_g = src->final_g; 00239 #ifdef VISUALIZE 00240 dst->popnode = src->popnode; 00241 #endif 00242 00243 if (src->region->graphout) { 00244 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00245 memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short) * peseqlen); 00246 memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB) * peseqlen); 00247 #endif 00248 dst->prevgraph = src->prevgraph; 00249 dst->lastcontext = src->lastcontext; 00250 #ifndef GRAPHOUT_PRECISE_BOUNDARY 00251 dst->tail_g_score = src->tail_g_score; 00252 #endif 00253 } 00254 return(dst); 00255 } 00256 00277 NODE * 00278 newnode(RecogProcess *r) 00279 { 00280 NODE *tmp; 00281 int i; 00282 int peseqlen; 00283 00284 peseqlen = r->peseqlen; 00285 00286 #ifdef STOCKER_DEBUG 00287 request_num++; 00288 #endif 00289 if ((tmp = r->pass2.stocker_root) != NULL) { 00290 /* re-use ones in the stocker */ 00291 r->pass2.stocker_root = tmp->next; 00292 #ifdef STOCKER_DEBUG 00293 stocked_num--; 00294 reused_num++; 00295 #endif 00296 } else { 00297 /* allocate new */ 00298 tmp = (NODE *)mymalloc(sizeof(NODE)); 00299 tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen); 00300 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00301 if (r->graphout) { 00302 tmp->wordend_frame = (short *)mymalloc(sizeof(short) * peseqlen); 00303 tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen); 00304 } 00305 #endif 00306 #ifdef STOCKER_DEBUG 00307 new_num++; 00308 #endif 00309 } 00310 00311 /* clear the data */ 00312 /*bzero(tmp,sizeof(NODE));*/ 00313 tmp->next=NULL; 00314 tmp->prev=NULL; 00315 tmp->last_ph = NULL; 00316 tmp->last_ph_sp_attached = FALSE; 00317 if (r->ccd_flag) { 00318 tmp->totallscore = LOG_ZERO; 00319 } 00320 tmp->endflag = FALSE; 00321 tmp->seqnum = 0; 00322 for(i = 0; i < peseqlen; i++) { 00323 tmp->g[i] = LOG_ZERO; 00324 } 00325 tmp->final_g = LOG_ZERO; 00326 #ifdef VISUALIZE 00327 tmp->popnode = NULL; 00328 #endif 00329 if (r->graphout) { 00330 tmp->prevgraph = NULL; 00331 tmp->lastcontext = NULL; 00332 } 00333 00334 tmp->region = r; 00335 00336 return(tmp); 00337 } 00338 00339 00340 /**********************************************************************/ 00341 /************ 前向きトレリス展開と尤度計算 ****************/ 00342 /************ Expand trellis and update forward score *****************/ 00343 /**********************************************************************/ 00344 00361 void 00362 malloc_wordtrellis(RecogProcess *r) 00363 { 00364 int maxwn; 00365 StackDecode *dwrk; 00366 00367 maxwn = r->lm->winfo->maxwn + 10; /* CCDによる変動を考慮 */ 00368 dwrk = &(r->pass2); 00369 00370 dwrk->wordtrellis[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn); 00371 dwrk->wordtrellis[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn); 00372 00373 dwrk->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen); 00374 00375 dwrk->phmmlen_max = r->lm->winfo->maxwlen + 2; 00376 dwrk->phmmseq = (HMM_Logical **)mymalloc(sizeof(HMM_Logical *) * dwrk->phmmlen_max); 00377 if (r->lm->config->enable_iwsp && r->am->hmminfo->multipath) { 00378 dwrk->has_sp = (boolean *)mymalloc(sizeof(boolean) * dwrk->phmmlen_max); 00379 } else { 00380 dwrk->has_sp = NULL; 00381 } 00382 00383 dwrk->wef = NULL; 00384 dwrk->wes = NULL; 00385 dwrk->wend_token_frame[0] = NULL; 00386 dwrk->wend_token_frame[1] = NULL; 00387 dwrk->wend_token_gscore[0] = NULL; 00388 dwrk->wend_token_gscore[1] = NULL; 00389 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00390 if (r->graphout) { 00391 dwrk->wef = (short *)mymalloc(sizeof(short) * r->peseqlen); 00392 dwrk->wes = (LOGPROB *)mymalloc(sizeof(LOGPROB) * r->peseqlen); 00393 dwrk->wend_token_frame[0] = (short *)mymalloc(sizeof(short) * maxwn); 00394 dwrk->wend_token_frame[1] = (short *)mymalloc(sizeof(short) * maxwn); 00395 dwrk->wend_token_gscore[0] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn); 00396 dwrk->wend_token_gscore[1] = (LOGPROB *)mymalloc(sizeof(LOGPROB) * maxwn); 00397 } 00398 #endif 00399 } 00400 00413 void 00414 free_wordtrellis(StackDecode *dwrk) 00415 { 00416 free(dwrk->wordtrellis[0]); 00417 free(dwrk->wordtrellis[1]); 00418 free(dwrk->g); 00419 free(dwrk->phmmseq); 00420 if (dwrk->has_sp) { 00421 free(dwrk->has_sp); 00422 dwrk->has_sp = NULL; 00423 } 00424 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00425 if (dwrk->wef) { 00426 free(dwrk->wef); 00427 free(dwrk->wes); 00428 free(dwrk->wend_token_frame[0]); 00429 free(dwrk->wend_token_frame[1]); 00430 free(dwrk->wend_token_gscore[0]); 00431 free(dwrk->wend_token_gscore[1]); 00432 dwrk->wef = NULL; 00433 } 00434 #endif 00435 } 00436 00437 00438 /**********************************************************************/ 00439 /************ 仮説の前向き尤度計算 *******************/ 00440 /************ Compute forward score of a hypothesis *******************/ 00441 /**********************************************************************/ 00442 00443 /* 与えられた音素のならび phmmseq[0..phmmlen-1]に対してviterbi計算を行う. 00444 g[0..framelen-1] のスコアを初期値として g_new[0..framelen-1]に更新値を代入. 00445 最低 least_frame まではscanする. */ 00446 /* Viterbi computation for the given phoneme sequence 'phmmseq[0..phmmlen-1]' 00447 with g[0..framelen-1] as initial values. The results are stored in 00448 g_new[0..framelen-1]. Scan should not terminate at least it reaches 00449 'least_frame'. */ 00491 static void 00492 do_viterbi(LOGPROB *g, LOGPROB *g_new, HMM_Logical **phmmseq, boolean *has_sp, int phmmlen, HTK_Param *param, int framelen, int least_frame, LOGPROB *final_g, short *wordend_frame_src, short *wordend_frame_dst, LOGPROB *wordend_gscore_src, LOGPROB *wordend_gscore_dst, RecogProcess *r) /* has_sp and final_g is for multipath only */ 00493 { 00494 HMM *whmm; /* HMM */ 00495 int wordhmmnum; /* length of above */ 00496 int startt; /* scan start frame */ 00497 LOGPROB tmpmax,tmpscore; /* variables for Viterbi process */ 00498 A_CELL *ac; 00499 int t,i,j; 00500 boolean node_exist_p; 00501 int tn; 00502 int tl; 00503 00504 /* store global values to local for rapid access */ 00505 StackDecode *dwrk; 00506 WORD_INFO *winfo; 00507 HTK_HMM_INFO *hmminfo; 00508 LOGPROB *framemaxscore; 00509 #ifdef SCAN_BEAM 00510 LOGPROB scan_beam_thres; 00511 #endif 00512 00513 dwrk = &(r->pass2); 00514 winfo = r->lm->winfo; 00515 hmminfo = r->am->hmminfo; 00516 framemaxscore = r->pass2.framemaxscore; 00517 #ifdef SCAN_BEAM 00518 scan_beam_thres = r->config->pass2.scan_beam_thres; 00519 #endif 00520 00521 00522 #ifdef TCD 00523 jlog("DEBUG: scan for:"); 00524 for (i=0;i<phmmlen;i++) { 00525 jlog(" %s", phmmseq[i]->name); 00526 } 00527 jlog("\n"); 00528 #endif 00529 00530 /* 単語HMMを作る */ 00531 /* make word HMM */ 00532 whmm = new_make_word_hmm(hmminfo, phmmseq, phmmlen, has_sp); 00533 if (whmm == NULL) { 00534 j_internal_error("Error: failed to make word hmm\n"); 00535 } 00536 wordhmmnum = whmm->len; 00537 if (wordhmmnum >= winfo->maxwn + 10) { 00538 j_internal_error("do_viterbi: word too long (>%d)\n", winfo->maxwn + 10); 00539 } 00540 00541 /* scan開始点を検索 -> starttへ*/ 00542 /* search for the start frame -> set to startt */ 00543 for(t = framelen-1; t >=0 ; t--) { 00544 if ( 00545 #ifdef SCAN_BEAM 00546 g[t] > framemaxscore[t] - scan_beam_thres && 00547 #endif 00548 g[t] > LOG_ZERO) { 00549 break; 00550 } 00551 } 00552 if (t < 0) { /* no node has score > LOG_ZERO */ 00553 /* reset all scores and end */ 00554 for(t=0;t<framelen;t++) { 00555 g_new[t] = LOG_ZERO; 00556 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00557 if (r->graphout) { 00558 wordend_frame_dst[t] = -1; 00559 wordend_gscore_dst[t] = LOG_ZERO; 00560 } 00561 #endif 00562 } 00563 free_hmm(whmm); 00564 return; 00565 } 00566 startt = t; 00567 00568 /* 開始点以降[startt+1..framelen-1] の g_new[] をリセット */ 00569 /* clear g_new[] for [startt+1..framelen-1] */ 00570 for(t=framelen-1;t>startt;t--) { 00571 g_new[t] = LOG_ZERO; 00572 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00573 if (r->graphout) { 00574 wordend_frame_dst[t] = -1; 00575 wordend_gscore_dst[t] = LOG_ZERO; 00576 } 00577 #endif 00578 } 00579 00580 /*****************/ 00581 /* viterbi start */ 00582 /*****************/ 00583 00584 /* set initial swap buffer */ 00585 tn = 0; tl = 1; 00586 00587 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00588 if (r->graphout) { 00589 for(i=0;i<wordhmmnum;i++) { 00590 dwrk->wend_token_frame[tn][i] = -1; 00591 dwrk->wend_token_gscore[tn][i] = LOG_ZERO; 00592 } 00593 } 00594 #endif 00595 00596 if (! hmminfo->multipath) { 00597 /* 時間 [startt] 上の値を初期化 */ 00598 /* initialize scores on frame [startt] */ 00599 for(i=0;i<wordhmmnum-1;i++) dwrk->wordtrellis[tn][i] = LOG_ZERO; 00600 dwrk->wordtrellis[tn][wordhmmnum-1] = g[startt] + outprob(&(r->am->hmmwrk), startt, &(whmm->state[wordhmmnum-1]), param); 00601 g_new[startt] = dwrk->wordtrellis[tn][0]; 00602 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00603 if (r->graphout) { 00604 dwrk->wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[startt]; 00605 dwrk->wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[startt]; 00606 wordend_frame_dst[startt] = dwrk->wend_token_frame[tn][0]; 00607 wordend_gscore_dst[startt] = dwrk->wend_token_gscore[tn][0]; 00608 } 00609 #endif 00610 } 00611 00612 /* メインループ: startt から始まり 0 に向かって Viterbi 計算 */ 00613 /* main loop: start from [startt], and compute Viterbi toward [0] */ 00614 for(t = hmminfo->multipath ? startt : startt - 1; t >= 0; t--) { 00615 00616 /* wordtrellisのワークエリアをスワップ */ 00617 /* swap workarea of wordtrellis */ 00618 i = tn; tn = tl; tl = i; 00619 00620 node_exist_p = FALSE; /* TRUE if there is at least 1 survived node in this frame */ 00621 00622 if (! hmminfo->multipath) { 00623 00624 /* 端のノード [t][wordhmmnum-1]は,内部遷移 か g[]の高い方になる */ 00625 /* the edge node [t][wordhmmnum-1] is either internal transitin or g[] */ 00626 tmpscore = LOG_ZERO; 00627 for (ac=whmm->state[wordhmmnum-1].ac;ac;ac=ac->next) { 00628 if (tmpscore < dwrk->wordtrellis[tl][ac->arc] + ac->a) { 00629 j = ac->arc; 00630 tmpscore = dwrk->wordtrellis[tl][ac->arc] + ac->a; 00631 } 00632 } 00633 if (g[t] > tmpscore) { 00634 tmpmax = g[t]; 00635 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00636 if (r->graphout) { 00637 dwrk->wend_token_frame[tn][wordhmmnum-1] = wordend_frame_src[t]; 00638 dwrk->wend_token_gscore[tn][wordhmmnum-1] = wordend_gscore_src[t]; 00639 } 00640 #endif 00641 } else { 00642 tmpmax = tmpscore; 00643 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00644 if (r->graphout) { 00645 dwrk->wend_token_frame[tn][wordhmmnum-1] = dwrk->wend_token_frame[tl][j]; 00646 dwrk->wend_token_gscore[tn][wordhmmnum-1] = dwrk->wend_token_gscore[tl][j]; 00647 } 00648 #endif 00649 } 00650 00651 /* 端のノードのスコアエンベロープチェック: 一定幅外なら落とす */ 00652 /* check if the edge node is within score envelope */ 00653 if ( 00654 #ifdef SCAN_BEAM 00655 tmpmax <= framemaxscore[t] - scan_beam_thres || 00656 #endif 00657 tmpmax <= LOG_ZERO 00658 ) { 00659 dwrk->wordtrellis[tn][wordhmmnum-1] = LOG_ZERO; 00660 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00661 if (r->graphout) { 00662 dwrk->wend_token_frame[tn][wordhmmnum-1] = -1; 00663 dwrk->wend_token_gscore[tn][wordhmmnum-1] = LOG_ZERO; 00664 } 00665 #endif 00666 } else { 00667 node_exist_p = TRUE; 00668 dwrk->wordtrellis[tn][wordhmmnum-1] = tmpmax + outprob(&(r->am->hmmwrk), t, &(whmm->state[wordhmmnum-1]), param); 00669 } 00670 00671 } 00672 00673 /* node[wordhmmnum-2..0]についてトレリスを展開 */ 00674 /* expand trellis for node [t][wordhmmnum-2..0] */ 00675 for(i=wordhmmnum-2;i>=0;i--) { 00676 00677 /* 最尤パスと最尤スコア tmpmax を見つける */ 00678 /* find most likely path and the max score 'tmpmax' */ 00679 tmpmax = LOG_ZERO; 00680 for (ac=whmm->state[i].ac;ac;ac=ac->next) { 00681 if (hmminfo->multipath) { 00682 if (ac->arc == wordhmmnum-1) tmpscore = g[t]; 00683 else if (t + 1 > startt) tmpscore = LOG_ZERO; 00684 else tmpscore = dwrk->wordtrellis[tl][ac->arc]; 00685 tmpscore += ac->a; 00686 } else { 00687 tmpscore = dwrk->wordtrellis[tl][ac->arc] + ac->a; 00688 } 00689 if (tmpmax < tmpscore) { 00690 tmpmax = tmpscore; 00691 j = ac->arc; 00692 } 00693 } 00694 00695 /* スコアエンベロープチェック: 一定幅外なら落とす */ 00696 /* check if score of this node is within the score envelope */ 00697 if ( 00698 #ifdef SCAN_BEAM 00699 tmpmax <= framemaxscore[t] - scan_beam_thres || 00700 #endif 00701 tmpmax <= LOG_ZERO 00702 ) { 00703 /* invalid node */ 00704 dwrk->wordtrellis[tn][i] = LOG_ZERO; 00705 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00706 if (r->graphout) { 00707 dwrk->wend_token_frame[tn][i] = -1; 00708 dwrk->wend_token_gscore[tn][i] = LOG_ZERO; 00709 } 00710 #endif 00711 } else { 00712 /* survived node */ 00713 node_exist_p = TRUE; 00714 dwrk->wordtrellis[tn][i] = tmpmax; 00715 if (! hmminfo->multipath || i > 0) { 00716 dwrk->wordtrellis[tn][i] += outprob(&(r->am->hmmwrk), t, &(whmm->state[i]), param); 00717 } 00718 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00719 if (r->graphout) { 00720 if (hmminfo->multipath) { 00721 if (j == wordhmmnum-1) { 00722 dwrk->wend_token_frame[tn][i] = wordend_frame_src[t]; 00723 dwrk->wend_token_gscore[tn][i] = wordend_gscore_src[t]; 00724 } else { 00725 dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j]; 00726 dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j]; 00727 } 00728 } else { 00729 dwrk->wend_token_frame[tn][i] = dwrk->wend_token_frame[tl][j]; 00730 dwrk->wend_token_gscore[tn][i] = dwrk->wend_token_gscore[tl][j]; 00731 } 00732 } 00733 #endif 00734 } 00735 } /* end of node loop */ 00736 00737 /* 時間 t のViterbi計算終了. 新たな前向きスコア g_new[t] をセット */ 00738 /* Viterbi end for frame [t]. set the new forward score g_new[t] */ 00739 g_new[t] = dwrk->wordtrellis[tn][0]; 00740 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00741 if (r->graphout) { 00742 /* new wordend */ 00743 wordend_frame_dst[t] = dwrk->wend_token_frame[tn][0]; 00744 wordend_gscore_dst[t] = dwrk->wend_token_gscore[tn][0]; 00745 } 00746 #endif 00747 /* 指定された least_frame より先まで t が進んでおり,かつこの t において 00748 スコアエンベロープによって生き残ったノードが一つも無かった場合, 00749 このフレームで計算を打ち切りそれ以上先([0..t-1])は計算しない */ 00750 /* if frame 't' already reached the 'least_frame' and no node was 00751 survived in this frame (all nodes pruned by score envelope), 00752 terminate computation at this frame and do not computer further 00753 frame ([0..t-1]). */ 00754 if (t < least_frame && (!node_exist_p)) { 00755 /* crear the rest scores */ 00756 for (i=t-1;i>=0;i--) { 00757 g_new[i] = LOG_ZERO; 00758 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00759 if (r->graphout) { 00760 wordend_frame_dst[i] = -1; 00761 wordend_gscore_dst[i] = LOG_ZERO; 00762 } 00763 #endif 00764 } 00765 /* terminate loop */ 00766 break; 00767 } 00768 00769 } /* end of time loop */ 00770 00771 if (hmminfo->multipath) { 00772 /* 前向きスコアの最終値を計算 (状態 0 から時間 0 への遷移) */ 00773 /* compute the total forward score (transition from state 0 to frame 0 */ 00774 if (t < 0) { /* computed till the end */ 00775 tmpmax = LOG_ZERO; 00776 for(ac=whmm->state[0].ac;ac;ac=ac->next) { 00777 tmpscore = dwrk->wordtrellis[tn][ac->arc] + ac->a; 00778 if (tmpmax < tmpscore) tmpmax = tmpscore; 00779 } 00780 *final_g = tmpmax; 00781 } else { 00782 *final_g = LOG_ZERO; 00783 } 00784 } 00785 00786 /* free work area */ 00787 free_hmm(whmm); 00788 } 00789 00813 static void 00814 do_viterbi_next_word(NODE *now, NODE *new, HMM_Logical *lastphone, boolean sp, HTK_Param *param, RecogProcess *r) /* sp is for multipath only */ 00815 { 00816 int t, n; 00817 LOGPROB a_value; /* for non multi-path */ 00818 int peseqlen; 00819 boolean multipath; 00820 StackDecode *dwrk; 00821 00822 dwrk = &(r->pass2); 00823 00824 multipath = r->am->hmminfo->multipath; 00825 00826 peseqlen = r->peseqlen; 00827 00828 if (! multipath) { 00829 00830 /* もし展開元仮説の最後の単語の音素長が 1 であれば,その音素は 00831 直前の scan_word で計算されていない. この場合, now->g[] に以前の 00832 初期値が格納されている. 00833 もし音素長が1以上であれば,now->g[] はその手前まで計算した状態 00834 のスコアが入っているので,now->g[t] から初期値を設定する必要がある */ 00835 /* If the length of last word is 1, it means the last phone was not 00836 scanned in the last call of scan_word(). In this case, now->g[] 00837 keeps the previous initial value, so start viterbi with the old scores. 00838 If the length is more than 1, the now->g[] keeps the values of the 00839 scan result till the previous phone, so make initial value 00840 considering last transition probability. */ 00841 if (r->lm->winfo->wlen[now->seq[now->seqnum-1]] > 1) { 00842 n = hmm_logical_state_num(lastphone); 00843 a_value = (hmm_logical_trans(lastphone))->a[n-2][n-1]; 00844 for(t=0; t<peseqlen-1; t++) dwrk->g[t] = now->g[t+1] + a_value; 00845 dwrk->g[peseqlen-1] = LOG_ZERO; 00846 } else { 00847 for(t=0; t<peseqlen; t++) dwrk->g[t] = now->g[t]; 00848 } 00849 00850 } else { 00851 00852 for(t=0; t<peseqlen; t++) dwrk->g[t] = now->g[t]; 00853 dwrk->phmmseq[0] = lastphone; 00854 if (r->lm->config->enable_iwsp) dwrk->has_sp[0] = sp; 00855 00856 } 00857 00858 do_viterbi(dwrk->g, new->g, 00859 multipath ? dwrk->phmmseq : &lastphone, 00860 (r->lm->config->enable_iwsp && multipath) ? dwrk->has_sp : NULL, 00861 1, param, peseqlen, now->estimated_next_t, &(new->final_g) 00862 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00863 , now->wordend_frame, new->wordend_frame 00864 , now->wordend_gscore, new->wordend_gscore 00865 #else 00866 , NULL, NULL 00867 , NULL, NULL 00868 #endif 00869 , r 00870 ); 00871 00872 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00873 if (! multipath) { 00874 if (r->graphout) { 00875 /* 次回の next_word 用に境界情報を調整 */ 00876 /* proceed word boundary for one step for next_word */ 00877 new->wordend_frame[r->peseqlen-1] = new->wordend_frame[0]; 00878 new->wordend_gscore[r->peseqlen-1] = new->wordend_gscore[0]; 00879 for (t=0;t<r->peseqlen-1;t++) { 00880 new->wordend_frame[t] = new->wordend_frame[t+1]; 00881 new->wordend_gscore[t] = new->wordend_gscore[t+1]; 00882 } 00883 } 00884 } 00885 #endif 00886 } 00887 00907 void 00908 scan_word(NODE *now, HTK_Param *param, RecogProcess *r) 00909 { 00910 int i,t; 00911 WORD_ID word; 00912 int phmmlen; 00913 HMM_Logical *tailph; 00914 00915 /* store global values to local for rapid access */ 00916 WORD_INFO *winfo; 00917 HTK_HMM_INFO *hmminfo; 00918 int peseqlen; 00919 boolean ccd_flag; 00920 boolean enable_iwsp; /* multipath */ 00921 StackDecode *dwrk; 00922 00923 dwrk = &(r->pass2); 00924 winfo = r->lm->winfo; 00925 hmminfo = r->am->hmminfo; 00926 peseqlen = r->peseqlen; 00927 ccd_flag = r->ccd_flag; 00928 if (hmminfo->multipath) { 00929 enable_iwsp = r->lm->config->enable_iwsp; 00930 } 00931 00932 #ifndef GRAPHOUT_PRECISE_BOUNDARY 00933 if (r->graphout) { 00934 if (ccd_flag) { 00935 now->tail_g_score = now->g[now->bestt]; 00936 } 00937 } 00938 #endif 00939 00940 /* ----------------------- prepare phoneme sequence ------------------ */ 00941 /* triphoneなら先頭の1音素はここでは対象外(あとでnext_wordでやる) */ 00942 /* 末尾の1音素はコンテキストにしたがって置換 */ 00943 /* with triphone, modify the tail phone of the last word according to the 00944 previous word, and do not compute the head phone here (that will be 00945 computed later in next_word() */ 00946 word = now->seq[now->seqnum-1]; 00947 00948 #ifdef TCD 00949 jlog("DEBUG: w="); 00950 for(i=0;i<winfo->wlen[word];i++) { 00951 jlog(" %s",(winfo->wseq[word][i])->name); 00952 } 00953 if (ccd_flag) { 00954 if (now->last_ph != NULL) { 00955 jlog(" | %s", (now->last_ph)->name); 00956 } 00957 } 00958 jlog("\n"); 00959 #endif /* TCD */ 00960 00961 if (ccd_flag) { 00962 00963 /* the tail triphone of the last word varies by context */ 00964 if (now->last_ph != NULL) { 00965 tailph = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo); 00966 if (tailph == NULL) { 00967 /* fallback to the original bi/mono-phone */ 00968 /* error if the original is pseudo phone (not explicitly defined 00969 in hmmdefs/hmmlist) */ 00970 /* exception: word with 1 phone (triphone may exist in the next expansion */ 00971 if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){ 00972 error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name); 00973 } 00974 00975 tailph = winfo->wseq[word][winfo->wlen[word]-1]; 00976 } 00977 } else { 00978 tailph = winfo->wseq[word][winfo->wlen[word]-1]; 00979 } 00980 /* 長さ1の単語は次のnextwordでさらに変化するのでここではscanしない */ 00981 /* do not scan word if the length is 1, as it further varies in the 00982 following next_word() */ 00983 if (winfo->wlen[word] == 1) { 00984 now->last_ph = tailph; 00985 if (enable_iwsp && hmminfo->multipath) now->last_ph_sp_attached = TRUE; 00986 #ifdef GRAPHOUT_PRECISE_BOUNDARY 00987 if (r->graphout) { 00988 /* 単語境界伝搬情報を初期化 */ 00989 /* initialize word boundary propagation info */ 00990 for (t=0;t<peseqlen;t++) { 00991 now->wordend_frame[t] = t; 00992 now->wordend_gscore[t] = now->g[t]; 00993 } 00994 } 00995 #endif 00996 #ifdef TCD 00997 jlog("DEBUG: suspended as %s\n", (now->last_ph)->name); 00998 #endif 00999 return; 01000 } 01001 01002 /* scan範囲の音素列を準備 */ 01003 /* prepare HMM of the scan range */ 01004 phmmlen = winfo->wlen[word] - 1; 01005 if (phmmlen > dwrk->phmmlen_max) { 01006 j_internal_error("scan_word: num of phonemes in a word exceed phmmlenmax (%d) ?\n", dwrk->phmmlen_max); 01007 } 01008 for (i=0;i<phmmlen-1;i++) { 01009 dwrk->phmmseq[i] = winfo->wseq[word][i+1]; 01010 } 01011 dwrk->phmmseq[phmmlen-1] = tailph; 01012 if (enable_iwsp && hmminfo->multipath) { 01013 for (i=0;i<phmmlen-1;i++) dwrk->has_sp[i] = FALSE; 01014 dwrk->has_sp[phmmlen-1] = TRUE; 01015 } 01016 01017 } else { /* ~ccd_flag */ 01018 01019 phmmlen = winfo->wlen[word]; 01020 for (i=0;i<phmmlen;i++) dwrk->phmmseq[i] = winfo->wseq[word][i]; 01021 if (enable_iwsp && hmminfo->multipath) { 01022 for (i=0;i<phmmlen;i++) dwrk->has_sp[i] = FALSE; 01023 dwrk->has_sp[phmmlen-1] = TRUE; 01024 } 01025 01026 } 01027 01028 /* 元のg[]をいったん待避しておく */ 01029 /* temporally keeps the original g[] */ 01030 for (t=0;t<peseqlen;t++) dwrk->g[t] = now->g[t]; 01031 01032 #ifdef GRAPHOUT_PRECISE_BOUNDARY 01033 if (r->graphout) { 01034 /* 単語境界伝搬情報を初期化 */ 01035 /* initialize word boundary propagation info */ 01036 for (t=0;t<peseqlen;t++) { 01037 dwrk->wef[t] = t; 01038 dwrk->wes[t] = now->g[t]; 01039 } 01040 } 01041 #endif 01042 01043 /* viterbiを実行して g[] から now->g[] を更新する */ 01044 /* do viterbi computation for phmmseq from g[] to now->g[] */ 01045 do_viterbi(dwrk->g, now->g, dwrk->phmmseq, (enable_iwsp && hmminfo->multipath) ? dwrk->has_sp : NULL, 01046 phmmlen, param, peseqlen, now->estimated_next_t, &(now->final_g) 01047 #ifdef GRAPHOUT_PRECISE_BOUNDARY 01048 /* 単語境界情報 we[] から now->wordend_frame[] を更新する */ 01049 /* propagate word boundary info from we[] to now->wordend_frame[] */ 01050 , dwrk->wef, now->wordend_frame 01051 , dwrk->wes, now->wordend_gscore 01052 #else 01053 , NULL, NULL 01054 , NULL, NULL 01055 #endif 01056 , r 01057 ); 01058 #ifdef GRAPHOUT_PRECISE_BOUNDARY 01059 if (! hmminfo->multipath) { 01060 if (r->graphout) { 01061 /* 次回の next_word 用に境界情報を調整 */ 01062 /* proceed word boundary for one step for next_word */ 01063 now->wordend_frame[peseqlen-1] = now->wordend_frame[0]; 01064 now->wordend_gscore[peseqlen-1] = now->wordend_gscore[0]; 01065 for (t=0;t<peseqlen-1;t++) { 01066 now->wordend_frame[t] = now->wordend_frame[t+1]; 01067 now->wordend_gscore[t] = now->wordend_gscore[t+1]; 01068 } 01069 } 01070 } 01071 #endif 01072 01073 if (ccd_flag) { 01074 /* 次回のために now->last_ph を更新 */ 01075 /* update 'now->last_ph' for future scan_word() */ 01076 now->last_ph = winfo->wseq[word][0]; 01077 if (enable_iwsp && hmminfo->multipath) now->last_ph_sp_attached = FALSE; /* wlen > 1 here */ 01078 #ifdef TCD 01079 jlog("DEBUG: last_ph = %s\n", (now->last_ph)->name); 01080 #endif 01081 } 01082 } 01083 01084 01085 /**************************************************************************/ 01086 /*** 新仮説の展開とヒューリスティックを繋いだ全体スコアを計算 ***/ 01087 /*** Expand new hypothesis and compute the total score (with heuristic) ***/ 01088 /**************************************************************************/ 01089 01115 void 01116 next_word(NODE *now, NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r) 01117 { 01118 HMM_Logical *lastphone, *newphone; 01119 LOGPROB *g_src; 01120 int t; 01121 int lastword; 01122 int i; 01123 LOGPROB a_value; 01124 LOGPROB tmpp; 01125 int startt; 01126 int word; 01127 TRELLIS_ATOM *tre; 01128 LOGPROB totalscore; 01129 BACKTRELLIS *backtrellis; 01130 WORD_INFO *winfo; 01131 HTK_HMM_INFO *hmminfo; 01132 int peseqlen; 01133 boolean ccd_flag; 01134 StackDecode *dwrk; 01135 01136 dwrk = &(r->pass2); 01137 backtrellis = r->backtrellis; 01138 winfo = r->lm->winfo; 01139 hmminfo = r->am->hmminfo; 01140 peseqlen = r->peseqlen; 01141 ccd_flag = r->ccd_flag; 01142 01143 word = nword->id; 01144 lastword = now->seq[now->seqnum-1]; 01145 01146 /* lastphone (直前単語の先頭音素) を準備 */ 01147 /* prepare lastphone (head phone of previous word) */ 01148 if (ccd_flag) { 01149 /* 最終音素 triphone を接続単語に会わせて変化 */ 01150 /* modify triphone of last phone according to the next word */ 01151 lastphone = get_left_context_HMM(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name, hmminfo); 01152 if (lastphone == NULL) { 01153 /* fallback to the original bi/mono-phone */ 01154 /* error if the original is pseudo phone (not explicitly defined 01155 in hmmdefs/hmmlist) */ 01156 /* exception: word with 1 phone (triphone may exist in the next expansion */ 01157 if (now->last_ph->is_pseudo){ 01158 error_missing_left_triphone(now->last_ph, winfo->wseq[word][winfo->wlen[word]-1]->name); 01159 } 01160 lastphone = now->last_ph; 01161 } 01162 } 01163 01164 /* newphone (接続単語の末尾音素) を準備 */ 01165 /* prepare newphone (tail phone of next word) */ 01166 if (ccd_flag) { 01167 newphone = get_right_context_HMM(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name, hmminfo); 01168 if (newphone == NULL) { 01169 /* fallback to the original bi/mono-phone */ 01170 /* error if the original is pseudo phone (not explicitly defined 01171 in hmmdefs/hmmlist) */ 01172 /* exception: word with 1 phone (triphone may exist in the next expansion */ 01173 if (winfo->wlen[word] > 1 && winfo->wseq[word][winfo->wlen[word]-1]->is_pseudo){ 01174 error_missing_right_triphone(winfo->wseq[word][winfo->wlen[word]-1], now->last_ph->name); 01175 } 01176 newphone = winfo->wseq[word][winfo->wlen[word]-1]; 01177 } 01178 } else { 01179 newphone = winfo->wseq[word][winfo->wlen[word]-1]; 01180 } 01181 01182 /* 単語並び、DFA状態番号、言語スコアを new へ継承・更新 */ 01183 /* inherit and update word sequence, DFA state and total LM score to 'new' */ 01184 new->score = LOG_ZERO; 01185 for (i=0;i< now->seqnum;i++){ 01186 new->seq[i] = now->seq[i]; 01187 #ifdef CM_SEARCH 01188 #ifdef CM_MULTIPLE_ALPHA 01189 memcpy(new->cmscore[i], now->cmscore[i], sizeof(LOGPROB) * r->config->annotate.cm_alpha_num); 01190 #else 01191 new->cmscore[i] = now->cmscore[i]; 01192 #endif 01193 #endif /* CM_SEARCH */ 01194 } 01195 new->seq[i] = word; 01196 new->seqnum = now->seqnum+1; 01197 new->state = nword->next_state; 01198 new->totallscore = now->totallscore + nword->lscore; 01199 if (ccd_flag) { 01200 /* 次仮説の履歴情報として保存 */ 01201 /* keep the lastphone for next scan_word() */ 01202 new->last_ph = lastphone; 01203 new->last_ph_sp_attached = now->last_ph_sp_attached; 01204 } 01205 01206 if (ccd_flag) { 01207 /* 最後の1音素(lastphone)分をscanし,更新したスコアを new に保存 */ 01208 /* scan the lastphone and set the updated score to new->g[] */ 01209 do_viterbi_next_word(now, new, lastphone, 01210 hmminfo->multipath ? now->last_ph_sp_attached : FALSE, 01211 param, r); 01212 g_src = new->g; 01213 } else { 01214 g_src = now->g; 01215 #ifdef GRAPHOUT_PRECISE_BOUNDARY 01216 if (r->graphout) { 01217 memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*peseqlen); 01218 memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*peseqlen); 01219 } 01220 #endif 01221 } 01222 01223 /* 次回の scan_word に備えて new->g[] を変更しておく */ 01224 /* prepare new->g[] for next scan_word() */ 01225 if (hmminfo->multipath) { 01226 startt = peseqlen-1; 01227 } else { 01228 startt = peseqlen-2; 01229 } 01230 i = hmm_logical_state_num(newphone); 01231 a_value = (hmm_logical_trans(newphone))->a[i-2][i-1]; 01232 if (hmminfo->multipath) { 01233 for(t=0; t <= startt; t++) { 01234 new->g[t] = g_src[t] + nword->lscore; 01235 } 01236 } else { 01237 for(t=0; t <= startt; t++) { 01238 new->g[t] = g_src[t+1] + a_value + nword->lscore; 01239 } 01240 } 01241 01242 /***************************************************************************/ 01243 /* 前向き(第2パス),後ろ向き(第1パス)トレリスを接続し最尤接続点を見つける */ 01244 /* connect forward/backward trellis to look for the best connection time */ 01245 /***************************************************************************/ 01246 /*-----------------------------------------------------------------*/ 01247 /* 単語トレリスを探して, 次単語の最尤接続点を発見する */ 01248 /* determine the best connection time of the new word, seeking the word 01249 trellis */ 01250 /*-----------------------------------------------------------------*/ 01251 01252 if (r->lmtype == LM_DFA && !r->config->pass2.looktrellis_flag) { 01253 /* すべてのフレームにわたって最尤を探す */ 01254 /* search for best trellis word throughout all frame */ 01255 for(t = startt; t >= 0; t--) { 01256 tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word); 01257 if (tre == NULL) continue; 01258 totalscore = new->g[t] + tre->backscore; 01259 if (! hmminfo->multipath) { 01260 if (newphone->is_pseudo) { 01261 tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param); 01262 } else { 01263 tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param); 01264 } 01265 totalscore += tmpp; 01266 } 01267 if (new->score < totalscore) { 01268 new->score = totalscore; 01269 new->bestt = t; 01270 new->estimated_next_t = tre->begintime - 1; 01271 new->tre = tre; 01272 } 01273 } 01274 01275 return; 01276 } 01277 01278 /* 最後に参照したTRELLIS_ATOMの終端時間の前後 */ 01279 /* newの推定時間は,上記で採用したTRELLIS_ATOMの始端時間 */ 01280 01281 /* この展開単語のトレリス上の終端時間の前後のみスキャンする 01282 前後に連続して存在するフレームについてのみ計算 */ 01283 /* search for best trellis word only around the estimated time */ 01284 /* 1. search forward */ 01285 for(t = (nword->tre)->endtime; t >= 0; t--) { 01286 tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word); 01287 if (tre == NULL) break; /* go to 2 if the trellis word disappear */ 01288 totalscore = new->g[t] + tre->backscore; 01289 if (! hmminfo->multipath) { 01290 if (newphone->is_pseudo) { 01291 tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param); 01292 } else { 01293 tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param); 01294 } 01295 totalscore += tmpp; 01296 } 01297 if (new->score < totalscore) { 01298 new->score = totalscore; 01299 new->bestt = t; 01300 new->estimated_next_t = tre->begintime - 1; 01301 new->tre = tre; 01302 } 01303 } 01304 /* 2. search bckward */ 01305 for(t = (nword->tre)->endtime + 1; t <= startt; t++) { 01306 tre = bt_binsearch_atom(backtrellis, t, (WORD_ID) word); 01307 if (tre == NULL) break; /* end if the trellis word disapper */ 01308 totalscore = new->g[t] + tre->backscore; 01309 if (! hmminfo->multipath) { 01310 if (newphone->is_pseudo) { 01311 tmpp = outprob_cd(&(r->am->hmmwrk), t, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param); 01312 } else { 01313 tmpp = outprob_state(&(r->am->hmmwrk), t, newphone->body.defined->s[newphone->body.defined->state_num-2], param); 01314 } 01315 totalscore += tmpp; 01316 } 01317 if (new->score < totalscore) { 01318 new->score = totalscore; 01319 new->bestt = t; 01320 new->estimated_next_t = tre->begintime - 1; 01321 new->tre = tre; 01322 } 01323 } 01324 01325 /* set current LM score */ 01326 new->lscore = nword->lscore; 01327 01328 } 01329 01330 01331 /**********************************************************************/ 01332 /********** 初期仮説の生成 ****************************/ 01333 /********** Generate an initial hypothesis ****************************/ 01334 /**********************************************************************/ 01335 01357 void 01358 start_word(NODE *new, NEXTWORD *nword, HTK_Param *param, RecogProcess *r) 01359 { 01360 HMM_Logical *newphone; 01361 WORD_ID word; 01362 TRELLIS_ATOM *tre = NULL; 01363 LOGPROB tmpp; 01364 int t; 01365 01366 BACKTRELLIS *backtrellis; 01367 WORD_INFO *winfo; 01368 01369 int peseqlen; 01370 boolean ccd_flag; 01371 boolean multipath; 01372 01373 backtrellis = r->backtrellis; 01374 winfo = r->lm->winfo; 01375 peseqlen = r->peseqlen; 01376 ccd_flag = r->ccd_flag; 01377 multipath = r->am->hmminfo->multipath; 01378 01379 /* initialize data */ 01380 word = nword->id; 01381 new->score = LOG_ZERO; 01382 new->seqnum = 1; 01383 new->seq[0] = word; 01384 01385 new->state = nword->next_state; 01386 new->totallscore = nword->lscore; 01387 01388 /* set current LM score */ 01389 new->lscore = nword->lscore; 01390 01391 /* cross-word triphone need not be handled on startup */ 01392 newphone = winfo->wseq[word][winfo->wlen[word]-1]; 01393 if (ccd_flag) { 01394 new->last_ph = NULL; 01395 } 01396 01397 new->g[peseqlen-1] = nword->lscore; 01398 01399 for (t=peseqlen-1; t>=0; t--) { 01400 tre = bt_binsearch_atom(backtrellis, t, word); 01401 if (tre != NULL) { 01402 if (r->graphout) { 01403 new->bestt = peseqlen-1; 01404 } else { 01405 new->bestt = t; 01406 } 01407 new->score = new->g[peseqlen-1] + tre->backscore; 01408 if (! multipath) { 01409 if (newphone->is_pseudo) { 01410 tmpp = outprob_cd(&(r->am->hmmwrk), peseqlen-1, &(newphone->body.pseudo->stateset[newphone->body.pseudo->state_num-2]), param); 01411 } else { 01412 tmpp = outprob_state(&(r->am->hmmwrk), peseqlen-1, newphone->body.defined->s[newphone->body.defined->state_num-2], param); 01413 } 01414 new->score += tmpp; 01415 } 01416 new->estimated_next_t = tre->begintime - 1; 01417 new->tre = tre; 01418 break; 01419 } 01420 } 01421 if (tre == NULL) { /* no word in backtrellis */ 01422 new->score = LOG_ZERO; 01423 } 01424 } 01425 01447 void 01448 last_next_word(NODE *now, NODE *new, HTK_Param *param, RecogProcess *r) 01449 { 01450 cpy_node(new, now); 01451 if (r->ccd_flag) { 01452 /* 最終音素分を viterbi して最終スコアを設定 */ 01453 /* scan the last phone and update the final score */ 01454 if (r->am->hmminfo->multipath) { 01455 do_viterbi_next_word(now, new, now->last_ph, now->last_ph_sp_attached, param, r); 01456 new->score = new->final_g; 01457 } else { 01458 do_viterbi_next_word(now, new, now->last_ph, FALSE, param, r); 01459 new->score = new->g[0]; 01460 } 01461 } else { 01462 if (r->am->hmminfo->multipath) { 01463 new->score = now->final_g; 01464 } else { 01465 new->score = now->g[0]; 01466 } 01467 #ifdef GRAPHOUT_PRECISE_BOUNDARY 01468 if (r->graphout) { 01469 /* last boundary has moved to [peseqlen-1] in last scan_word() */ 01470 memcpy(new->wordend_frame, now->wordend_frame, sizeof(short)*r->peseqlen); 01471 memcpy(new->wordend_gscore, now->wordend_gscore, sizeof(LOGPROB)*r->peseqlen); 01472 } 01473 #endif 01474 } 01475 } 01476 01477 #endif /* PASS2_STRICT_IWCD */ 01478 01479 /* end of file */