Julius 4.2
|
00001 00027 /* 00028 * Copyright (c) 2003-2005 Shikano Lab., Nara Institute of Science and Technology 00029 * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology 00030 * All rights reserved 00031 */ 00032 00033 #include <libmain.h> 00034 #include "app.h" 00035 00036 #ifdef VISUALIZE 00037 00038 #include <gtk/gtk.h> 00039 00040 /* Window constant properties */ 00041 #define WINTITLE "Julius word trellis viewer" ///< Window title 00042 #define DEFAULT_WINDOW_WIDTH 800 ///< Default window width 00043 #define DEFAULT_WINDOW_HEIGHT 600 ///< Default window height 00044 #define CANVAS_MARGIN 16 ///< Margin of drawable 00045 #define WAVE_HEIGHT 48 ///< Height of wave drawing canvas 00046 #define WAVE_MARGIN 6 ///< Height margin of wave drawing canvas 00047 #define RESULT_HEIGHT 0 ///< Offset of text output for each node 00048 #define FONTSET "-*-fixed-medium-r-normal--10-*-*-*-*-*-*-*" ///< Fontset 00049 00050 /* global valuables for window handling */ 00051 static GdkFont *fontset; 00052 static GdkPixmap *pixmap = NULL; 00053 static gint canvas_width; 00054 static gint canvas_height; 00055 00056 00057 /**********************************************************************/ 00058 /* view configuration switches */ 00059 /**********************************************************************/ 00060 static boolean sw_wid_axis = TRUE; 00061 static boolean sw_score_beam = FALSE; 00062 static boolean sw_text = TRUE; 00063 static boolean sw_line = TRUE; 00064 static boolean sw_level_thres = FALSE; 00065 static boolean sw_hypo = FALSE; 00066 00067 /**********************************************************************/ 00068 /* data to plot (1st pass / 2nd pass) */ 00069 /**********************************************************************/ 00070 static Recog *re; 00071 /* data to plot on 1st pass */ 00072 static BACKTRELLIS *btlocal = NULL; 00073 /* data to plot on 2nd pass */ 00074 static POPNODE *popped = NULL; 00075 static int pnum; 00076 static POPNODE *lastpop = NULL; 00077 00078 00079 /**********************************************************************/ 00080 /* GTK color allocation */ 00081 /**********************************************************************/ 00082 00083 #define NCOLS 15 00084 static GdkColor cols[NCOLS] = { 00085 {0, 63000, 63000, 63000}, /* background */ 00086 {0, 0, 0, 40000}, /* waveform */ 00087 {0, 50000, 20000, 0}, /* waveform level threshold line */ 00088 {0, 0, 0, 65535}, /* begin node of word arc */ 00089 {0, 60000, 60000, 0}, /* end node of word arc */ 00090 {0, 24000, 32000, 24000}, /* line (context word / word graph) */ 00091 {0, 10000, 10000, 40000}, /* text (context word / word graph) */ 00092 {0, 50000, 54000, 50000}, /* line (word indexed trellis = all survived words) */ 00093 {0, 50000, 30000, 0}, /* line (best path) */ 00094 {0, 55535, 0, 0}, /* end node (best path) */ 00095 {0, 50000, 30000, 0}, /* text (best path) */ 00096 {0, 12000, 20000, 12000}, /* line and text (2nd pass) */ 00097 {0, 50000, 50000, 12000}, /* line and text (2nd pass popped) */ 00098 {0, 50000, 0, 0}, /* 2nd pass best */ 00099 {0, 0, 0, 0} /* shadow for text decoration */ 00100 }; 00101 typedef enum {C_BG, C_WAVEFORM, C_LEVELTHRES, C_BGN, C_END, C_LINE, C_TEXT, C_LINE_FAINT, C_LINE_BEST, C_END_BEST, C_TEXT_BEST, C_PASS2_NEXT, C_PASS2, C_PASS2_BEST, C_SHADOW} UserColors; 00102 00103 static GdkGC *dgc = NULL; 00104 00113 static void 00114 color_init() 00115 { 00116 GdkColormap *defcolmap; 00117 gboolean success[NCOLS]; 00118 00119 defcolmap = gdk_colormap_get_system(); 00120 if (gdk_colormap_alloc_colors(defcolmap, cols, NCOLS, FALSE, TRUE, success) > 0) { 00121 fprintf(stderr, "Warning: some colors are not allocated\n"); 00122 } 00123 00124 } 00125 00126 00127 /**********************************************************************/ 00128 /* graph scaling */ 00129 /**********************************************************************/ 00130 00131 static LOGPROB *ftop = NULL; 00132 static LOGPROB *fbottom = NULL; 00133 static LOGPROB lowest; 00134 static LOGPROB maxrange; 00135 static LOGPROB maxrange2; 00136 00149 static void 00150 get_max_frame_score(BACKTRELLIS *bt) 00151 { 00152 int t, i; 00153 TRELLIS_ATOM *tre; 00154 LOGPROB x,y; 00155 00156 /* allocate */ 00157 if (ftop != NULL) free(ftop); 00158 ftop = mymalloc(sizeof(LOGPROB) * bt->framelen); 00159 if (fbottom != NULL) free(fbottom); 00160 fbottom = mymalloc(sizeof(LOGPROB) * bt->framelen); 00161 00162 /* get maxrange, ftop[], fbottom[] */ 00163 maxrange = 0.0; 00164 for (t=0;t<bt->framelen;t++) { 00165 x = LOG_ZERO; 00166 y = 0.0; 00167 for (i=0;i<bt->num[t];i++) { 00168 tre = bt->rw[t][i]; 00169 if (x < tre->backscore) x = tre->backscore; 00170 if (y > tre->backscore) y = tre->backscore; 00171 } 00172 ftop[t] = x; 00173 fbottom[t] = y; 00174 if (maxrange < x - y) maxrange = x - y; 00175 } 00176 00177 /* get the lowest score and range around y=(lowest/framelen)x */ 00178 lowest = 0.0; 00179 for (t=0;t<bt->framelen;t++) { 00180 if (lowest > fbottom[t]) lowest = fbottom[t]; 00181 } 00182 maxrange2 = 0.0; 00183 for (t=0;t<bt->framelen;t++) { 00184 x = lowest * (float)t / (float)bt->framelen; 00185 if (ftop[t] == LOG_ZERO) continue; 00186 if (maxrange2 < abs(ftop[t] - x)) maxrange2 = abs(ftop[t] - x); 00187 if (maxrange2 < abs(fbottom[t] - x)) maxrange2 = abs(fbottom[t] - x); 00188 } 00189 } 00190 00207 static gint 00208 scale_x(int t) 00209 { 00210 return(t * (canvas_width - CANVAS_MARGIN * 2) / btlocal->framelen + CANVAS_MARGIN); 00211 } 00212 00231 static gint 00232 scale_y(LOGPROB s, int t) 00233 { 00234 gint y; 00235 LOGPROB top, bottom; 00236 gint yoffset, height; 00237 00238 if (sw_score_beam) { 00239 /* beam threshold-based: upper is the maximum score on the frame */ 00240 top = ftop[t]; 00241 if (top == LOG_ZERO) { /* no token found on the time */ 00242 bottom = top; 00243 } else { 00244 bottom = ftop[t] - maxrange; 00245 } 00246 } else { 00247 /* total score based: show around (lowest/framelen) x time */ 00248 top = lowest * (float)t / (float)btlocal->framelen + maxrange2; 00249 bottom = lowest * (float)t / (float)btlocal->framelen - maxrange2; 00250 } 00251 00252 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT): 0); 00253 height = canvas_height - yoffset - CANVAS_MARGIN; 00254 if (top <= bottom) { /* single or no token on the time */ 00255 y = yoffset; 00256 } else { 00257 y = (top - s) * height / (top - bottom) + yoffset; 00258 } 00259 return(y); 00260 } 00261 00278 static gint 00279 scale_y_wid(WORD_ID wid) 00280 { 00281 gint y; 00282 gint yoffset, height; 00283 00284 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0); 00285 height = canvas_height - yoffset - CANVAS_MARGIN; 00286 if (wid == WORD_INVALID) { 00287 y = yoffset; 00288 } else { 00289 y = wid * height / re->model->winfo->num + yoffset; 00290 } 00291 return(y); 00292 } 00293 00294 00295 /**********************************************************************/ 00296 /* Draw wave data */ 00297 /**********************************************************************/ 00298 static SP16 max_level; 00299 00316 static gint 00317 scale_x_wave(int t) 00318 { 00319 return(t * (canvas_width - CANVAS_MARGIN * 2) / re->speechlen + CANVAS_MARGIN); 00320 } 00321 00338 static gint 00339 scale_y_wave(SP16 x) 00340 { 00341 return(WAVE_HEIGHT / 2 + WAVE_MARGIN - (x * WAVE_HEIGHT / (max_level * 2))); 00342 } 00343 00354 static void 00355 get_max_waveform_level() 00356 { 00357 int t; 00358 SP16 maxl; 00359 00360 if (re->speechlen == 0) return; /* no waveform data (MFCC) */ 00361 00362 maxl = 0; 00363 for(t=0;t<re->speechlen;t++) { 00364 if (maxl < abs(re->speech[t])) { 00365 maxl = abs(re->speech[t]); 00366 } 00367 } 00368 00369 max_level = maxl; 00370 if (max_level < 3000) max_level = 3000; 00371 } 00372 00385 static void 00386 draw_waveform(GtkWidget *widget) 00387 { 00388 int t; 00389 gint text_width; 00390 static char buf[20]; 00391 00392 if (re->speechlen == 0) return; /* no waveform data (MFCC) */ 00393 00394 /* first time, make gc for drawing */ 00395 if (dgc == NULL) { 00396 dgc = gdk_gc_new(widget->window); 00397 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]); 00398 } 00399 00400 00401 /* draw frame */ 00402 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM])); 00403 gdk_draw_rectangle(pixmap, dgc, FALSE, 00404 scale_x_wave(0), scale_y_wave(max_level), 00405 scale_x_wave(re->speechlen-1) - scale_x_wave(0), 00406 scale_y_wave(-max_level) - scale_y_wave(max_level)); 00407 00408 if (sw_level_thres) { 00409 /* draw level threshold line */ 00410 gdk_gc_set_foreground(dgc, &(cols[C_LEVELTHRES])); 00411 gdk_draw_line(pixmap, dgc, 00412 scale_x_wave(0), scale_y_wave(re->jconf->detect.level_thres), 00413 scale_x_wave(re->speechlen-1), scale_y_wave(re->jconf->detect.level_thres)); 00414 gdk_draw_line(pixmap, dgc, 00415 scale_x_wave(0), scale_y_wave(- re->jconf->detect.level_thres), 00416 scale_x_wave(re->speechlen-1), scale_y_wave(- re->jconf->detect.level_thres)); 00417 snprintf(buf, 20, "-lv %d", re->jconf->detect.level_thres); 00418 text_width = gdk_string_width(fontset, buf) + 1; 00419 gdk_draw_string(pixmap, fontset, dgc, 00420 canvas_width - CANVAS_MARGIN - text_width - 2, 00421 scale_y_wave(-max_level) - 2, 00422 buf); 00423 } 00424 00425 /* draw text */ 00426 snprintf(buf, 20, "max: %d", max_level); 00427 text_width = gdk_string_width(fontset, buf) + 1; 00428 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM])); 00429 gdk_draw_string(pixmap, fontset, dgc, 00430 canvas_width - CANVAS_MARGIN - text_width - 2, 00431 scale_y_wave(max_level) + 12, 00432 buf); 00433 00434 /* draw waveform */ 00435 for(t=1;t<re->speechlen;t++) { 00436 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 00437 gdk_draw_line(pixmap, dgc, 00438 scale_x_wave(t-1), scale_y_wave(re->speech[t-1]), 00439 scale_x_wave(t), scale_y_wave(re->speech[t])); 00440 } 00441 } 00442 00443 00444 /**********************************************************************/ 00445 /* GTK primitive functions to draw a trellis atom */ 00446 /**********************************************************************/ 00447 00470 static void 00471 mygdk_draw_arc(GtkWidget *widget, int x1, int y1, int x2, int y2, int sw) 00472 { 00473 int width; 00474 UserColors c; 00475 00476 /* first time, make gc for drawing */ 00477 if (dgc == NULL) { 00478 dgc = gdk_gc_new(widget->window); 00479 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]); 00480 } 00481 00482 /* change arc style by sw */ 00483 switch(sw) { 00484 case 0: c = C_LINE_FAINT; width = 1; break; 00485 case 1: c = C_LINE; width = 1; break; 00486 case 2: c = C_LINE_BEST; width = 3; break; 00487 case 3: c = C_PASS2_NEXT; width = 1; break; /* next */ 00488 case 4: c = C_PASS2; width = 1; break; /* popper (realigned) */ 00489 case 5: c = C_PASS2_NEXT; width = 2; break; /* popped (original) */ 00490 case 6: c = C_PASS2_BEST; width = 3; break; 00491 default: c = C_LINE; width = 1; break; 00492 } 00493 00494 /* draw arc line */ 00495 if (sw_line) { 00496 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 00497 gdk_gc_set_foreground(dgc, &(cols[c])); 00498 gdk_draw_line(pixmap, dgc, x1, y1, x2, y2); 00499 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 00500 } 00501 00502 /* draw begin/end point rectangle */ 00503 if (sw != 0 && sw != 5) { 00504 /* make edge */ 00505 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW])); 00506 gdk_draw_rectangle(pixmap, dgc, 00507 TRUE, 00508 x1 - width/2 - 2, 00509 y1 - width/2 -2, 00510 width+4, 00511 width+4); 00512 gdk_draw_rectangle(pixmap, dgc, 00513 TRUE, 00514 x2 - width/2 - 2, 00515 y2 - width/2 -2, 00516 width+4, 00517 width+4); 00518 } 00519 gdk_gc_set_foreground(dgc, &(cols[C_BGN])); 00520 gdk_draw_rectangle(pixmap, dgc, 00521 TRUE, 00522 x1 - width/2 - 1, 00523 y1 - width/2 -1, 00524 width+2, 00525 width+2); 00526 if (c == C_LINE_BEST || c == C_PASS2_BEST) { 00527 gdk_gc_set_foreground(dgc, &(cols[C_END_BEST])); 00528 } else { 00529 gdk_gc_set_foreground(dgc, &(cols[C_END])); 00530 } 00531 gdk_draw_rectangle(pixmap, dgc, 00532 TRUE, 00533 x2 - width/2 - 1, 00534 y2 - width/2 - 1, 00535 width+2, 00536 width+2); 00537 00538 } 00539 00558 static void 00559 draw_atom_sub(GtkWidget *widget, TRELLIS_ATOM *tre, TRELLIS_ATOM *last_tre, int sw) 00560 { 00561 int from_t; 00562 LOGPROB from_s; 00563 int from_w; 00564 00565 /* draw word arc */ 00566 if (sw_wid_axis) { 00567 if (tre->begintime <= 0) { 00568 from_t = 0; 00569 from_w = WORD_INVALID; 00570 } else { 00571 from_t = last_tre->endtime; 00572 from_w = last_tre->wid; 00573 } 00574 mygdk_draw_arc(widget, 00575 scale_x(from_t), 00576 scale_y_wid(from_w), 00577 scale_x(tre->endtime), 00578 scale_y_wid(tre->wid), 00579 sw); 00580 } else { 00581 if (tre->begintime <= 0) { 00582 from_t = 0; 00583 from_s = 0.0; 00584 } else { 00585 from_t = last_tre->endtime; 00586 from_s = last_tre->backscore; 00587 } 00588 mygdk_draw_arc(widget, 00589 scale_x(from_t), 00590 scale_y(from_s, from_t), 00591 scale_x(tre->endtime), 00592 scale_y(tre->backscore, tre->endtime), 00593 sw); 00594 } 00595 } 00596 00613 static void 00614 draw_atom(GtkWidget *widget, TRELLIS_ATOM *tre, int sw) 00615 { 00616 draw_atom_sub(widget, tre, tre->last_tre, sw); 00617 } 00618 00619 /* draw word output text */ 00636 static void 00637 draw_atom_text(GtkWidget *widget, TRELLIS_ATOM *tre, int sw) 00638 { 00639 gint text_width; 00640 UserColors c; 00641 int style; 00642 int dx, dy, x, y; 00643 WORD_INFO *winfo; 00644 00645 winfo = re->model->winfo; 00646 00647 if (winfo->woutput[tre->wid] != NULL && strlen(winfo->woutput[tre->wid]) > 0) { 00648 switch(sw) { 00649 case 0: style = -1; break; 00650 case 1: c = C_TEXT; style = 0; break; 00651 case 2: c = C_TEXT_BEST; style = 1; break; 00652 case 3: c = C_PASS2_NEXT; style = 0; break; 00653 case 4: c = C_PASS2; style = 0; break; 00654 case 5: c = C_PASS2; style = 1; break; 00655 case 6: c = C_PASS2_BEST; style = 1; break; 00656 default: c = C_TEXT; style = 0; break; 00657 } 00658 if (style == -1) return; /* do not draw text */ 00659 00660 text_width = gdk_string_width(fontset, winfo->woutput[tre->wid]) + 1; 00661 x = scale_x(tre->endtime) - text_width; 00662 if (sw_wid_axis) { 00663 y = scale_y_wid(tre->wid) - 4; 00664 } else { 00665 y = scale_y(tre->backscore, tre->endtime) - 4; 00666 } 00667 00668 if (style == 1) { /* make edge */ 00669 gdk_gc_set_foreground(dgc, &cols[C_SHADOW]); 00670 for (dx = -1; dx <= 1; dx++) { 00671 for (dy = -1; dy <= 1; dy++) { 00672 if (dx == 0 && dy == 0) continue; 00673 gdk_draw_string(pixmap, fontset, dgc, x + dx, y + dy, 00674 winfo->woutput[tre->wid]); 00675 } 00676 } 00677 } 00678 gdk_gc_set_foreground(dgc, &cols[c]); 00679 gdk_draw_string(pixmap, fontset, dgc, x, y, 00680 winfo->woutput[tre->wid]); 00681 } 00682 } 00683 00684 00685 /**********************************************************************/ 00686 /* wrapper for narrowing atoms to be drawn */ 00687 /**********************************************************************/ 00688 static WORD_ID *wordlist = NULL; 00689 static WORD_ID wordlistnum = 0; 00690 00707 static boolean 00708 wordlist_find(WORD_ID wid) 00709 { 00710 int left, right, mid; 00711 00712 if (wordlistnum == 0) return FALSE; 00713 00714 left = 0; 00715 right = wordlistnum - 1; 00716 while (left < right) { 00717 mid = (left + right) / 2; 00718 if (wordlist[mid] < wid) { 00719 left = mid + 1; 00720 } else { 00721 right = mid; 00722 } 00723 } 00724 if (wordlist[left] == wid) return TRUE; 00725 return FALSE; 00726 } 00727 00728 00729 /**********************************************************************/ 00730 /* Top trellis atom drawing functions including wrapper */ 00731 /* All functions below should call this */ 00732 /**********************************************************************/ 00733 00750 static void 00751 draw_atom_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw) 00752 { 00753 if (wordlistnum == 0 || wordlist_find(tre->wid)) { 00754 draw_atom(widget, tre, sw); 00755 } 00756 } 00757 00776 static void 00777 draw_atom_text_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw) 00778 { 00779 if (wordlistnum == 0 || wordlist_find(tre->wid)) { 00780 draw_atom_text(widget, tre, sw); 00781 } 00782 } 00783 00784 00785 /**********************************************************************/ 00786 /* Draw a set of atom according to their properties */ 00787 /**********************************************************************/ 00788 00801 static void 00802 draw_all_atom(GtkWidget *widget) 00803 { 00804 int t, i; 00805 TRELLIS_ATOM *tre; 00806 00807 for (t=0;t<btlocal->framelen;t++) { 00808 for (i=0;i<btlocal->num[t];i++) { 00809 tre = btlocal->rw[t][i]; 00810 draw_atom_top(widget, tre, 0); 00811 } 00812 } 00813 if (sw_text) { 00814 for (t=0;t<btlocal->framelen;t++) { 00815 for (i=0;i<btlocal->num[t];i++) { 00816 tre = btlocal->rw[t][i]; 00817 draw_atom_text_top(widget, tre, 0); 00818 } 00819 } 00820 } 00821 } 00822 00835 static void 00836 draw_context_valid_atom(GtkWidget *widget) 00837 { 00838 int t, i; 00839 TRELLIS_ATOM *tre; 00840 00841 for (t=0;t<btlocal->framelen;t++) { 00842 for (i=0;i<btlocal->num[t];i++) { 00843 tre = btlocal->rw[t][i]; 00844 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) { 00845 draw_atom_top(widget, tre->last_tre, 1); 00846 } 00847 } 00848 } 00849 if (sw_text) { 00850 for (t=0;t<btlocal->framelen;t++) { 00851 for (i=0;i<btlocal->num[t];i++) { 00852 tre = btlocal->rw[t][i]; 00853 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) { 00854 draw_atom_text_top(widget, tre->last_tre, 1); 00855 } 00856 } 00857 } 00858 } 00859 } 00860 00861 #ifdef WORD_GRAPH 00862 00874 static void 00875 draw_word_graph(GtkWidget *widget) 00876 { 00877 int t, i; 00878 TRELLIS_ATOM *tre; 00879 00880 /* assume (1)word atoms in word graph are already marked in 00881 generate_lattice() in beam.c, and (2) backtrellis is wid-sorted */ 00882 for (t=0;t<btlocal->framelen;t++) { 00883 for (i=0;i<btlocal->num[t];i++) { 00884 tre = btlocal->rw[t][i]; 00885 if (tre->within_wordgraph) { 00886 draw_atom_top(widget, tre, 1); 00887 } 00888 } 00889 } 00890 if (sw_text) { 00891 for (t=0;t<btlocal->framelen;t++) { 00892 for (i=0;i<btlocal->num[t];i++) { 00893 tre = btlocal->rw[t][i]; 00894 if (tre->within_wordgraph) { 00895 draw_atom_text_top(widget, tre, 1); 00896 } 00897 } 00898 } 00899 } 00900 00901 } 00902 #endif 00903 00916 static void 00917 draw_best_path(GtkWidget *widget) 00918 { 00919 int last_time; 00920 LOGPROB maxscore; 00921 TRELLIS_ATOM *tre, *last_tre; 00922 int i; 00923 00924 /* look for the beginning trellis word at end of speech */ 00925 for (last_time = btlocal->framelen - 1; last_time >= 0; last_time--) { 00926 #ifdef USE_NGRAM 00927 /* it is fixed to the tail silence model (winfo->tail_silwid) */ 00928 last_tre = bt_binsearch_atom(btlocal, last_time, re->model->winfo->tail_silwid); 00929 if (last_tre != NULL) break; 00930 #else /* USE_DFA */ 00931 /* the best trellis word on the last frame (not use cp_end[]) */ 00932 maxscore = LOG_ZERO; 00933 for (i=0;i<btlocal->num[last_time];i++) { 00934 tre = btlocal->rw[last_time][i]; 00935 /* if (dfa->cp_end[winfo->wton[tmp->wid]] == TRUE) {*/ 00936 if (maxscore < tre->backscore) { 00937 maxscore = tre->backscore; 00938 last_tre = tre; 00939 } 00940 /* }*/ 00941 } 00942 if (maxscore != LOG_ZERO) break; 00943 #endif 00944 } 00945 if (last_time < 0) return; /* last_tre not found */ 00946 00947 /* parse from the beginning word to find the best path */ 00948 draw_atom_top(widget, last_tre, 2); 00949 tre = last_tre; 00950 while (tre->begintime > 0) { 00951 tre = tre->last_tre; 00952 draw_atom_top(widget, tre, 2); 00953 } 00954 if (sw_text) { 00955 draw_atom_text_top(widget, last_tre, 2); 00956 tre = last_tre; 00957 while (tre->begintime > 0) { 00958 tre = tre->last_tre; 00959 draw_atom_text_top(widget, tre, 2); 00960 } 00961 } 00962 } 00963 00964 00965 /**********************************************************************/ 00966 /* 2nd pass drawing data collection functions */ 00967 /* will be called from search_bestfirst_main.c to gather the atoms 00968 referred to in the search process of the 2nd pass */ 00969 /**********************************************************************/ 00970 00983 void 00984 visual2_init(int maxhypo) 00985 { 00986 POPNODE *p, *ptmp; 00987 int i; 00988 00989 if (popped == NULL) { 00990 popped = (POPNODE *)mymalloc(sizeof(POPNODE) * (maxhypo + 1)); 00991 } else { 00992 for(i=0;i<pnum;i++) { 00993 p = popped[i].next; 00994 while(p) { 00995 ptmp = p->next; 00996 free(p); 00997 p = ptmp; 00998 } 00999 } 01000 } 01001 pnum = 1; 01002 /* for start words */ 01003 popped[0].tre = NULL; 01004 popped[0].score = LOG_ZERO; 01005 popped[0].last = NULL; 01006 popped[0].next = NULL; 01007 01008 /* for bests */ 01009 p = lastpop; 01010 while(p) { 01011 ptmp = p->next; 01012 free(p); 01013 p = ptmp; 01014 } 01015 lastpop = NULL; 01016 } 01017 01032 void 01033 visual2_popped(NODE *n, int popctr) 01034 { 01035 if (pnum < popctr + 1) pnum = popctr + 1; 01036 01037 popped[popctr].tre = n->popnode->tre; 01038 popped[popctr].score = n->popnode->score; 01039 popped[popctr].last = n->popnode->last; 01040 popped[popctr].next = NULL; 01041 01042 n->popnode = &(popped[popctr]); 01043 } 01044 01061 void 01062 visual2_next_word(NODE *next, NODE *prev, int popctr) 01063 { 01064 POPNODE *new; 01065 01066 /* allocate new popnode info */ 01067 new = (POPNODE *)mymalloc(sizeof(POPNODE)); 01068 new->tre = next->tre; 01069 new->score = next->score; 01070 /* link between previous POPNODE */ 01071 new->last = (prev) ? prev->popnode : NULL; 01072 next->popnode = new; 01073 /* store */ 01074 new->next = popped[popctr].next; 01075 popped[popctr].next = new; 01076 } 01077 01092 void 01093 visual2_best(NODE *now, WORD_INFO *winfo) 01094 { 01095 POPNODE *new; 01096 01097 new = (POPNODE *)mymalloc(sizeof(POPNODE)); 01098 new->tre = now->popnode->tre; 01099 new->score = now->popnode->score; 01100 new->last = now->popnode->last; 01101 new->next = lastpop; 01102 lastpop = new; 01103 } 01104 01105 /**********************************************************************/ 01106 /* Draw atoms refered at the 2nd pass */ 01107 /**********************************************************************/ 01108 01109 /* draw 2nd pass results */ 01122 static void 01123 draw_final_results(GtkWidget *widget) 01124 { 01125 POPNODE *firstp, *lastp, *p; 01126 01127 for(firstp = lastpop; firstp; firstp = firstp->next) { 01128 if (firstp->tre != NULL) { 01129 draw_atom(widget, firstp->tre, 6); 01130 } 01131 lastp = firstp; 01132 for(p = firstp->last; p; p = p->last) { 01133 if (p->tre != NULL) { 01134 draw_atom_sub(widget, p->tre, lastp->tre, 6); 01135 draw_atom_text_top(widget, p->tre, 6); 01136 } 01137 lastp = p; 01138 } 01139 } 01140 } 01141 01142 static LOGPROB maxscore; 01143 static LOGPROB minscore; 01144 01154 static void 01155 get_max_hypo_score() 01156 { 01157 POPNODE *p; 01158 int i; 01159 01160 maxscore = LOG_ZERO; 01161 minscore = 0.0; 01162 for(i=1;i<pnum;i++) { 01163 if (maxscore < popped[i].score) maxscore = popped[i].score; 01164 if (minscore > popped[i].score) minscore = popped[i].score; 01165 } 01166 } 01167 01184 static gint 01185 scale_hypo_y(LOGPROB s) 01186 { 01187 gint y; 01188 gint yoffset, height; 01189 01190 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0); 01191 height = canvas_height - yoffset - CANVAS_MARGIN; 01192 y = (maxscore - s) * height / (maxscore - minscore) + yoffset; 01193 return(y); 01194 } 01195 01196 /* draw popped words */ 01217 static void 01218 draw_popped(GtkWidget *widget, POPNODE *p, UserColors c, int width, int style) 01219 { 01220 int text_width; 01221 gint x, y; 01222 01223 if (p->tre == NULL) return; 01224 01225 if (p->last != NULL && p->last->tre != NULL) { 01226 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 01227 gdk_gc_set_foreground(dgc, &(cols[c])); 01228 gdk_draw_line(pixmap, dgc, 01229 scale_x(p->last->tre->endtime), 01230 scale_hypo_y(p->last->score), 01231 scale_x(p->tre->endtime), 01232 scale_hypo_y(p->score)); 01233 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 01234 } 01235 01236 if (p->tre != NULL) { 01237 x = scale_x(p->tre->endtime); 01238 y = scale_hypo_y(p->score); 01239 if (style == 1) { 01240 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW])); 01241 gdk_draw_rectangle(pixmap, dgc, 01242 TRUE, 01243 x - 3, 01244 y - 3, 01245 7, 01246 7); 01247 } else if (style == 2) { 01248 gdk_gc_set_foreground(dgc, &(cols[c])); 01249 gdk_draw_rectangle(pixmap, dgc, 01250 TRUE, 01251 x - 3, 01252 y - 3, 01253 7, 01254 7); 01255 } 01256 gdk_gc_set_foreground(dgc, &(cols[c])); 01257 gdk_draw_rectangle(pixmap, dgc, 01258 TRUE, 01259 x - 2, 01260 y - 2, 01261 5, 01262 5); 01263 if (p->tre->wid != WORD_INVALID) { 01264 text_width = gdk_string_width(fontset, re->model->winfo->woutput[p->tre->wid]) + 1; 01265 gdk_draw_string(pixmap, fontset, dgc, x - text_width-1, y - 5, 01266 re->model->winfo->woutput[p->tre->wid]); 01267 } 01268 } 01269 01270 01271 } 01272 01273 /* draw popped words at one hypothesis expantion */ 01274 01275 static int old_popctr; 01276 01291 static void 01292 draw_popnodes(GtkWidget *widget, int popctr) 01293 { 01294 POPNODE *p, *porg; 01295 01296 if (popctr < 0 || popctr >= pnum) { 01297 fprintf(stderr, "invalid popctr (%d > %d)!\n", popctr, pnum); 01298 return; 01299 } 01300 01301 porg = &(popped[popctr]); 01302 01303 /* draw expanded atoms */ 01304 for(p = porg->next; p; p = p->next) { 01305 draw_popped(widget, p, C_LINE_BEST, 1, 0); 01306 } 01307 01308 /* draw hypothesis context */ 01309 for(p = porg->last; p; p = p->last) { 01310 draw_popped(widget, p, C_PASS2_BEST, 2, 0); 01311 } 01312 draw_popped(widget, porg, C_PASS2_BEST, 3, 1); 01313 01314 old_popctr = popctr; 01315 } 01328 static void 01329 draw_popnodes_old(GtkWidget *widget) 01330 { 01331 POPNODE *p, *porg; 01332 01333 porg = &(popped[old_popctr]); 01334 01335 /* draw expanded atoms */ 01336 for(p = porg->next; p; p = p->next) { 01337 draw_popped(widget, p, C_LINE_FAINT, 1, 0); 01338 } 01339 01340 /* draw hypothesis context */ 01341 for(p = porg->last; p; p = p->last) { 01342 draw_popped(widget, p, C_PASS2, 2, 0); 01343 } 01344 draw_popped(widget, porg, C_PASS2, 3, 2); 01345 } 01346 01347 /**********************************************************************/ 01348 /* GTK TopLevel draw/redraw functions */ 01349 /* will be called for each exposure/configure event */ 01350 /**********************************************************************/ 01351 static boolean fitscreen = TRUE; 01352 01365 static void 01366 draw_background(GtkWidget *widget) 01367 { 01368 static char buf[MAX_HMMNAME_LEN]; 01369 01370 /* first time, make gc for drawing */ 01371 if (dgc == NULL) { 01372 dgc = gdk_gc_new(widget->window); 01373 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]); 01374 } 01375 /* clear pixmap background */ 01376 gdk_gc_set_foreground(dgc, &(cols[C_BG])); 01377 gdk_draw_rectangle(pixmap, dgc, TRUE, 01378 0,0,canvas_width,canvas_height); 01379 01380 /* display view mode and zoom status */ 01381 gdk_gc_set_foreground(dgc, &(cols[C_TEXT])); 01382 if (sw_hypo) { 01383 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16, 01384 "Hypothesis score (2nd pass)"); 01385 } else { 01386 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16, 01387 sw_wid_axis ? "Word ID" : (sw_score_beam ? "Beam score" : "Accumulated score (normalized by time)")); 01388 } 01389 snprintf(buf, 50, "x%3.1f", (float)canvas_width / (float)btlocal->framelen); 01390 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 3, buf); 01391 } 01392 01405 static void 01406 drawarea_draw(GtkWidget *widget) 01407 { 01408 /* allocate (new) pixmap */ 01409 if (pixmap) { 01410 gdk_pixmap_unref(pixmap); /* destroy old one */ 01411 } 01412 pixmap = gdk_pixmap_new(widget->window, canvas_width, canvas_height, -1); 01413 01414 /* make background */ 01415 draw_background(widget); 01416 01417 if (re->speechlen != 0) { 01418 draw_waveform(widget); 01419 } 01420 01421 if (!sw_hypo) { 01422 if (btlocal != NULL) { 01423 /* draw objects */ 01424 draw_all_atom(widget); 01425 #ifdef WORD_GRAPH 01426 draw_word_graph(widget); 01427 #else 01428 draw_context_valid_atom(widget); 01429 #endif 01430 draw_best_path(widget); 01431 } 01432 if (popped != NULL) { 01433 /* draw 2nd pass objects */ 01434 draw_final_results(widget); 01435 } 01436 } 01437 } 01438 01451 static void 01452 drawarea_expose(GtkWidget *widget) 01453 { 01454 GdkRectangle r; 01455 01456 r.x = 0; 01457 r.y = 0; 01458 r.width = canvas_width; 01459 r.height = canvas_height; 01460 gtk_widget_draw(widget, &r); 01461 } 01462 01483 static gboolean 01484 event_drawarea_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) 01485 { 01486 if (pixmap != NULL) { 01487 gdk_draw_pixmap(widget->window, 01488 widget->style->fg_gc[GTK_STATE_NORMAL], 01489 pixmap, 01490 event->area.x, event->area.y, 01491 event->area.x, event->area.y, 01492 event->area.width, event->area.height); 01493 } 01494 } 01495 01516 static gboolean 01517 event_drawarea_configure(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) 01518 { 01519 if (fitscreen) { /* if in zoom mode, resizing window does not cause resize of the canvas */ 01520 canvas_width = widget->allocation.width; /* get canvas size */ 01521 } 01522 /* canvas height will be always automatically changed by resizing */ 01523 canvas_height = widget->allocation.height; 01524 01525 /* redraw objects to pixmap */ 01526 drawarea_draw(widget); 01527 } 01528 01529 01530 /**********************************************************************/ 01531 /* GTK callbacks for buttons */ 01532 /**********************************************************************/ 01533 01548 static void 01549 action_toggle_thres(GtkWidget *widget) 01550 { 01551 01552 if (re->speechlen == 0) return; 01553 /* toggle switch */ 01554 if (sw_level_thres) sw_level_thres = FALSE; 01555 else sw_level_thres = TRUE; 01556 01557 /* redraw objects to pixmap */ 01558 drawarea_draw(widget); 01559 01560 /* tell X to issue expose event on this window */ 01561 drawarea_expose(widget); 01562 } 01563 01564 #ifdef PLAYCOMMAND 01565 01577 static void 01578 action_play_waveform(GtkWidget *widget) 01579 { 01580 char buf[80]; 01581 static char command[250]; 01582 int fd; 01583 01584 if (re->speechlen == 0) return; 01585 01586 /* play waveform */ 01587 snprintf(buf, 250, "/var/tmp/julius_visual_play.%d", getpid()); 01588 if ((fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) { 01589 fprintf(stderr, "cannot open %s for writing\n", buf); 01590 return; 01591 } 01592 if (wrsamp(fd, re->speech, re->speechlen) < 0) { 01593 fprintf(stderr, "failed to write to %s for playing\n", buf); 01594 return; 01595 } 01596 close(fd); 01597 01598 snprintf(command, 250, PLAYCOMMAND, re->jconf->analysis.para.smp_freq, buf); 01599 printf("play: [%s]\n", command); 01600 system(command); 01601 01602 unlink(buf); 01603 } 01604 #endif 01605 01620 static void 01621 action_view_wid(GtkWidget *button, GtkWidget *widget) 01622 { 01623 if (GTK_TOGGLE_BUTTON(button)->active) { 01624 /* set switch */ 01625 sw_wid_axis = TRUE; 01626 sw_hypo = FALSE; 01627 /* redraw objects to pixmap */ 01628 drawarea_draw(widget); 01629 /* tell X to issue expose event on this window */ 01630 drawarea_expose(widget); 01631 } else { 01632 sw_wid_axis = FALSE; 01633 } 01634 } 01635 01650 static void 01651 action_view_score(GtkWidget *button, GtkWidget *widget) 01652 { 01653 if (GTK_TOGGLE_BUTTON(button)->active) { 01654 /* set switch */ 01655 sw_score_beam = FALSE; 01656 sw_hypo = FALSE; 01657 /* redraw objects to pixmap */ 01658 drawarea_draw(widget); 01659 /* tell X to issue expose event on this window */ 01660 drawarea_expose(widget); 01661 } 01662 } 01663 01680 static void 01681 action_view_beam(GtkWidget *button, GtkWidget *widget) 01682 { 01683 if (GTK_TOGGLE_BUTTON(button)->active) { 01684 /* set switch */ 01685 sw_score_beam = TRUE; 01686 sw_hypo = FALSE; 01687 /* redraw objects to pixmap */ 01688 drawarea_draw(widget); 01689 /* tell X to issue expose event on this window */ 01690 drawarea_expose(widget); 01691 } 01692 } 01693 01710 static void 01711 action_toggle_arc(GtkWidget *button, GtkWidget *widget) 01712 { 01713 if (GTK_TOGGLE_BUTTON(button)->active) { 01714 sw_text = TRUE; 01715 sw_line = TRUE; 01716 } else { 01717 sw_text = FALSE; 01718 sw_line = FALSE; 01719 } 01720 /* redraw objects to pixmap */ 01721 drawarea_draw(widget); 01722 /* tell X to issue expose event on this window */ 01723 drawarea_expose(widget); 01724 } 01725 01742 static void 01743 action_set_wid(GtkWidget *widget, GtkWidget *draw) 01744 { 01745 gchar *entry_text; 01746 WORD_ID i; 01747 01748 entry_text = gtk_entry_get_text(GTK_ENTRY(widget)); 01749 01750 /* allocate */ 01751 if (wordlist == NULL) { 01752 wordlist = mymalloc(sizeof(WORD_ID) * re->model->winfo->num); 01753 } 01754 wordlistnum = 0; 01755 01756 /* pickup words with the specified output text and regiter them to the lsit */ 01757 if (strlen(entry_text) == 0) { 01758 wordlistnum = 0; 01759 } else { 01760 for (i=0;i<re->model->winfo->num;i++) { 01761 if (strmatch(entry_text, re->model->winfo->woutput[i])) { 01762 wordlist[wordlistnum] = i; 01763 wordlistnum++; 01764 } 01765 } 01766 if (wordlistnum == 0) { 01767 fprintf(stderr, "word \"%s\" not found, show all\n", entry_text); 01768 } else { 01769 fprintf(stderr, "%d words found for \"%s\"\n", wordlistnum, entry_text); 01770 } 01771 } 01772 01773 /* redraw objects to pixmap */ 01774 drawarea_draw(draw); 01775 /* tell X to issue expose event on this window */ 01776 drawarea_expose(draw); 01777 } 01778 01793 static void 01794 action_zoom(GtkWidget *widget) 01795 { 01796 fitscreen = FALSE; 01797 if (btlocal != NULL) { 01798 canvas_width = btlocal->framelen * 2; 01799 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height); 01800 01801 } 01802 drawarea_draw(widget); 01803 drawarea_expose(widget); 01804 } 01805 01820 static void 01821 action_zoom_4(GtkWidget *widget) 01822 { 01823 fitscreen = FALSE; 01824 if (btlocal != NULL) { 01825 canvas_width = btlocal->framelen * 4; 01826 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height); 01827 } 01828 01829 drawarea_draw(widget); 01830 drawarea_expose(widget); 01831 } 01832 01847 static void 01848 action_zoom_8(GtkWidget *widget) 01849 { 01850 fitscreen = FALSE; 01851 if (btlocal != NULL) { 01852 canvas_width = btlocal->framelen * 8; 01853 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height); 01854 } 01855 01856 drawarea_draw(widget); 01857 drawarea_expose(widget); 01858 } 01859 01874 static void 01875 action_fit_screen(GtkWidget *widget) 01876 { 01877 fitscreen = TRUE; 01878 canvas_width = widget->parent->allocation.width; 01879 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height); 01880 01881 drawarea_draw(widget); 01882 drawarea_expose(widget); 01883 } 01884 01900 static void 01901 action_toggle_popctr(GtkWidget *button, GtkWidget *widget) 01902 { 01903 if (GTK_TOGGLE_BUTTON(button)->active) { 01904 sw_hypo = TRUE; 01905 } else { 01906 sw_hypo = FALSE; 01907 } 01908 drawarea_draw(widget); 01909 drawarea_expose(widget); 01910 } 01911 01929 static void 01930 action_change_popctr(GtkAdjustment *adj, GtkWidget *widget) 01931 { 01932 int popctr; 01933 01934 if (sw_hypo) { 01935 popctr = adj->value; 01936 draw_popnodes_old(widget); 01937 draw_popnodes(widget, popctr); 01938 drawarea_expose(widget); 01939 } 01940 } 01941 01942 /**********************************************************************/ 01943 /* GTK delete/destroy event handler */ 01944 /**********************************************************************/ 01945 01966 static gint 01967 delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) 01968 { 01969 return (FALSE); /* emit destroy signal */ 01970 } 01971 01986 static void 01987 destroy(GtkWidget *widget, gpointer data) 01988 { 01989 gtk_main_quit(); 01990 } 01991 01992 /**********************************************************************/ 01993 /* Main public functions for visualization */ 01994 /**********************************************************************/ 01995 02004 void 02005 visual_init(Recog *recog) 02006 { 02007 POPNODE *p; 02008 02009 /* hold recognition instance to local */ 02010 re = recog; 02011 02012 /* reset values */ 02013 btlocal = NULL; 02014 02015 /* initialize Gtk/Gdk libraries */ 02016 /* no argument passed as gtk options */ 02017 /*gtk_init (&argc, &argv);*/ 02018 gtk_init(NULL, NULL); 02019 02020 /* set locale */ 02021 gtk_set_locale(); 02022 02023 /* load fontset */ 02024 fontset = gdk_fontset_load(FONTSET); 02025 if (fontset == NULL) { 02026 fprintf(stderr, "cannot load X font \"%s\" for visualize\n", FONTSET); exit(-1); 02027 } 02028 02029 /* initialize color */ 02030 color_init(); 02031 02032 fprintf(stderr, "GTK initialized\n"); 02033 02034 } 02035 02048 void 02049 visual_show(BACKTRELLIS *bt) 02050 { 02051 GtkWidget *window, *button, *draw, *entry, *scrolled_window, *scale; 02052 GtkWidget *box1, *box2, *label, *frame, *box3; 02053 GtkObject *adj; 02054 GSList *group; 02055 GList *glist; 02056 02057 02058 fprintf(stderr, "*** Showing word trellis view (close window to proceed)\n"); 02059 02060 /* store pointer to backtrellis data */ 02061 btlocal = bt; 02062 02063 /* prepare for Y axis score normalization */ 02064 get_max_frame_score(bt); 02065 02066 /* prepare for Y axis hypo score normalization */ 02067 get_max_hypo_score(); 02068 02069 /* prepare for waveform */ 02070 if (re->speechlen != 0) get_max_waveform_level(); 02071 02072 /* start with trellis view */ 02073 sw_hypo = FALSE; 02074 02075 /* reset value */ 02076 fitscreen = TRUE; 02077 if (dgc != NULL) { 02078 gdk_gc_unref(dgc); 02079 dgc = NULL; 02080 } 02081 02082 /* create main window */ 02083 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 02084 gtk_widget_set_usize(GTK_WIDGET(window), DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT); 02085 gtk_window_set_title(GTK_WINDOW(window), WINTITLE); 02086 gtk_signal_connect(GTK_OBJECT(window), "delete_event", 02087 GTK_SIGNAL_FUNC(delete_event), NULL); 02088 gtk_signal_connect(GTK_OBJECT(window), "destroy", 02089 GTK_SIGNAL_FUNC(destroy), NULL); 02090 gtk_container_border_width(GTK_CONTAINER(window), 10); 02091 02092 /* create horizontal packing box */ 02093 box1 = gtk_hbox_new(FALSE, 5); 02094 gtk_container_add(GTK_CONTAINER(window), box1); 02095 02096 /* create scrolled window */ 02097 scrolled_window = gtk_scrolled_window_new(NULL, NULL); 02098 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_ALWAYS,GTK_POLICY_AUTOMATIC); 02099 02100 /* create drawing area */ 02101 draw = gtk_drawing_area_new(); 02102 /* gtk_drawing_area_size(GTK_DRAWING_AREA(draw), DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT);*/ 02103 gtk_signal_connect(GTK_OBJECT(draw), "expose-event", GTK_SIGNAL_FUNC(event_drawarea_expose), NULL); 02104 gtk_signal_connect(GTK_OBJECT(draw), "configure-event", GTK_SIGNAL_FUNC(event_drawarea_configure), NULL); 02105 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), draw); 02106 gtk_box_pack_start(GTK_BOX(box1), scrolled_window, TRUE, TRUE, 0); 02107 02108 /* create packing box for buttons */ 02109 box2 = gtk_vbox_new(FALSE, 5); 02110 gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0); 02111 02112 if (re->speechlen != 0) { 02113 /* create waveform related frame */ 02114 frame = gtk_frame_new("waveform"); 02115 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02116 box3 = gtk_hbox_new(FALSE, 5); 02117 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02118 gtk_container_add(GTK_CONTAINER(frame), box3); 02119 02120 /* create play button if supported */ 02121 #ifdef PLAYCOMMAND 02122 button = gtk_button_new_with_label("play"); 02123 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02124 GTK_SIGNAL_FUNC(action_play_waveform), GTK_OBJECT(draw)); 02125 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02126 #endif 02127 02128 /* create level thres toggle button */ 02129 button = gtk_button_new_with_label("thres"); 02130 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02131 GTK_SIGNAL_FUNC(action_toggle_thres), GTK_OBJECT(draw)); 02132 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02133 } 02134 02135 /* create scaling frame */ 02136 frame = gtk_frame_new("change view"); 02137 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02138 box3 = gtk_hbox_new(FALSE, 5); 02139 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02140 gtk_container_add(GTK_CONTAINER(frame), box3); 02141 02142 /* create word view button */ 02143 button = gtk_radio_button_new_with_label(NULL, "word"); 02144 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE); 02145 gtk_signal_connect(GTK_OBJECT(button), "toggled", 02146 GTK_SIGNAL_FUNC(action_view_wid), GTK_OBJECT(draw)); 02147 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02148 02149 /* create score view button */ 02150 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); 02151 button = gtk_radio_button_new_with_label(group, "score"); 02152 gtk_signal_connect(GTK_OBJECT(button), "toggled", 02153 GTK_SIGNAL_FUNC(action_view_score), GTK_OBJECT(draw)); 02154 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02155 02156 /* create beam view button */ 02157 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); 02158 button = gtk_radio_button_new_with_label(group, "beam"); 02159 gtk_signal_connect(GTK_OBJECT(button), "toggled", 02160 GTK_SIGNAL_FUNC(action_view_beam), GTK_OBJECT(draw)); 02161 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02162 02163 /* create show/hide frame */ 02164 frame = gtk_frame_new("show/hide"); 02165 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02166 box3 = gtk_vbox_new(FALSE, 5); 02167 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02168 gtk_container_add(GTK_CONTAINER(frame), box3); 02169 02170 /* create text toggle button */ 02171 button = gtk_toggle_button_new_with_label("arcs"); 02172 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE); 02173 gtk_signal_connect(GTK_OBJECT(button), "toggled", 02174 GTK_SIGNAL_FUNC(action_toggle_arc), GTK_OBJECT(draw)); 02175 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02176 02177 /* create word entry frame */ 02178 frame = gtk_frame_new("view words"); 02179 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02180 box3 = gtk_vbox_new(FALSE, 5); 02181 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02182 gtk_container_add(GTK_CONTAINER(frame), box3); 02183 02184 /* create word ID entry */ 02185 entry = gtk_entry_new_with_max_length(16); 02186 gtk_signal_connect(GTK_OBJECT(entry), "activate", 02187 GTK_SIGNAL_FUNC(action_set_wid), GTK_OBJECT(draw)); 02188 gtk_box_pack_start(GTK_BOX(box3), entry, FALSE, FALSE, 0); 02189 02190 /* create zoom frame */ 02191 frame = gtk_frame_new("zoom"); 02192 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02193 box3 = gtk_hbox_new(FALSE, 5); 02194 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02195 gtk_container_add(GTK_CONTAINER(frame), box3); 02196 02197 /* create x zoom button */ 02198 button = gtk_button_new_with_label("x2"); 02199 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02200 GTK_SIGNAL_FUNC(action_zoom), GTK_OBJECT(draw)); 02201 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02202 02203 /* create x zoom button */ 02204 button = gtk_button_new_with_label("x4"); 02205 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02206 GTK_SIGNAL_FUNC(action_zoom_4), GTK_OBJECT(draw)); 02207 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02208 02209 /* create x more zoom button */ 02210 button = gtk_button_new_with_label("x8"); 02211 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02212 GTK_SIGNAL_FUNC(action_zoom_8), GTK_OBJECT(draw)); 02213 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02214 02215 /* create fit screen button */ 02216 button = gtk_button_new_with_label("fit"); 02217 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02218 GTK_SIGNAL_FUNC(action_fit_screen), GTK_OBJECT(draw)); 02219 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02220 02221 /* create replay frame */ 02222 frame = gtk_frame_new("pass2 replay"); 02223 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0); 02224 box3 = gtk_vbox_new(FALSE, 5); 02225 gtk_container_set_border_width(GTK_CONTAINER(box3), 5); 02226 gtk_container_add(GTK_CONTAINER(frame), box3); 02227 02228 adj = gtk_adjustment_new(0.0, 0.0, (pnum-1) + 5, 1.0, 1.0, 5.0); 02229 gtk_signal_connect(GTK_OBJECT(adj), "value_changed", 02230 GTK_SIGNAL_FUNC(action_change_popctr), GTK_OBJECT(draw)); 02231 02232 /* create replay start button */ 02233 button = gtk_toggle_button_new_with_label("start"); 02234 gtk_signal_connect(GTK_OBJECT(button), "toggled", 02235 GTK_SIGNAL_FUNC(action_toggle_popctr), GTK_OBJECT(draw)); 02236 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0); 02237 02238 /* create replay scale widget */ 02239 scale = gtk_hscale_new(GTK_ADJUSTMENT(adj)); 02240 gtk_scale_set_digits(GTK_SCALE(scale), 0); 02241 gtk_box_pack_start(GTK_BOX(box3), scale, FALSE, FALSE, 0); 02242 02243 /* create close button */ 02244 button = gtk_button_new_with_label("close"); 02245 /* connect click event to close the window */ 02246 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", 02247 GTK_SIGNAL_FUNC(gtk_widget_destroy), 02248 GTK_OBJECT(window)); 02249 02250 gtk_box_pack_start(GTK_BOX(box2), button, FALSE, FALSE, 0); 02251 02252 /* show all the widget */ 02253 gtk_widget_show_all(window); 02254 02255 /* enter the gtk event routine */ 02256 gtk_main(); 02257 } 02258 02259 #endif /* VISUALIZE */