PocketSphinx  0.6
mdef.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 Carnegie Mellon University. All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * This work was supported in part by funding from the Defense Advanced
19  * Research Projects Agency and the National Science Foundation of the
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 
38 /*
39  * mdef.c -- HMM model definition: base (CI) phones and triphones
40  *
41  * **********************************************
42  * CMU ARPA Speech Project
43  *
44  * Copyright (c) 1999 Carnegie Mellon University.
45  * ALL RIGHTS RESERVED.
46  * **********************************************
47  *
48  * HISTORY
49  *
50  *
51  * 22-Nov-2004 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
52  * Imported from s3.2, for supporting s3 format continuous
53  * acoustic models.
54  *
55  * 14-Oct-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
56  * Added mdef_sseq2sen_active().
57  *
58  * 06-May-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
59  * In mdef_phone_id(), added backing off to silence phone context from filler
60  * context if original triphone not found.
61  *
62  * 30-Apr-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon
63  * Added senone-sequence id (ssid) to phone_t and appropriate functions to
64  * maintain it. Instead, moved state sequence info to mdef_t.
65  *
66  * 13-Jul-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University.
67  * Added mdef_phone_str().
68  *
69  * 01-Jan-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University.
70  * Allowed mdef_phone_id_nearest to return base phone id if either
71  * left or right context (or both) is undefined.
72  *
73  * 01-Jan-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University.
74  * Created.
75  */
76 
77 
78 /*
79  * Major assumptions:
80  * All phones have same #states, same topology.
81  * Every phone has exactly one non-emitting, final state--the last one.
82  * CI phones must appear first in model definition file.
83  */
84 
85 /* System headers. */
86 #include <stdio.h>
87 #include <string.h>
88 #include <stdlib.h>
89 #include <assert.h>
90 
91 /* SphinxBase headers. */
92 #include <sphinxbase/ckd_alloc.h>
93 #include <sphinxbase/err.h>
94 
95 /* Local headers. */
96 #include "mdef.h"
97 
98 
99 #define MODEL_DEF_VERSION "0.3"
100 
101 static void
102 ciphone_add(mdef_t * m, char *ci, int p)
103 {
104  assert(p < m->n_ciphone);
105 
106  m->ciphone[p].name = (char *) ckd_salloc(ci); /* freed in mdef_free */
107  if (hash_table_enter(m->ciphone_ht, m->ciphone[p].name,
108  (void *)(long)p) != (void *)(long)p)
109  E_FATAL("hash_table_enter(%s) failed; duplicate CIphone?\n",
110  m->ciphone[p].name);
111 }
112 
113 
114 static ph_lc_t *
115 find_ph_lc(ph_lc_t * lclist, int lc)
116 {
117  ph_lc_t *lcptr;
118 
119  for (lcptr = lclist; lcptr && (lcptr->lc != lc); lcptr = lcptr->next);
120  return lcptr;
121 }
122 
123 
124 static ph_rc_t *
125 find_ph_rc(ph_rc_t * rclist, int rc)
126 {
127  ph_rc_t *rcptr;
128 
129  for (rcptr = rclist; rcptr && (rcptr->rc != rc); rcptr = rcptr->next);
130  return rcptr;
131 }
132 
133 
134 static void
135 triphone_add(mdef_t * m,
136  int ci, int lc, int rc, word_posn_t wpos,
137  int p)
138 {
139  ph_lc_t *lcptr;
140  ph_rc_t *rcptr;
141 
142  assert(p < m->n_phone);
143 
144  /* Fill in phone[p] information (state and tmat mappings added later) */
145  m->phone[p].ci = ci;
146  m->phone[p].lc = lc;
147  m->phone[p].rc = rc;
148  m->phone[p].wpos = wpos;
149 
150  /* Create <ci,lc,rc,wpos> -> p mapping if not a CI phone */
151  if (p >= m->n_ciphone) {
152  if ((lcptr = find_ph_lc(m->wpos_ci_lclist[wpos][(int) ci], lc))
153  == NULL) {
154  lcptr = (ph_lc_t *) ckd_calloc(1, sizeof(ph_lc_t)); /* freed at mdef_free, I believe */
155  lcptr->lc = lc;
156  lcptr->next = m->wpos_ci_lclist[wpos][(int) ci];
157  m->wpos_ci_lclist[wpos][(int) ci] = lcptr; /* This is what needs to be freed */
158  }
159  if ((rcptr = find_ph_rc(lcptr->rclist, rc)) != NULL) {
160  __BIGSTACKVARIABLE__ char buf[4096];
161 
162  mdef_phone_str(m, rcptr->pid, buf);
163  E_FATAL("Duplicate triphone: %s\n", buf);
164  }
165 
166  rcptr = (ph_rc_t *) ckd_calloc(1, sizeof(ph_rc_t)); /* freed in mdef_free, I believe */
167  rcptr->rc = rc;
168  rcptr->pid = p;
169  rcptr->next = lcptr->rclist;
170  lcptr->rclist = rcptr;
171  }
172 }
173 
174 
175 int
176 mdef_ciphone_id(mdef_t * m, char *ci)
177 {
178  int32 id;
179  if (hash_table_lookup_int32(m->ciphone_ht, ci, &id) < 0)
180  return -1;
181  return id;
182 }
183 
184 
185 const char *
187 {
188  assert(m);
189  assert((id >= 0) && (id < m->n_ciphone));
190 
191  return (m->ciphone[id].name);
192 }
193 
194 
195 int
196 mdef_phone_str(mdef_t * m, int pid, char *buf)
197 {
198  char *wpos_name;
199 
200  assert(m);
201  assert((pid >= 0) && (pid < m->n_phone));
202  wpos_name = WPOS_NAME;
203 
204  buf[0] = '\0';
205  if (pid < m->n_ciphone)
206  sprintf(buf, "%s", mdef_ciphone_str(m, pid));
207  else {
208  sprintf(buf, "%s %s %s %c",
209  mdef_ciphone_str(m, m->phone[pid].ci),
210  mdef_ciphone_str(m, m->phone[pid].lc),
211  mdef_ciphone_str(m, m->phone[pid].rc),
212  wpos_name[m->phone[pid].wpos]);
213  }
214  return 0;
215 }
216 
217 
218 int
220  int ci, int lc, int rc, word_posn_t wpos)
221 {
222  ph_lc_t *lcptr;
223  ph_rc_t *rcptr;
224  int newl, newr;
225 
226  assert(m);
227  assert((ci >= 0) && (ci < m->n_ciphone));
228  assert((lc >= 0) && (lc < m->n_ciphone));
229  assert((rc >= 0) && (rc < m->n_ciphone));
230  assert((wpos >= 0) && (wpos < N_WORD_POSN));
231 
232  if (((lcptr =
233  find_ph_lc(m->wpos_ci_lclist[wpos][(int) ci], lc)) == NULL)
234  || ((rcptr = find_ph_rc(lcptr->rclist, rc)) == NULL)) {
235  /* Not found; backoff to silence context if non-silence filler context */
236  if (m->sil < 0)
237  return -1;
238 
239  newl = m->ciphone[(int) lc].filler ? m->sil : lc;
240  newr = m->ciphone[(int) rc].filler ? m->sil : rc;
241  if ((newl == lc) && (newr == rc))
242  return -1;
243 
244  return (mdef_phone_id(m, ci, newl, newr, wpos));
245  }
246 
247  return (rcptr->pid);
248 }
249 
250 int
252 {
253  assert(m);
254  assert((p >= 0) && (p < m->n_phone));
255 
256  return ((p < m->n_ciphone) ? 1 : 0);
257 }
258 
259 int
261 {
262  assert(m);
263  if (s >= m->n_sen) {
264  return 0;
265  }
266  assert(s >= 0);
267  return ((s == m->cd2cisen[s]) ? 1 : 0);
268 }
269 
270 
271 /* Parse tmat and state->senone mappings for phone p and fill in structure */
272 static void
273 parse_tmat_senmap(mdef_t * m, char *line, int32 off, int p)
274 {
275  int32 wlen, n, s;
276  __BIGSTACKVARIABLE__ char word[1024], *lp;
277 
278  lp = line + off;
279 
280  /* Read transition matrix id */
281  if ((sscanf(lp, "%d%n", &n, &wlen) != 1) || (n < 0))
282  E_FATAL("Missing or bad transition matrix id: %s\n", line);
283  m->phone[p].tmat = n;
284  if (m->n_tmat <= n)
285  E_FATAL("tmat-id(%d) > #tmat in header(%d): %s\n", n, m->n_tmat,
286  line);
287  lp += wlen;
288 
289  /* Read senone mappings for each emitting state */
290  for (n = 0; n < m->n_emit_state; n++) {
291  if ((sscanf(lp, "%d%n", &s, &wlen) != 1) || (s < 0))
292  E_FATAL("Missing or bad state[%d]->senone mapping: %s\n", n,
293  line);
294 
295  if ((p < m->n_ciphone) && (m->n_ci_sen <= s))
296  E_FATAL("CI-senone-id(%d) > #CI-senones(%d): %s\n", s,
297  m->n_ci_sen, line);
298  if (m->n_sen <= s)
299  E_FATAL("Senone-id(%d) > #senones(%d): %s\n", s, m->n_sen,
300  line);
301 
302  m->sseq[p][n] = s;
303  lp += wlen;
304  }
305 
306  /* Check for the last non-emitting state N */
307  if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (strcmp(word, "N") != 0))
308  E_FATAL("Missing non-emitting state spec: %s\n", line);
309  lp += wlen;
310 
311  /* Check for end of line */
312  if (sscanf(lp, "%s%n", word, &wlen) == 1)
313  E_FATAL("Non-empty beyond non-emitting final state: %s\n", line);
314 }
315 
316 
317 static void
318 parse_base_line(mdef_t * m, char *line, int p)
319 {
320  int32 wlen, n;
321  __BIGSTACKVARIABLE__ char word[1024], *lp;
322  int ci;
323 
324  lp = line;
325 
326  /* Read base phone name */
327  if (sscanf(lp, "%s%n", word, &wlen) != 1)
328  E_FATAL("Missing base phone name: %s\n", line);
329  lp += wlen;
330 
331  /* Make sure it's not a duplicate */
332  ci = mdef_ciphone_id(m, word);
333  if (ci >= 0)
334  E_FATAL("Duplicate base phone: %s\n", line);
335 
336  /* Add ciphone to ciphone table with id p */
337  ciphone_add(m, word, p);
338  ci = (int) p;
339 
340  /* Read and skip "-" for lc, rc, wpos */
341  for (n = 0; n < 3; n++) {
342  if ((sscanf(lp, "%s%n", word, &wlen) != 1)
343  || (strcmp(word, "-") != 0))
344  E_FATAL("Bad context info for base phone: %s\n", line);
345  lp += wlen;
346  }
347 
348  /* Read filler attribute, if present */
349  if (sscanf(lp, "%s%n", word, &wlen) != 1)
350  E_FATAL("Missing filler atribute field: %s\n", line);
351  lp += wlen;
352  if (strcmp(word, "filler") == 0)
353  m->ciphone[(int) ci].filler = 1;
354  else if (strcmp(word, "n/a") == 0)
355  m->ciphone[(int) ci].filler = 0;
356  else
357  E_FATAL("Bad filler attribute field: %s\n", line);
358 
359  triphone_add(m, ci, -1, -1, WORD_POSN_UNDEFINED, p);
360 
361  /* Parse remainder of line: transition matrix and state->senone mappings */
362  parse_tmat_senmap(m, line, lp - line, p);
363 }
364 
365 
366 static void
367 parse_tri_line(mdef_t * m, char *line, int p)
368 {
369  int32 wlen;
370  __BIGSTACKVARIABLE__ char word[1024], *lp;
371  int ci, lc, rc;
373 
374  lp = line;
375 
376  /* Read base phone name */
377  if (sscanf(lp, "%s%n", word, &wlen) != 1)
378  E_FATAL("Missing base phone name: %s\n", line);
379  lp += wlen;
380 
381  ci = mdef_ciphone_id(m, word);
382  if (ci < 0)
383  E_FATAL("Unknown base phone: %s\n", line);
384 
385  /* Read lc */
386  if (sscanf(lp, "%s%n", word, &wlen) != 1)
387  E_FATAL("Missing left context: %s\n", line);
388  lp += wlen;
389  lc = mdef_ciphone_id(m, word);
390  if (lc < 0)
391  E_FATAL("Unknown left context: %s\n", line);
392 
393  /* Read rc */
394  if (sscanf(lp, "%s%n", word, &wlen) != 1)
395  E_FATAL("Missing right context: %s\n", line);
396  lp += wlen;
397  rc = mdef_ciphone_id(m, word);
398  if (rc < 0)
399  E_FATAL("Unknown right context: %s\n", line);
400 
401  /* Read tripone word-position within word */
402  if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (word[1] != '\0'))
403  E_FATAL("Missing or bad word-position spec: %s\n", line);
404  lp += wlen;
405  switch (word[0]) {
406  case 'b':
407  wpos = WORD_POSN_BEGIN;
408  break;
409  case 'e':
410  wpos = WORD_POSN_END;
411  break;
412  case 's':
413  wpos = WORD_POSN_SINGLE;
414  break;
415  case 'i':
416  wpos = WORD_POSN_INTERNAL;
417  break;
418  default:
419  E_FATAL("Bad word-position spec: %s\n", line);
420  }
421 
422  /* Read filler attribute, if present. Must match base phone attribute */
423  if (sscanf(lp, "%s%n", word, &wlen) != 1)
424  E_FATAL("Missing filler attribute field: %s\n", line);
425  lp += wlen;
426  if (((strcmp(word, "filler") == 0) && (m->ciphone[(int) ci].filler)) ||
427  ((strcmp(word, "n/a") == 0) && (!m->ciphone[(int) ci].filler))) {
428  /* Everything is fine */
429  }
430  else
431  E_FATAL("Bad filler attribute field: %s\n", line);
432 
433  triphone_add(m, ci, lc, rc, wpos, p);
434 
435  /* Parse remainder of line: transition matrix and state->senone mappings */
436  parse_tmat_senmap(m, line, lp - line, p);
437 }
438 
439 
440 static void
441 sseq_compress(mdef_t * m)
442 {
443  hash_table_t *h;
444  uint16 **sseq;
445  int32 n_sseq;
446  int32 p, j, k;
447  glist_t g;
448  gnode_t *gn;
449  hash_entry_t *he;
450 
451  k = m->n_emit_state * sizeof(int16);
452 
453  h = hash_table_new(m->n_phone, HASH_CASE_YES);
454  n_sseq = 0;
455 
456  /* Identify unique senone-sequence IDs. BUG: tmat-id not being considered!! */
457  for (p = 0; p < m->n_phone; p++) {
458  /* Add senone sequence to hash table */
459  if (n_sseq
460  == (j = hash_table_enter_bkey_int32(h, (char *)m->sseq[p], k, n_sseq)))
461  n_sseq++;
462 
463  m->phone[p].ssid = j;
464  }
465 
466  /* Generate compacted sseq table */
467  sseq = ckd_calloc_2d(n_sseq, m->n_emit_state, sizeof(**sseq)); /* freed in mdef_free() */
468 
469  g = hash_table_tolist(h, &j);
470  assert(j == n_sseq);
471 
472  for (gn = g; gn; gn = gnode_next(gn)) {
473  he = (hash_entry_t *) gnode_ptr(gn);
474  j = (long)hash_entry_val(he);
475  memcpy(sseq[j], hash_entry_key(he), k);
476  }
477  glist_free(g);
478 
479  /* Free the old, temporary senone sequence table, replace with compacted one */
480  ckd_free_2d(m->sseq);
481  m->sseq = sseq;
482  m->n_sseq = n_sseq;
483 
484  hash_table_free(h);
485 }
486 
487 
488 static int32
489 noncomment_line(char *line, int32 size, FILE * fp)
490 {
491  while (fgets(line, size, fp) != NULL) {
492  if (line[0] != '#')
493  return 0;
494  }
495  return -1;
496 }
497 
498 
499 /*
500  * Initialize phones (ci and triphones) and state->senone mappings from .mdef file.
501  */
502 mdef_t *
503 mdef_init(char *mdeffile, int32 breport)
504 {
505  FILE *fp;
506  int32 n_ci, n_tri, n_map, n;
507  __BIGSTACKVARIABLE__ char tag[1024], buf[1024];
508  uint16 **senmap;
509  int p;
510  int32 s, ci, cd;
511  mdef_t *m;
512 
513  if (!mdeffile)
514  E_FATAL("No mdef-file\n");
515 
516  if (breport)
517  E_INFO("Reading model definition: %s\n", mdeffile);
518 
519  m = (mdef_t *) ckd_calloc(1, sizeof(mdef_t)); /* freed in mdef_free */
520 
521  if ((fp = fopen(mdeffile, "r")) == NULL)
522  E_FATAL_SYSTEM("Failed to open mdef file '%s' for reading", mdeffile);
523 
524  if (noncomment_line(buf, sizeof(buf), fp) < 0)
525  E_FATAL("Empty file: %s\n", mdeffile);
526 
527  if (strncmp(buf, "BMDF", 4) == 0 || strncmp(buf, "FDMB", 4) == 0) {
528  E_INFO
529  ("Found byte-order mark %.4s, assuming this is a binary mdef file\n",
530  buf);
531  fclose(fp);
532  ckd_free(m);
533  return NULL;
534  }
535  if (strncmp(buf, MODEL_DEF_VERSION, strlen(MODEL_DEF_VERSION)) != 0)
536  E_FATAL("Version error: Expecing %s, but read %s\n",
537  MODEL_DEF_VERSION, buf);
538 
539  /* Read #base phones, #triphones, #senone mappings defined in header */
540  n_ci = -1;
541  n_tri = -1;
542  n_map = -1;
543  m->n_ci_sen = -1;
544  m->n_sen = -1;
545  m->n_tmat = -1;
546  do {
547  if (noncomment_line(buf, sizeof(buf), fp) < 0)
548  E_FATAL("Incomplete header\n");
549 
550  if ((sscanf(buf, "%d %s", &n, tag) != 2) || (n < 0))
551  E_FATAL("Error in header: %s\n", buf);
552 
553  if (strcmp(tag, "n_base") == 0)
554  n_ci = n;
555  else if (strcmp(tag, "n_tri") == 0)
556  n_tri = n;
557  else if (strcmp(tag, "n_state_map") == 0)
558  n_map = n;
559  else if (strcmp(tag, "n_tied_ci_state") == 0)
560  m->n_ci_sen = n;
561  else if (strcmp(tag, "n_tied_state") == 0)
562  m->n_sen = n;
563  else if (strcmp(tag, "n_tied_tmat") == 0)
564  m->n_tmat = n;
565  else
566  E_FATAL("Unknown header line: %s\n", buf);
567  } while ((n_ci < 0) || (n_tri < 0) || (n_map < 0) ||
568  (m->n_ci_sen < 0) || (m->n_sen < 0) || (m->n_tmat < 0));
569 
570  if ((n_ci == 0) || (m->n_ci_sen == 0) || (m->n_tmat == 0)
571  || (m->n_ci_sen > m->n_sen))
572  E_FATAL("%s: Error in header\n", mdeffile);
573 
574  /* Check typesize limits */
575  if (n_ci >= MAX_INT16)
576  E_FATAL("%s: #CI phones (%d) exceeds limit (%d)\n", mdeffile, n_ci,
577  MAX_INT16);
578  if (n_ci + n_tri >= MAX_INT32) /* Comparison is always false... */
579  E_FATAL("%s: #Phones (%d) exceeds limit (%d)\n", mdeffile,
580  n_ci + n_tri, MAX_INT32);
581  if (m->n_sen >= MAX_INT16)
582  E_FATAL("%s: #senones (%d) exceeds limit (%d)\n", mdeffile,
583  m->n_sen, MAX_INT16);
584  if (m->n_tmat >= MAX_INT32) /* Comparison is always false... */
585  E_FATAL("%s: #tmats (%d) exceeds limit (%d)\n", mdeffile,
586  m->n_tmat, MAX_INT32);
587 
588  m->n_emit_state = (n_map / (n_ci + n_tri)) - 1;
589  if ((m->n_emit_state + 1) * (n_ci + n_tri) != n_map)
590  E_FATAL
591  ("Header error: n_state_map not a multiple of n_ci*n_tri\n");
592 
593  /* Initialize ciphone info */
594  m->n_ciphone = n_ci;
595  m->ciphone_ht = hash_table_new(n_ci, HASH_CASE_YES); /* With case-insensitive string names *//* freed in mdef_free */
596  m->ciphone = (ciphone_t *) ckd_calloc(n_ci, sizeof(ciphone_t)); /* freed in mdef_free */
597 
598  /* Initialize phones info (ciphones + triphones) */
599  m->n_phone = n_ci + n_tri;
600  m->phone = (phone_t *) ckd_calloc(m->n_phone, sizeof(phone_t)); /* freed in mdef_free */
601 
602  /* Allocate space for state->senone map for each phone */
603  senmap = ckd_calloc_2d(m->n_phone, m->n_emit_state, sizeof(**senmap)); /* freed in mdef_free */
604  m->sseq = senmap; /* TEMPORARY; until it is compressed into just the unique ones */
605 
606  /* Allocate initial space for <ci,lc,rc,wpos> -> pid mapping */
607  m->wpos_ci_lclist = (ph_lc_t ***) ckd_calloc_2d(N_WORD_POSN, m->n_ciphone, sizeof(ph_lc_t *)); /* freed in mdef_free */
608 
609  /*
610  * Read base phones and triphones. They'll simply be assigned a running sequence
611  * number as their "phone-id". If the phone-id < n_ci, it's a ciphone.
612  */
613 
614  /* Read base phones */
615  for (p = 0; p < n_ci; p++) {
616  if (noncomment_line(buf, sizeof(buf), fp) < 0)
617  E_FATAL("Premature EOF reading CIphone %d\n", p);
618  parse_base_line(m, buf, p);
619  }
621 
622  /* Read triphones, if any */
623  for (; p < m->n_phone; p++) {
624  if (noncomment_line(buf, sizeof(buf), fp) < 0)
625  E_FATAL("Premature EOF reading phone %d\n", p);
626  parse_tri_line(m, buf, p);
627  }
628 
629  if (noncomment_line(buf, sizeof(buf), fp) >= 0)
630  E_ERROR("Non-empty file beyond expected #phones (%d)\n",
631  m->n_phone);
632 
633  /* Build CD senones to CI senones map */
634  if (m->n_ciphone * m->n_emit_state != m->n_ci_sen)
635  E_FATAL
636  ("#CI-senones(%d) != #CI-phone(%d) x #emitting-states(%d)\n",
637  m->n_ci_sen, m->n_ciphone, m->n_emit_state);
638  m->cd2cisen = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->cd2cisen)); /* freed in mdef_free */
639 
640  m->sen2cimap = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->sen2cimap)); /* freed in mdef_free */
641 
642  for (s = 0; s < m->n_sen; s++)
643  m->sen2cimap[s] = -1;
644  for (s = 0; s < m->n_ci_sen; s++) { /* CI senones */
645  m->cd2cisen[s] = s;
646  m->sen2cimap[s] = s / m->n_emit_state;
647  }
648  for (p = n_ci; p < m->n_phone; p++) { /* CD senones */
649  for (s = 0; s < m->n_emit_state; s++) {
650  cd = m->sseq[p][s];
651  ci = m->sseq[m->phone[p].ci][s];
652  m->cd2cisen[cd] = ci;
653  m->sen2cimap[cd] = m->phone[p].ci;
654  }
655  }
656 
657  sseq_compress(m);
658  fclose(fp);
659 
660  return m;
661 }
662 
663 void
665 {
666  E_INFO_NOFN("Initialization of mdef_t, report:\n");
667  E_INFO_NOFN
668  ("%d CI-phone, %d CD-phone, %d emitstate/phone, %d CI-sen, %d Sen, %d Sen-Seq\n",
669  m->n_ciphone, m->n_phone - m->n_ciphone, m->n_emit_state,
670  m->n_ci_sen, m->n_sen, m->n_sseq);
671  E_INFO_NOFN("\n");
672 
673 }
674 
675 /* RAH 4.23.01, Need to step down the ->next list to see if there are
676  any more things to free
677  */
678 
679 
680 
681 /* RAH 4.19.01, Attempt to free memory that was allocated within this module
682  I have not verified that all the memory has been freed. I've taken only a
683  reasonable effort for now.
684  RAH 4.24.01 - verified that all memory is released.
685  */
686 void
688 {
689  if (lc == NULL)
690  return;
691 
692  if (lc->rclist)
693  mdef_free_recursive_rc(lc->rclist);
694 
695  if (lc->next)
696  mdef_free_recursive_lc(lc->next);
697 
698  ckd_free((void *) lc);
699 }
700 
701 void
703 {
704  if (rc == NULL)
705  return;
706 
707  if (rc->next)
708  mdef_free_recursive_rc(rc->next);
709 
710  ckd_free((void *) rc);
711 }
712 
713 
714 /* RAH, Free memory that was allocated in mdef_init
715  Rational purify shows that no leaks exist
716  */
717 
718 void
720 {
721  int i, j;
722 
723  if (m) {
724  if (m->sen2cimap)
725  ckd_free((void *) m->sen2cimap);
726  if (m->cd2cisen)
727  ckd_free((void *) m->cd2cisen);
728 
729  /* RAH, go down the ->next list and delete all the pieces */
730  for (i = 0; i < N_WORD_POSN; i++)
731  for (j = 0; j < m->n_ciphone; j++)
732  if (m->wpos_ci_lclist[i][j]) {
733  mdef_free_recursive_lc(m->wpos_ci_lclist[i][j]->next);
735  rclist);
736  }
737 
738  for (i = 0; i < N_WORD_POSN; i++)
739  for (j = 0; j < m->n_ciphone; j++)
740  if (m->wpos_ci_lclist[i][j])
741  ckd_free((void *) m->wpos_ci_lclist[i][j]);
742 
743 
744  if (m->wpos_ci_lclist)
745  ckd_free_2d((void *) m->wpos_ci_lclist);
746  if (m->sseq)
747  ckd_free_2d((void *) m->sseq);
748  /* Free phone context */
749  if (m->phone)
750  ckd_free((void *) m->phone);
751  if (m->ciphone_ht)
752  hash_table_free(m->ciphone_ht);
753 
754  for (i = 0; i < m->n_ciphone; i++) {
755  if (m->ciphone[i].name)
756  ckd_free((void *) m->ciphone[i].name);
757  }
758 
759 
760  if (m->ciphone)
761  ckd_free((void *) m->ciphone);
762 
763  ckd_free((void *) m);
764  }
765 }
int32 n_sseq
No.
Definition: mdef.h:151
The main model definition structure.
Definition: mdef.h:138
int32 n_ciphone
number basephones actually present
Definition: mdef.h:139
word_posn_t wpos
Word position.
Definition: mdef.h:106
Single phone word (i.e.
Definition: mdef.h:79
#define WPOS_NAME
Printable code for each word position above.
Definition: mdef.h:83
int32 filler
Whether a filler phone; if so, can be substituted by silence phone in left or right context position...
Definition: mdef.h:92
Ending phone of word.
Definition: mdef.h:78
int32 n_phone
number basephones + number triphones actually present
Definition: mdef.h:140
int16 rc
Base, left, right context ciphones.
Definition: mdef.h:105
int mdef_is_ciphone(mdef_t *m, int p)
Decide whether the phone is ci phone.
Definition: mdef.c:251
char * name
The name of the CI phone.
Definition: mdef.h:91
int16 * cd2cisen
Parent CI-senone id for each senone; the first n_ci_sen are identity mappings; the CD-senones are con...
Definition: mdef.h:153
void mdef_free(mdef_t *mdef)
Free an mdef_t.
Definition: mdef.c:719
#define N_WORD_POSN
total # of word positions (excluding undefined)
Definition: mdef.h:82
int32 n_ci_sen
number CI senones; these are the first
Definition: mdef.h:142
int32 ssid
State sequence (or senone sequence) ID, considering the n_emit_state senone-ids are a unit...
Definition: mdef.h:101
void mdef_report(mdef_t *m)
Report the model definition&#39;s parameters.
Definition: mdef.c:664
#define S3_SILENCE_CIPHONE
Hard-coded silence CI phone name.
Definition: mdef.h:84
Structures for storing the left context.
int mdef_phone_str(mdef_t *m, int pid, char *buf)
Create a phone string for the given phone (base or triphone) id in the given buf. ...
Definition: mdef.c:196
uint16 ** sseq
Unique state (or senone) sequences in this model, shared among all phones/triphones.
Definition: mdef.h:149
Undefined value, used for initial conditions, etc.
Definition: mdef.h:80
mdef_t * mdef_init(char *mdeffile, int breport)
Initialize the phone structure from the given model definition file.
Triphone information, including base phones as a subset.
Definition: mdef.h:100
const char * mdef_ciphone_str(mdef_t *m, int ci)
Get the phone string given the ci phone id.
Definition: mdef.c:186
Model definition.
int mdef_phone_id(mdef_t *m, int b, int l, int r, word_posn_t pos)
Decide the phone id given the left, right and base phones.
Definition: mdef.c:219
ciphone_t * ciphone
CI-phone information for all ciphones.
Definition: mdef.h:147
hash_table_t * ciphone_ht
Hash table for mapping ciphone strings to ids.
Definition: mdef.h:146
CI phone information.
Definition: mdef.h:90
void mdef_free_recursive_lc(ph_lc_t *lc)
RAH, For freeing memory.
Definition: mdef.c:687
int32 n_sen
number senones (CI+CD)
Definition: mdef.h:143
Beginning phone of word.
Definition: mdef.h:77
int32 tmat
Transition matrix id.
Definition: mdef.h:104
int mdef_ciphone_id(mdef_t *m, char *ciphone)
Get the ciphone id given a string name.
Definition: mdef.c:176
int16 * sen2cimap
Parent CI-phone for each senone (CI or CD)
Definition: mdef.h:156
Internal phone of word.
Definition: mdef.h:76
int32 n_tmat
number transition matrices
Definition: mdef.h:144
int mdef_is_cisenone(mdef_t *m, int s)
Decide whether the senone is a senone for a ci phone, or a ci senone.
Definition: mdef.c:260
word_posn_t
Union of different type of word position.
Definition: mdef.h:75
int32 n_emit_state
number emitting states per phone
Definition: mdef.h:141
int16 sil
SILENCE_CIPHONE id.
Definition: mdef.h:158
ph_lc_t *** wpos_ci_lclist
wpos_ci_lclist[wpos][ci] = list of lc for <wpos,ci>.
Definition: mdef.h:160
Structures needed for mapping <ci,lc,rc,wpos> into pid.
void mdef_free_recursive_rc(ph_rc_t *rc)
Definition: mdef.c:702
phone_t * phone
Information for all ciphones and triphones.
Definition: mdef.h:148