PocketSphinx 5prealpha
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
101static void
102ciphone_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
114static ph_lc_t *
115find_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
124static ph_rc_t *
125find_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
134static void
135triphone_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
175int
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
185const char *
187{
188 assert(m);
189 assert((id >= 0) && (id < m->n_ciphone));
190
191 return (m->ciphone[id].name);
192}
193
194
195int
196mdef_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
218int
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
250int
252{
253 assert(m);
254 assert((p >= 0) && (p < m->n_phone));
255
256 return ((p < m->n_ciphone) ? 1 : 0);
257}
258
259int
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 */
272static void
273parse_tmat_senmap(mdef_t * m, char *line, long off, int p)
274{
275 int32 wlen, n, s;
276 char *lp;
277 __BIGSTACKVARIABLE__ char word[1024];
278
279 lp = line + off;
280
281 /* Read transition matrix id */
282 if ((sscanf(lp, "%d%n", &n, &wlen) != 1) || (n < 0))
283 E_FATAL("Missing or bad transition matrix id: %s\n", line);
284 m->phone[p].tmat = n;
285 if (m->n_tmat <= n)
286 E_FATAL("tmat-id(%d) > #tmat in header(%d): %s\n", n, m->n_tmat,
287 line);
288 lp += wlen;
289
290 /* Read senone mappings for each emitting state */
291 for (n = 0; n < m->n_emit_state; n++) {
292 if ((sscanf(lp, "%d%n", &s, &wlen) != 1) || (s < 0))
293 E_FATAL("Missing or bad state[%d]->senone mapping: %s\n", n,
294 line);
295
296 if ((p < m->n_ciphone) && (m->n_ci_sen <= s))
297 E_FATAL("CI-senone-id(%d) > #CI-senones(%d): %s\n", s,
298 m->n_ci_sen, line);
299 if (m->n_sen <= s)
300 E_FATAL("Senone-id(%d) > #senones(%d): %s\n", s, m->n_sen,
301 line);
302
303 m->sseq[p][n] = s;
304 lp += wlen;
305 }
306
307 /* Check for the last non-emitting state N */
308 if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (strcmp(word, "N") != 0))
309 E_FATAL("Missing non-emitting state spec: %s\n", line);
310 lp += wlen;
311
312 /* Check for end of line */
313 if (sscanf(lp, "%s%n", word, &wlen) == 1)
314 E_FATAL("Non-empty beyond non-emitting final state: %s\n", line);
315}
316
317
318static void
319parse_base_line(mdef_t * m, char *line, int p)
320{
321 int32 wlen, n;
322 __BIGSTACKVARIABLE__ char word[1024], *lp;
323 int ci;
324
325 lp = line;
326
327 /* Read base phone name */
328 if (sscanf(lp, "%s%n", word, &wlen) != 1)
329 E_FATAL("Missing base phone name: %s\n", line);
330 lp += wlen;
331
332 /* Make sure it's not a duplicate */
333 ci = mdef_ciphone_id(m, word);
334 if (ci >= 0)
335 E_FATAL("Duplicate base phone: %s\n", line);
336
337 /* Add ciphone to ciphone table with id p */
338 ciphone_add(m, word, p);
339 ci = (int) p;
340
341 /* Read and skip "-" for lc, rc, wpos */
342 for (n = 0; n < 3; n++) {
343 if ((sscanf(lp, "%s%n", word, &wlen) != 1)
344 || (strcmp(word, "-") != 0))
345 E_FATAL("Bad context info for base phone: %s\n", line);
346 lp += wlen;
347 }
348
349 /* Read filler attribute, if present */
350 if (sscanf(lp, "%s%n", word, &wlen) != 1)
351 E_FATAL("Missing filler atribute field: %s\n", line);
352 lp += wlen;
353 if (strcmp(word, "filler") == 0)
354 m->ciphone[(int) ci].filler = 1;
355 else if (strcmp(word, "n/a") == 0)
356 m->ciphone[(int) ci].filler = 0;
357 else
358 E_FATAL("Bad filler attribute field: %s\n", line);
359
360 triphone_add(m, ci, -1, -1, WORD_POSN_UNDEFINED, p);
361
362 /* Parse remainder of line: transition matrix and state->senone mappings */
363 parse_tmat_senmap(m, line, lp - line, p);
364}
365
366
367static void
368parse_tri_line(mdef_t * m, char *line, int p)
369{
370 int32 wlen;
371 __BIGSTACKVARIABLE__ char word[1024], *lp;
372 int ci, lc, rc;
374
375 lp = line;
376
377 /* Read base phone name */
378 if (sscanf(lp, "%s%n", word, &wlen) != 1)
379 E_FATAL("Missing base phone name: %s\n", line);
380 lp += wlen;
381
382 ci = mdef_ciphone_id(m, word);
383 if (ci < 0)
384 E_FATAL("Unknown base phone: %s\n", line);
385
386 /* Read lc */
387 if (sscanf(lp, "%s%n", word, &wlen) != 1)
388 E_FATAL("Missing left context: %s\n", line);
389 lp += wlen;
390 lc = mdef_ciphone_id(m, word);
391 if (lc < 0)
392 E_FATAL("Unknown left context: %s\n", line);
393
394 /* Read rc */
395 if (sscanf(lp, "%s%n", word, &wlen) != 1)
396 E_FATAL("Missing right context: %s\n", line);
397 lp += wlen;
398 rc = mdef_ciphone_id(m, word);
399 if (rc < 0)
400 E_FATAL("Unknown right context: %s\n", line);
401
402 /* Read tripone word-position within word */
403 if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (word[1] != '\0'))
404 E_FATAL("Missing or bad word-position spec: %s\n", line);
405 lp += wlen;
406 switch (word[0]) {
407 case 'b':
408 wpos = WORD_POSN_BEGIN;
409 break;
410 case 'e':
411 wpos = WORD_POSN_END;
412 break;
413 case 's':
414 wpos = WORD_POSN_SINGLE;
415 break;
416 case 'i':
417 wpos = WORD_POSN_INTERNAL;
418 break;
419 default:
420 E_FATAL("Bad word-position spec: %s\n", line);
421 }
422
423 /* Read filler attribute, if present. Must match base phone attribute */
424 if (sscanf(lp, "%s%n", word, &wlen) != 1)
425 E_FATAL("Missing filler attribute field: %s\n", line);
426 lp += wlen;
427 if (((strcmp(word, "filler") == 0) && (m->ciphone[(int) ci].filler)) ||
428 ((strcmp(word, "n/a") == 0) && (!m->ciphone[(int) ci].filler))) {
429 /* Everything is fine */
430 }
431 else
432 E_FATAL("Bad filler attribute field: %s\n", line);
433
434 triphone_add(m, ci, lc, rc, wpos, p);
435
436 /* Parse remainder of line: transition matrix and state->senone mappings */
437 parse_tmat_senmap(m, line, lp - line, p);
438}
439
440
441static void
442sseq_compress(mdef_t * m)
443{
444 hash_table_t *h;
445 uint16 **sseq;
446 int32 n_sseq;
447 int32 p, j, k;
448 glist_t g;
449 gnode_t *gn;
450 hash_entry_t *he;
451
452 k = m->n_emit_state * sizeof(int16);
453
454 h = hash_table_new(m->n_phone, HASH_CASE_YES);
455 n_sseq = 0;
456
457 /* Identify unique senone-sequence IDs. BUG: tmat-id not being considered!! */
458 for (p = 0; p < m->n_phone; p++) {
459 /* Add senone sequence to hash table */
460 if (n_sseq
461 == (j = hash_table_enter_bkey_int32(h, (char *)m->sseq[p], k, n_sseq)))
462 n_sseq++;
463
464 m->phone[p].ssid = j;
465 }
466
467 /* Generate compacted sseq table */
468 sseq = ckd_calloc_2d(n_sseq, m->n_emit_state, sizeof(**sseq)); /* freed in mdef_free() */
469
470 g = hash_table_tolist(h, &j);
471 assert(j == n_sseq);
472
473 for (gn = g; gn; gn = gnode_next(gn)) {
474 he = (hash_entry_t *) gnode_ptr(gn);
475 j = (int32)(long)hash_entry_val(he);
476 memcpy(sseq[j], hash_entry_key(he), k);
477 }
478 glist_free(g);
479
480 /* Free the old, temporary senone sequence table, replace with compacted one */
481 ckd_free_2d(m->sseq);
482 m->sseq = sseq;
483 m->n_sseq = n_sseq;
484
485 hash_table_free(h);
486}
487
488
489static int32
490noncomment_line(char *line, int32 size, FILE * fp)
491{
492 while (fgets(line, size, fp) != NULL) {
493 if (line[0] != '#')
494 return 0;
495 }
496 return -1;
497}
498
499
500/*
501 * Initialize phones (ci and triphones) and state->senone mappings from .mdef file.
502 */
503mdef_t *
504mdef_init(char *mdeffile, int32 breport)
505{
506 FILE *fp;
507 int32 n_ci, n_tri, n_map, n;
508 __BIGSTACKVARIABLE__ char tag[1024], buf[1024];
509 uint16 **senmap;
510 int p;
511 int32 s, ci, cd;
512 mdef_t *m;
513
514 if (!mdeffile)
515 E_FATAL("No mdef-file\n");
516
517 if (breport)
518 E_INFO("Reading model definition: %s\n", mdeffile);
519
520 m = (mdef_t *) ckd_calloc(1, sizeof(mdef_t)); /* freed in mdef_free */
521
522 if ((fp = fopen(mdeffile, "r")) == NULL)
523 E_FATAL_SYSTEM("Failed to open mdef file '%s' for reading", mdeffile);
524
525 if (noncomment_line(buf, sizeof(buf), fp) < 0)
526 E_FATAL("Empty file: %s\n", mdeffile);
527
528 if (strncmp(buf, "BMDF", 4) == 0 || strncmp(buf, "FDMB", 4) == 0) {
529 E_INFO
530 ("Found byte-order mark %.4s, assuming this is a binary mdef file\n",
531 buf);
532 fclose(fp);
533 ckd_free(m);
534 return NULL;
535 }
536 if (strncmp(buf, MODEL_DEF_VERSION, strlen(MODEL_DEF_VERSION)) != 0)
537 E_FATAL("Version error: Expecing %s, but read %s\n",
538 MODEL_DEF_VERSION, buf);
539
540 /* Read #base phones, #triphones, #senone mappings defined in header */
541 n_ci = -1;
542 n_tri = -1;
543 n_map = -1;
544 m->n_ci_sen = -1;
545 m->n_sen = -1;
546 m->n_tmat = -1;
547 do {
548 if (noncomment_line(buf, sizeof(buf), fp) < 0)
549 E_FATAL("Incomplete header\n");
550
551 if ((sscanf(buf, "%d %s", &n, tag) != 2) || (n < 0))
552 E_FATAL("Error in header: %s\n", buf);
553
554 if (strcmp(tag, "n_base") == 0)
555 n_ci = n;
556 else if (strcmp(tag, "n_tri") == 0)
557 n_tri = n;
558 else if (strcmp(tag, "n_state_map") == 0)
559 n_map = n;
560 else if (strcmp(tag, "n_tied_ci_state") == 0)
561 m->n_ci_sen = n;
562 else if (strcmp(tag, "n_tied_state") == 0)
563 m->n_sen = n;
564 else if (strcmp(tag, "n_tied_tmat") == 0)
565 m->n_tmat = n;
566 else
567 E_FATAL("Unknown header line: %s\n", buf);
568 } while ((n_ci < 0) || (n_tri < 0) || (n_map < 0) ||
569 (m->n_ci_sen < 0) || (m->n_sen < 0) || (m->n_tmat < 0));
570
571 if ((n_ci == 0) || (m->n_ci_sen == 0) || (m->n_tmat == 0)
572 || (m->n_ci_sen > m->n_sen))
573 E_FATAL("%s: Error in header\n", mdeffile);
574
575 /* Check typesize limits */
576 if (n_ci >= MAX_INT16)
577 E_FATAL("%s: #CI phones (%d) exceeds limit (%d)\n", mdeffile, n_ci,
578 MAX_INT16);
579 if (n_ci + n_tri >= MAX_INT32) /* Comparison is always false... */
580 E_FATAL("%s: #Phones (%d) exceeds limit (%d)\n", mdeffile,
581 n_ci + n_tri, MAX_INT32);
582 if (m->n_sen >= MAX_INT16)
583 E_FATAL("%s: #senones (%d) exceeds limit (%d)\n", mdeffile,
584 m->n_sen, MAX_INT16);
585 if (m->n_tmat >= MAX_INT32) /* Comparison is always false... */
586 E_FATAL("%s: #tmats (%d) exceeds limit (%d)\n", mdeffile,
587 m->n_tmat, MAX_INT32);
588
589 m->n_emit_state = (n_map / (n_ci + n_tri)) - 1;
590 if ((m->n_emit_state + 1) * (n_ci + n_tri) != n_map)
591 E_FATAL
592 ("Header error: n_state_map not a multiple of n_ci*n_tri\n");
593
594 /* Initialize ciphone info */
595 m->n_ciphone = n_ci;
596 m->ciphone_ht = hash_table_new(n_ci, HASH_CASE_YES); /* With case-insensitive string names *//* freed in mdef_free */
597 m->ciphone = (ciphone_t *) ckd_calloc(n_ci, sizeof(ciphone_t)); /* freed in mdef_free */
598
599 /* Initialize phones info (ciphones + triphones) */
600 m->n_phone = n_ci + n_tri;
601 m->phone = (phone_t *) ckd_calloc(m->n_phone, sizeof(phone_t)); /* freed in mdef_free */
602
603 /* Allocate space for state->senone map for each phone */
604 senmap = ckd_calloc_2d(m->n_phone, m->n_emit_state, sizeof(**senmap)); /* freed in mdef_free */
605 m->sseq = senmap; /* TEMPORARY; until it is compressed into just the unique ones */
606
607 /* Allocate initial space for <ci,lc,rc,wpos> -> pid mapping */
608 m->wpos_ci_lclist = (ph_lc_t ***) ckd_calloc_2d(N_WORD_POSN, m->n_ciphone, sizeof(ph_lc_t *)); /* freed in mdef_free */
609
610 /*
611 * Read base phones and triphones. They'll simply be assigned a running sequence
612 * number as their "phone-id". If the phone-id < n_ci, it's a ciphone.
613 */
614
615 /* Read base phones */
616 for (p = 0; p < n_ci; p++) {
617 if (noncomment_line(buf, sizeof(buf), fp) < 0)
618 E_FATAL("Premature EOF reading CIphone %d\n", p);
619 parse_base_line(m, buf, p);
620 }
622
623 /* Read triphones, if any */
624 for (; p < m->n_phone; p++) {
625 if (noncomment_line(buf, sizeof(buf), fp) < 0)
626 E_FATAL("Premature EOF reading phone %d\n", p);
627 parse_tri_line(m, buf, p);
628 }
629
630 if (noncomment_line(buf, sizeof(buf), fp) >= 0)
631 E_ERROR("Non-empty file beyond expected #phones (%d)\n",
632 m->n_phone);
633
634 /* Build CD senones to CI senones map */
635 if (m->n_ciphone * m->n_emit_state != m->n_ci_sen)
636 E_FATAL
637 ("#CI-senones(%d) != #CI-phone(%d) x #emitting-states(%d)\n",
638 m->n_ci_sen, m->n_ciphone, m->n_emit_state);
639 m->cd2cisen = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->cd2cisen)); /* freed in mdef_free */
640
641 m->sen2cimap = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->sen2cimap)); /* freed in mdef_free */
642
643 for (s = 0; s < m->n_sen; s++)
644 m->sen2cimap[s] = -1;
645 for (s = 0; s < m->n_ci_sen; s++) { /* CI senones */
646 m->cd2cisen[s] = s;
647 m->sen2cimap[s] = s / m->n_emit_state;
648 }
649 for (p = n_ci; p < m->n_phone; p++) { /* CD senones */
650 for (s = 0; s < m->n_emit_state; s++) {
651 cd = m->sseq[p][s];
652 ci = m->sseq[m->phone[p].ci][s];
653 m->cd2cisen[cd] = ci;
654 m->sen2cimap[cd] = m->phone[p].ci;
655 }
656 }
657
658 sseq_compress(m);
659 fclose(fp);
660
661 return m;
662}
663
664void
666{
667 E_INFO_NOFN("Initialization of mdef_t, report:\n");
668 E_INFO_NOFN
669 ("%d CI-phone, %d CD-phone, %d emitstate/phone, %d CI-sen, %d Sen, %d Sen-Seq\n",
670 m->n_ciphone, m->n_phone - m->n_ciphone, m->n_emit_state,
671 m->n_ci_sen, m->n_sen, m->n_sseq);
672 E_INFO_NOFN("\n");
673
674}
675
676/* RAH 4.23.01, Need to step down the ->next list to see if there are
677 any more things to free
678 */
679
680
681
682/* RAH 4.19.01, Attempt to free memory that was allocated within this module
683 I have not verified that all the memory has been freed. I've taken only a
684 reasonable effort for now.
685 RAH 4.24.01 - verified that all memory is released.
686 */
687void
689{
690 if (lc == NULL)
691 return;
692
693 if (lc->rclist)
694 mdef_free_recursive_rc(lc->rclist);
695
696 if (lc->next)
697 mdef_free_recursive_lc(lc->next);
698
699 ckd_free((void *) lc);
700}
701
702void
704{
705 if (rc == NULL)
706 return;
707
708 if (rc->next)
709 mdef_free_recursive_rc(rc->next);
710
711 ckd_free((void *) rc);
712}
713
714
715/* RAH, Free memory that was allocated in mdef_init
716 Rational purify shows that no leaks exist
717 */
718
719void
721{
722 int i, j;
723
724 if (m) {
725 if (m->sen2cimap)
726 ckd_free((void *) m->sen2cimap);
727 if (m->cd2cisen)
728 ckd_free((void *) m->cd2cisen);
729
730 /* RAH, go down the ->next list and delete all the pieces */
731 for (i = 0; i < N_WORD_POSN; i++)
732 for (j = 0; j < m->n_ciphone; j++)
733 if (m->wpos_ci_lclist[i][j]) {
736 rclist);
737 }
738
739 for (i = 0; i < N_WORD_POSN; i++)
740 for (j = 0; j < m->n_ciphone; j++)
741 if (m->wpos_ci_lclist[i][j])
742 ckd_free((void *) m->wpos_ci_lclist[i][j]);
743
744
745 if (m->wpos_ci_lclist)
746 ckd_free_2d((void *) m->wpos_ci_lclist);
747 if (m->sseq)
748 ckd_free_2d((void *) m->sseq);
749 /* Free phone context */
750 if (m->phone)
751 ckd_free((void *) m->phone);
752 if (m->ciphone_ht)
753 hash_table_free(m->ciphone_ht);
754
755 for (i = 0; i < m->n_ciphone; i++) {
756 if (m->ciphone[i].name)
757 ckd_free((void *) m->ciphone[i].name);
758 }
759
760
761 if (m->ciphone)
762 ckd_free((void *) m->ciphone);
763
764 ckd_free((void *) m);
765 }
766}
Model definition.
void mdef_free_recursive_lc(ph_lc_t *lc)
RAH, For freeing memory.
Definition: mdef.c:688
const char * mdef_ciphone_str(mdef_t *m, int ci)
Get the phone string given the ci phone id.
Definition: mdef.c:186
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
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
void mdef_free(mdef_t *mdef)
Free an mdef_t.
Definition: mdef.c:720
word_posn_t
Union of different type of word position.
Definition: mdef.h:72
@ WORD_POSN_INTERNAL
Internal phone of word.
Definition: mdef.h:73
@ WORD_POSN_SINGLE
Single phone word (i.e.
Definition: mdef.h:76
@ WORD_POSN_UNDEFINED
Undefined value, used for initial conditions, etc.
Definition: mdef.h:77
@ WORD_POSN_END
Ending phone of word.
Definition: mdef.h:75
@ WORD_POSN_BEGIN
Beginning phone of word.
Definition: mdef.h:74
mdef_t * mdef_init(char *mdeffile, int breport)
Initialize the phone structure from the given model definition file.
#define S3_SILENCE_CIPHONE
Hard-coded silence CI phone name.
Definition: mdef.h:81
#define WPOS_NAME
Printable code for each word position above.
Definition: mdef.h:80
int mdef_is_ciphone(mdef_t *m, int p)
Decide whether the phone is ci phone.
Definition: mdef.c:251
int mdef_ciphone_id(mdef_t *m, char *ciphone)
Get the ciphone id given a string name.
Definition: mdef.c:176
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
void mdef_free_recursive_rc(ph_rc_t *rc)
Definition: mdef.c:703
#define N_WORD_POSN
total # of word positions (excluding undefined)
Definition: mdef.h:79
void mdef_report(mdef_t *m)
Report the model definition's parameters.
Definition: mdef.c:665
CI phone information.
Definition: mdef.h:87
char * name
The name of the CI phone.
Definition: mdef.h:88
int32 filler
Whether a filler phone; if so, can be substituted by silence phone in left or right context position.
Definition: mdef.h:89
The main model definition structure.
Definition: mdef.h:135
hash_table_t * ciphone_ht
Hash table for mapping ciphone strings to ids.
Definition: mdef.h:143
uint16 ** sseq
Unique state (or senone) sequences in this model, shared among all phones/triphones.
Definition: mdef.h:146
phone_t * phone
Information for all ciphones and triphones.
Definition: mdef.h:145
int32 n_tmat
number transition matrices
Definition: mdef.h:141
int32 n_emit_state
number emitting states per phone
Definition: mdef.h:138
int16 * sen2cimap
Parent CI-phone for each senone (CI or CD)
Definition: mdef.h:153
ph_lc_t *** wpos_ci_lclist
wpos_ci_lclist[wpos][ci] = list of lc for <wpos,ci>.
Definition: mdef.h:157
int32 n_ci_sen
number CI senones; these are the first
Definition: mdef.h:139
int32 n_sen
number senones (CI+CD)
Definition: mdef.h:140
int32 n_phone
number basephones + number triphones actually present
Definition: mdef.h:137
ciphone_t * ciphone
CI-phone information for all ciphones.
Definition: mdef.h:144
int16 sil
SILENCE_CIPHONE id.
Definition: mdef.h:155
int32 n_sseq
No.
Definition: mdef.h:148
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:150
int32 n_ciphone
number basephones actually present
Definition: mdef.h:136
Structures for storing the left context.
Structures needed for mapping <ci,lc,rc,wpos> into pid.
Triphone information, including base phones as a subset.
Definition: mdef.h:97
int16 rc
Base, left, right context ciphones.
Definition: mdef.h:102
word_posn_t wpos
Word position.
Definition: mdef.h:103
int32 tmat
Transition matrix id.
Definition: mdef.h:101
int32 ssid
State sequence (or senone sequence) ID, considering the n_emit_state senone-ids are a unit.
Definition: mdef.h:98