| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <string.h> |
| |
|
| | #include "util/ckd_alloc.h" |
| | #include "util/bitvec.h" |
| | #include "s3types.h" |
| | #include "dict2pid.h" |
| | #include "hmm.h" |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | void |
| | compress_table(s3ssid_t * uncomp_tab, s3ssid_t * com_tab, |
| | s3cipid_t * ci_map, int32 n_ci) |
| | { |
| | int32 found; |
| | int32 r; |
| | int32 tmp_r; |
| |
|
| | for (r = 0; r < n_ci; r++) { |
| | com_tab[r] = BAD_S3SSID; |
| | ci_map[r] = BAD_S3CIPID; |
| | } |
| | |
| | for (r = 0; r < n_ci; r++) { |
| |
|
| | found = 0; |
| | for (tmp_r = 0; tmp_r < r && com_tab[tmp_r] != BAD_S3SSID; tmp_r++) { |
| | if (uncomp_tab[r] == com_tab[tmp_r]) { |
| | found = 1; |
| | ci_map[r] = tmp_r; |
| | break; |
| | } |
| | } |
| |
|
| | if (found == 0) { |
| | com_tab[tmp_r] = uncomp_tab[r]; |
| | ci_map[r] = tmp_r; |
| | } |
| | } |
| | } |
| |
|
| |
|
| | static void |
| | compress_right_context_tree(dict2pid_t * d2p, |
| | s3ssid_t ***rdiph_rc) |
| | { |
| | int32 n_ci; |
| | int32 b, l, r; |
| | s3ssid_t *rmap; |
| | s3ssid_t *tmpssid; |
| | s3cipid_t *tmpcimap; |
| | bin_mdef_t *mdef = d2p->mdef; |
| | size_t alloc; |
| |
|
| | n_ci = mdef->n_ciphone; |
| |
|
| | tmpssid = ckd_calloc(n_ci, sizeof(s3ssid_t)); |
| | tmpcimap = ckd_calloc(n_ci, sizeof(s3cipid_t)); |
| |
|
| | d2p->rssid = |
| | (xwdssid_t **) ckd_calloc(mdef->n_ciphone, sizeof(xwdssid_t *)); |
| | alloc = mdef->n_ciphone * sizeof(xwdssid_t *); |
| |
|
| | for (b = 0; b < n_ci; b++) { |
| | d2p->rssid[b] = |
| | (xwdssid_t *) ckd_calloc(mdef->n_ciphone, sizeof(xwdssid_t)); |
| | alloc += mdef->n_ciphone * sizeof(xwdssid_t); |
| |
|
| | for (l = 0; l < n_ci; l++) { |
| | rmap = rdiph_rc[b][l]; |
| | compress_table(rmap, tmpssid, tmpcimap, mdef->n_ciphone); |
| |
|
| | for (r = 0; r < mdef->n_ciphone && tmpssid[r] != BAD_S3SSID; |
| | r++); |
| |
|
| | if (tmpssid[0] != BAD_S3SSID) { |
| | d2p->rssid[b][l].ssid = ckd_calloc(r, sizeof(s3ssid_t)); |
| | memcpy(d2p->rssid[b][l].ssid, tmpssid, |
| | r * sizeof(s3ssid_t)); |
| | d2p->rssid[b][l].cimap = |
| | ckd_calloc(mdef->n_ciphone, sizeof(s3cipid_t)); |
| | memcpy(d2p->rssid[b][l].cimap, tmpcimap, |
| | (mdef->n_ciphone) * sizeof(s3cipid_t)); |
| | d2p->rssid[b][l].n_ssid = r; |
| | } |
| | else { |
| | d2p->rssid[b][l].ssid = NULL; |
| | d2p->rssid[b][l].cimap = NULL; |
| | d2p->rssid[b][l].n_ssid = 0; |
| | } |
| | } |
| | } |
| |
|
| | E_INFO("Allocated %d bytes (%d KiB) for word-final triphones\n", |
| | (int)alloc, (int)alloc / 1024); |
| | ckd_free(tmpssid); |
| | ckd_free(tmpcimap); |
| | } |
| |
|
| | static void |
| | compress_left_right_context_tree(dict2pid_t * d2p) |
| | { |
| | int32 n_ci; |
| | int32 b, l, r; |
| | s3ssid_t *rmap; |
| | s3ssid_t *tmpssid; |
| | s3cipid_t *tmpcimap; |
| | bin_mdef_t *mdef = d2p->mdef; |
| | size_t alloc; |
| |
|
| | n_ci = mdef->n_ciphone; |
| |
|
| | tmpssid = ckd_calloc(n_ci, sizeof(s3ssid_t)); |
| | tmpcimap = ckd_calloc(n_ci, sizeof(s3cipid_t)); |
| |
|
| | assert(d2p->lrdiph_rc); |
| |
|
| | d2p->lrssid = |
| | (xwdssid_t **) ckd_calloc(mdef->n_ciphone, sizeof(xwdssid_t *)); |
| | alloc = mdef->n_ciphone * sizeof(xwdssid_t *); |
| |
|
| | for (b = 0; b < n_ci; b++) { |
| |
|
| | d2p->lrssid[b] = |
| | (xwdssid_t *) ckd_calloc(mdef->n_ciphone, sizeof(xwdssid_t)); |
| | alloc += mdef->n_ciphone * sizeof(xwdssid_t); |
| |
|
| | for (l = 0; l < n_ci; l++) { |
| | rmap = d2p->lrdiph_rc[b][l]; |
| |
|
| | compress_table(rmap, tmpssid, tmpcimap, mdef->n_ciphone); |
| |
|
| | for (r = 0; r < mdef->n_ciphone && tmpssid[r] != BAD_S3SSID; |
| | r++); |
| |
|
| | if (tmpssid[0] != BAD_S3SSID) { |
| | d2p->lrssid[b][l].ssid = ckd_calloc(r, sizeof(s3ssid_t)); |
| | memcpy(d2p->lrssid[b][l].ssid, tmpssid, |
| | r * sizeof(s3ssid_t)); |
| | d2p->lrssid[b][l].cimap = |
| | ckd_calloc(mdef->n_ciphone, sizeof(s3cipid_t)); |
| | memcpy(d2p->lrssid[b][l].cimap, tmpcimap, |
| | (mdef->n_ciphone) * sizeof(s3cipid_t)); |
| | d2p->lrssid[b][l].n_ssid = r; |
| | } |
| | else { |
| | d2p->lrssid[b][l].ssid = NULL; |
| | d2p->lrssid[b][l].cimap = NULL; |
| | d2p->lrssid[b][l].n_ssid = 0; |
| | } |
| | } |
| | } |
| |
|
| | |
| | ckd_free(tmpssid); |
| | ckd_free(tmpcimap); |
| |
|
| | E_INFO("Allocated %d bytes (%d KiB) for single-phone word triphones\n", |
| | (int)alloc, (int)alloc / 1024); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | int32 |
| | get_rc_nssid(dict2pid_t * d2p, s3wid_t w) |
| | { |
| | int32 pronlen; |
| | s3cipid_t b, lc; |
| | dict_t *dict = d2p->dict; |
| |
|
| | pronlen = dict->word[w].pronlen; |
| | b = dict->word[w].ciphone[pronlen - 1]; |
| |
|
| | if (pronlen == 1) { |
| | |
| | |
| | |
| | |
| | return (d2p->lrssid[b][0].n_ssid); |
| | } |
| | else { |
| | |
| | lc = dict->word[w].ciphone[pronlen - 2]; |
| | return (d2p->rssid[b][lc].n_ssid); |
| | } |
| |
|
| | } |
| |
|
| | s3cipid_t * |
| | dict2pid_get_rcmap(dict2pid_t * d2p, s3wid_t w) |
| | { |
| | int32 pronlen; |
| | s3cipid_t b, lc; |
| | dict_t *dict = d2p->dict; |
| |
|
| | pronlen = dict->word[w].pronlen; |
| | b = dict->word[w].ciphone[pronlen - 1]; |
| |
|
| | if (pronlen == 1) { |
| | |
| | |
| | |
| | |
| | return (d2p->lrssid[b][0].cimap); |
| | } |
| | else { |
| | |
| | lc = dict->word[w].ciphone[pronlen - 2]; |
| | return (d2p->rssid[b][lc].cimap); |
| | } |
| | } |
| |
|
| | static void |
| | free_compress_map(xwdssid_t ** tree, int32 n_ci) |
| | { |
| | int32 b, l; |
| | for (b = 0; b < n_ci; b++) { |
| | for (l = 0; l < n_ci; l++) { |
| | ckd_free(tree[b][l].ssid); |
| | ckd_free(tree[b][l].cimap); |
| | } |
| | ckd_free(tree[b]); |
| | } |
| | ckd_free(tree); |
| | } |
| |
|
| | static void |
| | populate_lrdiph(dict2pid_t *d2p, s3ssid_t ***rdiph_rc, s3cipid_t b) |
| | { |
| | bin_mdef_t *mdef = d2p->mdef; |
| | s3cipid_t l, r; |
| |
|
| | for (l = 0; l < bin_mdef_n_ciphone(mdef); l++) { |
| | for (r = 0; r < bin_mdef_n_ciphone(mdef); r++) { |
| | s3pid_t p; |
| | p = bin_mdef_phone_id_nearest(mdef, (s3cipid_t) b, |
| | (s3cipid_t) l, |
| | (s3cipid_t) r, |
| | WORD_POSN_SINGLE); |
| | d2p->lrdiph_rc[b][l][r] |
| | = bin_mdef_pid2ssid(mdef, p); |
| | if (r == bin_mdef_silphone(mdef)) |
| | d2p->ldiph_lc[b][r][l] |
| | = bin_mdef_pid2ssid(mdef, p); |
| | if (rdiph_rc && l == bin_mdef_silphone(mdef)) |
| | rdiph_rc[b][l][r] |
| | = bin_mdef_pid2ssid(mdef, p); |
| | assert(IS_S3SSID(bin_mdef_pid2ssid(mdef, p))); |
| | E_DEBUG("%s(%s,%s) => %d / %d\n", |
| | bin_mdef_ciphone_str(mdef, b), |
| | bin_mdef_ciphone_str(mdef, l), |
| | bin_mdef_ciphone_str(mdef, r), |
| | p, bin_mdef_pid2ssid(mdef, p)); |
| | } |
| | } |
| | } |
| |
|
| | int |
| | dict2pid_add_word(dict2pid_t *d2p, |
| | int32 wid) |
| | { |
| | bin_mdef_t *mdef = d2p->mdef; |
| | dict_t *d = d2p->dict; |
| |
|
| | if (dict_pronlen(d, wid) > 1) { |
| | s3cipid_t l; |
| | |
| | |
| | if (d2p->ldiph_lc[dict_first_phone(d, wid)][dict_second_phone(d, wid)][0] |
| | == BAD_S3SSID) { |
| | E_DEBUG("Filling in left-context diphones for %s(?,%s)\n", |
| | bin_mdef_ciphone_str(mdef, dict_first_phone(d, wid)), |
| | bin_mdef_ciphone_str(mdef, dict_second_phone(d, wid))); |
| | for (l = 0; l < bin_mdef_n_ciphone(mdef); l++) { |
| | int p |
| | = bin_mdef_phone_id_nearest(mdef, |
| | dict_first_phone(d, wid), l, |
| | dict_second_phone(d, wid), |
| | WORD_POSN_BEGIN); |
| | d2p->ldiph_lc[dict_first_phone(d, wid)][dict_second_phone(d, wid)][l] |
| | = bin_mdef_pid2ssid(mdef, p); |
| | } |
| | } |
| | if (d2p->rssid[dict_last_phone(d, wid)][dict_second_last_phone(d, wid)].n_ssid |
| | == 0) { |
| | s3ssid_t *rmap; |
| | s3ssid_t *tmpssid; |
| | s3cipid_t *tmpcimap; |
| | s3cipid_t r; |
| |
|
| | E_DEBUG("Filling in right-context diphones for %s(%s,?)\n", |
| | bin_mdef_ciphone_str(mdef, dict_last_phone(d, wid)), |
| | bin_mdef_ciphone_str(mdef, dict_second_last_phone(d, wid))); |
| | rmap = ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(*rmap)); |
| | for (r = 0; r < bin_mdef_n_ciphone(mdef); r++) { |
| | int p |
| | = bin_mdef_phone_id_nearest(mdef, |
| | dict_last_phone(d, wid), |
| | dict_second_last_phone(d, wid), r, |
| | WORD_POSN_END); |
| | rmap[r] = bin_mdef_pid2ssid(mdef, p); |
| | } |
| | tmpssid = ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(*tmpssid)); |
| | tmpcimap = ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(*tmpcimap)); |
| | compress_table(rmap, tmpssid, tmpcimap, bin_mdef_n_ciphone(mdef)); |
| | for (r = 0; r < mdef->n_ciphone && tmpssid[r] != BAD_S3SSID; r++) |
| | ; |
| | d2p->rssid[dict_last_phone(d, wid)][dict_second_last_phone(d, wid)].ssid = tmpssid; |
| | d2p->rssid[dict_last_phone(d, wid)][dict_second_last_phone(d, wid)].cimap = tmpcimap; |
| | d2p->rssid[dict_last_phone(d, wid)][dict_second_last_phone(d, wid)].n_ssid = r; |
| | ckd_free(rmap); |
| | } |
| | } |
| | else { |
| | |
| | |
| | E_INFO("Filling in context triphones for %s(?,?)\n", |
| | bin_mdef_ciphone_str(mdef, dict_first_phone(d, wid))); |
| | if (d2p->lrdiph_rc[dict_first_phone(d, wid)][0][0] == BAD_S3SSID) { |
| | populate_lrdiph(d2p, NULL, dict_first_phone(d, wid)); |
| | } |
| | } |
| |
|
| | return 0; |
| | } |
| |
|
| | s3ssid_t |
| | dict2pid_internal(dict2pid_t *d2p, |
| | int32 wid, |
| | int pos) |
| | { |
| | int b, l, r, p; |
| | dict_t *dict = d2p->dict; |
| | bin_mdef_t *mdef = d2p->mdef; |
| |
|
| | if (pos == 0 || pos == dict_pronlen(dict, wid)) |
| | return BAD_S3SSID; |
| |
|
| | b = dict_pron(dict, wid, pos); |
| | l = dict_pron(dict, wid, pos - 1); |
| | r = dict_pron(dict, wid, pos + 1); |
| | p = bin_mdef_phone_id_nearest(mdef, (s3cipid_t) b, |
| | (s3cipid_t) l, (s3cipid_t) r, |
| | WORD_POSN_INTERNAL); |
| | return bin_mdef_pid2ssid(mdef, p); |
| | } |
| |
|
| | dict2pid_t * |
| | dict2pid_build(bin_mdef_t * mdef, dict_t * dict) |
| | { |
| | dict2pid_t *dict2pid; |
| | s3ssid_t ***rdiph_rc; |
| | bitvec_t *ldiph, *rdiph, *single; |
| | int32 pronlen; |
| | int32 b, l, r, w, p; |
| |
|
| | E_INFO("Building PID tables for dictionary\n"); |
| | assert(mdef); |
| | assert(dict); |
| |
|
| | dict2pid = (dict2pid_t *) ckd_calloc(1, sizeof(dict2pid_t)); |
| | dict2pid->refcount = 1; |
| | dict2pid->mdef = bin_mdef_retain(mdef); |
| | dict2pid->dict = dict_retain(dict); |
| | E_INFO("Allocating %d^3 * %d bytes (%d KiB) for word-initial triphones\n", |
| | mdef->n_ciphone, sizeof(s3ssid_t), |
| | mdef->n_ciphone * mdef->n_ciphone * mdef->n_ciphone * sizeof(s3ssid_t) / 1024); |
| | dict2pid->ldiph_lc = |
| | (s3ssid_t ***) ckd_calloc_3d(mdef->n_ciphone, mdef->n_ciphone, |
| | mdef->n_ciphone, sizeof(s3ssid_t)); |
| | |
| | rdiph_rc = |
| | (s3ssid_t ***) ckd_calloc_3d(mdef->n_ciphone, mdef->n_ciphone, |
| | mdef->n_ciphone, sizeof(s3ssid_t)); |
| |
|
| | dict2pid->lrdiph_rc = (s3ssid_t ***) ckd_calloc_3d(mdef->n_ciphone, |
| | mdef->n_ciphone, |
| | mdef->n_ciphone, |
| | sizeof |
| | (s3ssid_t)); |
| | |
| | |
| | for (b = 0; b < mdef->n_ciphone; ++b) { |
| | for (r = 0; r < mdef->n_ciphone; ++r) { |
| | for (l = 0; l < mdef->n_ciphone; ++l) { |
| | dict2pid->ldiph_lc[b][r][l] = BAD_S3SSID; |
| | dict2pid->lrdiph_rc[b][l][r] = BAD_S3SSID; |
| | rdiph_rc[b][l][r] = BAD_S3SSID; |
| | } |
| | } |
| | } |
| |
|
| | |
| | ldiph = bitvec_alloc(mdef->n_ciphone * mdef->n_ciphone); |
| | rdiph = bitvec_alloc(mdef->n_ciphone * mdef->n_ciphone); |
| | single = bitvec_alloc(mdef->n_ciphone); |
| |
|
| | for (w = 0; w < dict_size(dict2pid->dict); w++) { |
| | pronlen = dict_pronlen(dict, w); |
| |
|
| | if (pronlen >= 2) { |
| | b = dict_first_phone(dict, w); |
| | r = dict_second_phone(dict, w); |
| | |
| | if (bitvec_is_clear(ldiph, b * mdef->n_ciphone + r)) { |
| | |
| | bitvec_set(ldiph, b * mdef->n_ciphone + r); |
| |
|
| | |
| | for (l = 0; l < bin_mdef_n_ciphone(mdef); l++) { |
| | p = bin_mdef_phone_id_nearest(mdef, (s3cipid_t) b, |
| | (s3cipid_t) l, (s3cipid_t) r, |
| | WORD_POSN_BEGIN); |
| | dict2pid->ldiph_lc[b][r][l] = bin_mdef_pid2ssid(mdef, p); |
| | } |
| | } |
| |
|
| |
|
| | |
| | l = dict_second_last_phone(dict, w); |
| | b = dict_last_phone(dict, w); |
| | if (bitvec_is_clear(rdiph, b * mdef->n_ciphone + l)) { |
| | |
| | bitvec_set(rdiph, b * mdef->n_ciphone + l); |
| |
|
| | for (r = 0; r < bin_mdef_n_ciphone(mdef); r++) { |
| | p = bin_mdef_phone_id_nearest(mdef, (s3cipid_t) b, |
| | (s3cipid_t) l, (s3cipid_t) r, |
| | WORD_POSN_END); |
| | rdiph_rc[b][l][r] = bin_mdef_pid2ssid(mdef, p); |
| | } |
| | } |
| | } |
| | else if (pronlen == 1) { |
| | b = dict_pron(dict, w, 0); |
| | E_DEBUG("Building tables for single phone word %s phone %d = %s\n", |
| | dict_wordstr(dict, w), b, bin_mdef_ciphone_str(mdef, b)); |
| | |
| | if (bitvec_is_clear(single, b)) { |
| | populate_lrdiph(dict2pid, rdiph_rc, b); |
| | bitvec_set(single, b); |
| | } |
| | } |
| | } |
| |
|
| | bitvec_free(ldiph); |
| | bitvec_free(rdiph); |
| | bitvec_free(single); |
| |
|
| | |
| | compress_right_context_tree(dict2pid, rdiph_rc); |
| | compress_left_right_context_tree(dict2pid); |
| |
|
| | ckd_free_3d(rdiph_rc); |
| |
|
| | return dict2pid; |
| | } |
| |
|
| | dict2pid_t * |
| | dict2pid_retain(dict2pid_t *d2p) |
| | { |
| | ++d2p->refcount; |
| | return d2p; |
| | } |
| |
|
| | int |
| | dict2pid_free(dict2pid_t * d2p) |
| | { |
| | if (d2p == NULL) |
| | return 0; |
| | if (--d2p->refcount > 0) |
| | return d2p->refcount; |
| |
|
| | if (d2p->ldiph_lc) |
| | ckd_free_3d((void ***) d2p->ldiph_lc); |
| |
|
| | if (d2p->lrdiph_rc) |
| | ckd_free_3d((void ***) d2p->lrdiph_rc); |
| |
|
| | if (d2p->rssid) |
| | free_compress_map(d2p->rssid, bin_mdef_n_ciphone(d2p->mdef)); |
| |
|
| | if (d2p->lrssid) |
| | free_compress_map(d2p->lrssid, bin_mdef_n_ciphone(d2p->mdef)); |
| |
|
| | bin_mdef_free(d2p->mdef); |
| | dict_free(d2p->dict); |
| | ckd_free(d2p); |
| | return 0; |
| | } |
| |
|
| | void |
| | dict2pid_dump(FILE * fp, dict2pid_t * d2p) |
| | { |
| | int32 w, p, pronlen; |
| | int32 i, j, b, l, r; |
| | bin_mdef_t *mdef = d2p->mdef; |
| | dict_t *dict = d2p->dict; |
| |
|
| | fprintf(fp, "# INTERNAL (wd comssid ssid ssid ... ssid comssid)\n"); |
| | for (w = 0; w < dict_size(dict); w++) { |
| | fprintf(fp, "%30s ", dict_wordstr(dict, w)); |
| |
|
| | pronlen = dict_pronlen(dict, w); |
| | for (p = 0; p < pronlen; p++) |
| | fprintf(fp, " %5d", dict2pid_internal(d2p, w, p)); |
| | fprintf(fp, "\n"); |
| | } |
| | fprintf(fp, "#\n"); |
| |
|
| | fprintf(fp, "# LDIPH_LC (b r l ssid)\n"); |
| | for (b = 0; b < bin_mdef_n_ciphone(mdef); b++) { |
| | for (r = 0; r < bin_mdef_n_ciphone(mdef); r++) { |
| | for (l = 0; l < bin_mdef_n_ciphone(mdef); l++) { |
| | if (IS_S3SSID(d2p->ldiph_lc[b][r][l])) |
| | fprintf(fp, "%6s %6s %6s %5d\n", bin_mdef_ciphone_str(mdef, (s3cipid_t) b), bin_mdef_ciphone_str(mdef, (s3cipid_t) r), bin_mdef_ciphone_str(mdef, (s3cipid_t) l), d2p->ldiph_lc[b][r][l]); |
| | } |
| | } |
| | } |
| | fprintf(fp, "#\n"); |
| |
|
| | fprintf(fp, "# SSEQ %d (senid senid ...)\n", mdef->n_sseq); |
| | for (i = 0; i < mdef->n_sseq; i++) { |
| | fprintf(fp, "%5d ", i); |
| | for (j = 0; j < bin_mdef_n_emit_state(mdef); j++) |
| | fprintf(fp, " %5d", mdef->sseq[i][j]); |
| | fprintf(fp, "\n"); |
| | } |
| | fprintf(fp, "#\n"); |
| | fprintf(fp, "# END\n"); |
| |
|
| | fflush(fp); |
| | } |
| |
|