1 // osziview.cc
2 //
3 // oszi - widget for gtk--
4 //
5 // Copyright (C) 1999 Florian Berger
6 // Email: florian.berger@jk.uni-linz.ac.at
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License Version 2 as
10 // published by the Free Software Foundation;
11 //
12 // This program 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.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //
22
23 #include <stdio.h>
24 #include <string.h>
25
26 #include <math.h>
27
28 #include "resources.h"
29
30 #include "osziview.h"
31
32 #include <gtkmm/style.h>
33 #include <gdkmm/color.h>
34 #include <math.h>
35
36 #define SCALE_HEIGHT 20
37
38 #define xscr 20
39 #define yscr 5
40 #define wscr (get_width()-xscr*2)
41 #define hscr (get_height()-yscr-SCALE_HEIGHT-1)
42
OsziView()43 OsziView::OsziView() : Gtk::DrawingArea()
44 {
45 samp_byte_array = g_byte_array_new();
46
47 i_col_bg. set("black"); get_colormap()->alloc_color(i_col_bg );
48 i_col_trig. set("cyan" ); get_colormap()->alloc_color(i_col_trig );
49 i_col_mark. set("red" ); get_colormap()->alloc_color(i_col_mark );
50 i_col_data. set("green"); get_colormap()->alloc_color(i_col_data );
51 i_col_scale.set("#B8B8B8"); get_colormap()->alloc_color(i_col_scale);
52 i_col_ticks.set("#666"); get_colormap()->alloc_color(i_col_ticks);
53 i_col_zero. set("gray" ); get_colormap()->alloc_color(i_col_zero );
54 trigfact=0.6;
55 i_adaptive_scale=1;
56 freq=0.0;
57 startpoint=0;
58 endpoint=0;
59
60 // Default to three dummy samples
61 setSampleData((const unsigned char *) "\0\0\0", 3);
62 }
63
64
~OsziView()65 OsziView::~OsziView()
66 {
67 g_byte_array_free (samp_byte_array, TRUE);
68 }
69
calc_minmax(void)70 void OsziView::calc_minmax(void)
71 {
72 int i;
73 unsigned char * samp_uc;
74 short int * samp_s16le;
75
76 samp_s16le = (short int *) samp;
77 samp_uc = (unsigned char *) samp;
78
79 if(i_sampfmt == U8){
80 i_minsamp=255;
81 i_maxsamp=0;
82 for(i=0;i<sampnr;i++){
83 if ( samp_uc[i-1] > i_maxsamp ) i_maxsamp = samp_uc[i-1];
84 if ( samp_uc[i-1] < i_minsamp ) i_minsamp = samp_uc[i-1];
85 }
86 if ( !i_adaptive_scale ){
87 i_divisor = 0x100;
88 } else {
89 i_divisor = 8;
90 if ( 2*Abs(i_maxsamp-128) > i_divisor ) i_divisor=2*Abs(i_maxsamp-128);
91 if ( 2*Abs(i_minsamp-128) > i_divisor ) i_divisor=2*Abs(i_minsamp-128);
92 }
93 } else if(i_sampfmt == S16_LE){
94 i_minsamp= 33000;
95 i_maxsamp=-33000;
96 for(i=0;i<sampnr;i++){
97 if ( samp_s16le[i-1] > i_maxsamp ) i_maxsamp = samp_s16le[i-1];
98 if ( samp_s16le[i-1] < i_minsamp ) i_minsamp = samp_s16le[i-1];
99 }
100 if ( !i_adaptive_scale ){
101 i_divisor = 0x10000;
102 } else {
103 i_divisor = 2048;
104 if ( 2*Abs(i_maxsamp) > i_divisor ) i_divisor=2*Abs(i_maxsamp);
105 if ( 2*Abs(i_minsamp) > i_divisor ) i_divisor=2*Abs(i_minsamp);
106 }
107 }
108 }
109
calc_freq(void)110 void OsziView::calc_freq(void)
111 /* in units of sampfreq */
112 {
113 int t1, t2, A1, A2, tc, i, schmitt_triggered;
114 short int * samp_s16le;
115 unsigned char * samp_uc;
116
117 samp_s16le = (short int *) samp;
118 samp_uc = (unsigned char *) samp;
119
120 if(i_sampfmt==U8){
121 for(i=0,A1=0;i<sampnr;i++)
122 if (A1<Abs(samp_uc[i]-128) && samp_uc[i]-128>0) A1=Abs(samp_uc[i]-128);
123 for(i=0,A2=0;i<sampnr;i++)
124 if (A2<Abs(samp_uc[i]-128) && samp_uc[i]-128<0) A2=Abs(samp_uc[i]-128);
125 } else if(i_sampfmt==S16_LE){
126 for(i=0,A1=0;i<sampnr;i++)
127 if (A1<Abs(samp_s16le[i]) && samp_s16le[i]>0) A1=Abs(samp_s16le[i]);
128 for(i=0,A2=0;i<sampnr;i++)
129 if (A2<Abs(samp_s16le[i]) && samp_s16le[i]<0) A2=Abs(samp_s16le[i]);
130 }
131 // A1 = (int)( (double)A*M_PI/2.0/(double)sampnr+0.5 );
132 // A1 = (int)( (double)A*M_PI/2.0/(double)sampnr+0.5 );
133 if(i_sampfmt==U8){
134 t1 = 128 + (int)( A1 * trigfact + 0.5 );
135 t2 = 128 - (int)( A2 * trigfact + 0.5 );
136 } else if(i_sampfmt==S16_LE){
137 t1 = (int)( A1 * trigfact + 0.5 );
138 t2 = - (int)( A2 * trigfact + 0.5 );
139 }
140 startpoint=0;
141 if(i_sampfmt==U8){
142 for( i=1; samp_uc[i]<=t1 && i<sampnr; i++ );
143 for( ; !LEVTRIGN(samp_uc,i,t2) && i<sampnr; i++ );
144 } else if(i_sampfmt==S16_LE){
145 for( i=1; samp_s16le[i]<=t1 && i<sampnr; i++ );
146 for( ; !LEVTRIGN(samp_s16le,i,t2) && i<sampnr; i++ );
147 }
148 startpoint=i;
149 schmitt_triggered=NO;
150 endpoint=startpoint+1;
151 tc=0;
152 if(i_sampfmt==U8){
153 for( i=startpoint, tc=0; i<sampnr; i++ ) {
154 if( !schmitt_triggered )
155 schmitt_triggered = (samp_uc[i]>=t1);
156 else if( LEVTRIGN(samp_uc,i,t2) ) {
157 endpoint=i; tc++;
158 schmitt_triggered = NO;
159 }
160 }
161 } else if(i_sampfmt==S16_LE){
162 for( i=startpoint, tc=0; i<sampnr; i++ ) {
163 if( !schmitt_triggered )
164 schmitt_triggered = (samp_s16le[i]>=t1);
165 else if( LEVTRIGN(samp_s16le,i,t2) ) {
166 endpoint=i; tc++;
167 schmitt_triggered = NO;
168 }
169 }
170 }
171 if (endpoint==startpoint) endpoint++;
172 freq = (double)tc/(double)(endpoint-startpoint);
173 if (freq<1E-15) freq = 1E-15;
174
175 trigger_a = t1;
176 trigger_b = t2;
177 }
178
recalc(void)179 void OsziView::recalc(void)
180 {
181 calc_minmax();
182 calc_freq();
183 }
184
paint_sample(void)185 void OsziView::paint_sample(void)
186 {
187 int i,x1,x2,y1,y2;
188 unsigned char * samp_uc;
189 short int * samp_s16le;
190 //erase();
191 samp_s16le = (short int *) samp;
192 samp_uc = (unsigned char *) samp;
193
194 if (!i_GC)
195 i_GC = Gdk::GC::create( get_window() );
196
197 i_GC->set_foreground(i_col_zero);
198 get_window()->
199 draw_line( i_GC, xscr,yscr+hscr/2,xscr+wscr-1,yscr+hscr/2);
200
201 i_GC->set_foreground(i_col_data);
202 for(i=1;i<sampnr;i++){
203 x1=xscr+(i-1)*wscr/sampnr;
204 x2=xscr+i*wscr/sampnr;
205 if(i_sampfmt == U8){
206 y1=yscr+(samp_uc[i-1]-128+i_divisor/2)*hscr/i_divisor;
207 y2=yscr+(samp_uc[i]-128+i_divisor/2)*hscr/i_divisor;
208 } else if(i_sampfmt == S16_LE){
209 y1=yscr+((int)samp_s16le[i-1]+i_divisor/2)*hscr/i_divisor;
210 y2=yscr+((int)samp_s16le[i] +i_divisor/2)*hscr/i_divisor;
211 }
212 get_window()->draw_line( i_GC, x1, y1, x2, y2 );
213 }
214 //printf("hallo\n");
215 }
216
paint_marks(void)217 void OsziView::paint_marks(void)
218 {
219 int linex, liney;
220 int t1 = trigger_a, t2 = trigger_b;
221
222 i_GC->set_foreground(i_col_mark);
223 linex = xscr+endpoint*wscr/sampnr;
224 get_window()->draw_line( i_GC, linex, yscr, linex, yscr+hscr );
225 linex = xscr+startpoint*wscr/sampnr;
226 get_window()->draw_line( i_GC, linex, yscr, linex, yscr+hscr );
227
228 i_GC->set_foreground(i_col_trig);
229
230 if (i_sampfmt == U8)
231 {
232 t1 -= 128;
233 t2 -= 128;
234 }
235
236 liney = yscr+(t1+i_divisor/2)*hscr/i_divisor;
237 get_window()->draw_line( i_GC, xscr, liney, xscr+wscr, liney );
238 liney = yscr+(t2+i_divisor/2)*hscr/i_divisor;
239 get_window()->draw_line( i_GC, xscr, liney, xscr+wscr, liney );
240 }
241
copy_sample_data(const void * ptr,int data_size)242 void OsziView::copy_sample_data(const void *ptr, int data_size)
243 {
244 g_byte_array_set_size(samp_byte_array, 0);
245 g_byte_array_append(samp_byte_array, (guint8 *) ptr, data_size);
246 samp = (short int *) samp_byte_array->data;
247 }
248
setSampleData(const unsigned char * s,int num_samples)249 void OsziView::setSampleData(const unsigned char *s, int num_samples)
250 {
251 copy_sample_data(s, num_samples);
252 i_sampfmt = U8;
253 if (num_samples != sampnr)
254 {
255 sampnr = num_samples;
256 invalidate();
257 }
258 else
259 invalidate_sample();
260 recalc();
261 }
262
setSampleData(const short int * s,int num_samples)263 void OsziView::setSampleData(const short int *s, int num_samples)
264 {
265 copy_sample_data(s, num_samples * sizeof (short int));
266 i_sampfmt = S16_LE;
267 if (num_samples != sampnr)
268 {
269 sampnr = num_samples;
270 invalidate();
271 }
272 else
273 invalidate_sample();
274 recalc();
275 }
276
setSampleFreq(double f)277 void OsziView::setSampleFreq(double f) { sampfreq = f; invalidate(); }
278
279
setAdaptive(int active)280 void OsziView::setAdaptive(int active) { i_adaptive_scale = active; invalidate(); }
281
282
setTrigFact(double fact)283 void OsziView::setTrigFact(double fact) { trigfact=fact; invalidate(); }
284
285
getTrigFact()286 double OsziView::getTrigFact() { return(trigfact); }
287
invalidate(void)288 void OsziView::invalidate(void)
289 {
290 // Invalidate the whole window
291 if (is_realized())
292 {
293 Gdk::Rectangle rect = get_allocation();
294 rect.set_x(0);
295 rect.set_y(0);
296 // The gtkmm bindings won't let you call invalidate_rect
297 // with a NULL argument to clear the whole window, so you
298 // have to jump through these hoops
299 get_window()->invalidate_rect(rect, false);
300 }
301 }
302
invalidate_sample(void)303 void OsziView::invalidate_sample(void)
304 {
305 if (is_realized())
306 {
307 Gdk::Rectangle rect = get_allocation();
308 rect.set_x(0);
309 rect.set_y(0);
310 rect.set_height(rect.get_height() - SCALE_HEIGHT);
311 get_window()->invalidate_rect(rect, false);
312 }
313 }
314
paint_scale()315 void OsziView::paint_scale()
316 {
317 double i,j;
318 double di,dj;
319 double dim; //mantissa of di
320 char str[100];
321 // printf("nr=%d, freq=%lf\n",nr,f);
322
323 if (!i_GC)
324 i_GC = Gdk::GC::create( get_window() );
325
326 di = (double)sampnr/sampfreq/10.0;
327 for(dim=di;dim>=10.0;dim/=10.0);
328 for(;dim<1.0;dim*=10.0);
329 if (dim<=5.0)
330 { di=di/dim*5.0; dim=5.0; }
331 else
332 { di=di/dim*10.0; dim=10.0;}
333 dj=di/10.0;
334
335 int scale_top = get_height() - SCALE_HEIGHT;
336
337 i_GC->set_foreground(i_col_ticks);
338 for( j=0.0; j<(double)sampnr/sampfreq; j+=dj ){
339 get_window()->
340 draw_line( i_GC, xscr+(j*sampfreq)*wscr/sampnr,scale_top,
341 xscr+(j*sampfreq)*wscr/sampnr,scale_top+3 );
342 }
343
344 if (dim!=5.0){
345 dj=di/2.0;
346 i_GC->set_foreground(i_col_scale);
347 for( j=0.0; j<(double)sampnr/sampfreq; j+=dj ){
348 get_window()->
349 draw_line( i_GC, xscr+(j*sampfreq)*wscr/sampnr,scale_top,
350 xscr+(j*sampfreq)*wscr/sampnr,scale_top+5 );
351 }
352 }
353
354 i_GC->set_foreground(i_col_scale);
355
356
357 Glib::RefPtr<Pango::Layout> layout = create_pango_layout("");
358 layout->set_font_description( Pango::FontDescription("Sans 8 ") );
359
360 for( i=0.0; i<(double)sampnr/sampfreq; i+=di ){
361
362 get_window()->
363 draw_line( i_GC, xscr+(i*sampfreq)*wscr/sampnr,scale_top,
364 xscr+(i*sampfreq)*wscr/sampnr,scale_top+7 );
365
366 sprintf(str,"%.0f",i*1000); // in ms
367 layout->set_text( str );
368 Pango::Rectangle extents = layout->get_pixel_logical_extents();
369
370 get_window()->
371 draw_layout(i_GC,
372 xscr+(i*sampfreq)*wscr/sampnr-
373 extents.get_width()/2,
374 scale_top+7+extents.get_ascent(),
375 layout
376 );
377 }
378 }
379
380
on_expose_event(GdkEventExpose * event)381 bool OsziView::on_expose_event(GdkEventExpose *event)
382 {
383 Gtk::DrawingArea::on_expose_event(event);
384
385 // Avoid painting the scale if only the sample area has changed
386 if (event->area.y + event->area.height > get_height() - SCALE_HEIGHT)
387 paint_scale();
388
389 paint_sample();
390 paint_marks();
391
392 return true;
393 }
394
on_realize()395 void OsziView::on_realize()
396 {
397 Gtk::DrawingArea::on_realize();
398
399 get_window()->set_background( i_col_bg );
400 }
401