1 /**
2  * @file   pass1.c
3  *
4  * <JA>
5  * @brief  ��1�ѥ����ե졼��Ʊ���ӡ���õ��
6  *
7  * ��Ū�ڹ�¤������Ѥ��ơ�������ħ�̥٥��ȥ�����Ф��ơ�Julius���裱�ѥ�
8  * �Ǥ���ե졼��Ʊ���ӡ���õ����Ԥ��ޤ�.
9  *
10  * ���ϥǡ������Τ����餫���������Ƥ�����ϡ����Ƿ׻���
11  * �Ԥ��ؿ� get_back_trellis() ���ᥤ����ƤФ�ޤ�. ����饤��ǧ��
12  * �ξ��� realtime_1stpass.c ���顤��������ե졼�ऴ�Ȥη׻���
13  * ��λ�����Τ��줾�줬���ϤοʹԤˤ��碌�Ƹ��̤˸ƤФ�ޤ�.
14  *
15  * �ºݤθġ���ǧ�����������������Ȥν����� beam.c �˵��Ҥ���Ƥ��ޤ�.
16  *
17  * </JA>
18  *
19  * <EN>
20  * @brief  The first pass: frame-synchronous beam search
21  *
22  * These functions perform a frame-synchronous beam search using a static
23  * lexicon tree, as the first pass of Julius/Julian.
24  *
25  * When the whole input is already obtained, get_back_trellis() simply
26  * does all the processing of the 1st pass.  When performing online
27  * real-time recognition with concurrent speech input, each function
28  * will be called separately from realtime_1stpass.c according on the
29  * basis of input processing.
30  *
31  * The core recognition processing functions for each recognition
32  * process instances are written in beam.c.
33  *
34  * </EN>
35  *
36  * @author Akinobu Lee
37  * @date   Fri Oct 12 23:14:13 2007
38  *
39  * $Revision: 1.7 $
40  *
41  */
42 /*
43  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
44  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
45  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
46  * All rights reserved
47  */
48 
49 #include <julius/julius.h>
50 
51 /********************************************************************/
52 /* �裱�ѥ���¹Ԥ���ᥤ��ؿ�                                     */
53 /* ���Ϥ�ѥ��ץ饤������������ realtime_1stpass.c ���ȤΤ��� */
54 /* main function to execute 1st pass                                */
55 /* the pipeline processing is not here: see realtime_1stpass.c      */
56 /********************************************************************/
57 
58 /**
59  * <EN>
60  * @brief  Process one input frame for all recognition process instance.
61  *
62  * This function proceeds the recognition for one frame.  All
63  * recognition process instance will be processed synchronously.
64  * The input frame for each instance is stored in mfcc->f, where mfcc
65  * is the MFCC calculation instance assigned to each process instance.
66  *
67  * If an instance's mfcc->invalid is set to TRUE, its processing will
68  * be skipped.
69  *
70  * When using GMM, GMM computation will also be executed here.
71  * If GMM_VAD is defined, GMM-based voice detection will be performed
72  * inside this function, by using a scheme of short-pause segmentation.
73  *
74  * This function also handles segmentation of recognition process.  A
75  * segmentation will occur when end of speech is detected by level-based
76  * sound detection or GMM-based / decoder-based VAD, or by request from
77  * application.  When segmented, it stores current frame and return with
78  * that status.
79  *
80  * The frame-wise callbacks will be executed inside this function,
81  * when at least one valid recognition process instances exists.
82  *
83  * </EN>
84  * <JA>
85  * @brief  ���Ƥ�ǧ��������������������1�ե졼��ʬ�ʤ��.
86  *
87  * ���Ƥ�ǧ���������������ˤĤ��ơ�����դ����Ƥ���MFCC�׻���������
88  * �� mfcc->f �����ȥե졼��Ȥ��ƽ�����1�ե졼��ʤ��.
89  *
90  * �ʤ���mfcc->invalid �� TRUE �ȤʤäƤ���������������ν����ϥ����å�
91  * �����.
92  *
93  * GMM�η׻��⤳���ǸƤӽФ����. GMM_VAD ������ϡ�GMM �ˤ��
94  * ȯ�ö�ֳ��ϡ���λ�θ��Ф������ǹԤ���. �ޤ���GMM�η׻���̡�
95  * ���뤤��ǧ��������Υ��硼�ȥݡ����������ơ������Ƚ���ǥХ���������
96  * ������׵�ˤ�ꥻ�����ơ�������׵ᤵ�줿���ɤ�����Ƚ���Ԥ�.
97  *
98  * �ե졼��ñ�̤ǸƤӽФ���륳����Хå�����Ͽ����Ƥ�����ϡ�������
99  * �ƽФ���Ԥ�.
100  * </JA>
101  *
102  * @param recog [in] engine instance
103  *
104  * @return 0 on success, -1 on error, or 1 when an input segmentation
105  * occured/requested inside this function.
106  *
107  * @callgraph
108  * @callergraph
109  *
110  */
111 int
decode_proceed(Recog * recog)112 decode_proceed(Recog *recog)
113 {
114   MFCCCalc *mfcc;
115   boolean break_flag;
116   boolean break_decode;
117   RecogProcess *p;
118   boolean ok_p;
119 #ifdef GMM_VAD
120   GMMCalc *gmm;
121   boolean break_gmm;
122 #endif
123 
124   break_decode = FALSE;
125 
126   for(p = recog->process_list; p; p = p->next) {
127 #ifdef DETERMINE
128     p->have_determine = FALSE;
129 #endif
130     p->have_interim = FALSE;
131   }
132   for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
133     mfcc->segmented = FALSE;
134   }
135 
136 #ifdef POWER_REJECT
137   for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
138     if (!mfcc->valid) continue;
139     if (mfcc->f == 0) {
140       mfcc->avg_power = 0.0;
141       if (debug2_flag) jlog("STAT: power_reject: reset\n");
142     }
143   }
144 #endif
145 
146 
147 #ifdef GMM_VAD
148   if (recog->gmm != NULL) {
149     /* reset flags */
150     break_gmm = FALSE;
151     recog->gc->want_rewind = FALSE;
152   }
153 #endif
154   if (recog->gmm != NULL && recog->gmmmfcc->valid) {
155     /* GMM �׻���Ԥ� */
156     if (recog->gmmmfcc->f == 0) {
157       /* GMM �׻��ν���� */
158       gmm_prepare(recog);
159     }
160     /* ���Υե졼����Ф���GMM�����٤�׻� */
161     gmm_proceed(recog);
162 #ifdef GMM_VAD
163     /* Check for GMM-based VAD */
164     gmm = recog->gc;
165     gmm_check_trigger(recog);
166     if (gmm->after_trigger) {
167       /* after trigger, in speech area */
168       if (gmm->down_trigger) {
169 	/* down trigger, end segment */
170 #ifdef GMM_VAD_DEBUG
171 	printf("GMM_VAD: %d: down trigger\n", recog->gmmmfcc->f);
172 #endif
173 	recog->gmmmfcc->sparea_start = recog->gmmmfcc->f + 1 - recog->jconf->detect.gmm_margin;
174 	if (recog->gmmmfcc->sparea_start < 0) recog->gmmmfcc->sparea_start = 0;
175 	gmm->after_trigger = FALSE;
176 	recog->gmmmfcc->segmented = TRUE;
177 	break_gmm = TRUE;
178       } else {
179 	/* keep recognition */
180       }
181     } else {
182       /* before trigger, in noise area */
183       if (gmm->up_trigger) {
184 	/* start recognition */
185 	/* request caller to rewind to the backstep point and
186 	   re-start with normal search */
187 	if (recog->gmmmfcc->f + 1 < recog->jconf->detect.gmm_margin) {
188 	  gmm->rewind_frame = 0;
189 	} else {
190 	  gmm->rewind_frame = recog->gmmmfcc->f + 1 - recog->jconf->detect.gmm_margin;
191 	}
192 #ifdef GMM_VAD_DEBUG
193 	printf("GMM_VAD: %d: up trigger, start recognition with %d frame rewind\n", recog->gmmmfcc->f, recog->gmmmfcc->f - gmm->rewind_frame);
194 #endif
195 	gmm->want_rewind = TRUE;
196 	gmm->want_rewind_reprocess = TRUE;
197 	gmm->after_trigger = TRUE;
198 	return 0;
199       } else {
200 	/* before trigger, noise continues */
201 
202 	/* if noise goes more than a certain frame, shrink the noise area
203 	   to avoid unlimited memory usage */
204 	if (recog->gmmmfcc->f + 1 > GMM_VAD_AUTOSHRINK_LIMIT) {
205 	  gmm->want_rewind = TRUE;
206 	  gmm->want_rewind_reprocess = FALSE;
207 	  gmm->rewind_frame = recog->gmmmfcc->f + 1 - recog->jconf->detect.gmm_margin;
208 	  if (debug2_flag) {
209 	    jlog("DEBUG: GMM_VAD: pause exceeded %d, rewind\n", GMM_VAD_AUTOSHRINK_LIMIT);
210 	  }
211 	}
212 
213 	/* skip recognition processing */
214 	return 0;
215       }
216     }
217 #endif /* GMM_VAD */
218   }
219 
220   for(p = recog->process_list; p; p = p->next) {
221     if (!p->live) continue;
222     mfcc = p->am->mfcc;
223     if (!mfcc->valid) {
224       /* ���Υե졼��ν��������å� */
225       /* skip processing the frame */
226       continue;
227     }
228 
229     /* mfcc-f �Υե졼��ˤĤ���ǧ������(�ե졼��Ʊ���ӡ���õ��)��ʤ�� */
230     /* proceed beam search for mfcc->f */
231     if (mfcc->f == 0) {
232       /* �ǽ�Υե졼��: õ������������ */
233       /* initial frame: initialize search process */
234       if (get_back_trellis_init(mfcc->param, p) == FALSE) {
235 	jlog("ERROR: %02d %s: failed to initialize the 1st pass\n", p->config->id, p->config->name);
236 	return -1;
237       }
238     }
239     if (mfcc->f > 0 || p->am->hmminfo->multipath) {
240       /* 1�ե졼��õ����ʤ�� */
241       /* proceed search for 1 frame */
242       if (get_back_trellis_proceed(mfcc->f, mfcc->param, p, FALSE) == FALSE) {
243 	mfcc->segmented = TRUE;
244 	break_decode = TRUE;
245       }
246       if (p->config->successive.enabled) {
247 	if (detect_end_of_segment(p, mfcc->f - 1)) {
248 	  /* �������Ƚ�λ����: �裱�ѥ����������� */
249 	  mfcc->segmented = TRUE;
250 	  break_decode = TRUE;
251 	}
252       }
253     }
254   }
255 
256   /* �������Ȥ��٤����ɤ����ǽ�Ū��Ƚ���Ԥ���
257      �ǥ������١���VAD���뤤�� spsegment �ξ�硤ʣ�����������֤� OR
258      ���롥�ޤ���GMM�ʤ�ʣ����ब������ϴ��֤� AND ���롥*/
259   /* determine whether to segment at here
260      If multiple segmenter exists, take their AND */
261   break_flag = FALSE;
262   if (break_decode
263 #ifdef GMM_VAD
264       || (recog->gmm != NULL && break_gmm)
265 #endif
266       ) {
267     break_flag = TRUE;
268   }
269 
270   if (break_flag) {
271     /* õ�������ν�λ��ȯ�������ΤǤ�����ǧ��������.
272        �ǽ�Υե졼�फ�� [f-1] ���ܤޤǤ�ǧ�����줿���Ȥˤʤ�
273     */
274     /* the recognition process tells us to stop recognition, so
275        recognition should be terminated here.
276        the recognized data are [0..f-1] */
277 
278     /* �ǽ��ե졼��� last_time �˥��å� */
279     /* set the last frame to last_time */
280     for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
281       mfcc->last_time = mfcc->f - 1;
282     }
283 
284     if (! recog->jconf->decodeopt.segment) {
285       /* ���硼�ȥݡ����ʳ����ڤ줿��硤�Ĥ�Υ���ץ��ǧ�������˼ΤƤ� */
286       /* drop rest inputs if segmented by error */
287       for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
288 	mfcc->param->header.samplenum = mfcc->f;
289 	mfcc->param->samplenum = mfcc->f;
290       }
291     }
292 
293     return 1;
294   }
295 
296   /* call frame-wise callback for the processing results if any */
297 #ifdef DETERMINE
298   ok_p = FALSE;
299   for(p=recog->process_list;p;p=p->next) {
300     if (!p->live) continue;
301     if (p->have_determine) {
302       ok_p = TRUE;
303     }
304   }
305   if (ok_p) callback_exec(CALLBACK_RESULT_PASS1_DETERMINED, recog);
306 #endif
307   ok_p = FALSE;
308   for(p=recog->process_list;p;p=p->next) {
309     if (!p->live) continue;
310     if (p->have_interim) {
311       ok_p = TRUE;
312     }
313   }
314   if (ok_p) callback_exec(CALLBACK_RESULT_PASS1_INTERIM, recog);
315 
316   return 0;
317 }
318 
319 #ifdef POWER_REJECT
320 boolean
power_reject(Recog * recog)321 power_reject(Recog *recog)
322 {
323   MFCCCalc *mfcc;
324 
325   for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
326     /* skip if not realtime and raw file processing */
327     if (mfcc->avg_power == 0.0) continue;
328     if (debug2_flag) jlog("STAT: power_reject: MFCC%02d: avg_power = %f\n", mfcc->id, mfcc->avg_power / mfcc->param->samplenum);
329     if (mfcc->avg_power / mfcc->param->samplenum < recog->jconf->reject.powerthres) return TRUE;
330   }
331   return FALSE;
332 }
333 #endif
334 
335 /**
336  * <EN>
337  * @brief  End procedure of the first pass (when segmented)
338  *
339  * This function do things for ending the first pass and prepare for
340  * the next recognition, when the input was segmented at the middle of
341  * recognition by some reason.
342  *
343  * First, the best path at each recognition process instance will be parsed
344  * and stored.  In case of recognition error or input rejection, the error
345  * status will be set.
346  *
347  * Then, the last pause segment of the processed input will be cut and saved
348  * to be processed at first in the recognition of the next or remaining input.
349  *
350  * </EN>
351  * <JA>
352  * @brief  ��1�ѥ��ν�λ�����ʥ������Ȼ���
353  *
354  * ���Ϥ����餫�λ�ͳ�ˤ�ä�����ǥ������Ȥ��줿���ˡ���1�ѥ���ǧ��������
355  * ��λ���Ƽ���Ƴ����뤿��ν�����Ԥ�.
356  *
357  * �ޤ�����ǧ�����������������Ф��ơ�����ñ�������դ�����1�ѥ���
358  * ǧ����̤Ȥ��Ƴ�Ǽ����. �ޤ���ǧ�����ԡ����ϴ��Ѥλ��ϥ��顼���ơ�������
359  * �줾�쥻�åȤ���.
360  *
361  * �����ơ������ǧ���ǡ����Υ������Ȥ�ǧ�������Ф��줿��������
362  * ��֤���Ƴ����뤿��ˡ���������������֤��ڤ�Ф��Ƥ���������Ƥ�.
363  *
364  * </JA>
365  *
366  * @param recog [in] engine instance
367  *
368  * @callgraph
369  * @callergraph
370  */
371 void
decode_end_segmented(Recog * recog)372 decode_end_segmented(Recog *recog)
373 {
374   boolean ok_p;
375   int mseclen;
376   RecogProcess *p;
377   int last_status;
378 
379   /* rejectshort �����, ���Ϥ�û����Ф�������1�ѥ���̤���Ϥ��ʤ� */
380   /* suppress 1st pass output if -rejectshort and input shorter than specified */
381   ok_p = TRUE;
382   if (recog->jconf->reject.rejectshortlen > 0) {
383     mseclen = (float)recog->mfcclist->last_time * (float)recog->jconf->input.period * (float)recog->jconf->input.frameshift / 10000.0;
384     if (mseclen < recog->jconf->reject.rejectshortlen) {
385       last_status = J_RESULT_STATUS_REJECT_SHORT;
386       ok_p = FALSE;
387     }
388   }
389 
390 #ifdef POWER_REJECT
391   if (ok_p) {
392     if (power_reject(recog)) {
393       last_status = J_RESULT_STATUS_REJECT_POWER;
394       ok_p = FALSE;
395     }
396   }
397 #endif
398 
399   if (ok_p) {
400     for(p=recog->process_list;p;p=p->next) {
401       if (!p->live) continue;
402       finalize_1st_pass(p, p->am->mfcc->last_time);
403     }
404   } else {
405     for(p=recog->process_list;p;p=p->next) {
406       if (!p->live) continue;
407       p->result.status = last_status;
408     }
409   }
410   if (recog->jconf->decodeopt.segment) {
411     finalize_segment(recog);
412   }
413 
414   if (recog->gmm != NULL) {
415     /* GMM �׻��ν�λ */
416     gmm_end(recog);
417   }
418 }
419 
420 /**
421  * <EN>
422  * @brief  End procedure of the first pass
423  *
424  * This function finish the first pass, when the input was fully
425  * processed to the end.
426  *
427  * The best path at each recognition process instance will be parsed
428  * and stored.  In case of recognition error or input rejection, the
429  * error status will be set.
430  *
431  * </EN>
432  * <JA>
433  * @brief  ��1�ѥ��ν�λ����
434  *
435  * ���Ϥ��Ǹ�ޤǽ�������ƽ�λ�����Ȥ��ˡ���1�ѥ���ǧ��������
436  * ��λ������.
437  *
438  * ��ǧ�����������������Ф��ơ����λ����Ǥ���1�ѥ��κ���ñ��
439  * ������Ǽ����. �ޤ���ǧ�����ԡ����ϴ��Ѥλ��ϥ��顼���ơ�������
440  * �줾�쥻�åȤ���.
441  *
442  * </JA>
443  *
444  * @param recog [in] engine instance
445  *
446  * @callgraph
447  * @callergraph
448  */
449 void
decode_end(Recog * recog)450 decode_end(Recog *recog)
451 {
452   MFCCCalc *mfcc;
453   int mseclen;
454   boolean ok_p;
455   RecogProcess *p;
456   int last_status;
457 
458   for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
459     mfcc->segmented = FALSE;
460   }
461 
462   if (recog->gmm != NULL) {
463     /* GMM �׻��ν�λ */
464     gmm_end(recog);
465   }
466 
467 #ifdef GMM_VAD
468   /* �⤷�ȥꥬ��������ʤ��ޤ����Ͻ�λ��ã�����Τʤ顤���Τޤޥ��顼��λ */
469   if (recog->jconf->decodeopt.segment) {
470     if (recog->gmm) {
471       if (recog->gc->after_trigger == FALSE) {
472 	for(p=recog->process_list;p;p=p->next) {
473 	  p->result.status = J_RESULT_STATUS_ONLY_SILENCE;	/* reject by decoding */
474 	}
475 	/* ���硼�ȥݡ����������ơ������ξ��,
476 	   ���ϥѥ�᡼��ʬ��ʤɤκǽ�������Ԥʤ� */
477 	/* When short-pause segmentation enabled */
478 	finalize_segment(recog);
479 	return;
480       }
481     }
482   }
483 #endif
484 
485   /* �裱�ѥ��κǸ�Υե졼���ǧ��������Ԥ� */
486   /* finalize 1st pass */
487   for(p=recog->process_list;p;p=p->next) {
488     if (!p->live) continue;
489 #ifdef SPSEGMENT_NAIST
490     if (recog->jconf->decodeopt.segment) {
491       if (p->pass1.after_trigger == FALSE) continue;
492     }
493 #endif
494     mfcc = p->am->mfcc;
495     if (mfcc->f > 0) {
496       get_back_trellis_end(mfcc->param, p);
497     }
498   }
499 
500   /* ��λ���� */
501   for(p=recog->process_list;p;p=p->next) {
502     if (!p->live) continue;
503 
504     ok_p = TRUE;
505 
506     /* check rejection by no input */
507     if (ok_p) {
508       mfcc = p->am->mfcc;
509       /* ����Ĺ���ǥ륿�η׻��˽�ʬ�Ǥʤ���硤����̵���Ȥ��롥 */
510       /* if input is short for compute all the delta coeff., terminate here */
511       if (mfcc->f == 0) {
512 	jlog("STAT: no input frame\n");
513 	last_status = J_RESULT_STATUS_FAIL;
514 	ok_p = FALSE;
515       }
516     }
517 
518     /* check rejection by input length */
519     if (ok_p) {
520       if (recog->jconf->reject.rejectshortlen > 0) {
521 	mseclen = (float)mfcc->param->samplenum * (float)recog->jconf->input.period * (float)recog->jconf->input.frameshift / 10000.0;
522 	if (mseclen < recog->jconf->reject.rejectshortlen) {
523 	  last_status = J_RESULT_STATUS_REJECT_SHORT;
524 	  ok_p = FALSE;
525 	}
526       }
527     }
528 
529 #ifdef POWER_REJECT
530     /* check rejection by average power */
531     if (ok_p) {
532       if (power_reject(recog)) {
533 	last_status = J_RESULT_STATUS_REJECT_POWER;
534 	ok_p = FALSE;
535       }
536     }
537 #endif
538 
539 #ifdef SPSEGMENT_NAIST
540     /* check rejection non-triggered input segment */
541     if (ok_p) {
542       if (recog->jconf->decodeopt.segment) {
543 	if (p->pass1.after_trigger == FALSE) {
544 	  last_status = J_RESULT_STATUS_ONLY_SILENCE;	/* reject by decoding */
545 	  ok_p = FALSE;
546 	}
547       }
548     }
549 #endif
550 
551     if (ok_p) {
552       /* valid input segment, finalize it */
553       finalize_1st_pass(p, mfcc->param->samplenum);
554     } else {
555       /* invalid input segment */
556       p->result.status = last_status;
557     }
558   }
559   if (recog->jconf->decodeopt.segment) {
560     /* ���硼�ȥݡ����������ơ������ξ��,
561        ���ϥѥ�᡼��ʬ��ʤɤκǽ�������Ԥʤ� */
562     /* When short-pause segmentation enabled */
563     finalize_segment(recog);
564   }
565 }
566 
567 
568 /**
569  * <JA>
570  * @brief  �ե졼��Ʊ���ӡ���õ���ᥤ��ؿ��ʥХå������ѡ�
571  *
572  * Ϳ����줿���ϥ٥��ȥ�����Ф����裱�ѥ�(�ե졼��Ʊ���ӡ���õ��)��
573  * �Ԥ������η�̤���Ϥ���. �ޤ����ե졼����Ϥ�ñ�콪ü���裲�ѥ�
574  * �Τ����ñ��ȥ�ꥹ��¤�Τ˳�Ǽ����.
575  *
576  * ���δؿ������ϥ٥��ȥ������餫���������Ƥ�������Ѥ�����.
577  * �裱�ѥ������Ϥ������Ƽ¹Ԥ���륪��饤��ǧ���ξ�硤
578  * ���δؿ����Ѥ���줺������ˤ��Υե�������������Ƥ���ƥ��ִؿ���
579  * ľ�� realtime-1stpass.c �⤫��ƤФ��.
580  *
581  * @param recog [in] ������������
582  * </JA>
583  * <EN>
584  * @brief  Frame synchronous beam search: the main (for batch mode)
585  *
586  * This function perform the 1st recognition pass of frame-synchronous beam
587  * search and output the result.  It also stores all the word ends in every
588  * input frame to word trellis structure.
589  *
590  * This function will be called if the whole input vector is already given
591  * to the end.  When online recognition, where the 1st pass will be
592  * processed in parallel with input, this function will not be used.
593  * In that case, functions defined in this file will be directly called
594  * from functions in realtime-1stpass.c.
595  *
596  * @param recog [in] engine instance
597  * </EN>
598  * @callgraph
599  * @callergraph
600  */
601 boolean
get_back_trellis(Recog * recog)602 get_back_trellis(Recog *recog)
603 {
604   boolean ok_p;
605   MFCCCalc *mfcc;
606   int rewind_frame;
607   PROCESS_AM *am;
608   boolean reprocess;
609 
610   /* initialize mfcc instances */
611   for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
612     /* mark all as valid, since all frames are fully prepared beforehand */
613     if (mfcc->param->samplenum == 0) mfcc->valid = FALSE;
614     else mfcc->valid = TRUE;
615     /* set frame pointers to 0 */
616     mfcc->f = 0;
617   }
618 
619   /* callback of process start */
620 #ifdef BACKEND_VAD
621   if (recog->jconf->decodeopt.segment) {
622     /* at first time, recognition does not start yet */
623     /* reset segmentation flags */
624     spsegment_init(recog);
625   } else {
626     /* execute callback for pass1 begin here */
627     callback_exec(CALLBACK_EVENT_RECOGNITION_BEGIN, recog);
628     callback_exec(CALLBACK_EVENT_PASS1_BEGIN, recog);
629     recog->triggered = TRUE;
630   }
631 #else
632   if (recog->jconf->decodeopt.segment) {
633     if (!recog->process_segment) {
634       callback_exec(CALLBACK_EVENT_RECOGNITION_BEGIN, recog);
635     }
636     callback_exec(CALLBACK_EVENT_SEGMENT_BEGIN, recog);
637   } else {
638     callback_exec(CALLBACK_EVENT_RECOGNITION_BEGIN, recog);
639   }
640   callback_exec(CALLBACK_EVENT_PASS1_BEGIN, recog);
641   recog->triggered = TRUE;
642 #endif
643 
644   while(1) {
645     ok_p = TRUE;
646     for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
647       if (! mfcc->valid) continue;
648       if (mfcc->f < mfcc->param->samplenum) {
649 	mfcc->valid = TRUE;
650 	ok_p = FALSE;
651       } else {
652 	mfcc->valid = FALSE;
653       }
654     }
655     if (ok_p) {
656       /* ���٤Ƥ� MFCC ��������ã�����Τǥ롼�׽�λ */
657       /* all MFCC has been processed, end of loop  */
658       break;
659     }
660 
661     switch (decode_proceed(recog)) {
662     case -1: /* error */
663       return FALSE;
664       break;
665     case 0:			/* success */
666       break;
667     case 1:			/* segmented */
668       /* õ������: �������줿���Ϥ� 0 ���� t-2 �ޤ� */
669       /* search terminated: processed input = [0..t-2] */
670       /* ���λ�������1�ѥ���λ���� */
671       /* end the 1st pass at this point */
672       decode_end_segmented(recog);
673       /* terminate 1st pass here */
674       return TRUE;
675     }
676 
677 #ifdef BACKEND_VAD
678     /* check up trigger in case of VAD segmentation */
679     if (recog->jconf->decodeopt.segment) {
680       if (recog->triggered == FALSE) {
681 	if (spsegment_trigger_sync(recog)) {
682 	  if (!recog->process_segment) {
683 	    callback_exec(CALLBACK_EVENT_RECOGNITION_BEGIN, recog);
684 	  }
685 	  callback_exec(CALLBACK_EVENT_SEGMENT_BEGIN, recog);
686 	  callback_exec(CALLBACK_EVENT_PASS1_BEGIN, recog);
687 	  recog->triggered = TRUE;
688 	}
689       }
690     }
691 #endif
692 
693     if (spsegment_need_restart(recog, &rewind_frame, &reprocess) == TRUE) {
694       /* do rewind for all mfcc here */
695       spsegment_restart_mfccs(recog, rewind_frame, reprocess);
696       /* reset outprob cache for all AM */
697       for(am=recog->amlist;am;am=am->next) {
698 	outprob_prepare(&(am->hmmwrk), am->mfcc->param->samplenum);
699       }
700     }
701     /* call frame-wise callback */
702     callback_exec(CALLBACK_EVENT_PASS1_FRAME, recog);
703 
704     /* 1�ե졼��������ʤ���Τǥݥ�����ʤ�� */
705     /* proceed frame pointer */
706     for (mfcc = recog->mfcclist; mfcc; mfcc = mfcc->next) {
707       if (!mfcc->valid) continue;
708       mfcc->f++;
709     }
710 
711     if (recog->process_want_terminate) {
712       /* termination requested */
713       decode_end_segmented(recog);
714       return TRUE;
715     }
716   }
717 
718   /* �ǽ��ե졼�������Ԥ���ǧ���η�̽��ϤȽ�λ������Ԥ� */
719   decode_end(recog);
720 
721   return TRUE;
722 }
723 
724 /* end of file */
725