3 * gt2 spectrum analyzer
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)
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.
28 #include <gdk/gdkkeysyms.h>
31 static GtkDrawingAreaClass
*parent_class
= NULL
;
33 static void compute_imp_scale(GtkWidget
*widget
){
35 int height
=widget
->allocation
.height
-p
->pady
;
37 double lfreqs
[9]={10000000.,1000000.,100000.,10000.,1000.,100.,10.,1.,.1};
38 double tfreqs
[64]={9000000.,8000000.,7000000.,6000000.,
39 5000000.,4000000.,3000000.,2000000.,
40 900000.,800000.,700000.,600000.,
41 500000.,400000.,300000.,200000.,
42 90000.,80000.,70000.,60000.,
43 50000.,40000.,30000.,20000.,
44 9000.,8000.,7000.,6000.,
45 5000.,4000.,3000.,2000.,
56 p
->ygrid
[i
]=rint( (log10(p
->disp_ymax
)-log10(lfreqs
[i
]))/(log10(p
->disp_ymax
)-log10(.1)) * (height
-1));
58 p
->ytic
[i
]=rint( (log10(p
->disp_ymax
)-log10(tfreqs
[i
]))/(log10(p
->disp_ymax
)-log10(.1)) * (height
-1));
64 static void compute_metadata(GtkWidget
*widget
){
66 int width
=widget
->allocation
.width
-p
->padx
;
69 /* find the places to plot the x grid lines according to scale */
73 double lfreqs
[6]={1.,10.,100.,1000.,10000.,100000};
74 double tfreqs
[37]={5.,6.,7.,8.,9.,20.,30.,40.,50.,60.,70.,80.,90.
75 ,200.,300.,400.,500.,600.,700.,800.,900.,
76 2000.,3000.,4000.,5000.,6000.,7000.,8000.,9000.,
77 20000.,30000,40000,50000,60000,70000,80000,90000};
79 p
->xgrid
[i
]=rint( (log10(lfreqs
[i
])-log10(5.))/(log10(100000.)-log10(5.)) * (width
-1))+p
->padx
;
81 p
->xtic
[i
]=rint( (log10(tfreqs
[i
])-log10(5.))/(log10(100000.)-log10(5.)) * (width
-1))+p
->padx
;
89 double lfreqs
[10]={31.,63.,125.,250.,500.,1000.,2000.,4000.,8000.,16000.};
90 double tfreqs
[20]={25.,40.,50.,80.,100.,160.,200.,315.,400.,630.,800.,
91 1250.,1600.,2500.,3150.,5000.,6300.,10000.,12500.,20000.};
93 p
->xgrid
[i
]=rint( (log2(lfreqs
[i
])-log2(25.))/(log2(20000.)-log2(25.)) * (width
-1))+p
->padx
;
95 p
->xtic
[i
]=rint( (log2(tfreqs
[i
])-log2(25.))/(log2(20000.)-log2(25.)) * (width
-1))+p
->padx
;
101 case 2: /* linear; 2kHz spacing */
106 p
->xgrid
[i
]=rint(lfreq
/20000. * (width
-1))+p
->padx
;
111 while((lfreq
=(p
->xtics
+1)*500.)<20000.)
112 p
->xtic
[p
->xtics
++]=rint(lfreq
/20000. * (width
-1))+p
->padx
;
120 GdkColor
chcolor(int ch
){
121 GdkColor rgb
={0,0,0,0};
164 static void draw(GtkWidget
*widget
){
166 Plot
*p
=PLOT(widget
);
167 int height
=widget
->allocation
.height
;
168 int width
=widget
->allocation
.width
;
169 GtkWidget
*parent
=gtk_widget_get_parent(widget
);
170 int impedence
= (p
->link
== LINK_IMPEDENCE_p1
||
171 p
->link
== LINK_IMPEDENCE_1
||
172 p
->link
== LINK_IMPEDENCE_10
);
173 int phase
= (p
->link
== LINK_PHASE
);
177 /* are any of the phase channels actually active? */
182 for(gi
=0;gi
<p
->groups
&& !phase
;gi
++){
183 if(p
->ch_active
[ch
+1]){
193 p
->drawgc
=gdk_gc_new(p
->backing
);
194 gdk_gc_copy(p
->drawgc
,widget
->style
->black_gc
);
197 p
->dashes
=gdk_gc_new(p
->backing
);
198 gdk_gc_copy(p
->dashes
, p
->drawgc
);
199 gdk_gc_set_line_attributes(p
->dashes
, 1, GDK_LINE_ON_OFF_DASH
, GDK_CAP_BUTT
, GDK_JOIN_MITER
);
200 gdk_gc_set_dashes(p
->dashes
,0,"\002\002",2);
203 /* clear the old rectangle out */
205 GdkGC
*gc
=parent
->style
->bg_gc
[0];
206 gdk_draw_rectangle(p
->backing
,gc
,1,0,0,padx
,height
);
207 gdk_draw_rectangle(p
->backing
,gc
,1,0,height
-p
->pady
,width
,p
->pady
);
209 gc
=parent
->style
->white_gc
;
210 gdk_draw_rectangle(p
->backing
,gc
,1,padx
,0,width
-padx
,height
-p
->pady
+1);
213 /* draw the light x grid */
216 GdkColor rgb
={0,0,0,0};
221 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
223 for(i
=0;i
<p
->xtics
;i
++)
224 gdk_draw_line(p
->backing
,p
->drawgc
,p
->xtic
[i
],0,p
->xtic
[i
],height
-p
->pady
);
227 /* draw the x labels */
229 PangoLayout
**proper
;
232 proper
=p
->log_layout
;
235 proper
=p
->iso_layout
;
238 proper
=p
->lin_layout
;
241 for(i
=0;i
<p
->xgrids
;i
++){
243 pango_layout_get_pixel_size(proper
[i
],&px
,&py
);
245 gdk_draw_layout (p
->backing
,
246 widget
->style
->black_gc
,
247 p
->xgrid
[i
]-(px
/2), height
-py
+2,
252 /* draw the light y grid */
253 if(impedence
){ /* impedence mode */
255 GdkColor rgb
={0,0,0,0};
259 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
261 compute_imp_scale(widget
);
263 for(i
=0;i
<p
->ytics
;i
++)
264 gdk_draw_line(p
->backing
,p
->drawgc
,padx
,p
->ytic
[i
],width
,p
->ytic
[i
]);
267 float del
=(height
-p
->pady
-1)/(float)p
->disp_depth
,off
;
270 GdkColor rgb
={0,0,0,0};
277 off
=(p
->disp_ymax
-ceil(p
->disp_ymax
))*2;
282 off
=p
->disp_ymax
-ceil(p
->disp_ymax
);
286 off
=p
->disp_ymax
-ceil(p
->disp_ymax
*.5)*2;
290 off
=p
->disp_ymax
-ceil(p
->disp_ymax
*.2)*5;
296 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
297 gdk_gc_set_rgb_fg_color(p
->dashes
,&rgb
);
300 int ymid
=rint(del
* (i
* mul
+ off
));
301 if(ymid
>=0 && ymid
<height
-p
->pady
)
302 gdk_draw_line(p
->backing
,p
->drawgc
,padx
,ymid
,width
,ymid
);
306 int ymid
=rint(del
* (i
* mul
+ off
));
307 if(ymid
>=0 && ymid
<height
-p
->pady
)
308 gdk_draw_line(p
->backing
,(half
?p
->dashes
:p
->drawgc
),padx
,ymid
,width
,ymid
);
316 GdkColor rgb
={0,0,0,0};
321 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
323 for(i
=0;i
<p
->xgrids
;i
++)
324 gdk_draw_line(p
->backing
,p
->drawgc
,p
->xgrid
[i
],0,p
->xgrid
[i
],height
-p
->pady
);
329 GdkColor rgb
={0,0,0,0};
334 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
336 for(i
=0;i
<p
->ygrids
;i
++){
338 pango_layout_get_pixel_size(p
->imp_layout
[i
],&px
,&py
);
340 gdk_draw_layout (p
->backing
,
341 widget
->style
->black_gc
,
342 padx
-px
-2, p
->ygrid
[i
]-py
/2,
345 gdk_draw_line(p
->backing
,p
->drawgc
,padx
,p
->ygrid
[i
],width
,p
->ygrid
[i
]);
349 GdkColor rgb
={0,0,0,0};
350 int label
=ceil(p
->disp_ymax
/5+28),i
;
351 float del
=(height
-p
->pady
-1)/(float)p
->disp_depth
,step
;
352 float off
=p
->disp_ymax
-ceil(p
->disp_ymax
*.2)*5;
357 if(((label
-i
)&1)==0 || step
==1){
358 int ymid
=rint(del
* (i
*5+off
));
361 if(((label
-i
)&1)==0){
370 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
372 if(label
-i
>=0 && label
-i
<57 && ymid
>=0 && ymid
<height
-p
->pady
){
373 pango_layout_get_pixel_size(p
->db_layout
[label
-i
],&px
,&py
);
375 gdk_draw_layout (p
->backing
,
376 widget
->style
->black_gc
,
377 padx
-px
-2, ymid
-py
/2,
378 p
->db_layout
[label
-i
]);
379 gdk_draw_line(p
->backing
,p
->drawgc
,padx
,ymid
,width
,ymid
);
385 /* phase? draw in phase and tics on right axis */
387 GdkColor rgb
={0,0xd000,0x0000,0x0000};
388 float depth
= p
->disp_pmax
-p
->disp_pmin
;
389 int label
=ceil(p
->disp_pmax
/10+18),i
;
390 float del
=(height
-p
->pady
-1)/depth
,step
;
391 float off
=p
->disp_pmax
-ceil(p
->disp_pmax
*.1)*10;
395 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
397 if(((label
-i
)&1)==0 || step
==1){
398 int ymid
=rint(del
* (i
*10+off
));
401 if(label
-i
>=0 && label
-i
<37 && ymid
>=0 && ymid
<height
-p
->pady
){
402 pango_layout_get_pixel_size(p
->phase_layout
[label
-i
],&px
,&py
);
404 gdk_draw_layout (p
->backing
,p
->drawgc
,
405 width
-p
->phax
, ymid
-py
/2,
406 p
->phase_layout
[label
-i
]);
413 int ymid
=rint(del
* (i
+off
));
414 if(ymid
>=height
-p
->pady
)break;
416 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-(i
%5==0?15:10),ymid
,width
-p
->phax
-(i
%5==0?5:7),ymid
);
420 int ymid
=rint(del
* (i
*2+off
));
421 if(ymid
>=height
-p
->pady
)break;
423 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-12,ymid
,width
-p
->phax
-7,ymid
);
427 int ymid
=rint(del
* (i
*5+off
));
428 if(ymid
>=height
-p
->pady
)break;
430 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-15,ymid
,width
-p
->phax
-5,ymid
);
435 int ymid
=rint(del
* (i
*10+off
));
436 if(ymid
>=height
-p
->pady
)break;
438 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-5,ymid
-1,width
-p
->phax
-2,ymid
-1);
439 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-25,ymid
,width
-p
->phax
-2,ymid
);
440 gdk_draw_line(p
->backing
,p
->drawgc
,width
-p
->phax
-5,ymid
+1,width
-p
->phax
-2,ymid
+1);
446 /* draw actual data */
450 for(gi
=0;gi
<p
->groups
;gi
++){
454 for(ch
=cho
;ch
<cho
+p
->ch
[gi
];ch
++){
455 if(p
->ch_active
[ch
]){
461 gdk_gc_set_rgb_fg_color(p
->drawgc
,&rgb
);
463 for(i
=0;i
<width
-padx
;i
++){
464 float val
=p
->ydata
[ch
][i
];
467 if(isnan(yprev
) || isnan(val
)){
472 if(impedence
){ /* log scale for impedence */
473 y
=rint( (log10(p
->disp_ymax
)-log10(val
))/(log10(p
->disp_ymax
)-log10(.1)) *
475 }else if(phase
&& ch
==cho
+1){
476 y
= rint((height
-p
->pady
-1)/(p
->disp_pmax
-p
->disp_pmin
)*(p
->disp_pmax
-val
));
478 y
= rint((height
-p
->pady
-1)/p
->disp_depth
*(p
->disp_ymax
-val
));
481 if(first
&& (y
<height
-p
->pady
|| prev
<height
-p
->pady
)){
485 if(ly
>=height
-p
->pady
)ly
=height
-p
->pady
;
486 if(lp
>=height
-p
->pady
)lp
=height
-p
->pady
;
488 gdk_draw_line(p
->backing
,p
->drawgc
,padx
+i
-1,lp
,padx
+i
,ly
);
493 if(ly
>=height
-p
->pady
)ly
=height
-p
->pady
;
494 if(lp
>=height
-p
->pady
)lp
=height
-p
->pady
;
496 gdk_draw_line(p
->backing
,p
->drawgc
,padx
+i
-1,lp
,padx
+i
,ly
);
511 static void draw_and_expose(GtkWidget
*widget
){
512 Plot
*p
=PLOT(widget
);
513 if(!GDK_IS_DRAWABLE(p
->backing
))return;
515 if(!GTK_WIDGET_DRAWABLE(widget
))return;
516 if(!GDK_IS_DRAWABLE(widget
->window
))return;
517 gdk_draw_drawable(widget
->window
,
518 widget
->style
->fg_gc
[GTK_WIDGET_STATE (widget
)],
522 widget
->allocation
.width
,
523 widget
->allocation
.height
);
526 static gboolean
expose( GtkWidget
*widget
, GdkEventExpose
*event
){
527 Plot
*p
=PLOT(widget
);
528 gdk_draw_drawable(widget
->window
,
529 widget
->style
->fg_gc
[GTK_WIDGET_STATE (widget
)],
531 event
->area
.x
, event
->area
.y
,
532 event
->area
.x
, event
->area
.y
,
533 event
->area
.width
, event
->area
.height
);
538 static void size_request (GtkWidget
*widget
,GtkRequisition
*requisition
){
539 Plot
*p
=PLOT(widget
);
540 /* no smaller than 800x600 */
541 requisition
->width
= 800;
542 requisition
->height
= 600;
543 int axisy
=0,axisx
=0,pady
=0,padx
=0,phax
=0,px
,py
,i
;
545 /* find max lin layout */
548 for(i
=0;p
->lin_layout
[i
];i
++){
549 pango_layout_get_pixel_size(p
->lin_layout
[i
],&px
,&py
);
554 if(axisx
<max
)axisx
=max
;
556 /* find max log layout */
559 for(i
=0;p
->log_layout
[i
];i
++){
560 pango_layout_get_pixel_size(p
->log_layout
[i
],&px
,&py
);
565 if(axisx
<max
)axisx
=max
;
567 /* find max iso layout */
570 for(i
=0;p
->iso_layout
[i
];i
++){
571 pango_layout_get_pixel_size(p
->iso_layout
[i
],&px
,&py
);
576 if(axisx
<max
)axisx
=max
;
578 /* find max db layout */
581 for(i
=0;p
->db_layout
[i
];i
++){
582 pango_layout_get_pixel_size(p
->db_layout
[i
],&px
,&py
);
587 if(axisy
<max
)axisx
=max
;
589 /* find max imped layout */
592 for(i
=0;p
->imp_layout
[i
];i
++){
593 pango_layout_get_pixel_size(p
->imp_layout
[i
],&px
,&py
);
598 if(axisy
<max
)axisx
=max
;
600 /* find max phase layout */
603 for(i
=0;p
->phase_layout
[i
];i
++){
604 pango_layout_get_pixel_size(p
->phase_layout
[i
],&px
,&py
);
609 if(axisy
<max
)axisx
=max
;
612 if(requisition
->width
<axisx
+padx
)requisition
->width
=axisx
+padx
;
613 if(requisition
->height
<axisy
+pady
)requisition
->height
=axisy
+pady
;
619 static gboolean
configure(GtkWidget
*widget
, GdkEventConfigure
*event
){
620 Plot
*p
=PLOT(widget
);
624 g_object_unref(p
->backing
);
626 p
->backing
= gdk_pixmap_new(widget
->window
,
627 widget
->allocation
.width
,
628 widget
->allocation
.height
,
632 for(i
=0;i
<p
->total_ch
;i
++)free(p
->ydata
[i
]);
636 p
->ydata
=malloc(p
->total_ch
*sizeof(*p
->ydata
));
637 for(i
=0;i
<p
->total_ch
;i
++)
639 calloc(widget
->allocation
.width
,sizeof(**p
->ydata
));
641 compute_metadata(widget
);
642 plot_refresh(p
,NULL
);
643 draw_and_expose(widget
);
648 static void plot_class_init (PlotClass
*class){
649 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (class);
650 parent_class
= g_type_class_peek_parent (class);
652 widget_class
->expose_event
= expose
;
653 widget_class
->configure_event
= configure
;
654 widget_class
->size_request
= size_request
;
657 static void plot_init (Plot
*p
){
663 GType
plot_get_type (void){
664 static GType m_type
= 0;
666 static const GTypeInfo m_info
={
668 NULL
, /* base_init */
669 NULL
, /* base_finalize */
670 (GClassInitFunc
) plot_class_init
,
671 NULL
, /* class_finalize */
672 NULL
, /* class_data */
675 (GInstanceInitFunc
) plot_init
,
679 m_type
= g_type_register_static (GTK_TYPE_DRAWING_AREA
, "Plot", &m_info
, 0);
685 GtkWidget
* plot_new (int size
, int groups
, int *channels
, int *rate
){
686 GtkWidget
*ret
= GTK_WIDGET (g_object_new (plot_get_type (), NULL
));
692 for(g
=0;g
<groups
;g
++)
699 /* generate all the text layouts we'll need */
701 char *labels
[11]={"DC","2kHz","4kHz","6kHz","8kHz","10kHz","12kHz",
702 "14kHz","16kHz","18kHz",""};
703 p
->lin_layout
=calloc(12,sizeof(*p
->lin_layout
));
705 p
->lin_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
708 char *labels
[37]={"-180\xC2\xB0","-170\xC2\xB0","-160\xC2\xB0",
709 "-150\xC2\xB0","-140\xC2\xB0","-130\xC2\xB0",
710 "-120\xC2\xB0","-110\xC2\xB0","-100\xC2\xB0",
711 "-90\xC2\xB0","-80\xC2\xB0","-70\xC2\xB0",
712 "-60\xC2\xB0","-50\xC2\xB0","-40\xC2\xB0",
713 "-30\xC2\xB0","-20\xC2\xB0","-10\xC2\xB0",
714 "-0\xC2\xB0","+10\xC2\xB0","+20\xC2\xB0",
715 "+30\xC2\xB0","+40\xC2\xB0","+50\xC2\xB0",
716 "+60\xC2\xB0","+70\xC2\xB0","+80\xC2\xB0",
717 "+90\xC2\xB0","+100\xC2\xB0","+110\xC2\xB0",
718 "+120\xC2\xB0","+130\xC2\xB0","+140\xC2\xB0",
719 "+150\xC2\xB0","+160\xC2\xB0","+170\xC2\xB0",
721 p
->phase_layout
=calloc(38,sizeof(*p
->phase_layout
));
723 p
->phase_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
726 char *labels
[6]={"1Hz","10Hz","100Hz","1kHz","10kHz",""};
727 p
->log_layout
=calloc(7,sizeof(*p
->log_layout
));
729 p
->log_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
732 char *labels
[9]={"10M\xCE\xA9","1M\xCE\xA9","100k\xCE\xA9","10k\xCE\xA9",
733 "1k\xCE\xA9","100\xCE\xA9","10\xCE\xA9","1\xCE\xA9",".1\xCE\xA9"};
734 p
->imp_layout
=calloc(10,sizeof(*p
->imp_layout
));
736 p
->imp_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
739 char *labels
[10]={"31Hz","63Hz","125Hz","250Hz","500Hz","1kHz","2kHz",
740 "4kHz","8kHz","16kHz"};
741 p
->iso_layout
=calloc(11,sizeof(*p
->iso_layout
));
743 p
->iso_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
746 char *labels
[57]={"-140dB","-135dB","-130dB","-125dB","-120dB","-115dB",
747 "-110dB","-105dB","-100dB","-95dB","-90dB","-85dB",
748 "-80dB","-75dB","-70dB","-65dB","-60dB","-55dB","-50dB",
749 "-45dB","-40dB","-35dB","-30dB","-25dB","-20dB",
750 "-15dB","-10dB","-5dB","0dB","+5dB","+10dB","+15dB",
751 "+20dB","+25dB","+30dB","+35dB","+40dB","+45dB","+50dB",
752 "+55dB","+60dB","+65dB","+70dB","+75dB","+80dB","+85dB",
753 "+90dB","+95dB","+100dB","+105dB","+110dB","+115dB",
754 "+120dB","+125dB","+130dB","+135dB","+140dB"};
755 p
->db_layout
=calloc(58,sizeof(*p
->db_layout
));
757 p
->db_layout
[i
]=gtk_widget_create_pango_layout(ret
,labels
[i
]);
760 p
->ch_active
=calloc(ch
,sizeof(*p
->ch_active
));
761 p
->ch_process
=calloc(ch
,sizeof(*p
->ch_process
));
767 void plot_refresh (Plot
*p
, int *process
){
769 float ymax
,pmax
,pmin
;
770 int width
=GTK_WIDGET(p
)->allocation
.width
-p
->padx
;
771 int height
=GTK_WIDGET(p
)->allocation
.height
-p
->pady
;
777 memcpy(p
->ch_process
,process
,p
->total_ch
*sizeof(*process
));
779 data
= process_fetch(p
->res
, p
->scale
, p
->mode
, p
->link
,
780 p
->ch_process
,width
,&ymax
,&pmax
,&pmin
);
782 for(i
=0;i
<p
->total_ch
;i
++)
783 memcpy(p
->ydata
[i
],data
[i
],width
*sizeof(**p
->ydata
));
785 /* graph limit updates are conditional depending on mode/link */
789 if(pmin
>-30)pmin
=-30;
792 case LINK_INDEPENDENT
:
798 float dBpp
= p
->depth
/height
;
802 case LINK_IMPEDENCE_p1
:
803 case LINK_IMPEDENCE_1
:
804 case LINK_IMPEDENCE_10
:
809 //if(p->ymax>ymax)ymax=p->ymax;
810 //if(pmax<p->pmax)pmax=p->pmax;
811 //if(pmin>p->pmin)pmin=p->pmin;
813 /* scale regression is conditional and damped. Start the timer/run
814 the timer while any one scale measure should be dropping by more
815 than 50px. If any peaks occur above, reset timer. Once timer
816 runs out, drop 5px per frame */
819 #define TIMERFRAMES 20
821 float oldzero
= (height
-1)/p
->depth
*p
->ymax
;
822 float newzero
= (height
-1)/p
->depth
*ymax
;
824 if(newzero
+PXTHRESH
<oldzero
){
828 p
->ymax
= (oldzero
-PXDEL
)*p
->depth
/(height
-1);
831 p
->ymaxtimer
= TIMERFRAMES
;
834 p
->ymaxtimer
= TIMERFRAMES
;
836 if(p
->pmax
>pmax
|| p
->pmin
<pmin
){
837 float newmax
= (height
-1)/(p
->pmax
-p
->pmin
)*(p
->pmax
-pmax
);
838 float newmin
= (height
-1)/(p
->pmax
-p
->pmin
)*(pmin
-p
->pmin
);
840 if(newmax
>PXTHRESH
|| newmin
>PXTHRESH
){
845 p
->pmax
-= PXDEL
/(height
-1)*(p
->pmax
-p
->pmin
);
847 p
->pmin
+= PXDEL
/(height
-1)*(p
->pmax
-p
->pmin
);
850 p
->phtimer
= TIMERFRAMES
;
853 p
->phtimer
= TIMERFRAMES
;
855 if(ymax
<p
->depth
-140.)ymax
=p
->depth
-140.;
856 if(ymax
>140.)ymax
=140.;
857 if(pmax
>180)pmax
=180;
858 if(pmin
<-180)pmin
=-180;
859 if(ymax
>p
->ymax
)p
->ymax
=ymax
;
860 if(pmax
>p
->pmax
)p
->pmax
=pmax
;
861 if(pmin
<p
->pmin
)p
->pmin
=pmin
;
863 p
->disp_depth
= p
->depth
;
864 p
->disp_ymax
= p
->ymax
;
865 p
->disp_pmax
= p
->pmax
;
866 p
->disp_pmin
= p
->pmin
;
868 /* finally, align phase/response zeros on phase graphs */
869 if(p
->disp_ymax
>-140){
870 if(p
->link
== LINK_PHASE
){
871 /* In a phase/response graph, 0dB/0degrees are bound and always on-screen. */
872 float mzero
= (height
-1)/p
->disp_depth
*p
->disp_ymax
;
873 float pzero
= (height
-1)/(p
->disp_pmax
-p
->disp_pmin
)*p
->disp_pmax
;
876 /* straightforward; move the dB range down */
877 p
->disp_ymax
= pzero
*p
->disp_depth
/(height
-1);
879 /* a little harder as phase has a min and a max.
880 First increase the pmax to match the dB zero. */
881 p
->disp_pmax
= p
->disp_pmin
/(1-(height
-1)/mzero
);
882 pzero
= (height
-1)/(p
->disp_pmax
-p
->disp_pmin
)*p
->disp_pmax
;
884 /* That worked, but might have run p->max overrange */
885 if(p
->disp_pmax
>180.){
886 /* only way to reconcile this one is to increase the pdepth */
888 pzero
= (height
-1)/(p
->disp_pmax
-p
->disp_pmin
)*p
->disp_pmax
;
889 p
->disp_depth
= (height
-1)/pzero
*p
->disp_ymax
;
896 void plot_clear (Plot
*p
){
897 GtkWidget
*widget
=GTK_WIDGET(p
);
898 int width
=GTK_WIDGET(p
)->allocation
.width
-p
->padx
;
902 for(i
=0;i
<p
->total_ch
;i
++)
905 p
->ymax
=p
->depth
-140;
908 draw_and_expose(widget
);
911 float **plot_get (Plot
*p
){
915 void plot_setting (Plot
*p
, int res
, int scale
, int mode
, int link
, int depth
){
916 GtkWidget
*widget
=GTK_WIDGET(p
);
927 compute_metadata(widget
);
928 plot_refresh(p
,NULL
);
929 draw_and_expose(widget
);
932 void plot_draw (Plot
*p
){
933 GtkWidget
*widget
=GTK_WIDGET(p
);
934 draw_and_expose(widget
);
937 void plot_set_active(Plot
*p
, int *a
, int *b
){
938 GtkWidget
*widget
=GTK_WIDGET(p
);
939 memcpy(p
->ch_active
,a
,p
->total_ch
*sizeof(*a
));
940 memcpy(p
->ch_process
,b
,p
->total_ch
*sizeof(*b
));
941 plot_refresh(p
,NULL
);
942 draw_and_expose(widget
);