579 lines
19 KiB
C
579 lines
19 KiB
C
/* -*- c-basic-offset:4; indent-tabs-mode: nil -*- */
|
|
/* ====================================================================
|
|
* Copyright (c) 1999-2004 Carnegie Mellon University. All rights
|
|
* reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* This work was supported in part by funding from the Defense Advanced
|
|
* Research Projects Agency and the National Science Foundation of the
|
|
* United States of America, and the CMU Sphinx Speech Consortium.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
|
|
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
|
|
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ====================================================================
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "dict2pid.h"
|
|
#include "hmm.h"
|
|
|
|
|
|
/**
|
|
* @file dict2pid.c - dictionary word to senone sequence mappings
|
|
*/
|
|
|
|
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;
|
|
}
|
|
/** Compress this map */
|
|
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 it appears before, just filled in cimap; */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Try to compress lrdiph_rc into lrdiph_rc_compressed */
|
|
ckd_free(tmpssid);
|
|
ckd_free(tmpcimap);
|
|
|
|
E_INFO("Allocated %d bytes (%d KiB) for single-phone word triphones\n",
|
|
(int)alloc, (int)alloc / 1024);
|
|
}
|
|
|
|
/**
|
|
ARCHAN, A duplicate of get_rc_npid in ctxt_table.h. I doubt whether it is correct
|
|
because the compressed map has not been checked.
|
|
*/
|
|
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) {
|
|
/* Is this true ?
|
|
No known left context. But all cimaps (for any l) are identical; pick one
|
|
*/
|
|
/*E_INFO("Single phone word\n"); */
|
|
return (d2p->lrssid[b][0].n_ssid);
|
|
}
|
|
else {
|
|
/* E_INFO("Multiple phone word\n"); */
|
|
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) {
|
|
/* Is this true ?
|
|
No known left context. But all cimaps (for any l) are identical; pick one
|
|
*/
|
|
/*E_INFO("Single phone word\n"); */
|
|
return (d2p->lrssid[b][0].cimap);
|
|
}
|
|
else {
|
|
/* E_INFO("Multiple phone word\n"); */
|
|
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(2,("%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;
|
|
/* Make sure we have left and right context diphones for this
|
|
* word. */
|
|
if (d2p->ldiph_lc[dict_first_phone(d, wid)][dict_second_phone(d, wid)][0]
|
|
== BAD_S3SSID) {
|
|
E_DEBUG(2, ("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(2, ("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 {
|
|
/* Make sure we have a left-right context triphone entry for
|
|
* this word. */
|
|
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));
|
|
/* Only used internally to generate rssid */
|
|
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));
|
|
/* Actually could use memset for this, if BAD_S3SSID is guaranteed
|
|
* to be 65535... */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Track which diphones / ciphones have been seen. */
|
|
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);
|
|
/* Populate ldiph_lc */
|
|
if (bitvec_is_clear(ldiph, b * mdef->n_ciphone + r)) {
|
|
/* Mark this diphone as done */
|
|
bitvec_set(ldiph, b * mdef->n_ciphone + r);
|
|
|
|
/* Record all possible ssids for b(?,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);
|
|
}
|
|
}
|
|
|
|
|
|
/* Populate rdiph_rc */
|
|
l = dict_second_last_phone(dict, w);
|
|
b = dict_last_phone(dict, w);
|
|
if (bitvec_is_clear(rdiph, b * mdef->n_ciphone + l)) {
|
|
/* Mark this diphone as done */
|
|
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(1,("Building tables for single phone word %s phone %d = %s\n",
|
|
dict_wordstr(dict, w), b, bin_mdef_ciphone_str(mdef, b)));
|
|
/* Populate lrdiph_rc (and also ldiph_lc, rdiph_rc if needed) */
|
|
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);
|
|
|
|
/* Try to compress rdiph_rc into rdiph_rc_compressed */
|
|
compress_right_context_tree(dict2pid, rdiph_rc);
|
|
compress_left_right_context_tree(dict2pid);
|
|
|
|
ckd_free_3d(rdiph_rc);
|
|
|
|
dict2pid_report(dict2pid);
|
|
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_report(dict2pid_t * d2p)
|
|
{
|
|
}
|
|
|
|
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]); /* RAH, ldiph_lc is returning an int32, %d expects an int16 */
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|