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
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 #include <stdio.h>
00087 #include <string.h>
00088 #include <stdlib.h>
00089 #include <assert.h>
00090
00091
00092 #include <ckd_alloc.h>
00093 #include <err.h>
00094
00095
00096 #include "mdef.h"
00097
00098
00099 #define MODEL_DEF_VERSION "0.3"
00100
00101 static void
00102 ciphone_add(mdef_t * m, char *ci, int p)
00103 {
00104 assert(p < m->n_ciphone);
00105
00106 m->ciphone[p].name = (char *) ckd_salloc(ci);
00107 if (hash_table_enter(m->ciphone_ht, m->ciphone[p].name,
00108 (void *)(long)p) != (void *)(long)p)
00109 E_FATAL("hash_table_enter(%s) failed; duplicate CIphone?\n",
00110 m->ciphone[p].name);
00111 }
00112
00113
00114 static ph_lc_t *
00115 find_ph_lc(ph_lc_t * lclist, int lc)
00116 {
00117 ph_lc_t *lcptr;
00118
00119 for (lcptr = lclist; lcptr && (lcptr->lc != lc); lcptr = lcptr->next);
00120 return lcptr;
00121 }
00122
00123
00124 static ph_rc_t *
00125 find_ph_rc(ph_rc_t * rclist, int rc)
00126 {
00127 ph_rc_t *rcptr;
00128
00129 for (rcptr = rclist; rcptr && (rcptr->rc != rc); rcptr = rcptr->next);
00130 return rcptr;
00131 }
00132
00133
00134 static void
00135 triphone_add(mdef_t * m,
00136 int ci, int lc, int rc, word_posn_t wpos,
00137 int p)
00138 {
00139 ph_lc_t *lcptr;
00140 ph_rc_t *rcptr;
00141
00142 assert(p < m->n_phone);
00143
00144
00145 m->phone[p].ci = ci;
00146 m->phone[p].lc = lc;
00147 m->phone[p].rc = rc;
00148 m->phone[p].wpos = wpos;
00149
00150
00151 if (p >= m->n_ciphone) {
00152 if ((lcptr = find_ph_lc(m->wpos_ci_lclist[wpos][(int) ci], lc))
00153 == NULL) {
00154 lcptr = (ph_lc_t *) ckd_calloc(1, sizeof(ph_lc_t));
00155 lcptr->lc = lc;
00156 lcptr->next = m->wpos_ci_lclist[wpos][(int) ci];
00157 m->wpos_ci_lclist[wpos][(int) ci] = lcptr;
00158 }
00159 if ((rcptr = find_ph_rc(lcptr->rclist, rc)) != NULL) {
00160 __BIGSTACKVARIABLE__ char buf[4096];
00161
00162 mdef_phone_str(m, rcptr->pid, buf);
00163 E_FATAL("Duplicate triphone: %s\n", buf);
00164 }
00165
00166 rcptr = (ph_rc_t *) ckd_calloc(1, sizeof(ph_rc_t));
00167 rcptr->rc = rc;
00168 rcptr->pid = p;
00169 rcptr->next = lcptr->rclist;
00170 lcptr->rclist = rcptr;
00171 }
00172 }
00173
00174
00175 int
00176 mdef_ciphone_id(mdef_t * m, char *ci)
00177 {
00178 int32 id;
00179 if (hash_table_lookup_int32(m->ciphone_ht, ci, &id) < 0)
00180 return -1;
00181 return id;
00182 }
00183
00184
00185 const char *
00186 mdef_ciphone_str(mdef_t * m, int id)
00187 {
00188 assert(m);
00189 assert((id >= 0) && (id < m->n_ciphone));
00190
00191 return (m->ciphone[id].name);
00192 }
00193
00194
00195 int
00196 mdef_phone_str(mdef_t * m, int pid, char *buf)
00197 {
00198 char *wpos_name;
00199
00200 assert(m);
00201 assert((pid >= 0) && (pid < m->n_phone));
00202 wpos_name = WPOS_NAME;
00203
00204 buf[0] = '\0';
00205 if (pid < m->n_ciphone)
00206 sprintf(buf, "%s", mdef_ciphone_str(m, pid));
00207 else {
00208 sprintf(buf, "%s %s %s %c",
00209 mdef_ciphone_str(m, m->phone[pid].ci),
00210 mdef_ciphone_str(m, m->phone[pid].lc),
00211 mdef_ciphone_str(m, m->phone[pid].rc),
00212 wpos_name[m->phone[pid].wpos]);
00213 }
00214 return 0;
00215 }
00216
00217
00218 int
00219 mdef_phone_id(mdef_t * m,
00220 int ci, int lc, int rc, word_posn_t wpos)
00221 {
00222 ph_lc_t *lcptr;
00223 ph_rc_t *rcptr;
00224 int newl, newr;
00225
00226 assert(m);
00227 assert((ci >= 0) && (ci < m->n_ciphone));
00228 assert((lc >= 0) && (lc < m->n_ciphone));
00229 assert((rc >= 0) && (rc < m->n_ciphone));
00230 assert((wpos >= 0) && (wpos < N_WORD_POSN));
00231
00232 if (((lcptr =
00233 find_ph_lc(m->wpos_ci_lclist[wpos][(int) ci], lc)) == NULL)
00234 || ((rcptr = find_ph_rc(lcptr->rclist, rc)) == NULL)) {
00235
00236 if (m->sil < 0)
00237 return -1;
00238
00239 newl = m->ciphone[(int) lc].filler ? m->sil : lc;
00240 newr = m->ciphone[(int) rc].filler ? m->sil : rc;
00241 if ((newl == lc) && (newr == rc))
00242 return -1;
00243
00244 return (mdef_phone_id(m, ci, newl, newr, wpos));
00245 }
00246
00247 return (rcptr->pid);
00248 }
00249
00250 int
00251 mdef_is_ciphone(mdef_t * m, int p)
00252 {
00253 assert(m);
00254 assert((p >= 0) && (p < m->n_phone));
00255
00256 return ((p < m->n_ciphone) ? 1 : 0);
00257 }
00258
00259 int
00260 mdef_is_cisenone(mdef_t * m, int s)
00261 {
00262 assert(m);
00263 if (s >= m->n_sen) {
00264 return 0;
00265 }
00266 assert(s >= 0);
00267 return ((s == m->cd2cisen[s]) ? 1 : 0);
00268 }
00269
00270
00271
00272 static void
00273 parse_tmat_senmap(mdef_t * m, char *line, int32 off, int p)
00274 {
00275 int32 wlen, n, s;
00276 __BIGSTACKVARIABLE__ char word[1024], *lp;
00277
00278 lp = line + off;
00279
00280
00281 if ((sscanf(lp, "%d%n", &n, &wlen) != 1) || (n < 0))
00282 E_FATAL("Missing or bad transition matrix id: %s\n", line);
00283 m->phone[p].tmat = n;
00284 if (m->n_tmat <= n)
00285 E_FATAL("tmat-id(%d) > #tmat in header(%d): %s\n", n, m->n_tmat,
00286 line);
00287 lp += wlen;
00288
00289
00290 for (n = 0; n < m->n_emit_state; n++) {
00291 if ((sscanf(lp, "%d%n", &s, &wlen) != 1) || (s < 0))
00292 E_FATAL("Missing or bad state[%d]->senone mapping: %s\n", n,
00293 line);
00294
00295
00296 m->phone[p].state[n] = s;
00297
00298 if ((p < m->n_ciphone) && (m->n_ci_sen <= s))
00299 E_FATAL("CI-senone-id(%d) > #CI-senones(%d): %s\n", s,
00300 m->n_ci_sen, line);
00301 if (m->n_sen <= s)
00302 E_FATAL("Senone-id(%d) > #senones(%d): %s\n", s, m->n_sen,
00303 line);
00304
00305 m->sseq[p][n] = s;
00306 lp += wlen;
00307 }
00308
00309
00310 if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (strcmp(word, "N") != 0))
00311 E_FATAL("Missing non-emitting state spec: %s\n", line);
00312 lp += wlen;
00313
00314
00315 if (sscanf(lp, "%s%n", word, &wlen) == 1)
00316 E_FATAL("Non-empty beyond non-emitting final state: %s\n", line);
00317 }
00318
00319
00320 static void
00321 parse_base_line(mdef_t * m, char *line, int p)
00322 {
00323 int32 wlen, n;
00324 __BIGSTACKVARIABLE__ char word[1024], *lp;
00325 int ci;
00326
00327 lp = line;
00328
00329
00330 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00331 E_FATAL("Missing base phone name: %s\n", line);
00332 lp += wlen;
00333
00334
00335 ci = mdef_ciphone_id(m, word);
00336 if (ci >= 0)
00337 E_FATAL("Duplicate base phone: %s\n", line);
00338
00339
00340 ciphone_add(m, word, p);
00341 ci = (int) p;
00342
00343
00344 for (n = 0; n < 3; n++) {
00345 if ((sscanf(lp, "%s%n", word, &wlen) != 1)
00346 || (strcmp(word, "-") != 0))
00347 E_FATAL("Bad context info for base phone: %s\n", line);
00348 lp += wlen;
00349 }
00350
00351
00352 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00353 E_FATAL("Missing filler atribute field: %s\n", line);
00354 lp += wlen;
00355 if (strcmp(word, "filler") == 0)
00356 m->ciphone[(int) ci].filler = 1;
00357 else if (strcmp(word, "n/a") == 0)
00358 m->ciphone[(int) ci].filler = 0;
00359 else
00360 E_FATAL("Bad filler attribute field: %s\n", line);
00361
00362 triphone_add(m, ci, -1, -1, WORD_POSN_UNDEFINED, p);
00363
00364
00365 parse_tmat_senmap(m, line, lp - line, p);
00366 }
00367
00368
00369 static void
00370 parse_tri_line(mdef_t * m, char *line, int p)
00371 {
00372 int32 wlen;
00373 __BIGSTACKVARIABLE__ char word[1024], *lp;
00374 int ci, lc, rc;
00375 word_posn_t wpos = WORD_POSN_BEGIN;
00376
00377 lp = line;
00378
00379
00380 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00381 E_FATAL("Missing base phone name: %s\n", line);
00382 lp += wlen;
00383
00384 ci = mdef_ciphone_id(m, word);
00385 if (ci < 0)
00386 E_FATAL("Unknown base phone: %s\n", line);
00387
00388
00389 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00390 E_FATAL("Missing left context: %s\n", line);
00391 lp += wlen;
00392 lc = mdef_ciphone_id(m, word);
00393 if (lc < 0)
00394 E_FATAL("Unknown left context: %s\n", line);
00395
00396
00397 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00398 E_FATAL("Missing right context: %s\n", line);
00399 lp += wlen;
00400 rc = mdef_ciphone_id(m, word);
00401 if (rc < 0)
00402 E_FATAL("Unknown right context: %s\n", line);
00403
00404
00405 if ((sscanf(lp, "%s%n", word, &wlen) != 1) || (word[1] != '\0'))
00406 E_FATAL("Missing or bad word-position spec: %s\n", line);
00407 lp += wlen;
00408 switch (word[0]) {
00409 case 'b':
00410 wpos = WORD_POSN_BEGIN;
00411 break;
00412 case 'e':
00413 wpos = WORD_POSN_END;
00414 break;
00415 case 's':
00416 wpos = WORD_POSN_SINGLE;
00417 break;
00418 case 'i':
00419 wpos = WORD_POSN_INTERNAL;
00420 break;
00421 default:
00422 E_FATAL("Bad word-position spec: %s\n", line);
00423 }
00424
00425
00426 if (sscanf(lp, "%s%n", word, &wlen) != 1)
00427 E_FATAL("Missing filler attribute field: %s\n", line);
00428 lp += wlen;
00429 if (((strcmp(word, "filler") == 0) && (m->ciphone[(int) ci].filler)) ||
00430 ((strcmp(word, "n/a") == 0) && (!m->ciphone[(int) ci].filler))) {
00431
00432 }
00433 else
00434 E_FATAL("Bad filler attribute field: %s\n", line);
00435
00436 triphone_add(m, ci, lc, rc, wpos, p);
00437
00438
00439 parse_tmat_senmap(m, line, lp - line, p);
00440 }
00441
00442
00443 static void
00444 sseq_compress(mdef_t * m)
00445 {
00446 hash_table_t *h;
00447 int16 **sseq;
00448 int32 n_sseq;
00449 int32 p, j, k;
00450 glist_t g;
00451 gnode_t *gn;
00452 hash_entry_t *he;
00453
00454 k = m->n_emit_state * sizeof(int16);
00455
00456 h = hash_table_new(m->n_phone, HASH_CASE_YES);
00457 n_sseq = 0;
00458
00459
00460 for (p = 0; p < m->n_phone; p++) {
00461
00462 if (n_sseq
00463 == (j = hash_table_enter_bkey_int32(h, (char *)m->sseq[p], k, n_sseq)))
00464 n_sseq++;
00465
00466 m->phone[p].ssid = j;
00467 }
00468
00469
00470 sseq = (int16 **) ckd_calloc_2d(n_sseq, m->n_emit_state, sizeof(int16));
00471
00472 g = hash_table_tolist(h, &j);
00473 assert(j == n_sseq);
00474
00475 for (gn = g; gn; gn = gnode_next(gn)) {
00476 he = (hash_entry_t *) gnode_ptr(gn);
00477 j = (long)hash_entry_val(he);
00478 memcpy(sseq[j], hash_entry_key(he), k);
00479 }
00480 glist_free(g);
00481
00482
00483 ckd_free_2d(m->sseq);
00484 m->sseq = sseq;
00485 m->n_sseq = n_sseq;
00486
00487 hash_table_free(h);
00488 }
00489
00490
00491 static int32
00492 noncomment_line(char *line, int32 size, FILE * fp)
00493 {
00494 while (fgets(line, size, fp) != NULL) {
00495 if (line[0] != '#')
00496 return 0;
00497 }
00498 return -1;
00499 }
00500
00501
00502
00503
00504
00505 mdef_t *
00506 mdef_init(char *mdeffile, int32 breport)
00507 {
00508 FILE *fp;
00509 int32 n_ci, n_tri, n_map, n;
00510 __BIGSTACKVARIABLE__ char tag[1024], buf[1024];
00511 int16 **senmap;
00512 int p;
00513 int32 s, ci, cd;
00514 mdef_t *m;
00515
00516 if (!mdeffile)
00517 E_FATAL("No mdef-file\n");
00518
00519 if (breport)
00520 E_INFO("Reading model definition: %s\n", mdeffile);
00521
00522 m = (mdef_t *) ckd_calloc(1, sizeof(mdef_t));
00523
00524 if ((fp = fopen(mdeffile, "r")) == NULL)
00525 E_FATAL_SYSTEM("fopen(%s,r) failed\n", mdeffile);
00526
00527 if (noncomment_line(buf, sizeof(buf), fp) < 0)
00528 E_FATAL("Empty file: %s\n", mdeffile);
00529
00530 if (strncmp(buf, "BMDF", 4) == 0 || strncmp(buf, "FDMB", 4) == 0) {
00531 E_INFO
00532 ("Found byte-order mark %.4s, assuming this is a binary mdef file\n",
00533 buf);
00534 fclose(fp);
00535 ckd_free(m);
00536 return NULL;
00537 }
00538 if (strncmp(buf, MODEL_DEF_VERSION, strlen(MODEL_DEF_VERSION)) != 0)
00539 E_FATAL("Version error: Expecing %s, but read %s\n",
00540 MODEL_DEF_VERSION, buf);
00541
00542
00543 n_ci = -1;
00544 n_tri = -1;
00545 n_map = -1;
00546 m->n_ci_sen = -1;
00547 m->n_sen = -1;
00548 m->n_tmat = -1;
00549 do {
00550 if (noncomment_line(buf, sizeof(buf), fp) < 0)
00551 E_FATAL("Incomplete header\n");
00552
00553 if ((sscanf(buf, "%d %s", &n, tag) != 2) || (n < 0))
00554 E_FATAL("Error in header: %s\n", buf);
00555
00556 if (strcmp(tag, "n_base") == 0)
00557 n_ci = n;
00558 else if (strcmp(tag, "n_tri") == 0)
00559 n_tri = n;
00560 else if (strcmp(tag, "n_state_map") == 0)
00561 n_map = n;
00562 else if (strcmp(tag, "n_tied_ci_state") == 0)
00563 m->n_ci_sen = n;
00564 else if (strcmp(tag, "n_tied_state") == 0)
00565 m->n_sen = n;
00566 else if (strcmp(tag, "n_tied_tmat") == 0)
00567 m->n_tmat = n;
00568 else
00569 E_FATAL("Unknown header line: %s\n", buf);
00570 } while ((n_ci < 0) || (n_tri < 0) || (n_map < 0) ||
00571 (m->n_ci_sen < 0) || (m->n_sen < 0) || (m->n_tmat < 0));
00572
00573 if ((n_ci == 0) || (m->n_ci_sen == 0) || (m->n_tmat == 0)
00574 || (m->n_ci_sen > m->n_sen))
00575 E_FATAL("%s: Error in header\n", mdeffile);
00576
00577
00578 if (n_ci >= MAX_INT16)
00579 E_FATAL("%s: #CI phones (%d) exceeds limit (%d)\n", mdeffile, n_ci,
00580 MAX_INT16);
00581 if (n_ci + n_tri >= MAX_INT32)
00582 E_FATAL("%s: #Phones (%d) exceeds limit (%d)\n", mdeffile,
00583 n_ci + n_tri, MAX_INT32);
00584 if (m->n_sen >= MAX_INT16)
00585 E_FATAL("%s: #senones (%d) exceeds limit (%d)\n", mdeffile,
00586 m->n_sen, MAX_INT16);
00587 if (m->n_tmat >= MAX_INT32)
00588 E_FATAL("%s: #tmats (%d) exceeds limit (%d)\n", mdeffile,
00589 m->n_tmat, MAX_INT32);
00590
00591 m->n_emit_state = (n_map / (n_ci + n_tri)) - 1;
00592 if ((m->n_emit_state + 1) * (n_ci + n_tri) != n_map)
00593 E_FATAL
00594 ("Header error: n_state_map not a multiple of n_ci*n_tri\n");
00595
00596
00597 m->n_ciphone = n_ci;
00598 m->ciphone_ht = hash_table_new(n_ci, 1);
00599 m->ciphone = (ciphone_t *) ckd_calloc(n_ci, sizeof(ciphone_t));
00600
00601
00602 m->n_phone = n_ci + n_tri;
00603 m->phone = (phone_t *) ckd_calloc(m->n_phone, sizeof(phone_t));
00604
00605
00606 senmap = (int16 **) ckd_calloc_2d(m->n_phone, m->n_emit_state, sizeof(**senmap));
00607 m->sseq = senmap;
00608
00609
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 m->st2senmap =
00625 (int16 *) ckd_calloc(m->n_phone * m->n_emit_state,
00626 sizeof(*m->st2senmap));
00627 for (p = 0; p < m->n_phone; p++)
00628 m->phone[p].state = m->st2senmap + (p * m->n_emit_state);
00629
00630
00631
00632
00633 m->wpos_ci_lclist = (ph_lc_t ***) ckd_calloc_2d(N_WORD_POSN, m->n_ciphone, sizeof(ph_lc_t *));
00634
00635
00636
00637
00638
00639
00640
00641 for (p = 0; p < n_ci; p++) {
00642 if (noncomment_line(buf, sizeof(buf), fp) < 0)
00643 E_FATAL("Premature EOF reading CIphone %d\n", p);
00644 parse_base_line(m, buf, p);
00645 }
00646 m->sil = mdef_ciphone_id(m, S3_SILENCE_CIPHONE);
00647
00648
00649 for (; p < m->n_phone; p++) {
00650 if (noncomment_line(buf, sizeof(buf), fp) < 0)
00651 E_FATAL("Premature EOF reading phone %d\n", p);
00652 parse_tri_line(m, buf, p);
00653 }
00654
00655 if (noncomment_line(buf, sizeof(buf), fp) >= 0)
00656 E_ERROR("Non-empty file beyond expected #phones (%d)\n",
00657 m->n_phone);
00658
00659
00660 if (m->n_ciphone * m->n_emit_state != m->n_ci_sen)
00661 E_FATAL
00662 ("#CI-senones(%d) != #CI-phone(%d) x #emitting-states(%d)\n",
00663 m->n_ci_sen, m->n_ciphone, m->n_emit_state);
00664 m->cd2cisen = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->cd2cisen));
00665
00666 m->sen2cimap = (int16 *) ckd_calloc(m->n_sen, sizeof(*m->sen2cimap));
00667
00668 for (s = 0; s < m->n_sen; s++)
00669 m->sen2cimap[s] = -1;
00670 for (s = 0; s < m->n_ci_sen; s++) {
00671 m->cd2cisen[s] = s;
00672 m->sen2cimap[s] = s / m->n_emit_state;
00673 }
00674 for (p = n_ci; p < m->n_phone; p++) {
00675 for (s = 0; s < m->n_emit_state; s++) {
00676 cd = m->sseq[p][s];
00677 ci = m->sseq[m->phone[p].ci][s];
00678 m->cd2cisen[cd] = ci;
00679 m->sen2cimap[cd] = m->phone[p].ci;
00680 }
00681 }
00682
00683 sseq_compress(m);
00684 fclose(fp);
00685
00686 return m;
00687 }
00688
00689 void
00690 mdef_report(mdef_t * m)
00691 {
00692 E_INFO_NOFN("Initialization of mdef_t, report:\n");
00693 E_INFO_NOFN
00694 ("%d CI-phone, %d CD-phone, %d emitstate/phone, %d CI-sen, %d Sen, %d Sen-Seq\n",
00695 m->n_ciphone, m->n_phone - m->n_ciphone, m->n_emit_state,
00696 m->n_ci_sen, m->n_sen, m->n_sseq);
00697 E_INFO_NOFN("\n");
00698
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712 void
00713 mdef_free_recursive_lc(ph_lc_t * lc)
00714 {
00715 if (lc == NULL)
00716 return;
00717
00718 if (lc->rclist)
00719 mdef_free_recursive_rc(lc->rclist);
00720
00721 if (lc->next)
00722 mdef_free_recursive_lc(lc->next);
00723
00724 ckd_free((void *) lc);
00725 }
00726
00727 void
00728 mdef_free_recursive_rc(ph_rc_t * rc)
00729 {
00730 if (rc == NULL)
00731 return;
00732
00733 if (rc->next)
00734 mdef_free_recursive_rc(rc->next);
00735
00736 ckd_free((void *) rc);
00737 }
00738
00739
00740
00741
00742
00743
00744 void
00745 mdef_free(mdef_t * m)
00746 {
00747 int i, j;
00748
00749 if (m) {
00750 if (m->sen2cimap)
00751 ckd_free((void *) m->sen2cimap);
00752 if (m->cd2cisen)
00753 ckd_free((void *) m->cd2cisen);
00754
00755
00756 for (i = 0; i < N_WORD_POSN; i++)
00757 for (j = 0; j < m->n_ciphone; j++)
00758 if (m->wpos_ci_lclist[i][j]) {
00759 mdef_free_recursive_lc(m->wpos_ci_lclist[i][j]->next);
00760 mdef_free_recursive_rc(m->wpos_ci_lclist[i][j]->
00761 rclist);
00762 }
00763
00764 for (i = 0; i < N_WORD_POSN; i++)
00765 for (j = 0; j < m->n_ciphone; j++)
00766 if (m->wpos_ci_lclist[i][j])
00767 ckd_free((void *) m->wpos_ci_lclist[i][j]);
00768
00769
00770 if (m->wpos_ci_lclist)
00771 ckd_free_2d((void *) m->wpos_ci_lclist);
00772 if (m->sseq)
00773 ckd_free_2d((void *) m->sseq);
00774
00775 if (m->phone)
00776 ckd_free((void *) m->phone);
00777 if (m->ciphone_ht)
00778 hash_table_free(m->ciphone_ht);
00779
00780 for (i = 0; i < m->n_ciphone; i++) {
00781 if (m->ciphone[i].name)
00782 ckd_free((void *) m->ciphone[i].name);
00783 }
00784
00785
00786 if (m->ciphone)
00787 ckd_free((void *) m->ciphone);
00788
00789 if (m->st2senmap)
00790 ckd_free((void *) m->st2senmap);
00791
00792 ckd_free((void *) m);
00793 }
00794 }