📄 bin_mdef.c
字号:
/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- *//* ==================================================================== * Copyright (c) 2005 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. * * ==================================================================== * *//********************************************************************* * * File: bin_mdef.c * * Description: * Binary format model definition files, with support for * heterogeneous topologies and variable-size N-phones * * Author: * David Huggins-Daines <dhuggins@cs.cmu.edu> *********************************************************************/#include <stdio.h>#include <string.h>#include <assert.h>#include "bin_mdef.h"#include "s2types.h"#include "ckd_alloc.h"#include "byteorder.h"#include "err.h"bin_mdef_t *bin_mdef_read_text(const char *filename){ bin_mdef_t *bmdef; mdef_t *mdef; int i, nodes, ci_idx, lc_idx, rc_idx; int nchars; if ((mdef = mdef_init((char *) filename, TRUE)) == NULL) return NULL; bmdef = ckd_calloc(1, sizeof(*bmdef)); /* Easy stuff. The mdef.c code has done the heavy lifting for us. */ bmdef->n_ciphone = mdef->n_ciphone; bmdef->n_phone = mdef->n_phone; bmdef->n_emit_state = mdef->n_emit_state; bmdef->n_ci_sen = mdef->n_ci_sen; bmdef->n_sen = mdef->n_sen; bmdef->n_tmat = mdef->n_tmat; bmdef->n_sseq = mdef->n_sseq; bmdef->sseq = mdef->sseq; bmdef->cd2cisen = mdef->cd2cisen; bmdef->sen2cimap = mdef->sen2cimap; bmdef->n_ctx = 3; /* Triphones only. */ bmdef->sil = mdef->sil; mdef->sseq = NULL; /* We are taking over this one. */ mdef->cd2cisen = NULL; /* And this one. */ mdef->sen2cimap = NULL; /* And this one. */ /* Get the phone names. If they are not sorted * ASCII-betically then we are in a world of hurt and * therefore will simply refuse to continue. */ bmdef->ciname = ckd_calloc(bmdef->n_ciphone, sizeof(*bmdef->ciname)); nchars = 0; for (i = 0; i < bmdef->n_ciphone; ++i) nchars += strlen(mdef->ciphone[i].name) + 1; bmdef->ciname[0] = ckd_calloc(nchars, 1); strcpy(bmdef->ciname[0], mdef->ciphone[0].name); for (i = 1; i < bmdef->n_ciphone; ++i) { bmdef->ciname[i] = bmdef->ciname[i - 1] + strlen(bmdef->ciname[i - 1]) + 1; strcpy(bmdef->ciname[i], mdef->ciphone[i].name); if (i > 0 && strcmp(bmdef->ciname[i - 1], bmdef->ciname[i]) > 0) E_FATAL("Phone names are not in sorted order, sorry."); } /* Copy over phone information. */ bmdef->phone = ckd_calloc(bmdef->n_phone, sizeof(*bmdef->phone)); for (i = 0; i < mdef->n_phone; ++i) { bmdef->phone[i].ssid = mdef->phone[i].ssid; bmdef->phone[i].tmat = mdef->phone[i].tmat; if (i < bmdef->n_ciphone) { bmdef->phone[i].info.ci.filler = mdef->ciphone[i].filler; } else { bmdef->phone[i].info.cd.wpos = mdef->phone[i].wpos; bmdef->phone[i].info.cd.ctx[0] = mdef->phone[i].ci; bmdef->phone[i].info.cd.ctx[1] = mdef->phone[i].lc; bmdef->phone[i].info.cd.ctx[2] = mdef->phone[i].rc; } } /* Walk the wpos_ci_lclist once to find the total number of * nodes and the starting locations for each level. */ nodes = lc_idx = ci_idx = rc_idx = 0; for (i = 0; i < N_WORD_POSN; ++i) { int j; for (j = 0; j < mdef->n_ciphone; ++j) { ph_lc_t *lc; for (lc = mdef->wpos_ci_lclist[i][j]; lc; lc = lc->next) { ph_rc_t *rc; for (rc = lc->rclist; rc; rc = rc->next) { ++nodes; /* RC node */ } ++nodes; /* LC node */ ++rc_idx; /* Start of RC nodes (after LC nodes) */ } ++nodes; /* CI node */ ++lc_idx; /* Start of LC nodes (after CI nodes) */ ++rc_idx; /* Start of RC nodes (after CI and LC nodes) */ } ++nodes; /* wpos node */ ++ci_idx; /* Start of CI nodes (after wpos nodes) */ ++lc_idx; /* Start of LC nodes (after CI nodes) */ ++rc_idx; /* STart of RC nodes (after wpos, CI, and LC nodes) */ } E_INFO ("cd_tree: nodes %d wpos start 0 ci start %d lc start %d rc start %d\n", nodes, ci_idx, lc_idx, rc_idx); bmdef->n_cd_tree = nodes; bmdef->cd_tree = ckd_calloc(nodes, sizeof(*bmdef->cd_tree)); for (i = 0; i < N_WORD_POSN; ++i) { int j; bmdef->cd_tree[i].ctx = i; bmdef->cd_tree[i].n_down = mdef->n_ciphone; bmdef->cd_tree[i].c.down = ci_idx;#if 0 E_INFO("%d => %c (%d@%d)\n", i, (WPOS_NAME)[i], bmdef->cd_tree[i].n_down, bmdef->cd_tree[i].c.down);#endif /* Now we can build the rest of the tree. */ for (j = 0; j < mdef->n_ciphone; ++j) { ph_lc_t *lc; bmdef->cd_tree[ci_idx].ctx = j; bmdef->cd_tree[ci_idx].c.down = lc_idx; for (lc = mdef->wpos_ci_lclist[i][j]; lc; lc = lc->next) { ph_rc_t *rc; bmdef->cd_tree[lc_idx].ctx = lc->lc; bmdef->cd_tree[lc_idx].c.down = rc_idx; for (rc = lc->rclist; rc; rc = rc->next) { bmdef->cd_tree[rc_idx].ctx = rc->rc; bmdef->cd_tree[rc_idx].n_down = 0; bmdef->cd_tree[rc_idx].c.pid = rc->pid;#if 0 E_INFO("%d => %s %s %s %c (%d@%d)\n", rc_idx, bmdef->ciname[j], bmdef->ciname[lc->lc], bmdef->ciname[rc->rc], (WPOS_NAME)[i], bmdef->cd_tree[rc_idx].n_down, bmdef->cd_tree[rc_idx].c.down);#endif ++bmdef->cd_tree[lc_idx].n_down; ++rc_idx; } /* If there are no triphones here, * this is considered a leafnode, so * set the pid to BAD_S3PID. */ if (bmdef->cd_tree[lc_idx].n_down == 0) bmdef->cd_tree[lc_idx].c.pid = BAD_S3PID;#if 0 E_INFO("%d => %s %s %c (%d@%d)\n", lc_idx, bmdef->ciname[j], bmdef->ciname[lc->lc], (WPOS_NAME)[i], bmdef->cd_tree[lc_idx].n_down, bmdef->cd_tree[lc_idx].c.down);#endif ++bmdef->cd_tree[ci_idx].n_down; ++lc_idx; } /* As above, so below. */ if (bmdef->cd_tree[ci_idx].n_down == 0) bmdef->cd_tree[ci_idx].c.pid = BAD_S3PID;#if 0 E_INFO("%d => %d=%s (%d@%d)\n", ci_idx, j, bmdef->ciname[j], bmdef->cd_tree[ci_idx].n_down, bmdef->cd_tree[ci_idx].c.down);#endif ++ci_idx; } } mdef_free(mdef); bmdef->alloc_mode = BIN_MDEF_FROM_TEXT; return bmdef;}voidbin_mdef_free(bin_mdef_t * m){ if (m->alloc_mode == BIN_MDEF_FROM_TEXT) { ckd_free(m->sseq[0]); ckd_free(m->cd_tree); } if (m->alloc_mode == BIN_MDEF_IN_MEMORY) ckd_free(m->ciname[0]); ckd_free(m->ciname); ckd_free(m->sseq); ckd_free(m);}static const char format_desc[] = "BEGIN FILE FORMAT DESCRIPTION\n" "int32 n_ciphone; /**< Number of base (CI) phones */\n" "int32 n_phone; /**< Number of base (CI) phones + (CD) triphones */\n" "int32 n_emit_state; /**< Number of emitting states per phone (0 if heterogeneous) */\n" "int32 n_ci_sen; /**< Number of CI senones; these are the first */\n" "int32 n_sen; /**< Number of senones (CI+CD) */\n" "int32 n_tmat; /**< Number of transition matrices */\n" "int32 n_sseq; /**< Number of unique senone sequences */\n" "int32 n_ctx; /**< Number of phones of context */\n" "int32 n_cd_tree; /**< Number of nodes in CD tree structure */\n" "int32 sil; /**< CI phone ID for silence */\n" "char ciphones[][]; /**< CI phone strings (null-terminated) */\n" "char padding[]; /**< Padding to a 4-bytes boundary */\n" "struct { int16 ctx; int16 n_down; int32 pid/down } cd_tree[];\n" "struct { int32 ssid; int32 tmat; int8 attr[4] } phones[];\n" "int32 sseq[]; /**< Unique senone sequences */\n" "int8 sseq_len[]; /**< Number of states in each sseq (none if homogeneous) */\n" "END FILE FORMAT DESCRIPTION\n";bin_mdef_t *bin_mdef_read(const char *filename){ bin_mdef_t *m; FILE *fh; size_t tree_start; int32 val, i, swap, pos, end; int32 *sseq_size; /* Try to read it as text first. */ if ((m = bin_mdef_read_text(filename)) != NULL) return m; E_INFO("Reading binary model definition: %s\n", filename); if ((fh = fopen(filename, "rb")) == NULL) return NULL; if (fread(&val, 4, 1, fh) != 1) E_FATAL_SYSTEM("Failed to read byte-order marker from %s\n", filename); swap = 0; if (val == BIN_MDEF_OTHER_ENDIAN) { swap = 1; E_INFO("Must byte-swap %s\n", filename); } if (fread(&val, 4, 1, fh) != 1) E_FATAL_SYSTEM("Failed to read version from %s\n", filename); if (swap) SWAP_INT32(&val); if (val > BIN_MDEF_FORMAT_VERSION) { E_ERROR("File format version %d for %s is newer than library\n", val, filename); fclose(fh); return NULL; } if (fread(&val, 4, 1, fh) != 1) E_FATAL_SYSTEM("Failed to read header length from %s\n", filename); if (swap) SWAP_INT32(&val); /* Skip format descriptor. */ fseek(fh, val, SEEK_CUR); /* Finally allocate it. */ m = ckd_calloc(1, sizeof(*m)); /* Don't bother to check each one, since they will all fail if one failed. */ fread(&m->n_ciphone, 4, 1, fh); if (swap) SWAP_INT32(&m->n_ciphone); fread(&m->n_phone, 4, 1, fh); if (swap) SWAP_INT32(&m->n_phone); fread(&m->n_emit_state, 4, 1, fh); if (swap) SWAP_INT32(&m->n_emit_state); fread(&m->n_ci_sen, 4, 1, fh); if (swap) SWAP_INT32(&m->n_ci_sen); fread(&m->n_sen, 4, 1, fh); if (swap) SWAP_INT32(&m->n_sen); fread(&m->n_tmat, 4, 1, fh); if (swap) SWAP_INT32(&m->n_tmat); fread(&m->n_sseq, 4, 1, fh); if (swap) SWAP_INT32(&m->n_sseq); fread(&m->n_ctx, 4, 1, fh); if (swap) SWAP_INT32(&m->n_ctx); fread(&m->n_cd_tree, 4, 1, fh); if (swap) SWAP_INT32(&m->n_cd_tree); if (fread(&val, 4, 1, fh) != 1) E_FATAL_SYSTEM("Failed to read header from %s\n", filename); m->sil = val; /* Read the rest of the file as a big block of memory, and * carve it into the relevant chunks (in the future we will * mmap() it instead if possible). */ pos = ftell(fh); fseek(fh, 0, SEEK_END); end = ftell(fh); fseek(fh, pos, SEEK_SET); m->ciname = ckd_calloc(m->n_ciphone, sizeof(*m->ciname)); m->ciname[0] = ckd_malloc(end - pos); if (fread(m->ciname[0], 1, end - pos, fh) != end - pos) E_FATAL_SYSTEM("Failed to read %d bytes of data from %s\n", end - pos, filename); for (i = 1; i < m->n_ciphone; ++i) m->ciname[i] = m->ciname[i - 1] + strlen(m->ciname[i - 1]) + 1; /* Skip past the padding. */ tree_start = m->ciname[i - 1] + strlen(m->ciname[i - 1]) + 1 - m->ciname[0]; tree_start = (tree_start + 3) & ~3; m->cd_tree = (cd_tree_t *) (m->ciname[0] + tree_start); if (swap) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -