Julius 4.2
julius/output_module.c
説明を見る。
00001 
00018 /*
00019  * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University
00020  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00021  * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology
00022  * All rights reserved
00023  */
00024 
00025 #include "app.h"
00026 
00027 #include <time.h>
00028 
00029 extern int module_sd;
00030 extern boolean separate_score_flag;
00031 
00032 /**********************************************************************/
00033 /* process online/offline status  */
00034 
00045 static void
00046 status_process_online(Recog *recog, void *dummy)
00047 {
00048   module_send(module_sd, "<STARTPROC/>\n.\n");
00049 }
00060 static void
00061 status_process_offline(Recog *recog, void *dummy)
00062 {
00063   module_send(module_sd, "<STOPPROC/>\n.\n");
00064 }
00065 
00066 /**********************************************************************/
00067 /* decode outcode "WLPSwlps" to each boolean value */
00068 /* default: "WLPS" */
00069 static boolean out1_word = FALSE, out1_lm = FALSE, out1_phone = FALSE, out1_score = FALSE;
00070 static boolean out2_word = TRUE, out2_lm = TRUE, out2_phone = TRUE, out2_score = TRUE;
00071 static boolean out1_never = TRUE, out2_never = FALSE;
00072 #ifdef CONFIDENCE_MEASURE
00073 static boolean out2_cm = TRUE;
00074 #endif
00075 
00088 void
00089 decode_output_selection(char *str)
00090 {
00091   int i;
00092   out1_word = out1_lm = out1_phone = out1_score = FALSE;
00093   out2_word = out2_lm = out2_phone = out2_score = FALSE;
00094 #ifdef CONFIDENCE_MEASURE
00095   out2_cm = FALSE;
00096 #endif
00097   for(i = strlen(str) - 1; i >= 0; i--) {
00098     switch(str[i]) {
00099     case 'W': out2_word  = TRUE; break;
00100     case 'L': out2_lm    = TRUE; break;
00101     case 'P': out2_phone = TRUE; break;
00102     case 'S': out2_score = TRUE; break;
00103     case 'w': out1_word  = TRUE; break;
00104     case 'l': out1_lm    = TRUE; break;
00105     case 'p': out1_phone = TRUE; break;
00106     case 's': out1_score = TRUE; break;
00107 #ifdef CONFIDENCE_MEASURE
00108     case 'C': out2_cm    = TRUE; break;
00109 #endif
00110     default:
00111       fprintf(stderr, "Error: unknown outcode `%c', ignored\n", str[i]);
00112       break;
00113     }
00114   }
00115   out1_never = ! (out1_word | out1_lm | out1_phone | out1_score);
00116   out2_never = ! (out2_word | out2_lm | out2_phone | out2_score
00117 #ifdef CONFIDENCE_MEASURE
00118                   | out2_cm
00119 #endif
00120                   );
00121 
00122 }
00123 
00138 static void
00139 msock_word_out1(WORD_ID w, RecogProcess *r)
00140 {
00141   int j;
00142   static char buf[MAX_HMMNAME_LEN];
00143   WORD_INFO *winfo;
00144 
00145   winfo = r->lm->winfo;
00146 
00147   if (out1_word) {
00148     module_send(module_sd, " WORD=\"%s\"", winfo->woutput[w]);
00149   }
00150   if (out1_lm) {
00151     module_send(module_sd, " CLASSID=\"%s\"", winfo->wname[w]);
00152   }
00153   if (out1_phone) {
00154     module_send(module_sd, " PHONE=\"");
00155     for(j=0;j<winfo->wlen[w];j++) {
00156       center_name(winfo->wseq[w][j]->name, buf);
00157       if (j == 0) module_send(module_sd, "%s", buf);
00158       else module_send(module_sd, " %s", buf);
00159     }
00160     module_send(module_sd, "\"");
00161   }
00162 }
00163 
00178 static void
00179 msock_word_out2(WORD_ID w, RecogProcess *r)
00180 {
00181   int j;
00182   static char buf[MAX_HMMNAME_LEN];
00183   WORD_INFO *winfo;
00184 
00185   winfo = r->lm->winfo;
00186 
00187   if (out2_word) {
00188     module_send(module_sd, " WORD=\"%s\"", winfo->woutput[w]);
00189   }
00190   if (out2_lm) {
00191     module_send(module_sd, " CLASSID=\"%s\"", winfo->wname[w]);
00192   }
00193   if (out2_phone) {
00194     module_send(module_sd, " PHONE=\"");
00195     for(j=0;j<winfo->wlen[w];j++) {
00196       center_name(winfo->wseq[w][j]->name, buf);
00197       if (j == 0) module_send(module_sd, "%s", buf);
00198       else module_send(module_sd, " %s", buf);
00199     }
00200     module_send(module_sd, "\"");
00201   }
00202 }
00203 
00204 
00205 /**********************************************************************/
00206 /* 1st pass output */
00207 
00218 static void
00219 status_pass1_begin(Recog *recog, void *dummy)
00220 {
00221   module_send(module_sd, "<STARTRECOG/>\n.\n");
00222 }
00223 
00246 static void
00247 result_pass1_current(Recog *recog, void *dummy)
00248 {
00249   int i;
00250   WORD_INFO *winfo;
00251   WORD_ID *seq;
00252   int num;
00253   RecogProcess *r;
00254   boolean multi;
00255 
00256   if (out1_never) return;       /* no output specified */
00257 
00258   if (recog->process_list->next != NULL) multi = TRUE;
00259   else multi = FALSE;
00260 
00261   for(r=recog->process_list;r;r=r->next) {
00262     if (! r->live) continue;
00263     if (! r->have_interim) continue;
00264 
00265     winfo = r->lm->winfo;
00266     seq = r->result.pass1.word;
00267     num = r->result.pass1.word_num;
00268 
00269     if (multi) {
00270       module_send(module_sd, "<RECOGOUT ID=\"SR%02d\" NAME=\"%s\">\n", r->config->id, r->config->name);
00271     } else {
00272       module_send(module_sd, "<RECOGOUT>\n");
00273     }
00274     if (out1_score) {
00275       module_send(module_sd, "  <PHYPO PASS=\"1\" SCORE=\"%f\" FRAME=\"%d\" TIME=\"%ld\"/>\n", r->result.pass1.score, r->result.num_frame, time(NULL));
00276     } else {
00277       module_send(module_sd, "  <PHYPO PASS=\"1\" FRAME=\"%d\" TIME=\"%ld\"/>\n", r->result.num_frame, time(NULL));
00278     }
00279     for (i=0;i<num;i++) {
00280       module_send(module_sd, "    <WHYPO");
00281       msock_word_out1(seq[i], r);
00282       module_send(module_sd, "/>\n");
00283     }
00284     module_send(module_sd, "  </PHYPO>\n</RECOGOUT>\n.\n");
00285   }
00286 }
00287 
00311 static void
00312 result_pass1_final(Recog *recog, void *dummy)
00313 {
00314   int i;
00315   RecogProcess *r;
00316   boolean multi;
00317 
00318   if (out1_never) return;       /* no output specified */
00319 
00320   if (recog->process_list->next != NULL) multi = TRUE;
00321   else multi = FALSE;
00322 
00323   for(r=recog->process_list;r;r=r->next) {
00324     if (! r->live) continue;
00325     if (r->result.status < 0) continue; /* search already failed  */
00326 
00327     if (multi) {
00328       module_send(module_sd, "<RECOGOUT ID=\"SR%02d\" NAME=\"%s\">\n", r->config->id, r->config->name);
00329     } else {
00330       module_send(module_sd, "<RECOGOUT>\n");
00331     }
00332     if (out1_score) {
00333       module_send(module_sd, "  <SHYPO PASS=\"1\" SCORE=\"%f\">\n", r->result.pass1.score);
00334     } else {
00335       module_send(module_sd, "  <SHYPO PASS=\"1\">\n", r->result.pass1.score);
00336     }
00337     for (i=0;i<r->result.pass1.word_num;i++) {
00338       module_send(module_sd, "    <WHYPO");
00339       msock_word_out1(r->result.pass1.word[i], r);
00340       module_send(module_sd, "/>\n");
00341     }
00342     module_send(module_sd, "  </SHYPO>\n</RECOGOUT>\n.\n");
00343   }
00344 }
00345 
00356 static void
00357 status_pass1_end(Recog *recog, void *dummy)
00358 {
00359   module_send(module_sd, "<ENDRECOG/>\n.\n");
00360 }
00361 
00362 /**********************************************************************/
00363 /* 2nd pass output */
00364 
00381 static void
00382 result_pass2(Recog *recog, void *dummy)
00383 {
00384   int i, n, num;
00385   WORD_INFO *winfo;
00386   WORD_ID *seq;
00387   int seqnum;
00388   Sentence *s;
00389   RecogProcess *r;
00390   boolean multi;
00391   SentenceAlign *align;
00392 
00393   if (recog->process_list->next != NULL) multi = TRUE;
00394   else multi = FALSE;
00395 
00396   for(r=recog->process_list;r;r=r->next) {
00397     if (! r->live) continue;
00398 
00399     if (r->result.status < 0) {
00400       switch(r->result.status) {
00401       case J_RESULT_STATUS_REJECT_POWER:
00402         module_send(module_sd, "<REJECTED REASON=\"by power\"");
00403         break;
00404       case J_RESULT_STATUS_TERMINATE:
00405         module_send(module_sd, "<REJECTED REASON=\"input terminated by request\"");
00406         break;
00407       case J_RESULT_STATUS_ONLY_SILENCE:
00408         module_send(module_sd, "<REJECTED REASON=\"result has pause words only\"");
00409         break;
00410       case J_RESULT_STATUS_REJECT_GMM:
00411         module_send(module_sd, "<REJECTED REASON=\"by GMM\"");
00412         break;
00413       case J_RESULT_STATUS_REJECT_SHORT:
00414         module_send(module_sd, "<REJECTED REASON=\"too short input\"");
00415         break;
00416       case J_RESULT_STATUS_FAIL:
00417         module_send(module_sd, "<RECOGFAIL");
00418         break;
00419       }
00420       if (multi) {
00421         module_send(module_sd, " ID=\"SR%02d\" NAME=\"%s\"", r->config->id, r->config->name);
00422       }
00423       module_send(module_sd, "/>\n.\n");
00424       continue;
00425     }
00426 
00427     if (out2_never) continue;   /* no output specified */
00428 
00429     winfo = r->lm->winfo;
00430     num = r->result.sentnum;
00431 
00432     if (multi) {
00433       module_send(module_sd, "<RECOGOUT ID=\"SR%02d\" NAME=\"%s\">\n", r->config->id, r->config->name);
00434     } else {
00435       module_send(module_sd, "<RECOGOUT>\n");
00436     }
00437     for(n=0;n<num;n++) {
00438       s = &(r->result.sent[n]);
00439       seq = s->word;
00440       seqnum = s->word_num;
00441       
00442       module_send(module_sd, "  <SHYPO RANK=\"%d\"", n+1);
00443       if (out2_score) {
00444         module_send(module_sd, " SCORE=\"%f\"", s->score);
00445         if (r->lmtype == LM_PROB) {
00446           if (separate_score_flag) {
00447             module_send(module_sd, " AMSCORE=\"%f\" LMSCORE=\"%f\"", s->score_am, s->score_lm);
00448           }
00449         }
00450       }
00451       if (r->lmtype == LM_DFA) {
00452         /* output which grammar the best hypothesis belongs to */
00453         module_send(module_sd, " GRAM=\"%d\"", s->gram_id);
00454       }
00455       
00456       module_send(module_sd, ">\n");
00457       for (i=0;i<seqnum;i++) {
00458         module_send(module_sd, "    <WHYPO");
00459         msock_word_out2(seq[i], r);
00460 #ifdef CONFIDENCE_MEASURE
00461 #ifdef CM_MULTIPLE_ALPHA
00462         /* currently not handle multiple alpha output */
00463 #else
00464         if (out2_cm) {
00465           module_send(module_sd, " CM=\"%5.3f\"", s->confidence[i]);
00466         }
00467 #endif
00468 #endif /* CONFIDENCE_MEASURE */
00469         /* output alignment result if exist */
00470         for (align = s->align; align; align = align->next) {
00471           switch(align->unittype) {
00472           case PER_WORD:        /* word alignment */
00473             module_send(module_sd, " BEGINFRAME=\"%d\" ENDFRAME=\"%d\"", align->begin_frame[i], align->end_frame[i]);
00474             break;
00475           case PER_PHONEME:
00476           case PER_STATE:
00477             fprintf(stderr, "Error: \"-palign\" and \"-salign\" does not supported for module output\n");
00478             break;
00479           }
00480         }
00481         
00482         module_send(module_sd, "/>\n");
00483       }
00484       module_send(module_sd, "  </SHYPO>\n");
00485     }
00486     module_send(module_sd, "</RECOGOUT>\n.\n");
00487 
00488   }
00489 
00490 }
00491 
00492 
00493 /**********************************************************************/
00494 /* word graph output */
00495 
00510 static void
00511 result_graph(Recog *recog, void *dummy)
00512 {
00513   WordGraph *wg;
00514   int i;
00515   int nodenum, arcnum;
00516   WORD_INFO *winfo;
00517   WordGraph *root;
00518   RecogProcess *r;
00519   boolean multi;
00520 
00521   if (recog->process_list->next != NULL) multi = TRUE;
00522   else multi = FALSE;
00523 
00524   for(r=recog->process_list;r;r=r->next) {
00525     if (! r->live) continue;
00526     if (r->result.wg == NULL) continue; /* no graph obtained */
00527 
00528     winfo = r->lm->winfo;
00529     root = r->result.wg;
00530     nodenum = r->graph_totalwordnum;
00531     arcnum = 0;
00532     for(wg=root;wg;wg=wg->next) {
00533       arcnum += wg->rightwordnum;
00534     }
00535 
00536     module_send(module_sd, "<GRAPHOUT");
00537     if (multi) module_send(module_sd, " ID=\"SR%02d\" NAME=\"%s\"", r->config->id, r->config->name);
00538     module_send(module_sd, " NODENUM=\"%d\" ARCNUM=\"%d\">\n", nodenum, arcnum);
00539     for(wg=root;wg;wg=wg->next) {
00540       module_send(module_sd, "    <NODE GID=\"%d\"", wg->id);
00541       msock_word_out2(wg->wid, r);
00542       module_send(module_sd, " BEGIN=\"%d\"", wg->lefttime);
00543       module_send(module_sd, " END=\"%d\"", wg->righttime);
00544       module_send(module_sd, "/>\n");
00545     }
00546     for(wg=root;wg;wg=wg->next) {
00547       for(i=0;i<wg->rightwordnum;i++) {
00548         module_send(module_sd, "    <ARC FROM=\"%d\" TO=\"%d\"/>\n", wg->id, wg->rightword[i]->id);
00549       }
00550     }
00551     module_send(module_sd, "</GRAPHOUT>\n.\n");
00552   }
00553 }
00554 
00565 static void
00566 status_recready(Recog *recog, void *dummy)
00567 {
00568   module_send(module_sd, "<INPUT STATUS=\"LISTEN\" TIME=\"%ld\"/>\n.\n", time(NULL));
00569 }
00570 
00581 static void
00582 status_recstart(Recog *recog, void *dummy)
00583 {
00584   module_send(module_sd, "<INPUT STATUS=\"STARTREC\" TIME=\"%ld\"/>\n.\n", time(NULL));
00585 }
00596 static void
00597 status_recend(Recog *recog, void *dummy)
00598 {
00599   module_send(module_sd, "<INPUT STATUS=\"ENDREC\" TIME=\"%ld\"/>\n.\n", time(NULL));
00600 }
00613 static void
00614 status_param(Recog *recog, void *dummy)
00615 {
00616   MFCCCalc *mfcc;
00617   boolean multi;
00618   int frames;
00619   int msec;
00620 
00621   if (recog->mfcclist->next != NULL) multi = TRUE;
00622   else multi = FALSE;
00623 
00624   for(mfcc=recog->mfcclist;mfcc;mfcc=mfcc->next) {
00625     frames = mfcc->param->samplenum;
00626     msec = (float)mfcc->param->samplenum * (float)recog->jconf->input.period * (float)recog->jconf->input.frameshift / 10000.0;
00627     if (multi) {
00628       module_send(module_sd, "<INPUTPARAM MFCCID=\"%02d\" FRAMES=\"%d\" MSEC=\"%d\"/>\n.\n", mfcc->id, frames, msec);
00629     } else {
00630       module_send(module_sd, "<INPUTPARAM FRAMES=\"%d\" MSEC=\"%d\"/>\n.\n", frames, msec);
00631     }
00632   }
00633 }
00634 
00635 /********************* RESULT OUTPUT FOR GMM *************************/
00645 static void
00646 result_gmm(Recog *recog, void *dummy)
00647 {
00648   module_send(module_sd, "<GMM RESULT=\"%s\"", recog->gc->max_d->name);
00649 #ifdef CONFIDENCE_MEASURE
00650   module_send(module_sd, " CMSCORE=\"%f\"", recog->gc->gmm_max_cm);
00651 #endif
00652   module_send(module_sd, "/>\n.\n");
00653 }
00654 
00665 void
00666 send_gram_info(RecogProcess *r)
00667 {
00668   MULTIGRAM *m;
00669   char buf[1024];
00670 
00671   if (r->lmtype == LM_PROB) {
00672     module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00673     return;
00674   }
00675   module_send(module_sd, "<GRAMINFO>\n");
00676   for(m=r->lm->grammars;m;m=m->next) {
00677     buf[0] = '\0';
00678     if (m->dfa) {
00679       snprintf(buf, 1024, ", %3d categories, %4d nodes",
00680                m->dfa->term_num, m->dfa->state_num);
00681     }
00682     if (m->newbie) strcat(buf, " (new)");
00683     if (m->hook != 0) {
00684       strcat(buf, " (next:");
00685       if (m->hook & MULTIGRAM_DELETE) {
00686         strcat(buf, " delete");
00687       }
00688       if (m->hook & MULTIGRAM_ACTIVATE) {
00689         strcat(buf, " activate");
00690       }
00691       if (m->hook & MULTIGRAM_DEACTIVATE) {
00692         strcat(buf, " deactivate");
00693       }
00694       if (m->hook & MULTIGRAM_MODIFIED) {
00695         strcat(buf, " modified");
00696       }
00697       strcat(buf, ")");
00698     }
00699     module_send(module_sd, "  #%2d: [%-11s] %4d words%s \"%s\"\n",
00700                 m->id,
00701                 m->active ? "active" : "inactive",
00702                 m->winfo->num,
00703                 buf,
00704                 m->name);
00705   }
00706   if (r->lm->dfa != NULL) {
00707     module_send(module_sd, "  Global:            %4d words, %3d categories, %4d nodes\n", r->lm->winfo->num, r->lm->dfa->term_num, r->lm->dfa->state_num);
00708   }
00709   module_send(module_sd, "</GRAMINFO>\n.\n");
00710 }
00711 
00712 /**********************************************************************/
00713 /* register functions for module output */
00724 void
00725 setup_output_msock(Recog *recog, void *data)
00726 {
00727   callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, status_process_online, data);
00728   callback_add(recog, CALLBACK_EVENT_PROCESS_OFFLINE, status_process_offline, data);
00729   //callback_add(recog, CALLBACK_EVENT_STREAM_BEGIN,     , data);
00730   //callback_add(recog, CALLBACK_EVENT_STREAM_END,        , data);
00731   callback_add(recog, CALLBACK_EVENT_SPEECH_READY, status_recready, data);
00732   callback_add(recog, CALLBACK_EVENT_SPEECH_START, status_recstart, data);
00733   callback_add(recog, CALLBACK_EVENT_SPEECH_STOP, status_recend, data);
00734   callback_add(recog, CALLBACK_EVENT_PASS1_BEGIN, status_pass1_begin, data);
00735   callback_add(recog, CALLBACK_EVENT_PASS1_END, status_pass1_end, data);
00736   callback_add(recog, CALLBACK_RESULT_PASS1_INTERIM, result_pass1_current, data);
00737   callback_add(recog, CALLBACK_RESULT_PASS1, result_pass1_final, data);
00738 
00739   callback_add(recog, CALLBACK_STATUS_PARAM, status_param, data);
00740 
00741   callback_add(recog, CALLBACK_RESULT, result_pass2, data); // rejected, failed
00742   callback_add(recog, CALLBACK_RESULT_GMM, result_gmm, data);
00743   /* below will not be called if "-graphout" not specified */
00744   callback_add(recog, CALLBACK_RESULT_GRAPH, result_graph, data);
00745 
00746   //callback_add(recog, CALLBACK_EVENT_PAUSE, status_pause, data);
00747   //callback_add(recog, CALLBACK_EVENT_RESUME, status_resume, data);
00748 
00749 }