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  * corpus.c -- Corpus-file related misc functions.
38  *
39  * **********************************************
40  * CMU ARPA Speech Project
41  *
42  * Copyright (c) 1996-2004 Carnegie Mellon University.
43  * ALL RIGHTS RESERVED.
44  * **********************************************
45  *
46  * HISTORY
47  *
48  * $Log$
49  * Revision 1.12  2006/02/22  19:49:25  arthchan2003
50  * Merged from SPHINX3_5_2_RCI_IRII:
51  * 1, Add structure utt_res_t, this is an utterance-based resouce
52  * structure. Add basic operation such as free and report.
53  * 2, Modify the structure of the loop in ctl_corpus to make it not so
54  * clunky. Tested with make check .
55  * 3, Completely removed ctl_process_dyn_lm, it is a product of code
56  * duplication (alright, it is written by me......)
57  * 4, Fixed doc-dox.
58  *
59  * Revision 1.11.4.3  2005/08/02 21:09:07  arthchan2003
60  * Removed error message
61  *
62  * Revision 1.11.4.2  2005/07/27 23:19:11  arthchan2003
63  * 1, Added utt_res_t structure and its methods. 2, Changed the function pointer prototype. 3, Removed the lm and mllr set process out of ctl_process
64  *
65  * Revision 1.11.4.1  2005/07/26 03:14:17  arthchan2003
66  * Removed ctl_process_dyn_lm. One of my sin.
67  *
68  * Revision 1.11  2005/06/21 20:44:34  arthchan2003
69  * 1, Fixed doxygen documentation, 2, Add the $ keyword.
70  *
71  *
72  * 09-Dec-1999	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
73  * 		Added ctl_process_utt ().
74  *
75  * 01-Mar-1999	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
76  * 		Added check for already existing file extension in ctl_infile().
77  *
78  * 23-Mar-1998	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
79  * 		Added a general purpose data argument to ctl_process() and its function
80  * 		argument func.
81  *
82  * 22-Nov-1997	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
83  * 		Added an optional validation function argument and an optional
84  *		duplicate-resolution function argument to both corpus_load_headid() and
85  * 		corpus_load_tailid().
86  *
87  * 25-Oct-1997	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
88  * 		Started.
89  */
90 
91 
92 #include <string.h>
93 #ifndef WIN32
94 #include <unistd.h>
95 #else
96 #include <stdlib.h>
97 #endif
98 
99 #include "filename.h"
100 #include "pio.h"
101 #include "corpus.h"
102 #include "kb.h"
103 
104 #if (defined(WIN32) && !defined(__CYGWIN__))
105 #define SLEEP_SEC(sec)  (0)                     /* Why doesn't Sleep((sec)*1000) work? */
106 #else
107 #define SLEEP_SEC(sec)  sleep(sec)              /* sec must be integer */
108 #endif
109 
110 utt_res_t *
new_utt_res()111 new_utt_res()
112 {
113     utt_res_t *ur;
114     ur = ckd_calloc(1, sizeof(utt_res_t));
115     utt_res_set_uttfile(ur, NULL);
116     utt_res_set_lmname(ur, NULL);
117     utt_res_set_fsgname(ur, NULL);
118     utt_res_set_regmatname(ur, NULL);
119     utt_res_set_cb2mllrname(ur, NULL);
120 
121     return ur;
122 }
123 
124 void
free_utt_res(utt_res_t * ur)125 free_utt_res(utt_res_t * ur)
126 {
127     ckd_free(ur);
128 }
129 
130 void
report_utt_res(utt_res_t * ur)131 report_utt_res(utt_res_t * ur)
132 {
133     E_INFO_NOFN("Utt res, report:\n");
134     if (ur->uttfile != NULL)
135         E_INFO_NOFN("uttfile %s\n", ur->uttfile);
136     if (ur->lmname != NULL)
137         E_INFO_NOFN("lmname %s\n", ur->lmname);
138     if (ur->fsgname != NULL)
139         E_INFO_NOFN("fsgname %s\n", ur->fsgname);
140     if (ur->regmatname != NULL)
141         E_INFO_NOFN("regmatname %s\n", ur->regmatname);
142     if (ur->cb2mllrname != NULL)
143         E_INFO_NOFN("cb2mllrname %s\n", ur->cb2mllrname);
144 
145 
146 }
147 
148 corpus_t *
corpus_load_headid(const char * file,int32 (* validate)(char * str),int32 (* dup_resolve)(char * s1,char * s2))149 corpus_load_headid(const char *file,
150                    int32(*validate) (char *str),
151                    int32(*dup_resolve) (char *s1, char *s2))
152 {
153     FILE *fp;
154     char line[16384], wd[4096], *id;
155     int32 j, k, m, n;
156     corpus_t *corp;
157 
158     E_INFO("Loading corpus (%s)\n", file);
159 
160     if ((fp = fopen(file, "r")) == NULL)
161         E_FATAL_SYSTEM("fopen(%s,r) failed\n", file);
162 
163     corp = (corpus_t *) ckd_calloc(1, sizeof(corpus_t));
164 
165     n = 0;
166     while (fgets(line, sizeof(line), fp) != NULL) {
167         /* Skip empty lines */
168         if (sscanf(line, "%s", wd) == 1)
169             n++;
170     }
171     rewind(fp);
172 
173     corp->ht = hash_table_new(n, HASH_CASE_YES);
174     corp->n = 0;
175     corp->str = (char **) ckd_calloc(n, sizeof(char *));
176 
177     n = 0;
178     while (fgets(line, sizeof(line), fp) != NULL) {
179         /* Skip blank lines */
180         if (sscanf(line, "%s%n", wd, &k) != 1)
181             continue;
182 
183         /* Eliminate the line-terminating newline */
184         j = strlen(line);
185         if ((j > 0) && (line[j - 1] == '\n'))
186             line[j - 1] = '\0';
187 
188         /* Validate if a validation function is given */
189         if (validate && (!(*validate) (line + k))) {
190             E_INFO("Corpus validation %s failed; skipping\n", wd);
191             continue;
192         }
193 
194         id = ckd_salloc(wd);
195         if ((m = (long) hash_table_enter(corp->ht, id, (void *)(long)n)) != n) {
196             /* Duplicate entry */
197             if (!dup_resolve)
198                 E_FATAL
199                     ("corpus_load_headid(%s) failed; duplicate ID: %s\n",
200                      file, id);
201             else {
202                 /* Invoke the application provided duplicate resolver function */
203                 if ((j = (*dup_resolve) (corp->str[m], line + k)) < 0)
204                     E_FATAL
205                         ("corpus_load_headid(%s) failed; duplicate ID: %s\n",
206                          file, id);
207                 ckd_free(id);
208                 if (j > 0) {
209                     /* Overwrite the original with the new entry */
210                     ckd_free(corp->str[m]);
211                     corp->str[m] = ckd_salloc(line + k);
212                 }
213                 else {
214                     /* Retain the original entry, discard the new one */
215                 }
216             }
217         }
218         else {
219             /* Fill in new entry */
220             corp->str[n] = ckd_salloc(line + k);
221             n++;
222         }
223     }
224     corp->n = n;
225 
226     fclose(fp);
227 
228     E_INFO("%s: %d entries\n", file, n);
229 
230     return corp;
231 }
232 
233 
234 static int32
sep_tailid(char * line,char * uttid)235 sep_tailid(char *line, char *uttid)
236 {
237     int32 i, k, l;
238 
239     l = strlen(line);
240     uttid[0] = '\0';
241 
242     /* Find last close-paren */
243     for (i = l - 1; (i >= 0) && ((line[i] == '\n') || (line[i] == ' ')
244                                  || (line[i] == '\t')); --i);
245     if ((i < 0) || (line[i] != ')'))    /* Missing uttid */
246         return -1;
247     k = i;
248 
249     /* Find closest open-paren; no spaces allowed in uttid */
250     for (--i; (i >= 0) && (line[i] != ' ') && (line[i] != '\t')
251          && (line[i] != '('); --i);
252     if ((i < 0) || (k - i < 2) || (line[i] != '('))     /* Empty or missing uttid */
253         return -1;
254 
255     /* Remove parentheses and copy uttid */
256     line[k] = '\0';
257     strcpy(uttid, line + i + 1);
258 
259     /* Strip uttid from line */
260     line[i] = '\0';
261 
262     return 0;
263 }
264 
265 
266 corpus_t *
corpus_load_tailid(const char * file,int32 (* validate)(char * str),int32 (* dup_resolve)(char * s1,char * s2))267 corpus_load_tailid(const char *file,
268                    int32(*validate) (char *str),
269                    int32(*dup_resolve) (char *s1, char *s2))
270 {
271     FILE *fp;
272     char line[16384], uttid[4096], *id;
273     int32 j, m, n;
274     corpus_t *corp;
275 
276     E_INFO("Loading corpus (%s)\n", file);
277 
278     if ((fp = fopen(file, "r")) == NULL)
279         E_FATAL_SYSTEM("fopen(%s,r) failed\n", file);
280 
281     corp = (corpus_t *) ckd_calloc(1, sizeof(corpus_t));
282 
283     n = 0;
284     while (fgets(line, sizeof(line), fp) != NULL) {
285         /* Skip empty lines */
286         if (sscanf(line, "%s", uttid) == 1)
287             n++;
288     }
289     rewind(fp);
290 
291     corp->ht = hash_table_new(n, 0 /* Not no-case */ );
292     corp->n = 0;
293     corp->str = (char **) ckd_calloc(n, sizeof(char *));
294 
295     n = 0;
296     while (fgets(line, sizeof(line), fp) != NULL) {
297         /* Skip blank lines */
298         if (sscanf(line, "%s", uttid) < 1)
299             continue;
300 
301         /* Look for a (uttid) at the end */
302         if (sep_tailid(line, uttid) < 0)
303             E_FATAL("corpus_load_tailid(%s) failed; bad line: %s\n", file,
304                     line);
305 
306         /* Validate if a validation function is given */
307         if (validate && (!(*validate) (line))) {
308             E_INFO("Corpus validation %s failed; skipping\n", uttid);
309             continue;
310         }
311 
312         id = ckd_salloc(uttid);
313         if ((m = (long) hash_table_enter(corp->ht, id, (void *)(long)n)) != n) {
314             /* Duplicate entry */
315             if (!dup_resolve)
316                 E_FATAL
317                     ("corpus_load_tailid(%s) failed; duplicate ID: %s\n",
318                      file, id);
319             else {
320                 /* Invoke the application provided duplicate resolver function */
321                 if ((j = (*dup_resolve) (corp->str[m], line)) < 0)
322                     E_FATAL
323                         ("corpus_load(tailid(%s) failed; duplicate ID: %s\n",
324                          file, id);
325                 ckd_free(id);
326                 if (j > 0) {
327                     /* Overwrite the original with the new entry */
328                     ckd_free(corp->str[m]);
329                     corp->str[m] = ckd_salloc(line);
330                 }
331                 else {
332                     /* Retain the original entry, discard the new one */
333                 }
334             }
335         }
336         else {
337             /* Fill in new entry */
338             corp->str[n] = ckd_salloc(line);
339             n++;
340         }
341     }
342     corp->n = n;
343 
344     fclose(fp);
345 
346     E_INFO("%s: %d entries\n", file, n);
347 
348     return corp;
349 }
350 
351 
352 char *
corpus_lookup(corpus_t * corp,const char * id)353 corpus_lookup(corpus_t * corp, const char *id)
354 {
355     void *val;
356     int32 n;
357 
358     if (hash_table_lookup(corp->ht, id, &val) < 0)
359         return NULL;
360     n = (int32)(long)val;
361 
362     assert((n >= 0) && (n < corp->n));
363     return (corp->str[n]);
364 }
365 
366 
367 #if _CORPUS_TEST_
main(int32 argc,char * argv[])368 main(int32 argc, char *argv[])
369 {
370     corpus_t *ch, *ct;
371     char id[4096], *str;
372 
373     if (argc != 3)
374         E_FATAL("Usage: %s headid-corpusfile tailid-corpusfile\n",
375                 argv[0]);
376 
377     ch = corpus_load_headid(argv[1], NULL, NULL);
378     ct = corpus_load_tailid(argv[2], NULL, NULL);
379     for (;;) {
380         printf("> ");
381         scanf("%s", id);
382 
383         str = corpus_lookup(ch, id);
384         if (str == NULL)
385             printf("%s Not found in 1\n");
386         else
387             printf("%s(1): %s\n", id, str);
388 
389         str = corpus_lookup(ct, id);
390         if (str == NULL)
391             printf("%s Not found in 2\n");
392         else
393             printf("%s(2): %s\n", id, str);
394     }
395 }
396 #endif
397 
398 
399 int32
ctl_read_entry(FILE * fp,char * uttfile,int32 * sf,int32 * ef,char * uttid)400 ctl_read_entry(FILE * fp, char *uttfile, int32 * sf, int32 * ef,
401                char *uttid)
402 {
403     char line[16384];
404     char base[16384];
405     int32 k;
406 
407     do {
408         if (fgets(line, sizeof(line), fp) == NULL)
409             return -1;
410         if (line[0] == '#')
411             k = 0;
412         else
413             k = sscanf(line, "%s %d %d %s", uttfile, sf, ef, uttid);
414     } while (k <= 0);
415 
416     if ((k == 2) || ((k >= 3) && ((*sf >= *ef) || (*sf < 0))))
417         E_FATAL("Error in ctlfile: %s\n", line);
418 
419     if (k < 4) {
420         /* Create utt-id from mfc-filename (and sf/ef if specified) */
421         path2basename(uttfile, base);
422         /* strip_fileext (base, uttid); */
423         strcpy(uttid, base);
424 
425         if (k == 3) {
426             k = strlen(uttid);
427             sprintf(uttid + k, "_%d_%d", *sf, *ef);
428         }
429         else {
430             *sf = 0;
431             *ef = -1;           /* Signifies "until EOF" */
432         }
433     }
434 
435     return 0;
436 }
437 
438 #if 0
439 ptmr_t
440 ctl_process(char *ctlfile, char *ctlmllrfile, int32 nskip, int32 count,
441             void (*func) (void *kb, char *uttfile, int32 sf, int32 ef,
442                           char *uttid), void *kb)
443 {
444     FILE *fp, *mllrfp;
445     char uttfile[16384], uttid[4096];
446     char regmatfile[4096], cb2mllrfile[4096];
447     int32 sf, ef;
448     ptmr_t tm;
449 
450     mllrfp = NULL;
451     E_INFO("Batch mode recognition without dynamic LM\n");
452 
453     if (ctlfile) {
454         if ((fp = fopen(ctlfile, "r")) == NULL)
455             E_FATAL_SYSTEM("fopen(%s,r) failed\n", ctlfile);
456     }
457     else
458         fp = stdin;
459 
460     if (ctlmllrfile) {
461         if ((mllrfp = fopen(ctlmllrfile, "r")) == NULL)
462             E_FATAL_SYSTEM("fopen(%s,r) failed\n", ctlmllrfile);
463     }
464 
465     ptmr_init(&tm);
466 
467     if (nskip > 0) {
468         E_INFO("Skipping %d entries at the beginning of %s\n", nskip,
469                ctlfile);
470 
471         for (; nskip > 0; --nskip) {
472             if (ctl_read_entry(fp, uttfile, &sf, &ef, uttid) < 0) {
473                 fclose(fp);
474                 return tm;
475             }
476         }
477 
478         if (ctlmllrfile) {
479             for (; nskip > 0; --nskip) {
480                 if (ctl_read_entry(fp, regmatfile, &sf, &ef, cb2mllrfile) <
481                     0) {
482                     E_ERROR
483                         ("MLLR cannot be read when skipping the %d-th sentence\n",
484                          nskip);
485                     fclose(fp);
486                     return tm;
487                 }
488             }
489         }
490     }
491 
492     for (; count > 0; --count) {
493         if (ctl_read_entry(fp, uttfile, &sf, &ef, uttid) < 0)
494             break;
495 
496         if (ctlmllrfile) {
497             int32 tmp1, tmp2;
498 
499             if (ctl_read_entry
500                 (mllrfp, regmatfile, &tmp1, &tmp2, cb2mllrfile) < 0) {
501                 E_ERROR
502                     ("MLLR cannot be read when counting the %d-th sentence\n",
503                      count);
504                 break;
505             }
506             if (tmp2 == -1)
507                 strcpy(cb2mllrfile, ".1cls.");
508         }
509 
510         /* Process this utterance */
511         ptmr_start(&tm);
512         if (func) {
513             if (ctlmllrfile)
514                 kb_setmllr(regmatfile, cb2mllrfile, kb);
515             (*func) (kb, uttfile, sf, ef, uttid);
516         }
517         ptmr_stop(&tm);
518 
519         E_INFO
520             ("%s: %6.1f sec CPU, %6.1f sec Clk;  TOT: %8.1f sec CPU, %8.1f sec Clk\n\n",
521              uttid, tm.t_cpu, tm.t_elapsed, tm.t_tot_cpu,
522              tm.t_tot_elapsed);
523 
524 
525         ptmr_reset(&tm);
526     }
527 
528     if (fp)
529         fclose(fp);
530 
531 
532     return tm;
533 }
534 #endif
535 
536 ptmr_t
ctl_process(const char * ctlfile,const char * ctllmfile,const char * ctlmllrfile,int32 nskip,int32 count,void (* func)(void * kb,utt_res_t * ur,int32 sf,int32 ef,char * uttid),void * kb)537 ctl_process(const char *ctlfile, const char *ctllmfile, const char *ctlmllrfile, int32 nskip,
538             int32 count, void (*func) (void *kb, utt_res_t * ur, int32 sf,
539                                        int32 ef, char *uttid), void *kb)
540 {
541     FILE *fp;
542     FILE *ctllmfp;
543     FILE *ctlmllrfp;
544     char uttfile[16384], uttid[4096];
545     char lmname[4096];
546     char regmatname[4096], cb2mllrname[4096];
547     char tmp[4096];
548     int32 sf, ef;
549     utt_res_t *ur;
550     ptmr_t tm;
551     kb_t *k;
552 
553     k = (kb_t *) kb;
554 
555     ctllmfp = NULL;
556     ctlmllrfp = NULL;
557     ur = new_utt_res();
558 
559     if (ctlfile) {
560         if ((fp = fopen(ctlfile, "r")) == NULL)
561             E_FATAL_SYSTEM("fopen(%s,r) failed\n", ctlfile);
562     }
563     else
564         fp = stdin;
565 
566     if (ctllmfile) {
567         E_INFO("LM is used in this session\n");
568         if ((ctllmfp = fopen(ctllmfile, "r")) == NULL)
569             E_FATAL_SYSTEM("fopen(%s,r) failed\n", ctllmfile);
570     }
571 
572     if (ctlmllrfile) {
573         E_INFO("MLLR is used in this session\n");
574         if ((ctlmllrfp = fopen(ctlmllrfile, "r")) == NULL)
575             E_FATAL_SYSTEM("fopen(%s,r) failed\n", ctlmllrfile);
576     }
577 
578     ptmr_init(&tm);
579 
580     if (nskip > 0) {
581         E_INFO("Skipping %d entries at the beginning of %s\n", nskip,
582                ctlfile);
583 
584         for (; nskip > 0; --nskip) {
585             if (ctl_read_entry(fp, uttfile, &sf, &ef, uttid) < 0) {
586                 fclose(fp);
587                 return tm;
588             }
589 
590             /*This checks the size of the control file of the lm in batch mode */
591             if (ctllmfile) {
592                 if (ctl_read_entry(ctllmfp, lmname, &sf, &ef, tmp) < 0) {
593                     fclose(ctllmfp);
594                     E_ERROR
595                         ("An LM control file is specified but LM cannot be read when skipping the %d-th sentence\n",
596                          nskip);
597                     return tm;
598                 }
599             }
600 
601             /*This checks the size of the control file of the mllr in batch mode */
602             if (ctlmllrfile) {
603                 if (ctl_read_entry(ctlmllrfp, regmatname, &sf, &ef, tmp) <
604                     0) {
605                     fclose(ctlmllrfp);
606                     E_ERROR
607                         ("A MLLR control file is specified but MLLR cannot be read when skipping the %d-th sentence\n",
608                          nskip);
609                     return tm;
610                 }
611             }
612 
613         }
614     }
615 
616     for (; count > 0; --count) {
617         int32 tmp1, tmp2;
618 
619 
620         if (ctl_read_entry(fp, uttfile, &sf, &ef, uttid) < 0)
621             break;
622 
623         /*This checks the size of the control file in batch mode */
624         if (ctllmfile) {
625             if (ctl_read_entry(ctllmfp, lmname, &tmp1, &tmp2, tmp) < 0) {
626                 fclose(ctllmfp);
627                 E_ERROR
628                     ("LM control file is specified but LM cannot be read when counting the %d-th sentence\n",
629                      count);
630                 break;
631             }
632         }
633 
634         if (ctlmllrfile) {
635             if (ctl_read_entry
636                 (ctlmllrfp, regmatname, &tmp1, &tmp2, cb2mllrname) < 0) {
637                 E_ERROR
638                     ("MLLR control file is specified but MLLR cannot be read when counting the %d-th sentence\n",
639                      count);
640                 break;
641             }
642             if (tmp2 == -1)
643                 strcpy(cb2mllrname, ".1cls.");
644         }
645 
646 
647         /* Process this utterance */
648         ptmr_start(&tm);
649         if (func) {
650             utt_res_set_uttfile(ur, uttfile);
651             if (ctllmfile)
652                 utt_res_set_lmname(ur, lmname);
653             if (ctlmllrfile) {
654                 utt_res_set_regmatname(ur, regmatname);
655                 utt_res_set_cb2mllrname(ur, cb2mllrname);
656             }
657             (*func) (kb, ur, sf, ef, uttid);
658         }
659         ptmr_stop(&tm);
660 
661         E_INFO
662             ("%s: %6.1f sec CPU, %6.1f sec Clk;  TOT: %8.1f sec CPU, %8.1f sec Clk\n\n",
663              uttid, tm.t_cpu, tm.t_elapsed, tm.t_tot_cpu,
664              tm.t_tot_elapsed);
665 
666 
667         ptmr_reset(&tm);
668     }
669 
670     if (fp)
671         fclose(fp);
672     if (ctllmfp)
673         fclose(ctllmfp);
674     if (ctlmllrfp)
675         fclose(ctlmllrfp);
676     if (ur)
677         ckd_free(ur);
678 
679     return tm;
680 }
681 
682 
683 
684 ptmr_t
ctl_process_utt(const char * uttfile,int32 count,void (* func)(void * kb,utt_res_t * ur,int32 sf,int32 ef,char * uttid),void * kb)685 ctl_process_utt(const char *uttfile, int32 count,
686                 void (*func) (void *kb, utt_res_t * ur, int32 sf, int32 ef,
687                               char *uttid), void *kb)
688 {
689     char uttid[4096];
690     char base[16384];
691     int32 i, c;
692     int32 ts, newts;
693     ptmr_t tm;
694     utt_res_t *ur;
695 
696 
697     ptmr_init(&tm);
698     ur = new_utt_res();
699     path2basename(uttfile, base);
700     /* strip_fileext() copies base to uttid. So, copying uttid to base
701      *  is redundant if strip_fileext() is not called.
702      */
703     /*
704        strip_fileext (base, uttid);
705        strcpy (base, uttid);
706      */
707 
708     ts = -1;
709     for (c = 0; c < count; c++) {
710         /* Wait for uttfile to change from previous iteration */
711         for (i = 0;; i++) {
712             newts = stat_mtime(uttfile);
713             if ((newts >= 0) && (newts != ts))
714                 break;
715 
716             if (i == 0)
717                 E_INFO("Waiting for %s, count %d, c %d\n", uttfile, count,
718                        c);
719             SLEEP_SEC(1);
720         }
721         ts = newts;
722 
723         /* Form uttid */
724         sprintf(uttid, "%s_%08d", base, c);
725 
726         /* Process this utterance */
727         ptmr_start(&tm);
728         if (func) {
729             utt_res_set_uttfile(ur, uttfile);
730 
731             (*func) (kb, ur, 0, -1, uttid);
732         }
733         ptmr_stop(&tm);
734 
735         E_INFO
736             ("%s: %6.1f sec CPU, %6.1f sec Clk;  TOT: %8.1f sec CPU, %8.1f sec Clk\n\n",
737              uttid, tm.t_cpu, tm.t_elapsed, tm.t_tot_cpu,
738              tm.t_tot_elapsed);
739 
740         ptmr_reset(&tm);
741     }
742 
743     if (ur)
744         free_utt_res(ur);
745     return tm;
746 }
747 
748 
749 void
ctl_infile(char * file,const char * dir,const char * ext,const char * utt)750 ctl_infile(char *file, const char *dir, const char *ext, const char *utt)
751 {
752     int32 l1, l2;
753 
754     assert(utt);
755 
756     if (ext && (ext[0] != '\0')) {
757         l1 = strlen(ext);
758         l2 = strlen(utt);
759         if ((l2 > l1) && (utt[l2 - l1 - 1] == '.')
760             && (strcmp(utt + (l2 - l1), ext) == 0))
761             ext = NULL;         /* utt already has the desired extension */
762     }
763 
764     if ((utt[0] != '/') && dir) {
765         /* Dir specified for relative uttfile pathname */
766         if (ext && (ext[0] != '\0'))
767             sprintf(file, "%s/%s.%s", dir, utt, ext);
768         else
769             sprintf(file, "%s/%s", dir, utt);
770     }
771     else {
772         if (ext && (ext[0] != '\0'))
773             sprintf(file, "%s.%s", utt, ext);
774         else
775             strcpy(file, utt);
776     }
777 }
778 
779 
780 void
ctl_outfile(char * file,const char * dir,const char * ext,const char * utt,const char * uttid)781 ctl_outfile(char *file, const char *dir, const char *ext, const char *utt, const char *uttid)
782 {
783     int32 k;
784 
785     k = strlen(dir);
786 
787     if ((k > 4) && (strcmp(dir + k - 4, ",CTL") == 0)) {        /* HACK!! Hardwired ,CTL */
788         if (utt[0] != '/') {
789             strcpy(file, dir);
790             file[k - 4] = '/';
791             strcpy(file + k - 3, utt);
792         }
793         else
794             strcpy(file, utt);
795     }
796     else {
797         strcpy(file, dir);
798         file[k] = '/';
799         strcpy(file + k + 1, uttid);
800     }
801 
802     if (ext && (ext[0] != '\0')) {
803         strcat(file, ".");
804         strcat(file, ext);
805     }
806 }
807