00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <stdio.h>
00051 #include <string.h>
00052 #include <assert.h>
00053
00054
00055 #include <prim_type.h>
00056 #include <ckd_alloc.h>
00057 #include <byteorder.h>
00058 #include <case.h>
00059 #include <err.h>
00060
00061
00062 #include "mdef.h"
00063 #include "bin_mdef.h"
00064
00065 bin_mdef_t *
00066 bin_mdef_read_text(cmd_ln_t *config, const char *filename)
00067 {
00068 bin_mdef_t *bmdef;
00069 mdef_t *mdef;
00070 int i, nodes, ci_idx, lc_idx, rc_idx;
00071 int nchars;
00072
00073 if ((mdef = mdef_init((char *) filename, TRUE)) == NULL)
00074 return NULL;
00075
00076 bmdef = ckd_calloc(1, sizeof(*bmdef));
00077
00078
00079 bmdef->n_ciphone = mdef->n_ciphone;
00080 bmdef->n_phone = mdef->n_phone;
00081 bmdef->n_emit_state = mdef->n_emit_state;
00082 bmdef->n_ci_sen = mdef->n_ci_sen;
00083 bmdef->n_sen = mdef->n_sen;
00084 bmdef->n_tmat = mdef->n_tmat;
00085 bmdef->n_sseq = mdef->n_sseq;
00086 bmdef->sseq = mdef->sseq;
00087 bmdef->cd2cisen = mdef->cd2cisen;
00088 bmdef->sen2cimap = mdef->sen2cimap;
00089 bmdef->n_ctx = 3;
00090 bmdef->sil = mdef->sil;
00091 mdef->sseq = NULL;
00092 mdef->cd2cisen = NULL;
00093 mdef->sen2cimap = NULL;
00094
00095
00096
00097
00098 bmdef->ciname = ckd_calloc(bmdef->n_ciphone, sizeof(*bmdef->ciname));
00099 nchars = 0;
00100 for (i = 0; i < bmdef->n_ciphone; ++i)
00101 nchars += strlen(mdef->ciphone[i].name) + 1;
00102 bmdef->ciname[0] = ckd_calloc(nchars, 1);
00103 strcpy(bmdef->ciname[0], mdef->ciphone[0].name);
00104 for (i = 1; i < bmdef->n_ciphone; ++i) {
00105 bmdef->ciname[i] =
00106 bmdef->ciname[i - 1] + strlen(bmdef->ciname[i - 1]) + 1;
00107 strcpy(bmdef->ciname[i], mdef->ciphone[i].name);
00108 if (i > 0 && strcmp(bmdef->ciname[i - 1], bmdef->ciname[i]) > 0) {
00109
00110 E_ERROR("Phone names are not in sorted order, sorry.");
00111 bin_mdef_free(bmdef);
00112 return NULL;
00113 }
00114 }
00115
00116
00117 bmdef->phone = ckd_calloc(bmdef->n_phone, sizeof(*bmdef->phone));
00118 for (i = 0; i < mdef->n_phone; ++i) {
00119 bmdef->phone[i].ssid = mdef->phone[i].ssid;
00120 bmdef->phone[i].tmat = mdef->phone[i].tmat;
00121 if (i < bmdef->n_ciphone) {
00122 bmdef->phone[i].info.ci.filler = mdef->ciphone[i].filler;
00123 }
00124 else {
00125 bmdef->phone[i].info.cd.wpos = mdef->phone[i].wpos;
00126 bmdef->phone[i].info.cd.ctx[0] = (uint8)mdef->phone[i].ci;
00127 bmdef->phone[i].info.cd.ctx[1] = (uint8)mdef->phone[i].lc;
00128 bmdef->phone[i].info.cd.ctx[2] = (uint8)mdef->phone[i].rc;
00129 }
00130 }
00131
00132
00133
00134 nodes = lc_idx = ci_idx = rc_idx = 0;
00135 for (i = 0; i < N_WORD_POSN; ++i) {
00136 int j;
00137 for (j = 0; j < mdef->n_ciphone; ++j) {
00138 ph_lc_t *lc;
00139
00140 for (lc = mdef->wpos_ci_lclist[i][j]; lc; lc = lc->next) {
00141 ph_rc_t *rc;
00142 for (rc = lc->rclist; rc; rc = rc->next) {
00143 ++nodes;
00144 }
00145 ++nodes;
00146 ++rc_idx;
00147 }
00148 ++nodes;
00149 ++lc_idx;
00150 ++rc_idx;
00151 }
00152 ++nodes;
00153 ++ci_idx;
00154 ++lc_idx;
00155 ++rc_idx;
00156 }
00157 E_INFO
00158 ("cd_tree: nodes %d wpos start 0 ci start %d lc start %d rc start %d\n",
00159 nodes, ci_idx, lc_idx, rc_idx);
00160 bmdef->n_cd_tree = nodes;
00161 bmdef->cd_tree = ckd_calloc(nodes, sizeof(*bmdef->cd_tree));
00162 for (i = 0; i < N_WORD_POSN; ++i) {
00163 int j;
00164
00165 bmdef->cd_tree[i].ctx = i;
00166 bmdef->cd_tree[i].n_down = mdef->n_ciphone;
00167 bmdef->cd_tree[i].c.down = ci_idx;
00168 #if 0
00169 E_INFO("%d => %c (%d@%d)\n",
00170 i, (WPOS_NAME)[i],
00171 bmdef->cd_tree[i].n_down, bmdef->cd_tree[i].c.down);
00172 #endif
00173
00174
00175 for (j = 0; j < mdef->n_ciphone; ++j) {
00176 ph_lc_t *lc;
00177
00178 bmdef->cd_tree[ci_idx].ctx = j;
00179 bmdef->cd_tree[ci_idx].c.down = lc_idx;
00180 for (lc = mdef->wpos_ci_lclist[i][j]; lc; lc = lc->next) {
00181 ph_rc_t *rc;
00182
00183 bmdef->cd_tree[lc_idx].ctx = lc->lc;
00184 bmdef->cd_tree[lc_idx].c.down = rc_idx;
00185 for (rc = lc->rclist; rc; rc = rc->next) {
00186 bmdef->cd_tree[rc_idx].ctx = rc->rc;
00187 bmdef->cd_tree[rc_idx].n_down = 0;
00188 bmdef->cd_tree[rc_idx].c.pid = rc->pid;
00189 #if 0
00190 E_INFO("%d => %s %s %s %c (%d@%d)\n",
00191 rc_idx,
00192 bmdef->ciname[j],
00193 bmdef->ciname[lc->lc],
00194 bmdef->ciname[rc->rc],
00195 (WPOS_NAME)[i],
00196 bmdef->cd_tree[rc_idx].n_down,
00197 bmdef->cd_tree[rc_idx].c.down);
00198 #endif
00199
00200 ++bmdef->cd_tree[lc_idx].n_down;
00201 ++rc_idx;
00202 }
00203
00204
00205
00206 if (bmdef->cd_tree[lc_idx].n_down == 0)
00207 bmdef->cd_tree[lc_idx].c.pid = -1;
00208 #if 0
00209 E_INFO("%d => %s %s %c (%d@%d)\n",
00210 lc_idx,
00211 bmdef->ciname[j],
00212 bmdef->ciname[lc->lc],
00213 (WPOS_NAME)[i],
00214 bmdef->cd_tree[lc_idx].n_down,
00215 bmdef->cd_tree[lc_idx].c.down);
00216 #endif
00217
00218 ++bmdef->cd_tree[ci_idx].n_down;
00219 ++lc_idx;
00220 }
00221
00222
00223 if (bmdef->cd_tree[ci_idx].n_down == 0)
00224 bmdef->cd_tree[ci_idx].c.pid = -1;
00225 #if 0
00226 E_INFO("%d => %d=%s (%d@%d)\n",
00227 ci_idx, j, bmdef->ciname[j],
00228 bmdef->cd_tree[ci_idx].n_down,
00229 bmdef->cd_tree[ci_idx].c.down);
00230 #endif
00231
00232 ++ci_idx;
00233 }
00234 }
00235
00236 mdef_free(mdef);
00237
00238 bmdef->alloc_mode = BIN_MDEF_FROM_TEXT;
00239 return bmdef;
00240 }
00241
00242 void
00243 bin_mdef_free(bin_mdef_t * m)
00244 {
00245 switch (m->alloc_mode) {
00246 case BIN_MDEF_FROM_TEXT:
00247 ckd_free(m->ciname[0]);
00248 ckd_free(m->sseq[0]);
00249 ckd_free(m->phone);
00250 ckd_free(m->cd_tree);
00251 break;
00252 case BIN_MDEF_IN_MEMORY:
00253 ckd_free(m->ciname[0]);
00254 break;
00255 case BIN_MDEF_ON_DISK:
00256 break;
00257 }
00258 if (m->filemap)
00259 mmio_file_unmap(m->filemap);
00260 ckd_free(m->cd2cisen);
00261 ckd_free(m->sen2cimap);
00262 ckd_free(m->ciname);
00263 ckd_free(m->sseq);
00264 ckd_free(m);
00265 }
00266
00267 static const char format_desc[] =
00268 "BEGIN FILE FORMAT DESCRIPTION\n"
00269 "int32 n_ciphone; /**< Number of base (CI) phones */\n"
00270 "int32 n_phone; /**< Number of base (CI) phones + (CD) triphones */\n"
00271 "int32 n_emit_state; /**< Number of emitting states per phone (0 if heterogeneous) */\n"
00272 "int32 n_ci_sen; /**< Number of CI senones; these are the first */\n"
00273 "int32 n_sen; /**< Number of senones (CI+CD) */\n"
00274 "int32 n_tmat; /**< Number of transition matrices */\n"
00275 "int32 n_sseq; /**< Number of unique senone sequences */\n"
00276 "int32 n_ctx; /**< Number of phones of context */\n"
00277 "int32 n_cd_tree; /**< Number of nodes in CD tree structure */\n"
00278 "int32 sil; /**< CI phone ID for silence */\n"
00279 "char ciphones[][]; /**< CI phone strings (null-terminated) */\n"
00280 "char padding[]; /**< Padding to a 4-bytes boundary */\n"
00281 "struct { int16 ctx; int16 n_down; int32 pid/down } cd_tree[];\n"
00282 "struct { int32 ssid; int32 tmat; int8 attr[4] } phones[];\n"
00283 "int16 sseq[]; /**< Unique senone sequences */\n"
00284 "int8 sseq_len[]; /**< Number of states in each sseq (none if homogeneous) */\n"
00285 "END FILE FORMAT DESCRIPTION\n";
00286
00287 bin_mdef_t *
00288 bin_mdef_read(cmd_ln_t *config, const char *filename)
00289 {
00290 bin_mdef_t *m;
00291 FILE *fh;
00292 size_t tree_start;
00293 int32 val, i, swap, pos, end;
00294 int32 *sseq_size;
00295 int do_mmap;
00296
00297
00298 if ((m = bin_mdef_read_text(config, filename)) != NULL)
00299 return m;
00300
00301 E_INFO("Reading binary model definition: %s\n", filename);
00302 if ((fh = fopen(filename, "rb")) == NULL)
00303 return NULL;
00304
00305 if (fread(&val, 4, 1, fh) != 1)
00306 E_FATAL_SYSTEM("Failed to read byte-order marker from %s\n",
00307 filename);
00308 swap = 0;
00309 if (val == BIN_MDEF_OTHER_ENDIAN) {
00310 swap = 1;
00311 E_INFO("Must byte-swap %s\n", filename);
00312 }
00313 if (fread(&val, 4, 1, fh) != 1)
00314 E_FATAL_SYSTEM("Failed to read version from %s\n", filename);
00315 if (swap)
00316 SWAP_INT32(&val);
00317 if (val > BIN_MDEF_FORMAT_VERSION) {
00318 E_ERROR("File format version %d for %s is newer than library\n",
00319 val, filename);
00320 fclose(fh);
00321 return NULL;
00322 }
00323 if (fread(&val, 4, 1, fh) != 1)
00324 E_FATAL_SYSTEM("Failed to read header length from %s\n", filename);
00325 if (swap)
00326 SWAP_INT32(&val);
00327
00328 fseek(fh, val, SEEK_CUR);
00329
00330
00331 m = ckd_calloc(1, sizeof(*m));
00332
00333
00334 fread(&m->n_ciphone, 4, 1, fh);
00335 if (swap)
00336 SWAP_INT32(&m->n_ciphone);
00337 fread(&m->n_phone, 4, 1, fh);
00338 if (swap)
00339 SWAP_INT32(&m->n_phone);
00340 fread(&m->n_emit_state, 4, 1, fh);
00341 if (swap)
00342 SWAP_INT32(&m->n_emit_state);
00343 fread(&m->n_ci_sen, 4, 1, fh);
00344 if (swap)
00345 SWAP_INT32(&m->n_ci_sen);
00346 fread(&m->n_sen, 4, 1, fh);
00347 if (swap)
00348 SWAP_INT32(&m->n_sen);
00349 fread(&m->n_tmat, 4, 1, fh);
00350 if (swap)
00351 SWAP_INT32(&m->n_tmat);
00352 fread(&m->n_sseq, 4, 1, fh);
00353 if (swap)
00354 SWAP_INT32(&m->n_sseq);
00355 fread(&m->n_ctx, 4, 1, fh);
00356 if (swap)
00357 SWAP_INT32(&m->n_ctx);
00358 fread(&m->n_cd_tree, 4, 1, fh);
00359 if (swap)
00360 SWAP_INT32(&m->n_cd_tree);
00361 if (fread(&val, 4, 1, fh) != 1)
00362 E_FATAL_SYSTEM("Failed to read header from %s\n", filename);
00363 m->sil = val;
00364
00365
00366 m->ciname = ckd_calloc(m->n_ciphone, sizeof(*m->ciname));
00367
00368
00369 do_mmap = config ? cmd_ln_boolean_r(config, "-mmap") : TRUE;
00370 if (swap) {
00371 E_WARN("-mmap specified, but mdef is other-endian. Will not memory-map.\n");
00372 do_mmap = FALSE;
00373 }
00374
00375 if (do_mmap) {
00376 m->filemap = mmio_file_read(filename);
00377 if (m->filemap == NULL)
00378 do_mmap = FALSE;
00379 }
00380 pos = ftell(fh);
00381 if (do_mmap) {
00382
00383 m->ciname[0] = (char *)mmio_file_ptr(m->filemap) + pos;
00384
00385 m->alloc_mode = BIN_MDEF_ON_DISK;
00386 }
00387 else {
00388
00389 m->alloc_mode = BIN_MDEF_IN_MEMORY;
00390 fseek(fh, 0, SEEK_END);
00391 end = ftell(fh);
00392 fseek(fh, pos, SEEK_SET);
00393 m->ciname[0] = ckd_malloc(end - pos);
00394 if (fread(m->ciname[0], 1, end - pos, fh) != end - pos)
00395 E_FATAL_SYSTEM("Failed to read %d bytes of data from %s\n",
00396 end - pos, filename);
00397 }
00398
00399 for (i = 1; i < m->n_ciphone; ++i)
00400 m->ciname[i] = m->ciname[i - 1] + strlen(m->ciname[i - 1]) + 1;
00401
00402
00403 tree_start =
00404 m->ciname[i - 1] + strlen(m->ciname[i - 1]) + 1 - m->ciname[0];
00405 tree_start = (tree_start + 3) & ~3;
00406 m->cd_tree = (cd_tree_t *) (m->ciname[0] + tree_start);
00407 if (swap) {
00408 for (i = 0; i < m->n_cd_tree; ++i) {
00409 SWAP_INT16(&m->cd_tree[i].ctx);
00410 SWAP_INT16(&m->cd_tree[i].n_down);
00411 SWAP_INT32(&m->cd_tree[i].c.down);
00412 }
00413 }
00414 m->phone = (mdef_entry_t *) (m->cd_tree + m->n_cd_tree);
00415 if (swap) {
00416 for (i = 0; i < m->n_phone; ++i) {
00417 SWAP_INT32(&m->phone[i].ssid);
00418 SWAP_INT32(&m->phone[i].tmat);
00419 }
00420 }
00421 sseq_size = (int32 *) (m->phone + m->n_phone);
00422 if (swap)
00423 SWAP_INT32(sseq_size);
00424 m->sseq = ckd_calloc(m->n_sseq, sizeof(*m->sseq));
00425 m->sseq[0] = (int16 *) (sseq_size + 1);
00426 if (swap) {
00427 for (i = 0; i < *sseq_size; ++i)
00428 SWAP_INT16(m->sseq[0] + i);
00429 }
00430 if (m->n_emit_state) {
00431 for (i = 1; i < m->n_sseq; ++i)
00432 m->sseq[i] = m->sseq[0] + i * m->n_emit_state;
00433 }
00434 else {
00435 m->sseq_len = (uint8 *) (m->sseq[0] + *sseq_size);
00436 for (i = 1; i < m->n_sseq; ++i)
00437 m->sseq[i] = m->sseq[i - 1] + m->sseq_len[i - 1];
00438 }
00439
00440
00441
00442
00443
00444 m->cd2cisen = (int16 *) ckd_malloc(m->n_sen * sizeof(*m->cd2cisen));
00445 m->sen2cimap = (int16 *) ckd_malloc(m->n_sen * sizeof(*m->sen2cimap));
00446
00447
00448 for (i = 0; i < m->n_ci_sen; ++i)
00449 m->cd2cisen[i] = i;
00450 for (; i < m->n_sen; ++i)
00451 m->cd2cisen[i] = -1;
00452 for (i = 0; i < m->n_sen; ++i)
00453 m->sen2cimap[i] = -1;
00454 for (i = 0; i < m->n_phone; ++i) {
00455 int32 j, ssid = m->phone[i].ssid;
00456
00457 for (j = 0; j < bin_mdef_n_emit_state_phone(m, i); ++j) {
00458 int s = bin_mdef_sseq2sen(m, ssid, j);
00459 int ci = bin_mdef_pid2ci(m, i);
00460
00461 if (m->sen2cimap[s] == -1)
00462 m->sen2cimap[s] = ci;
00463 if (m->sen2cimap[s] != ci)
00464 E_WARN
00465 ("Senone %d is shared between multiple base phones\n",
00466 s);
00467
00468 if (j > bin_mdef_n_emit_state_phone(m, ci))
00469 E_WARN("CD phone %d has fewer states than CI phone %d\n",
00470 i, ci);
00471 else
00472 m->cd2cisen[s] =
00473 bin_mdef_sseq2sen(m, m->phone[ci].ssid, j);
00474 }
00475 }
00476
00477
00478 m->sil = bin_mdef_ciphone_id(m, S3_SILENCE_CIPHONE);
00479
00480 E_INFO
00481 ("%d CI-phone, %d CD-phone, %d emitstate/phone, %d CI-sen, %d Sen, %d Sen-Seq\n",
00482 m->n_ciphone, m->n_phone - m->n_ciphone, m->n_emit_state,
00483 m->n_ci_sen, m->n_sen, m->n_sseq);
00484 fclose(fh);
00485 return m;
00486 }
00487
00488 int
00489 bin_mdef_write(bin_mdef_t * m, const char *filename)
00490 {
00491 FILE *fh;
00492 int32 val, i;
00493
00494 if ((fh = fopen(filename, "wb")) == NULL)
00495 return -1;
00496
00497
00498 val = BIN_MDEF_NATIVE_ENDIAN;
00499 fwrite(&val, 1, 4, fh);
00500
00501 val = BIN_MDEF_FORMAT_VERSION;
00502 fwrite(&val, 1, sizeof(val), fh);
00503
00504
00505 val = ((sizeof(format_desc) + 3) & ~3);
00506 fwrite(&val, 1, sizeof(val), fh);
00507 fwrite(format_desc, 1, sizeof(format_desc), fh);
00508
00509 i = 0;
00510 fwrite(&i, 1, val - sizeof(format_desc), fh);
00511
00512
00513 fwrite(&m->n_ciphone, 4, 1, fh);
00514 fwrite(&m->n_phone, 4, 1, fh);
00515 fwrite(&m->n_emit_state, 4, 1, fh);
00516 fwrite(&m->n_ci_sen, 4, 1, fh);
00517 fwrite(&m->n_sen, 4, 1, fh);
00518 fwrite(&m->n_tmat, 4, 1, fh);
00519 fwrite(&m->n_sseq, 4, 1, fh);
00520 fwrite(&m->n_ctx, 4, 1, fh);
00521 fwrite(&m->n_cd_tree, 4, 1, fh);
00522
00523
00524
00525
00526 val = m->sil;
00527 fwrite(&val, 4, 1, fh);
00528
00529
00530 for (i = 0; i < m->n_ciphone; ++i)
00531 fwrite(m->ciname[i], 1, strlen(m->ciname[i]) + 1, fh);
00532
00533 val = (ftell(fh) + 3) & ~3;
00534 i = 0;
00535 fwrite(&i, 1, val - ftell(fh), fh);
00536
00537
00538 fwrite(m->cd_tree, sizeof(*m->cd_tree), m->n_cd_tree, fh);
00539
00540 fwrite(m->phone, sizeof(*m->phone), m->n_phone, fh);
00541 if (m->n_emit_state) {
00542
00543 val = m->n_sseq * m->n_emit_state;
00544 fwrite(&val, 4, 1, fh);
00545
00546
00547 fwrite(m->sseq[0], sizeof(**m->sseq),
00548 m->n_sseq * m->n_emit_state, fh);
00549 }
00550 else {
00551 int32 n;
00552
00553
00554 n = 0;
00555 for (i = 0; i < m->n_sseq; ++i)
00556 n += m->sseq_len[i];
00557
00558
00559 fwrite(&n, 4, 1, fh);
00560
00561
00562 fwrite(m->sseq[0], sizeof(**m->sseq), n, fh);
00563
00564
00565 fwrite(m->sseq_len, 1, m->n_sseq, fh);
00566 }
00567 fclose(fh);
00568
00569 return 0;
00570 }
00571
00572 int
00573 bin_mdef_write_text(bin_mdef_t * m, const char *filename)
00574 {
00575 FILE *fh;
00576 int p, i, n_total_state;
00577
00578 if (strcmp(filename, "-") == 0)
00579 fh = stdout;
00580 else {
00581 if ((fh = fopen(filename, "w")) == NULL)
00582 return -1;
00583 }
00584
00585 fprintf(fh, "0.3\n");
00586 fprintf(fh, "%d n_base\n", m->n_ciphone);
00587 fprintf(fh, "%d n_tri\n", m->n_phone - m->n_ciphone);
00588 if (m->n_emit_state)
00589 n_total_state = m->n_phone * (m->n_emit_state + 1);
00590 else {
00591 n_total_state = 0;
00592 for (i = 0; i < m->n_phone; ++i)
00593 n_total_state += m->sseq_len[m->phone[i].ssid] + 1;
00594 }
00595 fprintf(fh, "%d n_state_map\n", n_total_state);
00596 fprintf(fh, "%d n_tied_state\n", m->n_sen);
00597 fprintf(fh, "%d n_tied_ci_state\n", m->n_ci_sen);
00598 fprintf(fh, "%d n_tied_tmat\n", m->n_tmat);
00599 fprintf(fh, "#\n# Columns definitions\n");
00600 fprintf(fh, "#%4s %3s %3s %1s %6s %4s %s\n",
00601 "base", "lft", "rt", "p", "attrib", "tmat",
00602 " ... state id's ...");
00603
00604 for (p = 0; p < m->n_ciphone; p++) {
00605 int n_state;
00606
00607 fprintf(fh, "%5s %3s %3s %1s", m->ciname[p], "-", "-", "-");
00608
00609 if (bin_mdef_is_fillerphone(m, p))
00610 fprintf(fh, " %6s", "filler");
00611 else
00612 fprintf(fh, " %6s", "n/a");
00613 fprintf(fh, " %4d", m->phone[p].tmat);
00614
00615 if (m->n_emit_state)
00616 n_state = m->n_emit_state;
00617 else
00618 n_state = m->sseq_len[m->phone[p].ssid];
00619 for (i = 0; i < n_state; i++) {
00620 fprintf(fh, " %6u", m->sseq[m->phone[p].ssid][i]);
00621 }
00622 fprintf(fh, " N\n");
00623 }
00624
00625
00626 for (; p < m->n_phone; p++) {
00627 int n_state;
00628
00629 fprintf(fh, "%5s %3s %3s %c",
00630 m->ciname[m->phone[p].info.cd.ctx[0]],
00631 m->ciname[m->phone[p].info.cd.ctx[1]],
00632 m->ciname[m->phone[p].info.cd.ctx[2]],
00633 (WPOS_NAME)[m->phone[p].info.cd.wpos]);
00634
00635 if (bin_mdef_is_fillerphone(m, p))
00636 fprintf(fh, " %6s", "filler");
00637 else
00638 fprintf(fh, " %6s", "n/a");
00639 fprintf(fh, " %4d", m->phone[p].tmat);
00640
00641
00642 if (m->n_emit_state)
00643 n_state = m->n_emit_state;
00644 else
00645 n_state = m->sseq_len[m->phone[p].ssid];
00646 for (i = 0; i < n_state; i++) {
00647 fprintf(fh, " %6u", m->sseq[m->phone[p].ssid][i]);
00648 }
00649 fprintf(fh, " N\n");
00650 }
00651
00652 if (strcmp(filename, "-") != 0)
00653 fclose(fh);
00654 return 0;
00655 }
00656
00657 int
00658 bin_mdef_ciphone_id(bin_mdef_t * m, const char *ciphone)
00659 {
00660 int low, mid, high;
00661
00662
00663 low = 0;
00664 high = m->n_ciphone;
00665 while (low < high) {
00666 int c;
00667
00668 mid = (low + high) / 2;
00669 c = strcmp(ciphone, m->ciname[mid]);
00670 if (c == 0)
00671 return mid;
00672 else if (c > 0)
00673 low = mid + 1;
00674 else if (c < 0)
00675 high = mid;
00676 }
00677 return -1;
00678 }
00679
00680 int
00681 bin_mdef_ciphone_id_nocase(bin_mdef_t * m, const char *ciphone)
00682 {
00683 int low, mid, high;
00684
00685
00686 low = 0;
00687 high = m->n_ciphone;
00688 while (low < high) {
00689 int c;
00690
00691 mid = (low + high) / 2;
00692 c = strcmp_nocase(ciphone, m->ciname[mid]);
00693 if (c == 0)
00694 return mid;
00695 else if (c > 0)
00696 low = mid + 1;
00697 else if (c < 0)
00698 high = mid;
00699 }
00700 return -1;
00701 }
00702
00703 const char *
00704 bin_mdef_ciphone_str(bin_mdef_t * m, int32 ci)
00705 {
00706 assert(m != NULL);
00707 assert(ci < m->n_ciphone);
00708 return m->ciname[ci];
00709 }
00710
00711 int
00712 bin_mdef_phone_id(bin_mdef_t * m, int32 ci, int32 lc, int32 rc, int32 wpos)
00713 {
00714 cd_tree_t *cd_tree;
00715 int level, max;
00716 int16 ctx[4];
00717
00718 assert(m);
00719
00720
00721
00722 if (lc < 0 || rc < 0)
00723 return ci;
00724
00725 assert((ci >= 0) && (ci < m->n_ciphone));
00726 assert((lc >= 0) && (lc < m->n_ciphone));
00727 assert((rc >= 0) && (rc < m->n_ciphone));
00728 assert((wpos >= 0) && (wpos < N_WORD_POSN));
00729
00730
00731 ctx[0] = wpos;
00732 ctx[1] = ci;
00733 ctx[2] = (m->sil >= 0
00734 && m->phone[lc].info.ci.filler) ? m->sil : lc;
00735 ctx[3] = (m->sil >= 0
00736 && m->phone[rc].info.ci.filler) ? m->sil : rc;
00737
00738
00739 cd_tree = m->cd_tree;
00740 level = 0;
00741 max = N_WORD_POSN;
00742 while (level < 4) {
00743 int i;
00744
00745 #if 0
00746 E_INFO("Looking for context %d=%s in %d at %d\n",
00747 ctx[level], m->ciname[ctx[level]],
00748 max, cd_tree - m->cd_tree);
00749 #endif
00750 for (i = 0; i < max; ++i) {
00751 #if 0
00752 E_INFO("Look at context %d=%s at %d\n",
00753 cd_tree[i].ctx,
00754 m->ciname[cd_tree[i].ctx], cd_tree + i - m->cd_tree);
00755 #endif
00756 if (cd_tree[i].ctx == ctx[level])
00757 break;
00758 }
00759 if (i == max)
00760 return -1;
00761 #if 0
00762 E_INFO("Found context %d=%s at %d, n_down=%d, down=%d\n",
00763 ctx[level], m->ciname[ctx[level]],
00764 cd_tree + i - m->cd_tree,
00765 cd_tree[i].n_down, cd_tree[i].c.down);
00766 #endif
00767
00768 if (cd_tree[i].n_down == 0)
00769 return cd_tree[i].c.pid;
00770
00771
00772 max = cd_tree[i].n_down;
00773 cd_tree = m->cd_tree + cd_tree[i].c.down;
00774 ++level;
00775 }
00776
00777 return -1;
00778 }
00779
00780 int
00781 bin_mdef_phone_str(bin_mdef_t * m, int pid, char *buf)
00782 {
00783 char *wpos_name;
00784
00785 assert(m);
00786 assert((pid >= 0) && (pid < m->n_phone));
00787 wpos_name = WPOS_NAME;
00788
00789 buf[0] = '\0';
00790 if (pid < m->n_ciphone)
00791 sprintf(buf, "%s", bin_mdef_ciphone_str(m, pid));
00792 else {
00793 sprintf(buf, "%s %s %s %c",
00794 bin_mdef_ciphone_str(m, m->phone[pid].info.cd.ctx[0]),
00795 bin_mdef_ciphone_str(m, m->phone[pid].info.cd.ctx[1]),
00796 bin_mdef_ciphone_str(m, m->phone[pid].info.cd.ctx[2]),
00797 wpos_name[m->phone[pid].info.cd.wpos]);
00798 }
00799 return 0;
00800 }