Julius 4.2
|
00001 00064 /* 00065 * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University 00066 * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology 00067 * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology 00068 * All rights reserved 00069 */ 00070 00071 #include <julius/julius.h> 00072 00073 00097 boolean 00098 is_sil(WORD_ID w, RecogProcess *r) 00099 { 00100 WORD_INFO *winfo; 00101 HTK_HMM_INFO *hmm; 00102 int i; 00103 00104 winfo = r->lm->winfo; 00105 hmm = r->am->hmminfo; 00106 00107 /* num of phones should be 1 */ 00108 if (winfo->wlen[w] > 1) return FALSE; 00109 00110 if (r->pass1.pausemodel) { 00111 /* has pause model list */ 00112 for(i=0;i<r->pass1.pausemodelnum;i++) { 00113 if (strmatch(winfo->wseq[w][0]->name, r->pass1.pausemodel[i])) { 00114 return TRUE; 00115 } 00116 } 00117 } else { 00118 /* short pause (specified by "-spmodel") */ 00119 if (winfo->wseq[w][0] == hmm->sp) return TRUE; 00120 00121 if (r->lmtype == LM_PROB) { 00122 /* head/tail sil */ 00123 if (w == winfo->head_silwid || w == winfo->tail_silwid) return TRUE; 00124 } 00125 } 00126 00127 return FALSE; 00128 } 00129 00153 void 00154 mfcc_copy_to_rest_and_shrink(MFCCCalc *mfcc, int start, int end) 00155 { 00156 int t; 00157 00158 /* copy rest parameters for next process */ 00159 mfcc->rest_param = new_param(); 00160 memcpy(&(mfcc->rest_param->header), &(mfcc->param->header), sizeof(HTK_Param_Header)); 00161 mfcc->rest_param->samplenum = mfcc->param->samplenum - start; 00162 mfcc->rest_param->header.samplenum = mfcc->rest_param->samplenum; 00163 mfcc->rest_param->veclen = mfcc->param->veclen; 00164 if (param_alloc(mfcc->rest_param, mfcc->rest_param->samplenum, mfcc->rest_param->veclen) == FALSE) { 00165 j_internal_error("ERROR: segmented: failed to allocate memory for rest param\n"); 00166 } 00167 /* copy data */ 00168 for(t=start;t<mfcc->param->samplenum;t++) { 00169 memcpy(mfcc->rest_param->parvec[t-start], mfcc->param->parvec[t], sizeof(VECT) * mfcc->rest_param->veclen); 00170 } 00171 00172 /* shrink original param */ 00173 /* just shrink the length */ 00174 mfcc->param->samplenum = end; 00175 } 00176 00193 void 00194 mfcc_shrink(MFCCCalc *mfcc, int p) 00195 { 00196 int t; 00197 int len; 00198 00199 if (p > 0) { 00200 /* copy data */ 00201 for(t=p;t<mfcc->param->samplenum;t++) { 00202 memcpy(mfcc->param->parvec[t-p], mfcc->param->parvec[t], sizeof(VECT) * mfcc->param->veclen); 00203 } 00204 /* shrink original param */ 00205 /* just shrink the length */ 00206 len = mfcc->param->samplenum - p; 00207 mfcc->param->samplenum = len; 00208 mfcc->param->header.samplenum = len; 00209 } 00210 } 00211 00261 boolean 00262 detect_end_of_segment(RecogProcess *r, int time) 00263 { 00264 FSBeam *d; 00265 TRELLIS_ATOM *tre; 00266 LOGPROB maxscore = LOG_ZERO; 00267 TRELLIS_ATOM *tremax = NULL; 00268 int count = 0; 00269 boolean detected = FALSE; 00270 #ifdef SPSEGMENT_NAIST 00271 MFCCCalc *mfcc; 00272 WORD_ID wid; 00273 int j; 00274 TOKEN2 *tk; 00275 int startframe; 00276 #endif 00277 00278 d = &(r->pass1); 00279 00280 #ifdef SPSEGMENT_NAIST 00281 00282 if (! d->after_trigger) { 00283 /* we are in the first long pause segment before trigger */ 00284 00285 /* find word end of maximum score from beam status */ 00286 for (j = d->n_start; j <= d->n_end; j++) { 00287 tk = &(d->tlist[d->tn][d->tindex[d->tn][j]]); 00288 if (r->wchmm->stend[tk->node] != WORD_INVALID) { 00289 if (maxscore < tk->score) { 00290 maxscore = tk->score; 00291 wid = r->wchmm->stend[tk->node]; 00292 } 00293 } 00294 } 00295 if (maxscore == LOG_ZERO) detected = TRUE; 00296 else if (is_sil(wid, r)) detected = TRUE; 00297 00298 if (detected) { 00299 /***********************/ 00300 /* this is noise frame */ 00301 /***********************/ 00302 00303 /* reset trigger duration */ 00304 d->trigger_duration = 0; 00305 00306 /* if noise goes more than a certain frame, shrink the noise area 00307 to avoid unlimited memory usage */ 00308 if (r->am->mfcc->f > SPSEGMENT_NAIST_AUTOSHRINK_LIMIT) { 00309 d->want_rewind = TRUE; 00310 d->rewind_frame = r->am->mfcc->f - r->config->successive.sp_margin; 00311 d->want_rewind_reprocess = FALSE; 00312 if (debug2_flag) { 00313 jlog("DEBUG: pause exceeded %d, rewind\n", SPSEGMENT_NAIST_AUTOSHRINK_LIMIT); 00314 } 00315 return FALSE; 00316 } 00317 00318 /* keep going */ 00319 d->want_rewind = FALSE; 00320 00321 } else { 00322 /************************/ 00323 /* this is speech frame */ 00324 /************************/ 00325 00326 /* increment trigger duration */ 00327 d->trigger_duration++; 00328 00329 /* if not enough duration, not treat as up trigger */ 00330 if (d->trigger_duration < r->config->successive.sp_delay) { 00331 /* just continue detection */ 00332 return FALSE; 00333 } 00334 00335 /***************************/ 00336 /* found speech up-trigger */ 00337 /***************************/ 00338 /* set backstep point */ 00339 if (r->am->mfcc->f < r->config->successive.sp_margin) { 00340 startframe = 0; 00341 } else { 00342 startframe = r->am->mfcc->f - r->config->successive.sp_margin; 00343 } 00344 if (debug2_flag) { 00345 jlog("DEBUG: speech triggered\n"); 00346 jlog("DEBUG: word=[%s] dur=%d\n", r->lm->winfo->woutput[wid], d->trigger_duration); 00347 jlog("DEBUG: backstep behind %d (from %d to %d) frame and start process\n", r->config->successive.sp_margin, r->am->mfcc->f, startframe); 00348 } 00349 00350 /* if the pause segment was short, keep the context of last segment. 00351 else, reset the context */ 00352 if (r->lmtype == LM_PROB) { 00353 if (startframe > 0) { 00354 r->sp_break_last_word = WORD_INVALID; 00355 } 00356 } 00357 00358 /* reset sp duration */ 00359 d->sp_duration = 0; 00360 00361 /* request the caller to rewind the search to the backstep point and 00362 re-start with normal search */ 00363 d->want_rewind = TRUE; 00364 d->rewind_frame = startframe; 00365 d->want_rewind_reprocess = TRUE; 00366 /* this will enter to normal search in the next processing */ 00367 d->after_trigger = TRUE; 00368 } 00369 /* tell the caller not to segment */ 00370 return FALSE; 00371 } 00372 00373 #endif /* SPSEGMENT_NAIST */ 00374 00375 /* look for the best trellis word on the given time frame */ 00376 for(tre = r->backtrellis->list; tre != NULL && tre->endtime == time; tre = tre->next) { 00377 if (maxscore < tre->backscore) { 00378 maxscore = tre->backscore; 00379 tremax = tre; 00380 } 00381 count++; 00382 } 00383 if (tremax == NULL) { /* no word end: possible in the very beggining of input*/ 00384 detected = TRUE; /* assume it's in the short-pause duration */ 00385 } else if (count > 0) { /* many words found --- check if maximum is sp */ 00386 if (is_sil(tremax->wid, r)) { 00387 detected = TRUE; 00388 } 00389 } 00390 00391 00392 #ifdef SPSEGMENT_NAIST 00393 /************************************************************************/ 00394 /************************************************************************/ 00395 00396 /* detected = TRUE if noise frame, or FALSE if speech frame */ 00397 00398 /* sp区間持続チェック */ 00399 /* check sp segment duration */ 00400 if (d->first_sparea) { 00401 /* we are in the first sp segment */ 00402 if (d->in_sparea && detected) { 00403 /* sp continues */ 00404 d->sp_duration++; 00405 /* when sp continues more than -spdur plus -spmargin, 00406 it means that although a speech trigger has been detected 00407 by some reason, no actual speech has been found at first. */ 00408 /* in this case we force trigger to end this input */ 00409 if (d->sp_duration > r->config->successive.sp_delay + r->config->successive.sp_margin + r->config->successive.sp_frame_duration) { 00410 d->in_sparea = FALSE; 00411 d->first_sparea = FALSE; 00412 if (debug2_flag) { 00413 jlog("DEBUG: no valid speech starts, force trigger at %d\n", r->am->mfcc->f); 00414 } 00415 } 00416 } else if (d->in_sparea && !detected) { 00417 /* found speech frame */ 00418 d->in_sparea = FALSE; 00419 d->first_sparea = FALSE; 00420 if (debug2_flag) { 00421 jlog("DEBUG: speech segment start at %d\n", r->am->mfcc->f); 00422 } 00423 } 00424 } else { 00425 /* we are either in speech segment, or trailing sp segment */ 00426 if (!d->in_sparea) { 00427 /* we are in speech segment */ 00428 if (detected) { 00429 /* detected end of speech segment (begin of sp segment) */ 00430 /* 一時的に開始フレームとしてマーク */ 00431 /* mark this frame as "temporal" begging of short-pause segment */ 00432 d->tmp_sparea_start = time; 00433 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00434 if (r->lmtype == LM_PROB) { 00435 /* sp 区間開始時点の最尤単語を保存 */ 00436 /* store the best word in this frame as resuming word */ 00437 d->tmp_sp_break_last_word = tremax ? tremax->wid : WORD_INVALID; 00438 } 00439 #endif 00440 d->in_sparea = TRUE; 00441 d->sp_duration = 1; 00442 } else { 00443 /* speech continues */ 00444 /* keep recognizing */ 00445 } 00446 } else { 00447 /* we are in trailing sp segment */ 00448 if (detected) { 00449 /* short pause frame continues */ 00450 d->sp_duration++; 00451 /* keep word as the "beggining" of next sp segment */ 00452 if (r->lmtype == LM_PROB) { 00453 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00454 /* if this segment has triggered by (tremax == NULL) (in case the first 00455 several frame of input), the sp word (to be used as resuming 00456 word in the next segment) is not yet set. it will be detected here */ 00457 if (d->tmp_sp_break_last_word == WORD_INVALID) { 00458 if (tremax != NULL) d->tmp_sp_break_last_word = tremax->wid; 00459 } 00460 #else 00461 /* resume word at the "end" of sp segment */ 00462 /* simply update the best sp word */ 00463 if (tremax != NULL) d->last_tre_word = tremax->wid; 00464 #endif 00465 } 00466 00467 if (d->sp_duration >= r->config->successive.sp_frame_duration) { 00468 /* silence over, segment the recognition here */ 00469 /* store begging frame of the segment */ 00470 //d->sparea_start = d->tmp_sparea_start; 00471 r->am->mfcc->sparea_start = time - r->config->successive.sp_frame_duration; 00472 if (r->lmtype == LM_PROB) { 00473 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00474 /* resume word = most likely sp word on beginning frame of the segment */ 00475 r->sp_break_last_word = d->tmp_sp_break_last_word; 00476 #else 00477 /* resume word = most likely sp word on end frame of the segment */ 00478 r->sp_break_last_word = d->last_tre_word; 00479 #endif 00480 } 00481 00482 if (debug2_flag) { 00483 jlog("DEBUG: trailing silence end, end this segment at %d\n", r->am->mfcc->f); 00484 } 00485 00486 d->after_trigger = FALSE; 00487 d->trigger_duration = 0; 00488 d->want_rewind = FALSE; 00489 00490 /*** segment: [sparea_start - time-1] ***/ 00491 return(TRUE); 00492 } 00493 /* else, keep recognition */ 00494 } else { 00495 /* speech re-triggered */ 00496 /* keep recognition */ 00497 d->in_sparea = FALSE; 00498 } 00499 } 00500 } 00501 00502 d->want_rewind = FALSE; 00503 00504 00505 #else /* ~SPSEGMENT_NAIST */ 00506 /************************************************************************/ 00507 /************************************************************************/ 00508 00509 /* sp区間持続チェック */ 00510 /* check sp segment duration */ 00511 if (d->in_sparea && detected) { /* we are already in sp segment and sp continues */ 00512 d->sp_duration++; /* increment count */ 00513 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00514 /* resume word at the "beggining" of sp segment */ 00515 /* if this segment has triggered by (tremax == NULL) (in case the first 00516 several frame of input), the sp word (to be used as resuming 00517 word in the next segment) is not yet set. it will be detected here */ 00518 if (d->tmp_sp_break_last_word == WORD_INVALID) { 00519 if (tremax != NULL) d->tmp_sp_break_last_word = tremax->wid; 00520 } 00521 #else 00522 /* resume word at the "end" of sp segment */ 00523 /* simply update the best sp word */ 00524 if (tremax != NULL) d->last_tre_word = tremax->wid; 00525 #endif 00526 } 00527 00528 /* sp区間開始チェック */ 00529 /* check if sp segment begins at this frame */ 00530 else if (!d->in_sparea && detected) { 00531 /* 一時的に開始フレームとしてマーク */ 00532 /* mark this frame as "temporal" begging of short-pause segment */ 00533 d->tmp_sparea_start = time; 00534 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00535 /* sp 区間開始時点の最尤単語を保存 */ 00536 /* store the best word in this frame as resuming word */ 00537 d->tmp_sp_break_last_word = tremax ? tremax->wid : WORD_INVALID; 00538 #endif 00539 d->in_sparea = TRUE; /* yes, we are in sp segment */ 00540 d->sp_duration = 1; /* initialize duration count */ 00541 #ifdef SP_BREAK_DEBUG 00542 jlog("DEBUG: sp start %d\n", time); 00543 #endif /* SP_BREAK_DEBUG */ 00544 } 00545 00546 /* sp 区間終了チェック */ 00547 /* check if sp segment ends at this frame */ 00548 else if (d->in_sparea && !detected) { 00549 /* (time-1) is end frame of pause segment */ 00550 d->in_sparea = FALSE; /* we are not in sp segment */ 00551 #ifdef SP_BREAK_DEBUG 00552 jlog("DEBUG: sp end %d\n", time); 00553 #endif /* SP_BREAK_DEBUG */ 00554 /* sp 区間長チェック */ 00555 /* check length of the duration*/ 00556 if (d->sp_duration < r->config->successive.sp_frame_duration) { 00557 /* 短すぎる: 第1パスを中断せず続行 */ 00558 /* too short segment: not break, continue 1st pass */ 00559 #ifdef SP_BREAK_DEBUG 00560 jlog("DEBUG: too short (%d<%d), ignored\n", d->sp_duration, r->config->successive.sp_frame_duration); 00561 #endif /* SP_BREAK_DEBUG */ 00562 } else if (d->first_sparea) { 00563 /* 最初のsp区間は silB にあたるので,第1パスを中断せず続行 */ 00564 /* do not break at first sp segment: they are silB */ 00565 d->first_sparea = FALSE; 00566 #ifdef SP_BREAK_DEBUG 00567 jlog("DEBUG: first silence, ignored\n"); 00568 #endif /* SP_BREAK_DEBUG */ 00569 } else { 00570 /* 区間終了確定, 第1パスを中断して第2パスへ */ 00571 /* break 1st pass */ 00572 #ifdef SP_BREAK_DEBUG 00573 jlog("DEBUG: >> segment [%d..%d]\n", r->am->mfcc->sparea_start, time-1); 00574 #endif /* SP_BREAK_DEBUG */ 00575 /* store begging frame of the segment */ 00576 r->am->mfcc->sparea_start = d->tmp_sparea_start; 00577 #ifdef SP_BREAK_RESUME_WORD_BEGIN 00578 /* resume word = most likely sp word on beginning frame of the segment */ 00579 r->sp_break_last_word = d->tmp_sp_break_last_word; 00580 #else 00581 /* resume word = most likely sp word on end frame of the segment */ 00582 r->sp_break_last_word = d->last_tre_word; 00583 #endif 00584 00585 /*** segment: [sparea_start - time-1] ***/ 00586 return(TRUE); 00587 } 00588 } 00589 00590 00591 #endif /* ~SPSEGMENT_NAIST */ 00592 00593 00594 #ifdef SP_BREAK_EVAL 00595 jlog("DEBUG: [%d %d %d]\n", time, count, (detected) ? 50 : 0); 00596 #endif 00597 return (FALSE); 00598 } 00599 00600 /*******************************************************************/ 00601 /* 第1パスセグメント終了処理 (ショートポーズセグメンテーション用) */ 00602 /* end of 1st pass for a segment (for short pause segmentation) */ 00603 /*******************************************************************/ 00631 void 00632 finalize_segment(Recog *recog) 00633 { 00634 int spstart; 00635 RecogProcess *r; 00636 MFCCCalc *mfcc; 00637 boolean ok_p; 00638 00639 /* トレリス始終端における最尤単語を第2パスの始終端単語として格納 */ 00640 /* fix initial/last word hypothesis of the next 2nd pass to the best 00641 word hypothesis at the first/last frame in backtrellis*/ 00642 for(r=recog->process_list;r;r=r->next) { 00643 if (!r->live) continue; 00644 if (r->lmtype == LM_PROB) { 00645 set_terminal_words(r); 00646 } 00647 } 00648 00649 /* パラメータを, 今第1パスが終了したセグメント区間と残りの区間に分割する. 00650 ただし接続部のsp区間部分(sparea_start..len-1)は「のりしろ」として両方に 00651 コピーする */ 00652 /* Divide input parameter into two: the last segment and the rest. 00653 The short-pause area (sparea_start..len-1) is considered as "tab", 00654 copied in both parameters 00655 */ 00656 /* param[sparea_start..framelen] -> rest_param 00657 param[0..len-1] -> param 00658 [sparea_start...len-1] overlapped 00659 */ 00660 00661 ok_p = FALSE; 00662 for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) { 00663 if (mfcc->segmented) { 00664 spstart = mfcc->sparea_start; 00665 ok_p = TRUE; 00666 break; 00667 } 00668 } 00669 00670 if (ok_p) { 00671 /* the input was segmented in an instance */ 00672 /* shrink all param the len and store restart parameters in rest_param */ 00673 /* for each mfcc */ 00674 if (verbose_flag) jlog("STAT: segmented: next decoding will restart from %d\n", spstart); 00675 00676 for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) { 00677 if (verbose_flag) jlog("STAT: MFCC%02d: segmented: processed length=%d\n", mfcc->id, mfcc->last_time); 00678 00679 /* copy the rest to mfcc->rest_param and shrink mfcc->param */ 00680 mfcc_copy_to_rest_and_shrink(mfcc, spstart, mfcc->last_time); 00681 } 00682 00683 /* reset last_word info */ 00684 for(r=recog->process_list;r;r=r->next) { 00685 if (!r->live) continue; 00686 r->sp_break_last_nword_allow_override = TRUE; 00687 } 00688 00689 } else { 00690 00691 /* last segment is on end of input: no rest parameter */ 00692 for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) { 00693 mfcc->rest_param = NULL; 00694 } 00695 /* reset last_word info */ 00696 for(r=recog->process_list;r;r=r->next) { 00697 if (!r->live) continue; 00698 r->sp_break_2_begin_word = WORD_INVALID; 00699 r->sp_break_last_word = WORD_INVALID; 00700 r->sp_break_last_nword = WORD_INVALID; 00701 r->sp_break_last_nword_allow_override = FALSE; 00702 } 00703 } 00704 } 00705 00706 #ifdef BACKEND_VAD 00707 00723 void 00724 spsegment_init(Recog *recog) 00725 { 00726 RecogProcess *p; 00727 /* at first time, recognition does not start yet */ 00728 #ifdef SPSEGMENT_NAIST 00729 for(p=recog->process_list;p;p=p->next) { 00730 p->pass1.after_trigger = FALSE; 00731 p->pass1.trigger_duration = 0; 00732 } 00733 #endif 00734 #ifdef GMM_VAD 00735 if (recog->gmm) { 00736 recog->gc->after_trigger = FALSE; 00737 recog->gc->duration = 0; 00738 } 00739 #endif 00740 recog->triggered = FALSE; 00741 } 00742 00767 boolean 00768 spsegment_trigger_sync(Recog *recog) 00769 { 00770 RecogProcess *p; 00771 boolean ok_p; 00772 00773 ok_p = FALSE; 00774 if (recog->jconf->decodeopt.segment) { 00775 #ifdef SPSEGMENT_NAIST 00776 for(p = recog->process_list; p; p = p->next) { 00777 if (!p->live) continue; 00778 if (p->pass1.after_trigger) { 00779 ok_p = TRUE; 00780 break; 00781 } 00782 } 00783 #endif 00784 #ifdef GMM_VAD 00785 if (recog->gmm) { 00786 if (recog->gc->after_trigger) { 00787 ok_p = TRUE; 00788 } 00789 } 00790 #endif 00791 } 00792 if (ok_p) { 00793 /* up trigger detected */ 00794 #ifdef SPSEGMENT_NAIST 00795 for(p = recog->process_list; p; p = p->next) { 00796 if (!p->live) continue; 00797 p->pass1.after_trigger = TRUE; 00798 } 00799 #endif 00800 #ifdef GMM_VAD 00801 if (recog->gmm) { 00802 recog->gc->after_trigger = TRUE; 00803 } 00804 #endif 00805 } 00806 00807 return ok_p; 00808 } 00809 00810 #endif /* BACKEND_VAD */ 00811 00836 boolean 00837 spsegment_need_restart(Recog *recog, int *rf_ret, boolean *repro_ret) 00838 { 00839 #ifdef SPSEGMENT_NAIST 00840 RecogProcess *p; 00841 #endif 00842 boolean ok_p; 00843 int rewind_frame = 0; 00844 boolean reprocess = FALSE; 00845 00846 ok_p = FALSE; 00847 if (recog->jconf->decodeopt.segment) { 00848 #ifdef SPSEGMENT_NAIST 00849 /* check for rewind request from each process */ 00850 for(p = recog->process_list; p; p = p->next) { 00851 if (!p->live) continue; 00852 if (p->pass1.want_rewind) { 00853 p->pass1.want_rewind = FALSE; 00854 rewind_frame = p->pass1.rewind_frame; 00855 reprocess = p->pass1.want_rewind_reprocess; 00856 ok_p = TRUE; 00857 break; 00858 } 00859 } 00860 #endif /* SPSEGMENT_NAIST */ 00861 #ifdef GMM_VAD 00862 if (recog->gmm) { 00863 if (recog->gc->want_rewind) { 00864 recog->gc->want_rewind = FALSE; 00865 #ifdef SPSEGMENT_NAIST 00866 /* set to earlier one */ 00867 if (rewind_frame > recog->gc->rewind_frame) rewind_frame = recog->gc->rewind_frame; 00868 #else 00869 rewind_frame = recog->gc->rewind_frame; 00870 #endif 00871 reprocess = recog->gc->want_rewind_reprocess; 00872 ok_p = TRUE; 00873 } 00874 } 00875 #endif 00876 *rf_ret = rewind_frame; 00877 *repro_ret = reprocess; 00878 } 00879 00880 return(ok_p); 00881 } 00882 00909 void 00910 spsegment_restart_mfccs(Recog *recog, int rewind_frame, boolean reprocess) 00911 { 00912 MFCCCalc *mfcc; 00913 00914 for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) { 00915 if (!mfcc->valid) continue; 00916 /* set last segmented time */ 00917 mfcc->last_time = mfcc->f - 1; 00918 /* reset frame pointers */ 00919 if (reprocess) { 00920 /* set all mfcc to initial point for re-process the whole frames */ 00921 mfcc->f = -1; 00922 } else { 00923 /* just bring back to the new last point after shrink */ 00924 mfcc->f -= rewind_frame; 00925 } 00926 /* shrink the current mfcc */ 00927 mfcc_shrink(mfcc, rewind_frame); 00928 } 00929 } 00930 00931 /* end of file */