92 #include <sphinxbase/ckd_alloc.h>
93 #include <sphinxbase/err.h>
99 #define MODEL_DEF_VERSION "0.3"
102 ciphone_add(
mdef_t * m,
char *ci,
int p)
104 assert(p < m->n_ciphone);
108 (
void *)(
long)p) != (
void *)(
long)p)
109 E_FATAL(
"hash_table_enter(%s) failed; duplicate CIphone?\n",
115 find_ph_lc(
ph_lc_t * lclist,
int lc)
119 for (lcptr = lclist; lcptr && (lcptr->lc != lc); lcptr = lcptr->next);
125 find_ph_rc(
ph_rc_t * rclist,
int rc)
129 for (rcptr = rclist; rcptr && (rcptr->rc != rc); rcptr = rcptr->next);
142 assert(p < m->n_phone);
159 if ((rcptr = find_ph_rc(lcptr->rclist, rc)) != NULL) {
160 __BIGSTACKVARIABLE__
char buf[4096];
163 E_FATAL(
"Duplicate triphone: %s\n", buf);
169 rcptr->next = lcptr->rclist;
170 lcptr->rclist = rcptr;
179 if (hash_table_lookup_int32(m->
ciphone_ht, ci, &
id) < 0)
189 assert((
id >= 0) && (id < m->n_ciphone));
201 assert((pid >= 0) && (pid < m->n_phone));
205 if (pid < m->n_ciphone)
208 sprintf(buf,
"%s %s %s %c",
227 assert((ci >= 0) && (ci < m->n_ciphone));
228 assert((lc >= 0) && (lc < m->n_ciphone));
229 assert((rc >= 0) && (rc < m->n_ciphone));
234 || ((rcptr = find_ph_rc(lcptr->rclist, rc)) == NULL)) {
239 newl = m->
ciphone[(int) lc].filler ? m->
sil : lc;
241 if ((newl == lc) && (newr == rc))
254 assert((p >= 0) && (p < m->n_phone));
256 return ((p < m->n_ciphone) ? 1 : 0);
267 return ((s == m->
cd2cisen[s]) ? 1 : 0);
273 parse_tmat_senmap(
mdef_t * m,
char *line,
long off,
int p)
277 __BIGSTACKVARIABLE__
char word[1024];
282 if ((sscanf(lp,
"%d%n", &n, &wlen) != 1) || (n < 0))
283 E_FATAL(
"Missing or bad transition matrix id: %s\n", line);
286 E_FATAL(
"tmat-id(%d) > #tmat in header(%d): %s\n", n, m->
n_tmat,
292 if ((sscanf(lp,
"%d%n", &s, &wlen) != 1) || (s < 0))
293 E_FATAL(
"Missing or bad state[%d]->senone mapping: %s\n", n,
296 if ((p < m->n_ciphone) && (m->
n_ci_sen <= s))
297 E_FATAL(
"CI-senone-id(%d) > #CI-senones(%d): %s\n", s,
300 E_FATAL(
"Senone-id(%d) > #senones(%d): %s\n", s, m->
n_sen,
308 if ((sscanf(lp,
"%s%n", word, &wlen) != 1) || (strcmp(word,
"N") != 0))
309 E_FATAL(
"Missing non-emitting state spec: %s\n", line);
313 if (sscanf(lp,
"%s%n", word, &wlen) == 1)
314 E_FATAL(
"Non-empty beyond non-emitting final state: %s\n", line);
319 parse_base_line(
mdef_t * m,
char *line,
int p)
322 __BIGSTACKVARIABLE__
char word[1024], *lp;
328 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
329 E_FATAL(
"Missing base phone name: %s\n", line);
335 E_FATAL(
"Duplicate base phone: %s\n", line);
338 ciphone_add(m, word, p);
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);
350 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
351 E_FATAL(
"Missing filler atribute field: %s\n", line);
353 if (strcmp(word,
"filler") == 0)
354 m->
ciphone[(int) ci].filler = 1;
355 else if (strcmp(word,
"n/a") == 0)
358 E_FATAL(
"Bad filler attribute field: %s\n", line);
363 parse_tmat_senmap(m, line, lp - line, p);
368 parse_tri_line(
mdef_t * m,
char *line,
int p)
371 __BIGSTACKVARIABLE__
char word[1024], *lp;
378 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
379 E_FATAL(
"Missing base phone name: %s\n", line);
384 E_FATAL(
"Unknown base phone: %s\n", line);
387 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
388 E_FATAL(
"Missing left context: %s\n", line);
392 E_FATAL(
"Unknown left context: %s\n", line);
395 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
396 E_FATAL(
"Missing right context: %s\n", line);
400 E_FATAL(
"Unknown right context: %s\n", line);
403 if ((sscanf(lp,
"%s%n", word, &wlen) != 1) || (word[1] !=
'\0'))
404 E_FATAL(
"Missing or bad word-position spec: %s\n", line);
420 E_FATAL(
"Bad word-position spec: %s\n", line);
424 if (sscanf(lp,
"%s%n", word, &wlen) != 1)
425 E_FATAL(
"Missing filler attribute field: %s\n", line);
427 if (((strcmp(word,
"filler") == 0) && (m->
ciphone[(
int) ci].
filler)) ||
428 ((strcmp(word,
"n/a") == 0) && (!m->
ciphone[(
int) ci].
filler))) {
432 E_FATAL(
"Bad filler attribute field: %s\n", line);
434 triphone_add(m, ci, lc, rc, wpos, p);
437 parse_tmat_senmap(m, line, lp - line, p);
454 h = hash_table_new(m->
n_phone, HASH_CASE_YES);
458 for (p = 0; p < m->
n_phone; p++) {
461 == (j = hash_table_enter_bkey_int32(h, (
char *)m->
sseq[p], k, n_sseq)))
468 sseq = ckd_calloc_2d(n_sseq, m->
n_emit_state,
sizeof(**sseq));
470 g = hash_table_tolist(h, &j);
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);
481 ckd_free_2d(m->
sseq);
490 noncomment_line(
char *line, int32 size, FILE * fp)
492 while (fgets(line, size, fp) != NULL) {
507 int32 n_ci, n_tri, n_map, n;
508 __BIGSTACKVARIABLE__
char tag[1024], buf[1024];
515 E_FATAL(
"No mdef-file\n");
518 E_INFO(
"Reading model definition: %s\n", mdeffile);
522 if ((fp = fopen(mdeffile,
"r")) == NULL)
523 E_FATAL_SYSTEM(
"Failed to open mdef file '%s' for reading", mdeffile);
525 if (noncomment_line(buf,
sizeof(buf), fp) < 0)
526 E_FATAL(
"Empty file: %s\n", mdeffile);
528 if (strncmp(buf,
"BMDF", 4) == 0 || strncmp(buf,
"FDMB", 4) == 0) {
530 (
"Found byte-order mark %.4s, assuming this is a binary mdef file\n",
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);
548 if (noncomment_line(buf,
sizeof(buf), fp) < 0)
549 E_FATAL(
"Incomplete header\n");
551 if ((sscanf(buf,
"%d %s", &n, tag) != 2) || (n < 0))
552 E_FATAL(
"Error in header: %s\n", buf);
554 if (strcmp(tag,
"n_base") == 0)
556 else if (strcmp(tag,
"n_tri") == 0)
558 else if (strcmp(tag,
"n_state_map") == 0)
560 else if (strcmp(tag,
"n_tied_ci_state") == 0)
562 else if (strcmp(tag,
"n_tied_state") == 0)
564 else if (strcmp(tag,
"n_tied_tmat") == 0)
567 E_FATAL(
"Unknown header line: %s\n", buf);
568 }
while ((n_ci < 0) || (n_tri < 0) || (n_map < 0) ||
573 E_FATAL(
"%s: Error in header\n", mdeffile);
576 if (n_ci >= MAX_INT16)
577 E_FATAL(
"%s: #CI phones (%d) exceeds limit (%d)\n", mdeffile, n_ci,
579 if (n_ci + n_tri >= MAX_INT32)
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)
586 E_FATAL(
"%s: #tmats (%d) exceeds limit (%d)\n", mdeffile,
592 (
"Header error: n_state_map not a multiple of n_ci*n_tri\n");
596 m->
ciphone_ht = hash_table_new(n_ci, HASH_CASE_YES);
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);
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);
630 if (noncomment_line(buf,
sizeof(buf), fp) >= 0)
631 E_ERROR(
"Non-empty file beyond expected #phones (%d)\n",
637 (
"#CI-senones(%d) != #CI-phone(%d) x #emitting-states(%d)\n",
643 for (s = 0; s < m->
n_sen; s++)
649 for (p = n_ci; p < m->
n_phone; p++) {
667 E_INFO_NOFN(
"Initialization of mdef_t, report:\n");
669 (
"%d CI-phone, %d CD-phone, %d emitstate/phone, %d CI-sen, %d Sen, %d Sen-Seq\n",
699 ckd_free((
void *) lc);
711 ckd_free((
void *) rc);
748 ckd_free_2d((
void *) m->
sseq);
751 ckd_free((
void *) m->
phone);
764 ckd_free((
void *) m);
The main model definition structure.
int32 n_ciphone
number basephones actually present
word_posn_t wpos
Word position.
#define WPOS_NAME
Printable code for each word position above.
int32 filler
Whether a filler phone; if so, can be substituted by silence phone in left or right context position...
int32 n_phone
number basephones + number triphones actually present
int16 rc
Base, left, right context ciphones.
int mdef_is_ciphone(mdef_t *m, int p)
Decide whether the phone is ci phone.
char * name
The name of the CI phone.
int16 * cd2cisen
Parent CI-senone id for each senone; the first n_ci_sen are identity mappings; the CD-senones are con...
void mdef_free(mdef_t *mdef)
Free an mdef_t.
#define N_WORD_POSN
total # of word positions (excluding undefined)
int32 n_ci_sen
number CI senones; these are the first
int32 ssid
State sequence (or senone sequence) ID, considering the n_emit_state senone-ids are a unit...
void mdef_report(mdef_t *m)
Report the model definition's parameters.
#define S3_SILENCE_CIPHONE
Hard-coded silence CI phone name.
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. ...
uint16 ** sseq
Unique state (or senone) sequences in this model, shared among all phones/triphones.
Undefined value, used for initial conditions, etc.
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.
const char * mdef_ciphone_str(mdef_t *m, int ci)
Get the phone string given the ci phone id.
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.
ciphone_t * ciphone
CI-phone information for all ciphones.
hash_table_t * ciphone_ht
Hash table for mapping ciphone strings to ids.
void mdef_free_recursive_lc(ph_lc_t *lc)
RAH, For freeing memory.
int32 n_sen
number senones (CI+CD)
int32 tmat
Transition matrix id.
int mdef_ciphone_id(mdef_t *m, char *ciphone)
Get the ciphone id given a string name.
int16 * sen2cimap
Parent CI-phone for each senone (CI or CD)
int32 n_tmat
number transition matrices
int mdef_is_cisenone(mdef_t *m, int s)
Decide whether the senone is a senone for a ci phone, or a ci senone.
word_posn_t
Union of different type of word position.
int32 n_emit_state
number emitting states per phone
int16 sil
SILENCE_CIPHONE id.
ph_lc_t *** wpos_ci_lclist
wpos_ci_lclist[wpos][ci] = list of lc for .
Structures needed for mapping into pid.
void mdef_free_recursive_rc(ph_rc_t *rc)
phone_t * phone
Information for all ciphones and triphones.