s3pid_t mdef_phone_id_nearest(mdef_t * m, s3cipid_t b, s3cipid_t l, s3cipid_t r, word_posn_t pos) { word_posn_t tmppos; s3pid_t p; s3cipid_t newl, newr; assert(m); assert((b >= 0) && (b < m->n_ciphone)); assert((pos >= 0) && (pos < N_WORD_POSN)); if ((NOT_CIPID(l)) || (NOT_CIPID(r))) return ((s3pid_t) b); assert((l >= 0) && (l < m->n_ciphone)); assert((r >= 0) && (r < m->n_ciphone)); p = mdef_phone_id(m, b, l, r, pos); if (IS_PID(p)) return p; /* Exact triphone not found; backoff to other word positions */ for (tmppos = 0; tmppos < N_WORD_POSN; tmppos++) { if (tmppos != pos) { p = mdef_phone_id(m, b, l, r, tmppos); if (IS_PID(p)) return p; } } /* Nothing yet; backoff to silence phone if non-silence filler context */ if (IS_CIPID(m->sil)) { newl = m->ciphone[l].filler ? m->sil : l; newr = m->ciphone[r].filler ? m->sil : r; if ((newl != l) || (newr != r)) { p = mdef_phone_id(m, b, newl, newr, pos); if (IS_PID(p)) return p; for (tmppos = 0; tmppos < N_WORD_POSN; tmppos++) { if (tmppos != pos) { p = mdef_phone_id(m, b, newl, newr, tmppos); if (IS_PID(p)) return p; } } } } /* Nothing yet; backoff to base phone */ return ((s3pid_t) b); }
static int32 dict_read (FILE *fp, dict_t *d) { char line[16384], **wptr; s3cipid_t p[4096]; int32 lineno, nwd; s3wid_t w; int32 i, maxwd; maxwd = 4092; wptr = (char **) ckd_calloc (maxwd, sizeof(char *)); lineno = 0; while (fgets (line, sizeof(line), fp) != NULL) { lineno++; if (line[0] == '#') /* Comment line */ continue; if ((nwd = str2words (line, wptr, maxwd)) < 0) E_FATAL("str2words(%s) failed; Increase maxwd from %d\n", line, maxwd); if (nwd == 0) /* Empty line */ continue; /* wptr[0] is the word-string and wptr[1..nwd-1] the pronunciation sequence */ if (nwd == 1) { E_ERROR("Line %d: No pronunciation for word %s; ignored\n", lineno, wptr[0]); continue; } /* Convert pronunciation string to CI-phone-ids */ for (i = 1; i < nwd; i++) { p[i-1] = dict_ciphone_id (d, wptr[i]); if (NOT_CIPID(p[i-1])) { E_ERROR("Line %d: Bad ciphone: %s; word %s ignored\n", lineno, wptr[i], wptr[0]); break; } } if (i == nwd) { /* All CI-phones successfully converted to IDs */ w = dict_add_word (d, wptr[0], p, nwd-1); if (NOT_WID(w)) E_ERROR("Line %d: dict_add_word (%s) failed (duplicate?); ignored\n", lineno, wptr[0]); } } ckd_free (wptr); return 0; }
static int32 parse_tri_line (mdef_t *m, char *line, int32 lineno, s3pid_t p) { int32 wlen; char *word; s3cipid_t ci, lc, rc; word_posn_t wpos; char tmp; /* Read base phone name */ if ((wlen = nextword (line, delim, &word, &tmp)) < 0) /* Empty line */ E_FATAL("Line %d: Incomplete triphone line\n", lineno); ci = mdef_ciphone_id (m, word); if (NOT_CIPID(ci)) E_FATAL("Line %d: Unknown base phone in triphone: %s\n", lineno, word); line = word+wlen; word[wlen] = tmp; /* Read lc */ if ((wlen = nextword (line, delim, &word, &tmp)) < 0) E_FATAL("Line %d: Incomplete triphone line\n", lineno); lc = mdef_ciphone_id (m, word); if (NOT_CIPID(lc)) E_FATAL("Line %d: Unknown left context in triphone: %s\n", lineno, word); line = word+wlen; word[wlen] = tmp; /* Read rc */ if ((wlen = nextword (line, delim, &word, &tmp)) < 0) E_FATAL("Line %d: Incomplete triphone line\n", lineno); rc = mdef_ciphone_id (m, word); if (NOT_CIPID(rc)) E_FATAL("Line %d: Unknown left context in triphone: %s\n", lineno, word); line = word+wlen; word[wlen] = tmp; /* Read tripone word-position within word */ if (((wlen = nextword (line, delim, &word, &tmp)) < 0) || (word[1] != '\0')) E_FATAL("Line %d: Missing or bad triphone word-position spec\n", lineno); switch (word[0]) { case 'b': wpos = WORD_POSN_BEGIN; break; case 'e': wpos = WORD_POSN_END; break; case 's': wpos = WORD_POSN_SINGLE; break; case 'i': wpos = WORD_POSN_INTERNAL; break; default: E_FATAL("Line %d: Bad word-position spec: %s\n", lineno, word); } line = word+wlen; word[wlen] = tmp; /* Read filler attribute, if present. Must match base phone attribute */ if ((wlen = nextword (line, delim, &word, &tmp)) < 0) E_FATAL("Line %d: Incomplete base phone line\n", lineno); if (((strcmp (word, "filler") == 0) && (m->ciphone[ci].filler)) || ((strcmp (word, "n/a") == 0) && (! m->ciphone[ci].filler))) { } else E_FATAL("Line %d: Bad attribute string: %s\n", lineno, word); line = word+wlen; word[wlen] = tmp; if (triphone_add (m, ci, lc, rc, wpos, p) < 0) E_FATAL("Line %d: Duplicate/Bad triphone\n", lineno); /* Parse remainder of line: transition matrix and state->senone mappings */ parse_tmat_senmap (m, line, lineno, p); return 0; }
static wseg_t *line2wseg (char *line, s3wid_t *ref, s3cipid_t *ap, int8 *ap_err, int32 aplen, char *id) { char word[1024], uttid[1024], *lp; int32 i, k, n_hypci, n_refwd, n_refci, pronlen; s3cipid_t ci; typedef enum {CORR=0, REFERR=1, HYPERR=2} state_t; state_t state; static wseg_t *wseg = NULL; if (! wseg) wseg = (wseg_t *) ckd_calloc (MAX_UTT_LEN, sizeof(wseg_t)); lp = line; n_hypci = n_refci = pronlen = 0; n_refwd = -1; uttid[0] = '\0'; state = CORR; while (sscanf (lp, "%s%n", word, &k) == 1) { lp += k; if (is_uttid (word, uttid)) break; if (strcmp (word, "[[") == 0) { if (state != CORR) E_FATAL("%s: Illegal [[\n", id); state = REFERR; if (n_refci < pronlen) wseg[n_refwd].err = 1; } else if (strcmp (word, "]]") == 0) { if (state != HYPERR) E_FATAL("%s: Illegal ]]\n", id); state = CORR; } else if (strcmp (word, "=>") == 0) { if (state != REFERR) E_FATAL("%s: Illegal =>\n", id); state = HYPERR; } else { ci = mdef_ciphone_id (mdef, word); if (NOT_CIPID(ci)) E_FATAL("%s: Unknown CIphone %s\n", id, word); if (state != HYPERR) { /* Check if matches next pron in ref word */ if (n_refci >= pronlen) { assert (n_refci == pronlen); n_refwd++; pronlen = dict->word[ref[n_refwd]].pronlen; assert (pronlen > 0); wseg[n_refwd].s = (state == CORR) ? n_hypci : -1; wseg[n_refwd].e = -1; wseg[n_refwd].err = 0; n_refci = 0; } if (NOT_WID(ref[n_refwd])) E_FATAL("%s: Premature end of ref wid\n", id); if (dict->word[ref[n_refwd]].ciphone[n_refci] != ci) E_FATAL("%s: CIphone mismatch at word %d, ciphone %d\n", id, n_refwd, n_refci); n_refci++; if ((n_refci == pronlen) && (state == CORR)) wseg[n_refwd].e = n_hypci; if (state != CORR) wseg[n_refwd].err = 1; } if (state != REFERR) { if (n_hypci >= aplen) E_FATAL("%s: Too many CIphones: >%d\n", id, aplen); ap[n_hypci] = ci; ap_err[n_hypci] = (state == CORR) ? 0 : 1; n_hypci++; } } } assert (n_refci == pronlen); n_refwd++; assert (NOT_WID(ref[n_refwd])); wseg[n_refwd].s = wseg[n_refwd].e = n_hypci; wseg[n_refwd].err = 0; ap[n_hypci] = BAD_CIPID; ap_err[n_hypci] = 1; if (strcmp (uttid, id) != 0) E_FATAL("Uttid mismatch: %s expected, %s found\n", id, uttid); #if 0 for (i = 0; IS_WID(ref[i]); i++) { printf ("%s: %4d %4d %d %s\n", id, wseg[i].s, wseg[i].e, wseg[i].err, dict_wordstr (dict, ref[i])); } #endif return wseg; }
/* * Create phone-level HMM for a single word and append to partial sentence HMM. * Replicate HMM nodes as needed to account for all possible left and right context * phones. * Return a list of the final HMM nodes for the single word appended. */ static pnode_t *append_word (s3wid_t w, pnode_t *prev_end, s3cipid_t *pred_ci, s3cipid_t *succ_ci) { int32 i, M, N, m, n, pronlen, pron; pnode_t *node, *nodelist, *p; plink_t *l, *new_end; for (i = 0; IS_CIPID(pred_ci[i]); i++); M = (i > 0) ? i : 1; /* #predecessor CI phones */ for (i = 0; IS_CIPID(succ_ci[i]); i++); N = (i > 0) ? i : 1; /* #successor CI phones */ if ((pronlen = dict->word[w].pronlen) == 1) { /* Single phone case; replicated MxN times for all possible contexts */ nodelist = NULL; for (m = 0; m < M; m++) { for (n = 0; n < N; n++) { node = alloc_pnode (w, 0, dict->word[w].ciphone[0], pred_ci[m], succ_ci[n], WORD_POSN_SINGLE); /* Link to all predecessor nodes matching context requirements */ for (p = prev_end; p; p = p->next) { if ((p->ci == node->lc) && ((NOT_CIPID(p->rc)) || (p->rc == node->ci))) { link_pnodes (p, node); } } node->next = nodelist; nodelist = node; } } return nodelist; } /* Multi-phone case. First phone, replicated M times */ nodelist = NULL; for (m = 0; m < M; m++) { node = alloc_pnode (w, 0, dict->word[w].ciphone[0], pred_ci[m], dict->word[w].ciphone[1], WORD_POSN_BEGIN); /* Link to predecessor node(s) matching context requirements */ for (p = prev_end; p; p = p->next) { if ((p->ci == node->lc) && ((NOT_CIPID(p->rc)) || (p->rc == node->ci))) { link_pnodes (p, node); } } node->next = nodelist; nodelist = node; } /* Intermediate phones */ for (pron = 1; pron < pronlen-1; pron++) { node = alloc_pnode (w, pron, dict->word[w].ciphone[pron], dict->word[w].ciphone[pron-1], dict->word[w].ciphone[pron+1], WORD_POSN_INTERNAL); for (p = nodelist; p; p = p->next) link_pnodes (p, node); nodelist = node; } /* Final phone, replicated N times */ prev_end = nodelist; nodelist = NULL; for (n = 0; n < N; n++) { node = alloc_pnode (w, pron, dict->word[w].ciphone[pron], dict->word[w].ciphone[pron-1], succ_ci[n], WORD_POSN_END); for (p = prev_end; p; p = p->next) link_pnodes (p, node); node->next = nodelist; nodelist = node; } return nodelist; }