| /*---------------------------------------------------------------------------* |
| * make_cfst.cpp * |
| * * |
| * Copyright 2007, 2008 Nuance Communciations, Inc. * |
| * * |
| * Licensed under the Apache License, Version 2.0 (the 'License'); * |
| * you may not use this file except in compliance with the License. * |
| * * |
| * You may obtain a copy of the License at * |
| * http://www.apache.org/licenses/LICENSE-2.0 * |
| * * |
| * Unless required by applicable law or agreed to in writing, software * |
| * distributed under the License is distributed on an 'AS IS' BASIS, * |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * |
| * See the License for the specific language governing permissions and * |
| * limitations under the License. * |
| * * |
| *---------------------------------------------------------------------------*/ |
| |
| #include "ptypes.h" |
| #include "srec_arb.h" |
| #include "simapi.h" |
| |
| #include "fst/lib/fstlib.h" |
| #include "fst/lib/fst-decl.h" |
| #include "fst/lib/vector-fst.h" |
| #include "fst/lib/arcsort.h" |
| #include "fst/lib/invert.h" |
| #include "fst/lib/rmepsilon.h" |
| |
| #define MAX_LINE_LENGTH 256 |
| #define MAX_PRONS_LENGTH 1024 |
| #define EPSILON_LABEL 0 |
| #define MAX_MODELS 1024 |
| #define MAXPHID 8888 |
| #define MAX_PHONEMES 128 |
| |
| using namespace fst; |
| |
| int usage(const char* prog) |
| { |
| printf("usage: %s -phones models/phones.map -models models/models128x.map -cfst models/generic.C -swiarb models/generic.swiarb\n", prog); |
| return 1; |
| } |
| |
| typedef struct Minifst_t |
| { |
| char lcontexts[MAX_PHONEMES]; |
| char rcontexts[MAX_PHONEMES]; |
| int modelId; |
| int stateSt; |
| int stateEn; |
| phonemeID phonemeId; |
| unsigned char phonemeCode; |
| int lcontext_state[MAX_PHONEMES]; |
| int rcontext_state[MAX_PHONEMES]; |
| } Minifst; |
| |
| int main(int argc, char **argv) |
| { |
| char* cfstFilename = 0; |
| char* swiarbFilename = 0; |
| char* phonesMap; |
| char* modelsMap; |
| int i; |
| phonemeID lphonId, cphonId, rphonId; |
| unsigned char cphon; |
| modelID modelId, max_modelId = 0; |
| int stateSt, stateEn; |
| int stateN, stateNp1; |
| int rc; |
| Minifst minifst[MAX_MODELS]; |
| int do_show_text = 1; |
| int do_until_step = 99; |
| |
| /* initial memory */ |
| rc = PMemInit(); |
| ASSERT( rc == ESR_SUCCESS); |
| |
| // A vector FST is a general mutable FST |
| fst::StdVectorFst myCfst; |
| // fst::Fst<fst::StdArc> myCfst; |
| |
| if(argc <= 1) |
| return usage(argv[0]); |
| |
| for(i=1; i<argc; i++) |
| { |
| if(0) ; |
| else if(!strcmp(argv[i],"-phones")) |
| phonesMap = argv[++i]; |
| else if(!strcmp(argv[i],"-models")) |
| modelsMap = argv[++i]; |
| else if(!strcmp(argv[i],"-cfst")) |
| cfstFilename = argv[++i]; |
| else if(!strcmp(argv[i],"-step")) |
| do_until_step = atoi(argv[++i]); |
| else if(!strcmp(argv[i],"-swiarb")) |
| swiarbFilename = argv[++i]; |
| else { |
| return usage(argv[0]); |
| } |
| } |
| |
| printf("loading %s ...\n", swiarbFilename); |
| CA_Arbdata* ca_arbdata = CA_LoadArbdata(swiarbFilename); |
| srec_arbdata *allotree = (srec_arbdata*)ca_arbdata; |
| |
| |
| /*------------------------------------------------------------------------- |
| * |
| * /---<---<---<---<---<---<---\ |
| * / \ |
| * / -wb-- -wb- \ |
| * / \ / \ / \ |
| * 0 ---#---> n ----M---> n+1 ---#---> 1 |
| * |
| * |
| * |
| * |
| *------------------------------------------------------------------------- |
| */ |
| |
| // Adds state 0 to the initially empty FST and make it the start state. |
| stateSt = myCfst.AddState(); // 1st state will be state 0 (returned by AddState) |
| stateEn = myCfst.AddState(); |
| myCfst.SetStart(stateSt); // arg is state ID |
| myCfst.SetFinal(stateEn, 0.0); // 1st arg is state ID, 2nd arg weight |
| myCfst.AddArc(stateEn, fst::StdArc(EPSILON_LABEL, EPSILON_LABEL, 0.0, stateSt)); |
| |
| phonemeID silencePhonId = 0; |
| modelID silenceModelId = 0; |
| silenceModelId = (modelID)get_modelid_for_pic(allotree, silencePhonId, silencePhonId, silencePhonId); |
| // silenceModelId += MODEL_LABEL_OFFSET; #define MODEL_LABEL_OFFSET 128 |
| |
| for(modelId=0; modelId<MAX_MODELS; modelId++) { |
| minifst[modelId].modelId = MAXmodelID; |
| minifst[modelId].stateSt = minifst[modelId].stateEn = 0; |
| minifst[modelId].phonemeId = MAXphonemeID; |
| minifst[modelId].phonemeCode = 0; |
| for(i=0;i<MAX_PHONEMES;i++) { |
| minifst[modelId].lcontexts[i] = minifst[modelId].rcontexts[i] = 0; |
| minifst[modelId].lcontext_state[i] = minifst[modelId].rcontext_state[i] = 0; |
| } |
| } |
| |
| for(cphonId=0; cphonId<allotree->num_phonemes && cphonId<MAXPHID; cphonId++) { |
| cphon = allotree->pdata[cphonId].code; |
| printf("processing phoneme %d of %d %d %c\n", cphonId, allotree->num_phonemes, cphon, cphon); |
| |
| for(lphonId=0; lphonId<allotree->num_phonemes && lphonId<MAXPHID; lphonId++) { |
| unsigned char lphon = allotree->pdata[lphonId].code; |
| for(rphonId=0; rphonId<allotree->num_phonemes && rphonId<MAXPHID; rphonId++) { |
| unsigned char rphon = allotree->pdata[rphonId].code; |
| if( 1|| cphon=='a') { //22222 |
| modelId = (modelID)get_modelid_for_pic(allotree, lphonId, cphonId, rphonId); |
| } else { |
| modelId = (modelID)get_modelid_for_pic(allotree, 0, cphonId, 0); |
| } |
| if(modelId == MAXmodelID) { |
| printf("error while get_modelid_for_pic( %p, %d, %d, %d)\n", |
| allotree, lphonId, cphonId, rphonId); |
| continue; |
| } else |
| if(do_show_text) printf("%c %c %c hmm%03d_%c %d %d %d\n", lphon, cphon, rphon, modelId, cphon, lphonId, cphonId, rphonId); |
| ASSERT(modelId < MAX_MODELS); |
| minifst[ modelId].phonemeId = cphonId; |
| minifst[ modelId].phonemeCode = cphon; |
| minifst[ modelId].modelId = modelId; |
| minifst[ modelId].lcontexts[lphonId] = 1; |
| minifst[ modelId].rcontexts[rphonId] = 1; |
| if(modelId>max_modelId) max_modelId = modelId; |
| } |
| } |
| } |
| |
| printf("adding model arcs .. max_modelId %d\n",max_modelId); |
| for(modelId=0; modelId<=max_modelId; modelId++) { |
| if( minifst[modelId].modelId == MAXmodelID) continue; |
| cphon = minifst[modelId].phonemeCode; |
| minifst[modelId].stateSt = (stateN = myCfst.AddState()); |
| minifst[modelId].stateEn = (stateNp1 = myCfst.AddState()); /* n plus 1 */ |
| myCfst.AddArc( stateN, fst::StdArc(cphon,modelId,0.0,stateNp1)); |
| myCfst.AddArc( stateNp1, fst::StdArc(WORD_BOUNDARY,WORD_BOUNDARY,0.0,stateNp1)); |
| |
| if(do_show_text) printf("%d\t\%d\t%c\t\%d\n", stateN,stateNp1,cphon,modelId); |
| #if 1 |
| for( lphonId=0; lphonId<allotree->num_phonemes; lphonId++) { |
| minifst[modelId].lcontext_state[lphonId] = myCfst.AddState(); |
| myCfst.AddArc( minifst[modelId].lcontext_state[lphonId], |
| fst::StdArc(EPSILON_LABEL,EPSILON_LABEL,0.0, |
| minifst[modelId].stateSt)); |
| |
| } |
| for( rphonId=0; rphonId<allotree->num_phonemes; rphonId++) { |
| minifst[modelId].rcontext_state[rphonId] = myCfst.AddState(); |
| myCfst.AddArc( minifst[modelId].stateEn, |
| fst::StdArc(EPSILON_LABEL,EPSILON_LABEL,0.0, |
| minifst[modelId].rcontext_state[rphonId])); |
| } |
| #endif |
| } |
| #if 1 |
| printf("adding cross-connections\n"); |
| for( modelId=0; modelId<=max_modelId; modelId++) { |
| printf("processing model %d\n", modelId); |
| if( minifst[modelId].modelId == MAXmodelID) continue; |
| cphonId = minifst[modelId].phonemeId; |
| for( modelID mId=0; mId<=max_modelId; mId++) { |
| if( minifst[mId].modelId != MAXmodelID && |
| // minifst[mId].phonemeId == rphonId && |
| minifst[modelId].rcontexts[ minifst[mId].phonemeId] == 1 && |
| minifst[mId].lcontexts[ cphonId] == 1) { |
| myCfst.AddArc( minifst[modelId].stateEn, |
| fst::StdArc(EPSILON_LABEL,EPSILON_LABEL,0.0, |
| minifst[mId].stateSt)); |
| } |
| } |
| } |
| /* start node connections */ |
| myCfst.AddArc( stateSt, |
| fst::StdArc(EPSILON_LABEL, EPSILON_LABEL, 0.0, |
| minifst[silenceModelId].stateSt)); |
| myCfst.AddArc( minifst[silenceModelId].stateEn, |
| fst::StdArc(EPSILON_LABEL, EPSILON_LABEL, 0.0, stateEn)); |
| #endif |
| |
| fst::StdVectorFst fst2; |
| fst::StdVectorFst* ofst = &myCfst; |
| if(do_until_step>0) { |
| printf("invert\n"); |
| fst::Invert(&myCfst); |
| bool FLAGS_connect = true; |
| if(do_until_step>1) { |
| printf("rmepsilon\n"); |
| fst::RmEpsilon( &myCfst, FLAGS_connect); |
| if(do_until_step>2) { |
| printf("determinize\n"); |
| fst::Determinize(myCfst, &fst2); |
| ofst = &fst2; |
| if(do_until_step>3) { |
| printf("arcsort olabels\n"); |
| fst::ArcSort(&fst2, fst::StdOLabelCompare()); |
| } |
| } |
| } |
| } |
| |
| #if 0 |
| for(fst::SymbolTableIterator syms_iter( *syms); !syms_iter.Done(); syms_iter.Next() ) { |
| int value = (int)syms_iter.Value(); |
| const char* key = syms_iter.Symbol(); |
| } |
| #endif |
| |
| printf("writing output file %s\n", cfstFilename); |
| |
| // We can save this FST to a file with: |
| /* fail compilation if char and LCHAR aren't the same! */ |
| |
| { char zzz[ 1 - (sizeof(LCHAR)!=sizeof(char))]; zzz[0] = 0; } |
| ofst->Write((const char*)cfstFilename); |
| |
| CA_FreeArbdata( ca_arbdata); |
| |
| PMemShutdown(); |
| |
| // CLEANUP: |
| return (int)rc; |
| } |
| |
| |