Recognizes if input is ogg or not.
[xiph.git] / spectrum / panel.c
blob3957fd2650a8ed8fde3a27b206332afbf177b666
1 /*
3 * gtk2 spectrum analyzer
4 *
5 * Copyright (C) 2004 Monty
7 * This analyzer is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
12 * The analyzer is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Postfish; see the file COPYING. If not, write to the
19 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "analyzer.h"
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include "fisharray.h"
28 #include "plot.h"
30 sig_atomic_t increment_fish=0;
32 static struct panel {
33 GtkWidget *twirlimage;
34 GdkPixmap *ff[19];
35 GdkBitmap *fb[19];
37 GtkAccelGroup *group;
38 GtkWidget *toplevel;
41 guint fishframe_timer;
42 int fishframe_init;
43 int fishframe;
45 GtkWidget *plot;
46 GtkWidget *run;
47 GtkWidget **chbuttons;
49 } p;
51 int plot_res=0;
52 int plot_scale=0;
53 int plot_mode=0;
54 int plot_link=0;
55 int plot_hold=0;
56 int plot_depth=90;
57 int plot_noise=0;
58 int plot_last_update=0;
59 int *active;
61 static void replot(struct panel *p){
62 int i,lactive[total_ch];
63 for(i=0;i<total_ch;i++)
64 lactive[i]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->chbuttons[i]));
66 /* update the spectral display; send new data */
67 if(!plot_hold){
68 pthread_mutex_lock(&feedback_mutex);
69 plot_refresh(PLOT(p->plot),lactive);
70 plot_last_update=feedback_increment;
71 pthread_mutex_unlock(&feedback_mutex);
75 static void shutdown(void){
76 gtk_main_quit();
79 /* gotta have the Fucking Fish */
80 static int reanimate_fish(struct panel *p){
81 if(process_active || (p->fishframe>0 && p->fishframe<12)){
82 /* continue spinning */
83 if(increment_fish)p->fishframe++;
84 if(p->fishframe>=12)p->fishframe=0;
86 gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage),
87 p->ff[p->fishframe],
88 p->fb[p->fishframe]);
90 if(p->fishframe==0 && !process_active){
91 /* reschedule to blink */
92 p->fishframe_timer=
93 g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
94 return FALSE;
97 }else{
98 p->fishframe++;
99 if(p->fishframe<=1)p->fishframe=12;
100 if(p->fishframe>=19)p->fishframe=0;
102 gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage),
103 p->ff[p->fishframe],
104 p->fb[p->fishframe]);
107 if(p->fishframe==12){
108 /* reschedule to animate */
109 p->fishframe_timer=
110 g_timeout_add(10,(GSourceFunc)reanimate_fish,p);
111 return FALSE;
113 if(p->fishframe==0){
114 /* reschedule to blink */
115 p->fishframe_timer=
116 g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
117 return FALSE;
120 return TRUE;
123 static void animate_fish(struct panel *p){
124 if(p->fishframe_init){
125 g_source_remove(p->fishframe_timer);
126 p->fishframe_timer=
127 g_timeout_add(80,(GSourceFunc)reanimate_fish,p);
128 }else{
129 p->fishframe_init=1;
130 p->fishframe_timer=
131 g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
135 static void dump(GtkWidget *widget,struct panel *p){
136 process_dump(plot_mode);
139 static void noise(GtkWidget *widget,struct panel *p){
140 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){
141 if(plot_noise){
142 plot_noise=0;
143 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),0);
144 clear_noise_floor();
145 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,0);
146 }else{
147 plot_noise=1;
148 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,0);
150 }else{
151 if(plot_noise){
152 gtk_button_set_label(GTK_BUTTON(widget),"clear _noise floor");
153 plot_noise=2;
154 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,1);
155 }else
156 gtk_button_set_label(GTK_BUTTON(widget),"sample _noise floor");
161 static void depthchange(GtkWidget *widget,struct panel *p){
162 int choice=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
163 switch(choice){
164 case 0: /* 10dB */
165 plot_depth=10;
166 break;
167 case 1: /* 20dB */
168 plot_depth=20;
169 break;
170 case 2: /* 45dB */
171 plot_depth=45;
172 break;
173 case 3: /* 90dB */
174 plot_depth=90;
175 break;
176 case 4: /*140dB */
177 plot_depth=140;
178 break;
180 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
183 static void set_fg(GtkWidget *c, gpointer in){
184 GdkColor *rgb = in;
185 gtk_widget_modify_fg(c,GTK_STATE_NORMAL,rgb);
186 gtk_widget_modify_fg(c,GTK_STATE_ACTIVE,rgb);
187 gtk_widget_modify_fg(c,GTK_STATE_PRELIGHT,rgb);
188 gtk_widget_modify_fg(c,GTK_STATE_SELECTED,rgb);
190 /* buttons usually have internal labels */
191 if(GTK_IS_CONTAINER(c))
192 gtk_container_forall (GTK_CONTAINER(c),set_fg,in);
195 static void set_via_active(struct panel *p, int *active, int *bactive){
196 int fi,i;
197 int ch=0;
198 for(fi=0;fi<inputs;fi++){
199 for(i=ch;i<ch+channels[fi];i++)
200 gtk_widget_set_sensitive(p->chbuttons[i],1);
201 ch+=channels[fi];
203 plot_set_active(PLOT(p->plot),active,bactive);
206 static void chlabels(GtkWidget *widget,struct panel *p){
207 /* scan state, update labels on channel buttons, set sensitivity
208 based on grouping and mode */
209 int fi,ch,i;
210 char buf[80];
211 int bactive[total_ch];
213 for(i=0;i<total_ch;i++)
214 bactive[i]=active[i]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->chbuttons[i]));
216 /* set sensitivity */
217 switch(plot_link){
218 case LINK_IMPEDENCE_p1:
219 case LINK_IMPEDENCE_1:
220 case LINK_IMPEDENCE_10:
221 case LINK_THD:
222 case LINK_THDN:
223 case LINK_THD2:
224 case LINK_THDN2:
225 case LINK_SUB_REF:
227 /* first channel in each group insensitive/inactive, used as a reference */
228 ch=0;
229 for(fi=0;fi<inputs;fi++){
230 for(i=ch;i<ch+channels[fi];i++){
231 if(i==ch){
232 gtk_widget_set_sensitive(p->chbuttons[i],0);
233 active[i]=0; /* do not frob widget, only plot settings */
234 }else{
235 gtk_widget_set_sensitive(p->chbuttons[i],1);
238 ch+=channels[fi];
241 plot_set_active(PLOT(p->plot),active,bactive);
242 break;
244 case LINK_SUMMED: /* summing mode */
245 case LINK_SUB_FROM: /* subtract channels from reference */
246 ch=0;
247 for(fi=0;fi<inputs;fi++){
248 int any=0;
249 for(i=ch;i<ch+channels[fi];i++){
250 if(active[i])any=1;
251 active[i]=0;
253 active[ch]=any;
254 ch+=channels[fi];
257 set_via_active(p,active,bactive);
258 break;
260 case LINK_INDEPENDENT: /* normal/independent mode */
261 set_via_active(p,active,bactive);
262 break;
264 case LINK_PHASE: /* response/phase */
265 ch=0;
266 for(fi=0;fi<inputs;fi++){
267 for(i=ch;i<ch+channels[fi];i++)
268 if(channels[fi]<2){
269 gtk_widget_set_sensitive(p->chbuttons[i],0);
270 active[i]=0;
271 }else{
272 if(i<ch+2){
273 gtk_widget_set_sensitive(p->chbuttons[i],1);
274 }else{
275 gtk_widget_set_sensitive(p->chbuttons[i],0);
276 active[i]=0;
279 ch+=channels[fi];
281 plot_set_active(PLOT(p->plot),active,bactive);
282 break;
285 /* set labels */
286 switch(plot_link){
287 case LINK_THD:
288 case LINK_THDN:
289 case LINK_THD2:
290 case LINK_THDN2:
291 case LINK_IMPEDENCE_p1:
292 case LINK_IMPEDENCE_1:
293 case LINK_IMPEDENCE_10:
294 case LINK_SUB_REF:
295 ch=0;
296 for(fi=0;fi<inputs;fi++){
297 for(i=ch;i<ch+channels[fi];i++){
298 if(i==ch){
299 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"reference");
300 }else{
301 sprintf(buf,"channel %d", i-ch);
302 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
305 ch+=channels[fi];
307 break;
308 case LINK_SUB_FROM:
309 ch=0;
310 for(fi=0;fi<inputs;fi++){
311 for(i=ch;i<ch+channels[fi];i++){
312 if(i==ch){
313 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"output");
314 }else{
315 sprintf(buf,"channel %d", i-ch);
316 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
319 ch+=channels[fi];
321 break;
323 case LINK_INDEPENDENT:
324 case LINK_SUMMED:
326 ch=0;
327 for(fi=0;fi<inputs;fi++){
328 for(i=ch;i<ch+channels[fi];i++){
329 sprintf(buf,"channel %d", i-ch);
330 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
332 ch+=channels[fi];
334 break;
336 case LINK_PHASE:
338 ch=0;
339 for(fi=0;fi<inputs;fi++){
340 for(i=ch;i<ch+channels[fi];i++){
341 if(channels[fi]<2){
342 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"unused");
343 }else if(i==ch){
344 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"response");
345 }else if(i==ch+1){
346 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"phase");
347 }else{
348 gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"unused");
351 ch+=channels[fi];
353 break;
356 /* set colors */
357 switch(plot_link){
358 case LINK_SUMMED:
359 case LINK_SUB_FROM:
360 ch=0;
361 for(fi=0;fi<inputs;fi++){
362 GdkColor rgb = chcolor(ch);
364 for(i=ch;i<ch+channels[fi];i++){
365 GtkWidget *button=p->chbuttons[i];
366 set_fg(button,&rgb);
368 ch+=channels[fi];
370 break;
372 default:
373 ch=0;
374 for(fi=0;fi<inputs;fi++){
375 for(i=ch;i<ch+channels[fi];i++){
376 GdkColor rgb = chcolor(i);
377 GtkWidget *button=p->chbuttons[i];
378 set_fg(button,&rgb);
380 ch+=channels[fi];
382 break;
387 static void reschange(GtkWidget *widget,struct panel *p){
388 plot_res=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
389 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
392 static void scalechange(GtkWidget *widget,struct panel *p){
393 plot_scale=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
394 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
397 static void modechange(GtkWidget *widget,struct panel *p){
398 plot_mode=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
399 replot(p);
400 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
403 static void linkchange(GtkWidget *widget,struct panel *p){
404 plot_link=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
405 replot(p);
406 plot_setting(PLOT(p->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
407 chlabels(widget,p);
410 static void runchange(GtkWidget *widget,struct panel *p){
411 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){
412 if(!process_active){
413 pthread_t thread_id;
414 process_active=1;
415 process_exit=0;
416 animate_fish(p);
417 pthread_create(&thread_id,NULL,&process_thread,NULL);
419 }else{
420 process_exit=1;
421 while(process_active)sched_yield();
425 static void holdchange(GtkWidget *widget,struct panel *p){
426 plot_hold=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
427 replot(p);
428 plot_draw(PLOT(p->plot));
431 static void loopchange(GtkWidget *widget,struct panel *p){
432 acc_loop=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
435 static void clearchange(GtkWidget *widget,struct panel *p){
436 acc_clear=1;
437 plot_clear(PLOT(p->plot));
438 if(!process_active){
439 rundata_clear();
443 static void rewindchange(GtkWidget *widget,struct panel *p){
444 acc_rewind=1;
447 extern char *version;
448 void panel_create(struct panel *panel){
449 int i;
451 GtkWidget *topplace,*topal,*topalb;
453 GtkWidget *topframe=gtk_frame_new (NULL);
454 GtkWidget *toplabel=gtk_label_new (NULL);
455 GtkWidget *quitbutton=gtk_button_new_with_mnemonic("_quit");
456 GtkWidget *mainbox=gtk_hbox_new(0,6);
457 GdkWindow *root=gdk_get_default_root_window();
458 GtkWidget *rightbox=gtk_vbox_new(0,0);
459 GtkWidget *leftbox=gtk_vbox_new(0,6);
461 panel->toplevel=gtk_window_new (GTK_WINDOW_TOPLEVEL);
462 panel->group = gtk_accel_group_new ();
463 gtk_window_add_accel_group (GTK_WINDOW(panel->toplevel), panel->group);
465 char versionmarkup[240];
466 snprintf(versionmarkup,240," <span size=\"large\" weight=\"bold\" "
467 "style=\"italic\" foreground=\"dark blue\">"
468 "Spectrum Analyzer</span> <span size=\"small\" foreground=\"#606060\">"
469 "revision %s</span> ",
470 version);
472 /* the Fucking Fish */
473 for(i=0;i<19;i++)
474 panel->ff[i]=gdk_pixmap_create_from_xpm_d(root,
475 panel->fb+i,NULL,ff_xpm[i]);
476 panel->twirlimage=gtk_image_new_from_pixmap(panel->ff[0],panel->fb[0]);
478 active = calloc(total_ch,sizeof(*active));
480 topplace=gtk_table_new(1,1,0);
481 topalb=gtk_hbox_new(0,0);
482 topal=gtk_alignment_new(1,0,0,0);
484 gtk_widget_set_name(quitbutton,"quitbutton");
486 gtk_box_pack_start(GTK_BOX(topalb),quitbutton,0,0,0);
487 gtk_container_add (GTK_CONTAINER(topal),topalb);
489 gtk_table_attach_defaults(GTK_TABLE(topplace),
490 topal,0,1,0,1);
491 gtk_table_attach_defaults(GTK_TABLE(topplace),
492 topframe,0,1,0,1);
494 gtk_container_add (GTK_CONTAINER (panel->toplevel), topplace);
495 gtk_container_set_border_width (GTK_CONTAINER (quitbutton), 3);
497 g_signal_connect (G_OBJECT (quitbutton), "clicked",
498 G_CALLBACK (shutdown), NULL);
499 gtk_widget_add_accelerator (quitbutton, "activate", panel->group, GDK_q, 0, 0);
501 gtk_container_set_border_width (GTK_CONTAINER (topframe), 3);
502 gtk_container_set_border_width (GTK_CONTAINER (mainbox), 3);
503 gtk_frame_set_shadow_type(GTK_FRAME(topframe),GTK_SHADOW_ETCHED_IN);
504 gtk_frame_set_label_widget(GTK_FRAME(topframe),toplabel);
505 gtk_label_set_markup(GTK_LABEL(toplabel),versionmarkup);
507 gtk_container_add (GTK_CONTAINER(topframe), mainbox);
509 g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
510 G_CALLBACK (shutdown), NULL);
512 /* add the spectrum plot box */
513 panel->plot=plot_new(blocksize/2+1,inputs,channels,rate);
514 gtk_box_pack_end(GTK_BOX(leftbox),panel->plot,1,1,0);
515 gtk_box_pack_start(GTK_BOX(mainbox),leftbox,1,1,0);
517 /*fish */
519 GtkWidget *box=gtk_hbox_new(1,1);
520 GtkWidget *fishbox=gtk_hbox_new(0,0);
521 gtk_box_pack_end(GTK_BOX(fishbox),panel->twirlimage,0,0,0);
522 gtk_container_set_border_width (GTK_CONTAINER (fishbox), 3);
524 gtk_box_pack_start(GTK_BOX(box),fishbox,0,0,0);
525 gtk_box_pack_start(GTK_BOX(rightbox),box,0,0,0);
528 /* rate */
529 /* channels */
530 /* bits */
532 int fi;
533 int ch=0;
534 char buffer[160];
535 GtkWidget *label;
536 //GtkWidget *vbox=gtk_vbox_new(1,1);
538 GtkWidget *sep=gtk_hseparator_new();
539 gtk_box_pack_start(GTK_BOX(rightbox),sep,0,0,6);
541 panel->chbuttons = calloc(total_ch,sizeof(*panel->chbuttons));
542 for(fi=0;fi<inputs;fi++){
544 char *lastslash = strrchr(inputname[fi],'/');
545 sprintf(buffer,"%s",(lastslash?lastslash+1:inputname[fi]));
546 label=gtk_label_new(buffer);
547 gtk_widget_set_name(label,"readout");
548 gtk_box_pack_start(GTK_BOX(rightbox),label,0,0,0);
550 sprintf(buffer,"%dHz %dbit",rate[fi],bits[fi]);
551 label=gtk_label_new(buffer);
552 gtk_widget_set_name(label,"readout");
553 gtk_box_pack_start(GTK_BOX(rightbox),label,0,0,0);
555 for(i=ch;i<ch+channels[fi];i++){
556 GtkWidget *button=panel->chbuttons[i]=gtk_toggle_button_new();
558 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),1);
559 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (chlabels), panel);
560 gtk_box_pack_start(GTK_BOX(rightbox),button,0,0,0);
563 GtkWidget *sep=gtk_hseparator_new();
564 gtk_box_pack_start(GTK_BOX(rightbox),sep,0,0,6);
566 ch+=channels[fi];
569 chlabels(NULL,panel);
572 GtkWidget *bbox=gtk_vbox_new(0,0);
574 /* add the action buttons */
575 /* scale */
577 GtkWidget *menu=gtk_combo_box_new_text();
578 char *entries[]={"single-pixel","1/24th octave","1/12th octave","1/3 octave"};
579 for(i=0;i<4;i++)
580 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
581 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),plot_res);
582 gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
583 g_signal_connect (G_OBJECT (menu), "changed",
584 G_CALLBACK (reschange), panel);
588 GtkWidget *menu=gtk_combo_box_new_text();
589 char *entries[]={"log scale","ISO log scale","linear scale"};
590 for(i=0;i<3;i++)
591 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
592 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),plot_scale);
593 plot_setting(PLOT(panel->plot),plot_res,plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
594 gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
596 g_signal_connect (G_OBJECT (menu), "changed",
597 G_CALLBACK (scalechange), panel);
600 /* depth */
602 GtkWidget *menu=gtk_combo_box_new_text();
603 char *entries[]={"10dB","20dB","45dB","90dB","140dB"};
604 for(i=0;i<5;i++)
605 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
606 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),3);
607 gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
609 g_signal_connect (G_OBJECT (menu), "changed",
610 G_CALLBACK (depthchange), panel);
613 /* mode */
615 GtkWidget *menu=gtk_combo_box_new_text();
616 char *entries[]={"realtime","maximum","accumulate"};
617 for(i=0;i<3;i++)
618 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
619 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),plot_mode);
620 gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
622 g_signal_connect (G_OBJECT (menu), "changed",
623 G_CALLBACK (modechange), panel);
626 /* link */
628 GtkWidget *menu=gtk_combo_box_new_text();
629 for(i=0;i<LINKS;i++)
630 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), link_entries[i]);
631 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
632 gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
634 g_signal_connect (G_OBJECT (menu), "changed",
635 G_CALLBACK (linkchange), panel);
639 GtkWidget *sep=gtk_hseparator_new();
640 gtk_box_pack_start(GTK_BOX(bbox),sep,0,0,4);
643 /* run/pause */
645 GtkWidget *button=gtk_toggle_button_new_with_mnemonic("_run");
646 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_space, 0, 0);
647 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_r, 0, 0);
648 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (runchange), panel);
649 gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
650 panel->run=button;
653 /* hold */
654 /* loop */
656 GtkWidget *box=gtk_hbox_new(1,1);
657 GtkWidget *button=gtk_toggle_button_new_with_mnemonic("_hold");
658 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_h, 0, 0);
659 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (holdchange), panel);
660 gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
662 button=gtk_toggle_button_new_with_mnemonic("_loop");
663 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_l, 0, 0);
664 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (loopchange), panel);
665 gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
666 gtk_widget_set_sensitive(button,global_seekable);
668 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
671 /* clear */
672 /* rewind */
674 GtkWidget *box=gtk_hbox_new(1,1);
675 GtkWidget *button=gtk_button_new_with_mnemonic("_clear");
676 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_c, 0, 0);
677 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (clearchange), panel);
678 gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
680 button=gtk_button_new_with_mnemonic("re_wind");
681 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_w, 0, 0);
682 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (rewindchange), panel);
683 gtk_widget_set_sensitive(button,global_seekable);
684 gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
686 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
689 /* dump */
691 GtkWidget *button=gtk_button_new_with_mnemonic("_dump data");
692 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_d, 0, 0);
693 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dump), panel);
694 gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
697 /* noise floor */
699 GtkWidget *button=gtk_toggle_button_new_with_mnemonic("sample _noise floor");
700 gtk_widget_add_accelerator (button, "activate", panel->group, GDK_n, 0, 0);
701 g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (noise), panel);
702 gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
705 gtk_box_pack_end(GTK_BOX(rightbox),bbox,0,0,0);
706 gtk_box_pack_start(GTK_BOX(mainbox),rightbox,0,0,0);
709 gtk_widget_show_all(panel->toplevel);
710 //gtk_window_set_resizable(GTK_WINDOW(panel->toplevel),0);
714 static gboolean async_event_handle(GIOChannel *channel,
715 GIOCondition condition,
716 gpointer data){
717 struct panel *panel=data;
718 char buf[1];
720 /* read all pending */
721 while(read(eventpipe[0],buf,1)>0);
723 increment_fish=1;
725 /* check playback status and update the run button if needed */
726 if(process_active && panel->run &&
727 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->run)))
728 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->run),1);
729 if(!process_active && panel->run &&
730 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->run)))
731 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->run),0);
733 /* update the spectral display; send new data */
734 pthread_mutex_lock(&feedback_mutex);
735 if(plot_last_update!=feedback_increment){
736 pthread_mutex_unlock(&feedback_mutex);
737 replot(panel);
738 plot_draw(PLOT(panel->plot));
740 while (gtk_events_pending())
741 gtk_main_iteration();
742 }else
743 pthread_mutex_unlock(&feedback_mutex);
745 return TRUE;
748 static int look_for_gtkrc(char *filename){
749 FILE *f=fopen(filename,"r");
750 if(!f)return 0;
751 fprintf(stderr,"Loading spectrum-gtkrc file found at %s\n",filename);
752 gtk_rc_add_default_file(filename);
753 return 1;
756 void panel_go(int argc,char *argv[]){
757 char *homedir=getenv("HOME");
758 int found=0;
759 memset(&p,0,sizeof(p));
761 found|=look_for_gtkrc(ETCDIR"/spectrum-gtkrc");
763 char *rcdir=getenv("HOME");
764 if(rcdir){
765 char *rcfile="/.spectrum/spectrum-gtkrc";
766 char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
767 strcat(homerc,homedir);
768 strcat(homerc,rcfile);
769 found|=look_for_gtkrc(homerc);
773 char *rcdir=getenv("SPECTRUM_RCDIR");
774 if(rcdir){
775 char *rcfile="/spectrum-gtkrc";
776 char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
777 strcat(homerc,homedir);
778 strcat(homerc,rcfile);
779 found|=look_for_gtkrc(homerc);
782 found|=look_for_gtkrc("./spectrum-gtkrc");
784 if(!found){
786 fprintf(stderr,"Could not find the spectrum-gtkrc configuration file normally\n"
787 "installed in one of the following places:\n"
789 "\t./spectrum-gtkrc\n"
790 "\t$(SPECTRUM_RCDIR)/spectrum-gtkrc\n"
791 "\t~/.spectrum/spectrum-gtkrc\n\t"
792 ETCDIR"/spectrum-gtkrc\n"
793 "This configuration file is used to tune the color, font and other detail aspects\n"
794 "of the user interface. Although the analyzer will work without it, the UI\n"
795 "appearence will likely make the application harder to use due to missing visual\n"
796 "cues.\n");
799 gtk_rc_add_default_file(ETCDIR"/spectrum-gtkrc");
800 if(homedir){
801 char *rcfile="/.spectrum-gtkrc";
802 char *homerc=calloc(1,strlen(homedir)+strlen(rcfile)+1);
803 strcat(homerc,homedir);
804 strcat(homerc,rcfile);
805 gtk_rc_add_default_file(homerc);
807 gtk_rc_add_default_file(".spectrum-gtkrc");
808 gtk_rc_add_default_file("spectrum-gtkrc");
809 gtk_init (&argc, &argv);
811 panel_create(&p);
812 animate_fish(&p);
814 /* set up watching the event pipe */
816 GIOChannel *channel = g_io_channel_unix_new (eventpipe[0]);
817 guint id;
819 g_io_channel_set_encoding (channel, NULL, NULL);
820 g_io_channel_set_buffered (channel, FALSE);
821 g_io_channel_set_close_on_unref (channel, TRUE);
823 id = g_io_add_watch (channel, G_IO_IN, async_event_handle, &p);
825 g_io_channel_unref (channel);
829 /* we want to be running by default */
831 pthread_t thread_id;
832 animate_fish(&p);
833 process_active=1;
834 pthread_create(&thread_id,NULL,&process_thread,NULL);
837 gtk_main ();