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