构建单词发音词内环境依赖音子,如果发音序列包含的音子数少于2,则为零。
也就是当nphones>=3时,才会触发这个操作,看for循环,只有当q>=2时,才执行循环体内。
void CreateWIModels(PronHolder *pInst,int p,int q, Network *net,HMMSetCxtInfo *hci)
{
NetNode *node;
HLink hmm;
int j;
for(j=q-1;j>p;j--) {
hmm=GetHCIModel(hci,FindLContext(hci,pInst,j,0),
pInst->phones[j],
FindRContext(hci,pInst,j,0));
if (hmm->transP[1][hmm->numStates]<LSMALL) pInst->tee=FALSE;
nwi++;
node=NewNode(net->heap,hmm,(pInst->chain==NULL?0:1));
if (pInst->chain!=NULL) {
nil++;
node->links[0].node=pInst->chain;
node->links[0].like=pInst->fct;
}
node->chain=pInst->chain;
pInst->chain=node;
}
}
比如word“STEVE”对应的pron为“s t iy v sp”,那么传到该函数的参数p=0,q=4。在for循环里,是从phone“v”开始构建节点,并逐次添加到pInst->chain后面,且节点之间也是通过各自的chain连接。但是每个发音pron的开始和结尾phone音子并没有处理,所以该函数在pInt的chain列表是t->iy->v。
再看接下来的一个函数
void CreateIEModels(Word thisWord,PronHolder *pInst,int p,int q,
Network *net, HMMSetCxtInfo *hci)
{
NetNode *node,*wordNode;
HLink hmm;
if (q==p) {
/* One phone word */
// 单音子单词的情况, 暂时不考虑
}
else {
/* End */
hmm=GetHCIModel(hci,FindLContext(hci,pInst,q,0),
pInst->phones[q],0);
if (hmm->transP[1][hmm->numStates]<LSMALL) pInst->tee=FALSE;
wordNode = FindWordNode(NULL,pInst->pron,pInst,n_word);
nfi++; nil++;
node=NewNode(net->heap,hmm,1);
node->links[0].node=wordNode;
node->links[0].like=pInst->fct;
pInst->ends=node;
pInst->nend=1;
/* Start */
hmm=GetHCIModel(hci,0,pInst->phones[p],
FindRContext(hci,pInst,p,0));
if (hmm->transP[1][hmm->numStates]<LSMALL) pInst->tee=FALSE;
nin++; nil++;
node=NewNode(net->heap,hmm,1);
node->links[0].node=(pInst->chain?pInst->chain:pInst->ends);
node->links[0].like=pInst->fct;
pInst->starts=node;
pInst->nstart=1;
/* Chain */
if (pInst->chain!=NULL) {
for (node=pInst->chain;node->chain!=NULL;
node=node->chain);
node->nlinks=1;
nil++;
node->links=(NetLink*) New(net->heap,
sizeof(NetLink));
node->links[0].node=pInst->ends;
node->links[0].like=pInst->fct;
}
}
}
当q不等于p时(pron包含不止一个phone),走的是else分支。这里q为4,根据Steve单词的发音信息“s t iy v sp”,phone[4]为sp。
首先是构建(查找)单词的节点wordNode,系统把所有的单词安排在一个hash表中。然后为当前的hmm创建节点(sp),并且连接到所在单词wordNode。(这个hmm是sp,也就是词的结尾,它指向word节点。)并且pInst的ends指向该节点。看下面两行:
node=NewNode(net->heap,hmm,1); // hmm为sp的模型
node->links[0].node=wordNode; // sp节点指向wordNode
node->links[0].like=pInst->fct;
pInst->ends=node; // 发音对象的结尾指向sp node
pInst->nend=1;
再看下,它是如何处理pInst的开始节点的。
首先,传递给GetHCIModel的是phone是“s”(最开始的phone),获取“s”的hmm;然后利用hmm创建Node,并且把该node指向pInst的chain(它指向pron的第二个音子);并且把该节点赋给pInst的starts;预示着它作为单词发音序列的开始。
最后/* Chain */代码完成由“v”到“sp”的连接。这样整个pInst的chain模型就完整了。
/* Chain */
if (pInst->chain!=NULL) {
for (node=pInst->chain;node->chain!=NULL; node=node->chain);
// 该行代码将node指向pInst的chain的结尾(sp之前的那个音子)
node->nlinks=1;
nil++;
node->links=(NetLink*) New(net->heap, sizeof(NetLink)); // 创建一个连接
node->links[0].node=pInst->ends; // 使得它指向pInst->ends(sp)
node->links[0].like=pInst->fct;
}
到此为止,pInst对象内,从starts开始到ends结束,完成了lattice词格到phone网络的扩展(单音子方式)。