1 /* ====================================================================
2 * Copyright (c) 1999-2004 Carnegie Mellon University.	All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the
15 *    distribution.
16 *
17 * This work was supported in part by funding from the Defense Advanced
18 * Research Projects Agency and the National Science Foundation of the
19 * United States of America, and the CMU Sphinx Speech Consortium.
20 *
21 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
22 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
25 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * ====================================================================
34 *
35 */
36 /*************************************************
37 * CMU ARPA Speech Project
38 *
39 * Copyright (c) 2000 Carnegie Mellon University.
40 * ALL RIGHTS RESERVED.
41 *************************************************
42 *
43 * HISTORY
44  * $Log$
45  * Revision 1.26  2006/03/07  21:04:19  dhdfu
46  * Fill in the word string in srch_hyp_t
47  *
48  * Revision 1.25  2006/02/24 13:41:26  arthchan2003
49  * Used lm_read_advance instead of lm_read
50  *
51  * Revision 1.24  2006/02/22 22:36:56  arthchan2003
52  * changed cmd_ln_access to cmd_ln_int32 in live_decode_API.c
53  *
54  * Revision 1.23  2006/02/22 21:46:51  arthchan2003
55  * Merged from branch SPHINX3_5_2_RCI_IRII:
56  *
57  * 1, Supported -dither (also -seed).
58  * 2, Changed implementation from hyp_t to srch_hyp_t.  The definition will have NO CHANGE because hyp_t will be typedef as srch_hyp_t.
59  * 3, Supported reading, addition and deletion of LMs through ld_read,
60  * ld_set_lm and ld_delete_lm.
61  *
62  * Revision 1.22.4.7  2005/09/25 18:56:11  arthchan2003
63  * Added dict argument into vithist_backtrace.
64  *
65  * Revision 1.22.4.6  2005/07/26 02:16:42  arthchan2003
66  * Merged hyp_t with srch_hyp_t
67  *
68  * Revision 1.22.4.5  2005/07/20 19:42:30  arthchan2003
69  * Completed live decode layer of lm add. Added command-line arguments for fsg and phone insertion.
70  *
71  * Revision 1.22.4.4  2005/07/18 19:00:36  arthchan2003
72  * Changed the type of machine_endian and input_endian to "little" or "big" , changed the type of sampling rate to float32.
73  *
74  * Revision 1.22.4.3  2005/07/13 02:02:52  arthchan2003
75  * Added -dither and -seed in the option.  Dithering is also support in livepretend. The behavior will be conformed s3.x's wave2feat, start to re-incorproate lm_read. Not completed yet.
76  *
77  * Revision 1.22.4.2  2005/07/07 02:31:54  arthchan2003
78  * Remove -lminsearch, it proves to be useless and FSG implementation.
79  *
80  * Revision 1.22.4.1  2005/06/28 06:57:41  arthchan2003
81  * Added protype of initializing and reading FSG, still not working.
82  *
83  * Revision 1.22  2005/06/22 02:49:34  arthchan2003
84  * 1, changed ld_set_lm to call srch_set_lm, 2, hand the accounting tasks to stat_t, 3, added several empty functions for future use.
85  *
86  * Revision 1.6  2005/06/15 21:13:27  archan
87  * Open ld_set_lm, ld_delete_lm in live_decode_API.[ch], Not yet decided whether ld_add_lm and ld_update_lm should be added at this point.
88  *
89  * Revision 1.5  2005/04/20 03:40:23  archan
90  * Add many empty functions into ld, many of them are not yet implemented.
91  *
92  * Revision 1.4  2005/03/30 01:22:47  archan
93  * Fixed mistakes in last updates. Add
94  *
95 * May 14, 2004
96 *   Created by Yitao Sun (yitao@cs.cmu.edu) based on the live.c created by
97 *   Rita Singh.  This version is meant to expose features with a simpler and
98 *   more explicit API.
99 *
100 * Jun 10, 2004
101 *   Modified by Yitao Sun.  Added argument parsing.
102 */
103 
104 /* OLD LOGS before renaming to live_decode_API.h
105 ----------------------------
106 revision 1.8
107 date: 2004/09/03 18:17:11;  author: yitao;  state: Exp;  lines: +15 -11
108 
109 changed ld_process_frames to ld_process_ceps
110 ----------------------------
111 revision 1.7
112 date: 2004/08/25 20:44:31;  author: yitao;  state: Exp;  lines: +65 -41
113 
114 
115 1.  added code to record uttid in live-decode
116 2.  added more code to flesh out remote-decode.  not compiling yet.
117 ----------------------------
118 revision 1.6
119 date: 2004/08/24 18:05:50;  author: yitao;  state: Exp;  lines: +2 -2
120 
121 fixed compilation bug in function ld_utt_free_hyps().
122 ----------------------------
123 revision 1.5
124 date: 2004/08/23 20:41:36;  author: yitao;  state: Exp;  lines: +7 -14
125 
126 basic implementation for remote-decode API.  not compiling yet.
127 ----------------------------
128 revision 1.4
129 date: 2004/08/10 22:13:48;  author: yitao;  state: Exp;  lines: +18 -10
130 
131 added some minor comments in the code.  no significant change.
132 ----------------------------
133 revision 1.3
134 date: 2004/08/09 21:40:36;  author: yitao;  state: Exp;  lines: +122 -93
135 
136 1.  fixed some bugs in Live-Decode API.  changed kb.c, kb.h, utt.c, live_decode.c, liv
137 e_decode.h.
138 2.  changed some filenames in src/programs/.  now there are 2 sets of livedecode and l
139 ivepretend: one that uses the old API (livedecode and livepretend), and one that uses
140 the new API (livedecode2 and livepretend2).
141 3.  modified Makefile.am to reflect the filename changes above.
142 ----------------------------
143 revision 1.2
144 date: 2004/08/08 23:34:50;  author: arthchan2003;  state: Exp;  lines: +1 -1
145 temporary fixes of live_decode.c and live_decode.h
146 ----------------------------
147 revision 1.1
148 date: 2004/08/06 15:07:39;  author: yitao;  state: Exp;
149 *** empty log message ***
150 =============================================================================
151 */
152 
153 #include <time.h>
154 #include <feat.h>
155 #include "s3_decode.h"
156 #include "cmdln_macro.h"
157 #include "utt.h"
158 #include "lm.h"
159 #include "srch.h"
160 
161 arg_t S3_DECODE_ARG_DEFS[] = {
162     waveform_to_cepstral_command_line_macro(),
163     cepstral_to_feature_command_line_macro(),
164 
165     acoustic_model_command_line_macro(),
166     speaker_adaptation_command_line_macro(),
167 
168     language_model_command_line_macro(),
169     log_table_command_line_macro(),
170     dictionary_command_line_macro(),
171     phoneme_lookahead_command_line_macro(),
172     histogram_pruning_command_line_macro(),
173     fast_GMM_computation_command_line_macro(),
174     common_filler_properties_command_line_macro(),
175     common_s3x_beam_properties_command_line_macro(),
176     control_file_handling_command_line_macro(),
177     hypothesis_file_handling_command_line_macro(),
178     score_handling_command_line_macro(),
179     output_lattice_handling_command_line_macro(),
180     dag_handling_command_line_macro(),
181     second_stage_dag_handling_command_line_macro(),
182     input_lattice_handling_command_line_macro(),
183     flat_fwd_debugging_command_line_macro(),
184     history_table_command_line_macro(),
185 
186     decode_specific_command_line_macro(),
187     search_specific_command_line_macro(),
188     search_modeTST_specific_command_line_macro(),
189     search_modeWST_specific_command_line_macro(),
190     control_lm_mllr_file_command_line_macro(),
191     finite_state_grammar_command_line_macro(),
192     phone_insertion_penalty_command_line_macro(),
193 
194     partial_hypothesis_command_line_macro(),
195 
196     {
197 	"-bestscoredir",
198 	ARG_STRING,
199 	NULL,
200 	"(Mode 3) Directory for writing best score/frame (used to set "
201 	"beamwidth; one file/utterance)"
202     },
203 
204     {
205 	"-machine_endian",
206 	ARG_STRING,
207 #ifdef WORDS_BIGENDIAN
208 	"big",
209 #else
210 	"little",
211 #endif
212 	"Endianness of machine, big or little"
213     },
214 
215     {
216 	"-rawext",
217 	ARG_STRING,
218 	".raw",
219 	"Input raw files extension"
220     },
221 
222     {NULL, ARG_INT32, NULL, NULL}
223 };
224 
225 /* Utility function declarations */
226 static int
227 s3_decode_set_uttid(s3_decode_t * _decode, char *_uttid);
228 
229 static int
230 s3_decode_record_hyps(s3_decode_t * _decode, int _end_utt);
231 
232 static void
233 s3_decode_free_hyps(s3_decode_t * _decode);
234 
235 int
s3_decode_init(s3_decode_t * _decode,cmd_ln_t * _config)236 s3_decode_init(s3_decode_t * _decode, cmd_ln_t *_config)
237 {
238     if (_decode == NULL)
239         return S3_DECODE_ERROR_NULL_POINTER;
240 
241     /* capture decoder parameters */
242     kb_init(&_decode->kb, _config);
243 
244     /* initialize decoder variables */
245     _decode->kbcore = _decode->kb.kbcore;
246     _decode->hyp_frame_num = -1;
247     _decode->uttid = NULL;
248     _decode->state = S3_DECODE_STATE_IDLE;
249     _decode->hyp_str = NULL;
250     _decode->hyp_segs = NULL;
251 
252     _decode->swap =
253             strcmp(cmd_ln_str_r(_config,"-machine_endian"),
254                    cmd_ln_str_r(_config,"-input_endian"));
255 
256     if (_decode->swap)
257         E_INFO("Input data WILL be byte swapped\n");
258     else
259         E_INFO("Input data will NOT be byte swapped\n");
260 
261     _decode->phypdump = (cmd_ln_int32_r(_config, "-phypdump"));
262 
263     if (_decode->phypdump)
264         E_INFO("Partial hypothesis WILL be dumped\n");
265     else
266         E_INFO("Partial hypothesis will NOT be dumped\n");
267 
268     _decode->rawext = (cmd_ln_str_r(_config, "-rawext"));
269 
270     return S3_DECODE_SUCCESS;
271 }
272 
273 void
s3_decode_close(s3_decode_t * _decode)274 s3_decode_close(s3_decode_t * _decode)
275 {
276     if (_decode == NULL)
277         return;
278 
279     kb_free(&_decode->kb);
280     s3_decode_free_hyps(_decode);
281     if (_decode->uttid != NULL) {
282         ckd_free(_decode->uttid);
283         _decode->uttid = NULL;
284     }
285     _decode->state = S3_DECODE_STATE_FINISHED;
286 }
287 
288 int
s3_decode_begin_utt(s3_decode_t * _decode,char * _uttid)289 s3_decode_begin_utt(s3_decode_t * _decode, char *_uttid)
290 {
291     if (_decode == NULL)
292         return S3_DECODE_ERROR_NULL_POINTER;
293 
294     if (_decode->state != S3_DECODE_STATE_IDLE) {
295         E_WARN("Cannot begin new utterance in current decoder state.\n");
296         return S3_DECODE_ERROR_INVALID_STATE;
297     }
298 
299     s3_decode_free_hyps(_decode);
300 
301     utt_begin(&_decode->kb);
302 
303     _decode->num_frames_decoded = 0;
304     _decode->num_frames_entered = 0;
305     _decode->state = S3_DECODE_STATE_DECODING;
306 
307     stat_clear_utt(_decode->kb.stat);
308 
309     return s3_decode_set_uttid(_decode, _uttid);
310 }
311 
312 void
s3_decode_end_utt(s3_decode_t * _decode)313 s3_decode_end_utt(s3_decode_t * _decode)
314 {
315     int32 num_features;
316 
317     if (_decode == NULL)
318         return;
319 
320     if (_decode->state != S3_DECODE_STATE_DECODING) {
321         E_WARN("Cannot end utterance in current decoder state.\n");
322         return;
323     }
324 
325     /* Call this with no frames, to update CMN and AGC statistics. */
326     num_features = feat_s2mfc2feat_live(kbcore_fcb(_decode->kbcore),
327                                         NULL, NULL, FALSE,
328                                         TRUE, _decode->kb.feat);
329     if (num_features > 0)
330         utt_decode_block(_decode->kb.feat,
331                          num_features,
332                          &_decode->num_frames_decoded,
333                          &_decode->kb);
334 
335     _decode->kb.stat->tot_fr += _decode->kb.stat->nfr;
336     s3_decode_record_hyps(_decode, TRUE);
337     utt_end(&_decode->kb);
338     _decode->state = S3_DECODE_STATE_IDLE;
339 }
340 
341 int
s3_decode_process(s3_decode_t * _decode,float32 ** _cep_frames,int32 _num_frames)342 s3_decode_process(s3_decode_t * _decode,
343                   float32 ** _cep_frames,
344                   int32 _num_frames)
345 {
346     int32 num_features = 0;
347     int32 begin_utt = _decode->num_frames_entered == 0;
348 
349     if (_decode == NULL)
350         return S3_DECODE_ERROR_NULL_POINTER;
351 
352     if (_num_frames >= S3_MAX_FRAMES)
353         return S3_DECODE_ERROR_OUT_OF_MEMORY;
354 
355 
356     if (_num_frames > 0) {
357         num_features = feat_s2mfc2feat_live(kbcore_fcb(_decode->kbcore),
358                                             _cep_frames,
359                                             &_num_frames,
360                                             begin_utt,
361                                             FALSE,
362                                             _decode->kb.feat);
363         _decode->num_frames_entered += _num_frames;
364 
365         if (num_features > 0) {
366             if (_decode->num_frames_entered >= S3_MAX_FRAMES)
367                 return S3_DECODE_ERROR_OUT_OF_MEMORY;
368 
369             utt_decode_block(_decode->kb.feat,
370                              num_features,
371                              &_decode->num_frames_decoded,
372                              &_decode->kb);
373         }
374     }
375 
376     return S3_DECODE_SUCCESS;
377 }
378 
379 int
s3_decode_hypothesis(s3_decode_t * _decode,char ** _uttid,char ** _hyp_str,hyp_t *** _hyp_segs)380 s3_decode_hypothesis(s3_decode_t * _decode, char **_uttid, char **_hyp_str,
381                      hyp_t *** _hyp_segs)
382 {
383     int rv = S3_DECODE_SUCCESS;
384 
385     if (_decode == NULL)
386         return S3_DECODE_ERROR_NULL_POINTER;
387 
388     /* re-record the hypothesis if there is a frame number mismatch */
389     if (_decode->num_frames_decoded != _decode->hyp_frame_num)
390         rv = s3_decode_record_hyps(_decode, FALSE);
391 
392     if (_uttid != NULL)
393         *_uttid = _decode->uttid;
394 
395     if (_hyp_str != NULL)
396         *_hyp_str = _decode->hyp_str;
397 
398     if (_hyp_segs != NULL)
399         *_hyp_segs = _decode->hyp_segs;
400 
401     return rv;
402 }
403 
404 dag_t *
s3_decode_word_graph(s3_decode_t * _decode)405 s3_decode_word_graph(s3_decode_t *_decode)
406 {
407     srch_t *s;
408 
409     if (_decode == NULL)
410         return NULL;
411 
412     if (_decode->state != S3_DECODE_STATE_IDLE) {
413         E_WARN("Cannot retrieve word graph in current decoder state.\n");
414         return NULL;
415     }
416 
417     s = (srch_t *) _decode->kb.srch;
418     assert(s != NULL);
419 
420     return srch_get_dag(s);
421 }
422 
423 void
s3_decode_read_lm(s3_decode_t * _decode,const char * lmpath,const char * lmname)424 s3_decode_read_lm(s3_decode_t * _decode,
425            const char *lmpath, const char *lmname)
426 {
427     srch_t *s;
428     lm_t *lm;
429     int32 ndict;
430     s = (srch_t *) _decode->kb.srch;
431 
432     ndict = dict_size(_decode->kb.kbcore->dict);
433 
434 
435     lm = lm_read_advance(lmpath, lmname,
436                          cmd_ln_float32_r(kbcore_config(_decode->kbcore), "-lw"),
437                          cmd_ln_float32_r(kbcore_config(_decode->kbcore), "-wip"),
438                          cmd_ln_float32_r(kbcore_config(_decode->kbcore), "-uw"),
439                          ndict, NULL, 1,   /* Weight apply */
440                          kbcore_logmath(s->kbc)
441         );
442 
443     s->funcs->add_lm(s, lm, lmname);
444 }
445 
446 void
s3_decode_set_lm(s3_decode_t * _decode,const char * lmname)447 s3_decode_set_lm(s3_decode_t * _decode, const char *lmname)
448 {
449     srch_t *s;
450     s = (srch_t *) _decode->kb.srch;
451     s->funcs->set_lm(s, lmname);
452 }
453 
454 void
s3_decode_delete_lm(s3_decode_t * _decode,const char * lmname)455 s3_decode_delete_lm(s3_decode_t * _decode, const char *lmname)
456 {
457     srch_t *s;
458     s = (srch_t *) _decode->kb.srch;
459     s->funcs->delete_lm(s, lmname);
460 }
461 
462 /***************************************************************************/
463 /***************************************************************************/
464 /***************************************************************************/
465 
466 int
s3_decode_set_uttid(s3_decode_t * _decode,char * _uttid)467 s3_decode_set_uttid(s3_decode_t * _decode, char *_uttid)
468 {
469     char *local_uttid = NULL;
470     struct tm *times;
471     time_t t;
472 
473     if (_decode == NULL)
474         return S3_DECODE_ERROR_NULL_POINTER;
475 
476     if (_decode->uttid != NULL) {
477         ckd_free(_decode->uttid);
478         _decode->uttid = NULL;
479     }
480 
481     /* automatically-generated uttid */
482     if (_uttid == NULL) {
483         t = time(NULL);
484         times = localtime(&t);
485         if ((local_uttid = ckd_malloc(17)) == NULL) {
486             E_WARN("Failed to allocate space for utterance id.\n");
487             return S3_DECODE_ERROR_OUT_OF_MEMORY;
488         }
489         sprintf(local_uttid, "*%4d%2d%2dZ%2d%2d%2d",
490                 times->tm_year, times->tm_mon, times->tm_mday,
491                 times->tm_hour, times->tm_min, times->tm_sec);
492     }
493     /* user-defined uttid */
494     else {
495         if ((local_uttid = ckd_malloc(strlen(_uttid) + 1)) == NULL) {
496             E_WARN("Failed to allocate space for utterance id.\n");
497             return S3_DECODE_ERROR_OUT_OF_MEMORY;
498         }
499         strcpy(local_uttid, _uttid);
500     }
501     _decode->uttid = local_uttid;
502     /* Also set the kb internal uttid. This sets the uttid in the results. */
503     kb_set_uttid(_decode->uttid, NULL, &(_decode->kb));
504 
505     return S3_DECODE_SUCCESS;
506 }
507 
508 int
s3_decode_record_hyps(s3_decode_t * _decode,int _end_utt)509 s3_decode_record_hyps(s3_decode_t * _decode, int _end_utt)
510 {
511     int32 i = 0;
512     glist_t hyp_list;
513     gnode_t *node;
514     srch_hyp_t *hyp;
515     char *hyp_strptr = 0;
516     char *hyp_str = 0;
517     srch_t *srch;
518     srch_hyp_t **hyp_segs = 0;
519     int hyp_seglen = 0;
520     int hyp_strlen = 0;
521     int finish_wid = 0;
522     kb_t *kb = 0;
523     dict_t *dict;
524     int rv;
525 
526     if (_decode == NULL)
527         return S3_DECODE_ERROR_NULL_POINTER;
528 
529     s3_decode_free_hyps(_decode);
530 
531     kb = &_decode->kb;
532     dict = kbcore_dict(_decode->kbcore);
533     srch = (srch_t *) _decode->kb.srch;
534     hyp_list = srch_get_hyp(srch);
535     if (hyp_list == NULL) {
536         E_WARN("Failed to retrieve viterbi history.\n");
537         return S3_DECODE_ERROR_INTERNAL;
538     }
539 
540     /** record the segment length and the overall string length */
541     finish_wid = dict_finishwid(dict);
542     for (node = hyp_list; node != NULL; node = gnode_next(node)) {
543         hyp = (srch_hyp_t *) gnode_ptr(node);
544         hyp_seglen++;
545         if (!dict_filler_word(dict, hyp->id) && hyp->id != finish_wid) {
546             hyp_strlen +=
547                 strlen(dict_wordstr(dict, dict_basewid(dict, hyp->id))) +
548                 1;
549         }
550     }
551 
552     if (hyp_strlen == 0) {
553         hyp_strlen = 1;
554     }
555 
556   /** allocate array to hold the segments and/or decoded string */
557     hyp_str = (char *) ckd_calloc(hyp_strlen, sizeof(char));
558     hyp_segs =
559         (srch_hyp_t **) ckd_calloc(hyp_seglen + 1, sizeof(srch_hyp_t *));
560     if (hyp_segs == NULL || hyp_str == NULL) {
561         E_WARN("Failed to allocate storage for hypothesis.\n");
562         rv = S3_DECODE_ERROR_OUT_OF_MEMORY;
563         goto s3_decode_record_hyps_cleanup;
564     }
565 
566   /** iterate thru to fill in the array of segments and/or decoded string */
567     i = 0;
568     hyp_strptr = hyp_str;
569     for (node = hyp_list; node != NULL; node = gnode_next(node), i++) {
570         hyp = (srch_hyp_t *) gnode_ptr(node);
571         hyp_segs[i] = hyp;
572 
573         hyp->word = dict_wordstr(dict, dict_basewid(dict, hyp->id));
574         if (!dict_filler_word(dict, hyp->id) && hyp->id != finish_wid) {
575             strcat(hyp_strptr,
576                    dict_wordstr(dict, dict_basewid(dict, hyp->id)));
577             hyp_strptr += strlen(hyp_strptr);
578             *hyp_strptr = ' ';
579             hyp_strptr += 1;
580         }
581     }
582     glist_free(hyp_list);
583 
584     hyp_str[hyp_strlen - 1] = '\0';
585     hyp_segs[hyp_seglen] = 0;
586     _decode->hyp_frame_num = _decode->num_frames_decoded;
587     _decode->hyp_segs = hyp_segs;
588     _decode->hyp_str = hyp_str;
589 
590     return S3_DECODE_SUCCESS;
591 
592   s3_decode_record_hyps_cleanup:
593     if (hyp_segs != NULL) {
594         ckd_free(hyp_segs);
595     }
596     if (hyp_str != NULL) {
597         ckd_free(hyp_str);
598     }
599     if (hyp_list != NULL) {
600         for (node = hyp_list; node != NULL; node = gnode_next(node)) {
601             if ((hyp = (srch_hyp_t *) gnode_ptr(node)) != NULL) {
602                 ckd_free(hyp);
603             }
604         }
605         glist_free(hyp_list);
606     }
607 
608     return rv;
609 }
610 
611 void
s3_decode_free_hyps(s3_decode_t * _decode)612 s3_decode_free_hyps(s3_decode_t * _decode)
613 {
614     srch_hyp_t **h;
615 
616     if (_decode == NULL)
617         return;
618 
619   /** set the reference frame number to something invalid */
620     _decode->hyp_frame_num = -1;
621 
622   /** free and reset the hypothesis string */
623     if (_decode->hyp_str) {
624         ckd_free(_decode->hyp_str);
625         _decode->hyp_str = 0;
626     }
627 
628   /** free and reset the hypothesis word segments */
629     if (_decode->hyp_segs) {
630         for (h = _decode->hyp_segs; *h; h++) {
631             ckd_free(*h);
632         }
633         ckd_free(_decode->hyp_segs);
634         _decode->hyp_segs = 0;
635     }
636 }
637