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