1 /**
2 * @file rdhmmdef_tiedmix.c
3 *
4 * <JA>
5 * @brief HTK %HMM ����ե�������ɤ߹��ߡ�tied-mixture��ǥ�κ���ʬ�ۥ����ɥ֥å�
6 * </JA>
7 *
8 * <EN>
9 * @brief Read HTK %HMM definition file: mixture codebook in tied-mixture model
10 * </EN>
11 *
12 * @author Akinobu LEE
13 * @date Wed Feb 16 03:25:11 2005
14 *
15 * $Revision: 1.4 $
16 *
17 */
18 /*
19 * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
20 * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
21 * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
22 * All rights reserved
23 */
24
25 #include <sent/stddefs.h>
26 #include <sent/htk_hmm.h>
27
28 extern char *rdhmmdef_token; ///< Current token
29
30 /**
31 * Look up a data macro by the name.
32 *
33 * @param hmm [in] %HMM definition data
34 * @param keyname [in] macro name to find
35 *
36 * @return pointer to the found data, or NULL if not found.
37 */
38 static GCODEBOOK *
codebook_lookup(HTK_HMM_INFO * hmm,char * keyname)39 codebook_lookup(HTK_HMM_INFO *hmm, char *keyname)
40 {
41 GCODEBOOK *book;
42
43 if (hmm->codebook_root == NULL) return(NULL);
44 book = aptree_search_data(keyname, hmm->codebook_root);
45 if (book != NULL && strmatch(book->name, keyname)) {
46 return book;
47 } else {
48 return NULL;
49 }
50 }
51
52 /**
53 * Add a new data to the global structure.
54 *
55 * @param hmm [i/o] %HMM definition data to store it
56 * @param new [in] new data to be added
57 */
58 void
codebook_add(HTK_HMM_INFO * hmm,GCODEBOOK * new)59 codebook_add(HTK_HMM_INFO *hmm, GCODEBOOK *new)
60 {
61 GCODEBOOK *match;
62 if (hmm->codebook_root == NULL) {
63 hmm->codebook_root = aptree_make_root_node(new, &(hmm->mroot));
64 } else {
65 match = aptree_search_data(new->name, hmm->codebook_root);
66 if (match != NULL && strmatch(match->name, new->name)) {
67 jlog("Error: rdhmmdef_tiedmix: ~s \"%s\" is already defined\n", new->name);
68 rderr(NULL);
69 } else {
70 aptree_add_entry(new->name, new, match->name, &(hmm->codebook_root), &(hmm->mroot));
71 }
72 }
73 }
74
75 /**
76 * @brief Convert codebook ID to the defined %HMM density
77 *
78 * This function assigns a list of %HMM density definition to the
79 * given codebook. The densities are searched by the name of
80 * codebook name followed by the mixture component ID starting from 1.
81 * For example, if you have a codebook whose name is "ny4s2m", The densities
82 * of names like "ny4s2m1", "ny4s2m2", ... will be searched through the
83 * %HMM definition data. The resulting list will be stored in the codebook.
84 *
85 * If some density definitions are not found, they are just skipped.
86 * In this case, a warning message will be output to standard error.
87 *
88 * @param hmminfo [in] %HMM definition data that has densities
89 * @param book [i/o] codebook, name given and density list will be stored.
90 */
91 static void
tmix_create_codebook_index(HTK_HMM_INFO * hmminfo,GCODEBOOK * book)92 tmix_create_codebook_index(HTK_HMM_INFO *hmminfo, GCODEBOOK *book)
93 {
94 char *mixname;
95 HTK_HMM_Dens *dtmp;
96 int i;
97 int realbooknum = 0;
98
99 mixname = (char *)mymalloc(strlen(book->name)+30);
100 book->d = (HTK_HMM_Dens **) mybmalloc2(sizeof(HTK_HMM_Dens *) * book->num, &(hmminfo->mroot));
101 for (i=0;i<book->num;i++) {
102 sprintf(mixname, "%s%d", book->name, i + 1);
103 if ((dtmp = dens_lookup(hmminfo, mixname)) == NULL) {
104 /*
105 * jlog("Error: mixture \"%s\" (%dth mixture in codebook \"%s\") not found\n", mixname, i + 1, book->name);
106 * rderr(NULL);
107 */
108 book->d[i] = NULL;
109 } else {
110 book->d[i] = dtmp;
111 realbooknum++;
112 }
113 }
114 if (realbooknum < book->num) {
115 jlog("Warning: rdhmmdef_tiedmix: book [%s]: defined=%d < %d\n",
116 book->name, realbooknum, book->num);
117 }
118
119 free(mixname);
120 }
121
122 /**
123 * @brief Read a codebook name and weights, build the codebook structure
124 * on demand, and assigns them to the current mixture PDF.
125 *
126 * The required codebook on the current token will be assigned to this
127 * mpdf. If the corresponding codebook structure is not built yet,
128 * it will be constructed here on demand by gathering corresponding mixture
129 * density definitions. Then this mpdf will store the pointer to the
130 * codebook, together with its own mixture weights in the following tokens.
131 *
132 * @param fp [in] file pointer
133 * @param mpdf [i/o] current %HMM mixture PDF to hold pointer to the codebook and their weights
134 * @param hmm [i/o] %HMM definition data, codebook statistics and tied-mixture marker will be modified.
135 */
136 void
tmix_read(FILE * fp,HTK_HMM_PDF * mpdf,HTK_HMM_INFO * hmm)137 tmix_read(FILE *fp, HTK_HMM_PDF *mpdf, HTK_HMM_INFO *hmm)
138 {
139 char *bookname;
140 GCODEBOOK *thebook;
141 int mid, i;
142
143 NoTokErr("missing TMIX bookname");
144 bookname = rdhmmdef_token;
145 /* check whether the specified codebook exist */
146 if ((thebook = codebook_lookup(hmm, bookname)) == NULL) {
147 /* create GCODEBOOK global index structure from mixture macros */
148 thebook = (GCODEBOOK *)mybmalloc2(sizeof(GCODEBOOK), &(hmm->mroot));
149 thebook->name = mybstrdup2(bookname, &(hmm->mroot));
150 thebook->num = mpdf->mix_num;
151 /* map codebook id to HTK_HMM_Dens* */
152 tmix_create_codebook_index(hmm, thebook);
153 /* register the new codebook */
154 codebook_add(hmm, thebook);
155 thebook->id = hmm->codebooknum;
156 hmm->codebooknum++;
157 /* set maximum codebook size */
158 if (hmm->maxcodebooksize < thebook->num) hmm->maxcodebooksize = thebook->num;
159 } else {
160 /* check coherence */
161 if (mpdf->mix_num != thebook->num) {
162 rderr("tmix_read: TMIX weight num don't match the codebook size");
163 }
164 }
165
166 /* set pointer to the GCODEBOOK structure */
167 mpdf->b = (HTK_HMM_Dens **)thebook;
168
169 /* store the weights to `mpdf->bweight[]' */
170 read_token(fp);
171 mpdf->bweight = (PROB *) mybmalloc2(sizeof(PROB) * mpdf->mix_num, &(hmm->mroot));
172 {
173 int len;
174 double w;
175
176 mid = 0;
177 while (mid < mpdf->mix_num)
178 {
179 char *p, q;
180 NoTokErr("missing some TMIX weights");
181 if ((p = strchr(rdhmmdef_token, '*')) == NULL) {
182 len = 1;
183 w = atof(rdhmmdef_token);
184 } else {
185 len = atoi(p+1);
186 q = *p;
187 *p = '\0';
188 w = atof(rdhmmdef_token);
189 *p = q;
190 }
191 read_token(fp);
192 for(i=0;i<len;i++) {
193 mpdf->bweight[mid] = (PROB)log(w);
194 mid++;
195 }
196 }
197 }
198
199 /* mark info as tied mixture */
200 hmm->is_tied_mixture = TRUE;
201 }
202
203