/**
* @file hmm_lookup.c
*
*
* @brief %HMM の名前から実体を検索する
*
* "g-u+i" などの %HMM 論理名から,対応する %HMM の定義を検索します.
*
* 検索結果は論理%HMM HMM_Logical へのポインタで返されます.HMM_Logical は,
* 実際に定義されている %HMM へのポインタか,あるいはバイフォン・モノフォン
* の論理%HMM名でかつそれらが%HMM定義ファイルやHMMListで定義されていない場合,
* 対応する pseudo %HMM set へのポインタのどちらかを保持しています.
*
* また,論理名から定義名へのマッピング関数への実%HMM名と pseudo %HMM名の
* 追加登録もここで行ないます.
*
*
*
* @brief Look up logical %HMM entry from phone name
*
* These function is for searching %HMM definition from phone name
* like "g-u+i".
*
* The result is pointer to the corresponding logical %HMM (HMM_Logical).
* The logical %HMM holds either pointer to an actual %HMM data defined in
* HTK %HMM definition, or pointer to a pseudo %HMM set when the query name
* is biphone or monophone and they are not defined in either HTK %HMM
* definition or HMMList mapping file.
*
* Adding physical %HMM defined in HTK %HMM definitions and pseudo phones
* to the logical %HMM mapping function is also done here.
*
*
* @author Akinobu LEE
* @date Tue Feb 15 22:34:30 2005
*
* $Revision: 1.6 $
*
*/
/*
* Copyright (c) 1991-2012 Kawahara Lab., Kyoto University
* Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
* Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology
* All rights reserved
*/
/* physical HMMs ... already indexed when reading in hmmdefs */
/* logical HMMs ... already indexed when reading in HMMList */
#include
#include
#include
/**
* Look up physical (defined in HTK %HMM definition file) %HMM by its name.
*
* @param hmminfo [in] HMM definition data
* @param keyname [in] key string of %HMM name
*
* @return pointer to the found physical %HMM, NULL if not found.
*/
HTK_HMM_Data *
htk_hmmdata_lookup_physical(HTK_HMM_INFO *hmminfo, char *keyname)
{
HTK_HMM_Data *tmp;
tmp = aptree_search_data(keyname, hmminfo->physical_root);
if (tmp != NULL && strmatch(tmp->name, keyname)) {
return tmp;
} else {
return NULL;
}
}
/**
* Look up logical %HMM by its name.
*
* @param hmminfo [in] HMM definition data
* @param keyname [in] key string of %HMM name
*
* @return pointer to the found logical %HMM, NULL if not found.
*/
HMM_Logical *
htk_hmmdata_lookup_logical(HTK_HMM_INFO *hmminfo, char *keyname)
{
HMM_Logical *tmp;
tmp = aptree_search_data(keyname, hmminfo->logical_root);
if (tmp != NULL && strmatch(tmp->name, keyname)) {
return tmp;
} else {
return NULL;
}
}
/**
* Count the number of logical %HMM and store it.
*
* @param hmminfo [in] %HMM definition data.
*/
static void
hmm_count_logical_num(HTK_HMM_INFO *hmminfo)
{
HMM_Logical *lg;
int n;
n = 0;
for (lg = hmminfo->lgstart; lg; lg = lg->next) n++;
hmminfo->totallogicalnum = n;
}
/**
* @brief Add all physical %HMM to logical %HMM.
*
* This function should be called only if HMMList is not specified.
* Julius assumes all the triphones should be explicitly mapped
* using HMMList file.
*
* @param hmminfo [in] %HMM definition data.
*/
void
hmm_add_physical_to_logical(HTK_HMM_INFO *hmminfo)
{
HMM_Logical *new, *match = NULL;
HTK_HMM_Data *ph;
for (ph = hmminfo->start; ph; ph = ph->next) {
/* check if same name already exist */
if (hmminfo->logical_root != NULL) {
match = aptree_search_data(ph->name, hmminfo->logical_root);
if (match != NULL && strmatch(match->name, ph->name)) {
/* the physcal name was already mapped to other HMMs in HMMList */
jlog("Warning: hmm_lookup: \"%s\" is defined in hmmdefs, but \"%s\" will be used instead\n", ph->name, (match->body.defined)->name);
continue;
}
}
/* create new HMM_Logical */
/* body refers to the physical HMM */
new = (HMM_Logical *)mybmalloc2(sizeof(HMM_Logical), &(hmminfo->lroot));
new->name = (char *)mybmalloc2(strlen(ph->name) + 1, &(hmminfo->lroot));
strcpy(new->name, ph->name);
new->is_pseudo = FALSE;
new->body.defined = ph;
new->next = hmminfo->lgstart;
hmminfo->lgstart = new;
if (hmminfo->logical_root == NULL) {
hmminfo->logical_root = aptree_make_root_node(new, &(hmminfo->lroot));
} else {
aptree_add_entry(new->name, new, match->name, &(hmminfo->logical_root), &(hmminfo->lroot));
}
}
/* re-count total number */
hmm_count_logical_num(hmminfo);
}
/**
* @brief Add a pseudo monophone and pseudo biphone to logical %HMM.
*
* Logical %HMM specified in HMMlist precedes
* pseudo %HMM: if some monophones or biphones are already
* defined in HMMList, pseudo %HMM will not be added.
*
* @param hmminfo [in] %HMM definition data.
* @param name [in] name of the pseudo phone to add.
*/
static boolean
hmm_add_pseudo_phones_sub(HTK_HMM_INFO *hmminfo, char *name)
{
HMM_Logical *new, *match;
/* check if already exist */
match = aptree_search_data(name, hmminfo->logical_root);
if (match != NULL && strmatch(match->name, name)) {
/* already exist in list */
/* if (! match->is_pseudo) {*/
/* this pseudo-HMM is already defined as real HMM in hmmdefs or in HMMList */
/*designated_count++;
}*/
} else {
/* create new HMM_Logical with pseudo body */
new = (HMM_Logical *)mybmalloc2(sizeof(HMM_Logical), &(hmminfo->lroot));
new->name = (char *)mybmalloc2(strlen(name) + 1, &(hmminfo->lroot));
strcpy(new->name, name);
new->is_pseudo = TRUE;
new->body.pseudo = cdset_lookup(hmminfo, name);
if (new->body.pseudo == NULL) { /* should never happen */
jlog("Error: hmm_lookup: tried to add pseudo phone \"%s\" to logical HMM, but no corresponding CD_Set found. Why??\n");
return FALSE;
}
new->next = hmminfo->lgstart;
hmminfo->lgstart = new;
if (hmminfo->logical_root == NULL) {
hmminfo->logical_root = aptree_make_root_node(new, &(hmminfo->lroot));
} else {
aptree_add_entry(new->name, new, match->name, &(hmminfo->logical_root), &(hmminfo->lroot));
}
hmminfo->totalpseudonum++;
}
return TRUE;
}
/**
* Update logical %HMM list by adding all the possible pseudo monophone
* and biphone to the list.
*
* @param hmminfo [in] %HMM definition data.
*/
void
hmm_add_pseudo_phones(HTK_HMM_INFO *hmminfo)
{
HMM_Logical *lg;
char buf[MAX_HMMNAME_LEN];
boolean ok_p = TRUE;
hmminfo->totalpseudonum = 0;
/* add pseudo monophone */
for (lg = hmminfo->lgstart; lg; lg = lg->next) {
if (lg->is_pseudo) continue;
if (hmm_add_pseudo_phones_sub(hmminfo, center_name(lg->name, buf)) == FALSE) {
jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", center_name(lg->name, buf));
ok_p = FALSE;
}
}
/* add pseudo biphone, i.e. "a-k" etc. */
for (lg = hmminfo->lgstart; lg; lg = lg->next) {
if (lg->is_pseudo) continue;
if (hmm_add_pseudo_phones_sub(hmminfo, leftcenter_name(lg->name, buf)) == FALSE) {
jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", leftcenter_name(lg->name, buf));
ok_p = FALSE;
}
}
/* add pseudo biphone, i.e. "k+e" etc. */
for (lg = hmminfo->lgstart; lg; lg = lg->next) {
if (lg->is_pseudo) continue;
if (hmm_add_pseudo_phones_sub(hmminfo, rightcenter_name(lg->name, buf)) == FALSE) {
jlog("Error: hmm_lookup: failed to add \"%s\" as logical\n", rightcenter_name(lg->name, buf));
ok_p = FALSE;
}
}
jlog("Stat: hmm_lookup: %d pseudo phones are added to logical HMM list\n", hmminfo->totalpseudonum);
/* re-count total number */
hmm_count_logical_num(hmminfo);
}
/**
* Generic function to get the number of states in a logical %HMM.
*
* @param lg [in] logical %HMM
*
* @return the number of states in the logical %HMM.
*/
int
hmm_logical_state_num(HMM_Logical *lg)
{
int len;
if (lg->is_pseudo) len = lg->body.pseudo->state_num;
else len = lg->body.defined->state_num;
return(len);
}
/**
* Generic function to get transition matrix of a logical %HMM.
*
* @param lg [in] logical %HMM
*
* @return pointer to the transition matrix of the logical %HMM.
*/
HTK_HMM_Trans *
hmm_logical_trans(HMM_Logical *lg)
{
HTK_HMM_Trans *tr;
if (lg->is_pseudo) tr = lg->body.pseudo->tr;
else tr = lg->body.defined->tr;
return(tr);
}