tomwalters@0: /**************************************************************************** tomwalters@0: * tomwalters@0: * x11play -Animate successive plots of n points. tomwalters@0: The points are read as binary shorts. tomwalters@0: * Like x11plot, but plots successive blocks of n points tomwalters@0: * on top of each other, rubbing out the previous plot, so tomwalters@0: * as to form an "animated" sequence of plots. tomwalters@0: * tomwalters@0: * -Help: x11play -H tomwalters@0: * -Usage, EG: tomwalters@0: * fft -n128 -o120 file | x11play -n64 -y0 -c5000 tomwalters@0: * Quit program with left mouse button. tomwalters@0: * -Step-mode tomwalters@0: * With a -S flag, single-step through frames using tomwalters@0: * the mouse as follows: tomwalters@0: * tomwalters@0: * left - quit tomwalters@0: * centre - freeze animation (successive centre tomwalters@0: * buttons give single successive frames). tomwalters@0: * right - continue animation tomwalters@0: * tomwalters@0: * Note: animation is slower in step-mode because tomwalters@0: * XSynchronise has to be on. tomwalters@0: ****************************************************************************/ tomwalters@0: #include tomwalters@0: #include tomwalters@0: #include "x11coord.h" tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Defaults tomwalters@0: ****************************************************************************/ tomwalters@0: #define UNSET (-9999) tomwalters@0: tomwalters@0: #define DEFAMPL 1000 tomwalters@0: #define DEFSCALE 256 tomwalters@0: tomwalters@0: float argXd0=UNSET, argYd0=UNSET; tomwalters@0: float argXd1=UNSET, argYd1=UNSET; tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Input-file arguments tomwalters@0: ****************************************************************************/ tomwalters@0: int n = DEFSCALE; /* num points to read from file */ tomwalters@0: int s = 0; /* start position in file */ tomwalters@0: short summary= 0; /* Flag for method of block summary in downsample */ tomwalters@0: short z = 1; /* Flag for drawing zero line */ tomwalters@0: short stepmode=0; /* Flag for single-step mode */ tomwalters@0: short overplot=0; /* Flag for overplot mode */ tomwalters@0: short stepcount=0; tomwalters@0: char DEFNAME[]="stdin"; tomwalters@0: char *name=DEFNAME; tomwalters@0: short *data; tomwalters@0: XPoint *points; tomwalters@0: tomwalters@0: FILE *fp, *fopen(); tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * main tomwalters@0: * The window is plotted when an expose event is (automatically) generated. tomwalters@0: * The plotting routines are called from within the event monitor. tomwalters@0: ****************************************************************************/ tomwalters@0: main(argc, argv) tomwalters@0: int argc ; tomwalters@0: char *argv[] ; tomwalters@0: { tomwalters@0: Window w; tomwalters@0: int npoints; tomwalters@0: tomwalters@0: while (--argc > 0 && **++argv == '-') tomwalters@0: switch (*++*argv) { tomwalters@0: case 'n': n = atoi(++*argv); break; tomwalters@0: case 's': s = atoi(++*argv); break; tomwalters@0: case 'x': argXd0 = atof(++*argv); break; tomwalters@0: case 'y': argYd0 = atof(++*argv); break; tomwalters@0: case 'c': argXd1 = atof(++*argv); break; tomwalters@0: case 'a': argYd1 = atof(++*argv); break; tomwalters@0: case 'b': summary = atoi(++*argv); break; tomwalters@0: case 'z': z = 0; break; tomwalters@0: case 'S': stepmode++; break; tomwalters@0: case 'O': overplot++; break; tomwalters@0: case 'F': theFontString = ++*argv; break; tomwalters@0: case 'H': tomwalters@0: default: help(); tomwalters@0: } tomwalters@0: tomwalters@0: if (argXd0==UNSET) argXd0 = s; tomwalters@0: if (argXd1==UNSET) argXd1 = n; tomwalters@0: else argXd1 = argXd1-argXd0; /* ie, a range */ tomwalters@0: if (argYd0==UNSET) { tomwalters@0: if (argYd1==UNSET) argYd1 = 2*DEFAMPL; tomwalters@0: else argYd1 = 2*argYd1; tomwalters@0: argYd0 = argYd1/2; tomwalters@0: } tomwalters@0: else { tomwalters@0: if (argYd1==UNSET) argYd1 = DEFAMPL+argYd0; tomwalters@0: else argYd1 = argYd1+argYd0; tomwalters@0: } tomwalters@0: argYd0 = (-argYd0); tomwalters@0: tomwalters@0: if ((data = (short*) malloc(n * sizeof(short))) == NULL) tomwalters@0: error("malloc out of space\n"); tomwalters@0: if ((points = (XPoint*)malloc(n * sizeof(XPoint))) == NULL) tomwalters@0: error("malloc out of space\n"); tomwalters@0: tomwalters@0: if (argc) { tomwalters@0: /* Open data file */ tomwalters@0: name = *argv; tomwalters@0: if ((fp = fopen(name, "r")) == NULL) { tomwalters@0: fprintf(stderr,"can't open %s\n", *argv); tomwalters@0: exit(1); tomwalters@0: } tomwalters@0: } tomwalters@0: else fp = stdin; tomwalters@0: tomwalters@0: /* Seek start of data in file */ tomwalters@0: if (s > 0) seekstart(s,fp); tomwalters@0: tomwalters@0: set_window_parameters(PLOTXORG,PLOTYORG, PLOTWIDTH,PLOTHEIGHT); tomwalters@0: set_bordered_box(10); tomwalters@0: set_data_parameters(0,0, argXd0,argYd0, argXd1,argYd1); tomwalters@0: xopen(); tomwalters@0: xgc( 1, theFontString ) ; tomwalters@0: w = xcreate(name, ButtonPressMask | ExposureMask); tomwalters@0: init_xevent(w); tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Seek s points from current position in stream. tomwalters@0: * This general seek works even when fp is stdin, unlike fseek. tomwalters@0: ****************************************************************************/ tomwalters@0: seekstart(s,fp) tomwalters@0: int s; tomwalters@0: FILE *fp; tomwalters@0: { tomwalters@0: int i; tomwalters@0: short p; tomwalters@0: tomwalters@0: for (i=0 ; i 0) { tomwalters@0: XNextEvent(theDisplay,&event); tomwalters@0: switch (event.type) { tomwalters@0: case ButtonPress: tomwalters@0: switch(event.xbutton.button) { tomwalters@0: case Button1: /* Left */ tomwalters@0: XDestroyWindow(theDisplay,w); tomwalters@0: exit(0); tomwalters@0: case Button2: /* Middle */ tomwalters@0: if (stepmode) { tomwalters@0: if (wait) single_shot(w,fp); tomwalters@0: else wait=1; tomwalters@0: } tomwalters@0: break; tomwalters@0: case Button3: if (stepmode) wait=0; break;/* Right */ tomwalters@0: default: tomwalters@0: fprintf(stderr,"button %d not used\n", event.xbutton.button); tomwalters@0: } tomwalters@0: break; tomwalters@0: default: tomwalters@0: fprintf(stderr,"event type %d not found\n", event.type); tomwalters@0: } tomwalters@0: } tomwalters@0: } while (wait); tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Draw a calibrated box in a window and plot data inside it. tomwalters@0: ****************************************************************************/ tomwalters@0: draw_plot(w) tomwalters@0: Window w; tomwalters@0: { tomwalters@0: int i, npoints; tomwalters@0: tomwalters@0: if (z) draw_Xaxis(w,0); /* Draw zero line */ tomwalters@0: if (!overplot) XSetFunction(theDisplay,theGC,GXinvert); tomwalters@0: if (stepmode) XSynchronize(theDisplay,True); tomwalters@0: if (n <= pwidth()) npoints = upsample(w,fp); tomwalters@0: else fprintf(stderr,"successive downsampling not implemented yet!\n"); tomwalters@0: /* npoints = downsample(w,fp); */ tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Up and Down sampling. tomwalters@0: ****************************************************************************/ tomwalters@0: char stepcountstr[128]; tomwalters@0: tomwalters@0: upsample (w,fp) tomwalters@0: Window w; tomwalters@0: FILE *fp; tomwalters@0: { tomwalters@0: int i, x, j=0; tomwalters@0: int lastx,lasty, X,Y; tomwalters@0: short y, notfirst=0; tomwalters@0: float res, incr, carry; tomwalters@0: tomwalters@0: res = (float)pwidth()/(n-1); /* resolution of plot */ tomwalters@0: incr = res; /* x-value increment */ tomwalters@0: x = 0; /* initial x-value */ tomwalters@0: while (fread(&y, sizeof(short), 1, fp)) { tomwalters@0: if (stepmode) { tomwalters@0: if (stepcount > 0) supertopline(w,stepcountstr); tomwalters@0: sprintf(stepcountstr,"%d", ++stepcount); tomwalters@0: supertopline(w,stepcountstr); tomwalters@0: } tomwalters@0: lastx=pleft(); lasty=py(y); tomwalters@0: carry = res - (int)res; tomwalters@0: incr = res + carry; tomwalters@0: x = (int)incr; tomwalters@0: for (i=1 ; i pbottom()) Y = pbottom(); tomwalters@0: if (Y < ptop()) Y = ptop(); tomwalters@0: tomwalters@0: /* rub-out a segment of last plot */ tomwalters@0: if (notfirst) tomwalters@0: XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y); tomwalters@0: else notfirst=1; tomwalters@0: /* draw a new segment for current plot */ tomwalters@0: XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y); tomwalters@0: tomwalters@0: points[i-1].x = lastx; tomwalters@0: points[i-1].y = lasty; tomwalters@0: lastx = X; tomwalters@0: lasty = Y; tomwalters@0: tomwalters@0: carry = incr - (int)incr; tomwalters@0: incr = res + carry; tomwalters@0: x += (int)incr; tomwalters@0: } tomwalters@0: points[i-1].x = lastx; tomwalters@0: points[i-1].y = lasty; tomwalters@0: /* if (XEventsQueued(theDisplay,QueuedAlready) > 0) */ tomwalters@0: xevent_monitor(w); tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: single_shot (w,fp) tomwalters@0: Window w; tomwalters@0: FILE *fp; tomwalters@0: { tomwalters@0: int i, x, j=0; tomwalters@0: int lastx,lasty, X,Y; tomwalters@0: short y, notfirst=0; tomwalters@0: float res, incr, carry; tomwalters@0: tomwalters@0: res = (float)pwidth()/(n-1); /* resolution of plot */ tomwalters@0: incr = res; /* x-value increment */ tomwalters@0: x = 0; /* initial x-value */ tomwalters@0: if (fread(&y, sizeof(short), 1, fp)) { tomwalters@0: if (stepmode) { tomwalters@0: if (stepcount > 0) supertopline(w,stepcountstr); tomwalters@0: sprintf(stepcountstr,"%d", ++stepcount); tomwalters@0: supertopline(w,stepcountstr); tomwalters@0: } tomwalters@0: lastx=pleft(); lasty=py(y); tomwalters@0: carry = res - (int)res; tomwalters@0: incr = res + carry; tomwalters@0: x = (int)incr; tomwalters@0: for (i=1 ; i pbottom()) Y = pbottom(); tomwalters@0: if (Y < ptop()) Y = ptop(); tomwalters@0: tomwalters@0: /* rub-out a segment of last plot */ tomwalters@0: if (notfirst) tomwalters@0: XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y); tomwalters@0: else notfirst=1; tomwalters@0: /* draw a new segment for current plot */ tomwalters@0: XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y); tomwalters@0: tomwalters@0: points[i-1].x = lastx; tomwalters@0: points[i-1].y = lasty; tomwalters@0: lastx = X; tomwalters@0: lasty = Y; tomwalters@0: tomwalters@0: carry = incr - (int)incr; tomwalters@0: incr = res + carry; tomwalters@0: x += (int)incr; tomwalters@0: } tomwalters@0: points[i-1].x = lastx; tomwalters@0: points[i-1].y = lasty; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: #define BLOCK 256 tomwalters@0: float block; /* for averaging in downsample */ tomwalters@0: tomwalters@0: tomwalters@0: downsample (w,fp) tomwalters@0: Window w; tomwalters@0: FILE *fp; tomwalters@0: { tomwalters@0: int i, x, j = 0; tomwalters@0: short y; tomwalters@0: float rate; tomwalters@0: float res; tomwalters@0: float incr; tomwalters@0: float carry; tomwalters@0: tomwalters@0: rate = (float)n/pwidth(); tomwalters@0: if ((block = rate) >= BLOCK) tomwalters@0: error ("excessive downsampling; re-define BLOCK\n"); tomwalters@0: tomwalters@0: res = (float)pwidth()/(n-1); /* resolution of plot */ tomwalters@0: incr = res; /* x-value increment */ tomwalters@0: x = 0; /* initial x-value */ tomwalters@0: for (i=0 ; i= 1.0) { tomwalters@0: if (sample(&y, i, rate)) { tomwalters@0: points[j].x = x+pleft(); tomwalters@0: points[j].y = py(y); tomwalters@0: tomwalters@0: /* Plot only inside y-limits of box */ tomwalters@0: if (points[j].y > pbottom()) points[j].y = pbottom(); tomwalters@0: if (points[j].y < ptop()) points[j].y = ptop(); tomwalters@0: j++; tomwalters@0: } tomwalters@0: } tomwalters@0: carry = incr - (int)incr; tomwalters@0: incr = res + carry; tomwalters@0: x += (int)incr; tomwalters@0: } tomwalters@0: return j; tomwalters@0: } tomwalters@0: tomwalters@0: sample (y, i, rate) tomwalters@0: short *y; tomwalters@0: int i; tomwalters@0: float rate; tomwalters@0: { tomwalters@0: short average(); tomwalters@0: float carry; tomwalters@0: tomwalters@0: if (block <= n-i) { tomwalters@0: *y = average ((int)block, &data[i]); tomwalters@0: carry = block - (int)block; tomwalters@0: block = rate + carry; tomwalters@0: return 1; tomwalters@0: } tomwalters@0: else tomwalters@0: return 0; tomwalters@0: } tomwalters@0: tomwalters@0: /* tomwalters@0: short tomwalters@0: average (block, p) tomwalters@0: int block; tomwalters@0: short p[]; tomwalters@0: { tomwalters@0: int i; tomwalters@0: float sum = 0; tomwalters@0: tomwalters@0: for (i = 0 ; i < block ; i++) tomwalters@0: sum += p[i]; tomwalters@0: return (short)(sum / block); tomwalters@0: } tomwalters@0: */ tomwalters@0: tomwalters@0: short tomwalters@0: average (block, p) tomwalters@0: int block; tomwalters@0: short p[]; tomwalters@0: { tomwalters@0: int i; tomwalters@0: float sum = 0; tomwalters@0: short MIN = 32000, MAX = 0; tomwalters@0: tomwalters@0: for (i = 0 ; i < block ; i++) { tomwalters@0: sum += p[i]; tomwalters@0: if (p[i] < MIN) MIN = p[i]; tomwalters@0: if (p[i] > MAX) MAX = p[i]; tomwalters@0: } tomwalters@0: if (summary==0) { /* summary of block is largest extremal value */ tomwalters@0: if (MAX >= (-MIN)) return MAX; /* summary of block is MAX value */ tomwalters@0: else return MIN; /* summary of block is MIN value */ tomwalters@0: } tomwalters@0: if (summary == 1) return (p[0]); /* summary of block is sample value */ tomwalters@0: return (short)(sum / block); /* summary of block is mean value */ tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * Miscellaneous tomwalters@0: ****************************************************************************/ tomwalters@0: error(s) tomwalters@0: { tomwalters@0: fprintf(stderr,"%s",s); tomwalters@0: exit(1); tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: help () tomwalters@0: { tomwalters@0: printf ("\nx11play: animated plot of sets of n points, read as binary shorts.\n"); tomwalters@0: printf ("Usage: a) x11play [options] filename\n"); tomwalters@0: printf (" b) cat filename | x11play [options]\n"); tomwalters@0: printf (" where filename is an input stream of 16-bit binary numbers (shorts)\n"); tomwalters@0: printf ("Options:\n"); tomwalters@0: printf ("-n [int] = Number of points plotted (default=%d).\n", DEFSCALE); tomwalters@0: printf ("-s [int] = Offset points from start of file (default=0).\n"); tomwalters@0: printf ("-a [float] = Amplitude between zero-line and top of box (default=%d).\n", DEFAMPL); tomwalters@0: printf ("-y [int] = Amplitude between zero-line and bottom of box (default=a).\n"); tomwalters@0: printf ("-c [float] = Calibration at right end of x-axis (default=n+s).\n"); tomwalters@0: printf ("-x [int] = Calibration at left end of x-axis (default=s).\n"); tomwalters@0: printf ("-z = Suppress zero-line.\n"); tomwalters@0: printf ("-b [0,1,2] = Method of block summary for down-sampling.\n"); tomwalters@0: printf (" 0=MAX, 1=SAMPLE, 2=MEAN, (default=MAX).\n"); tomwalters@0: printf ("-S = Step-mode, (centre-button=single-step, right-button=play).\n"); tomwalters@0: printf ("-O = Over-plot successive plots of n points.\n"); tomwalters@0: printf ("-F [font] = Font name (default=%s)\n", theFontString); tomwalters@0: exit (0); tomwalters@0: } tomwalters@0: tomwalters@0: