1 #include "snd.h"
2 
is_x_axis_style(int n)3 bool is_x_axis_style(int n)
4 {
5   switch (n)
6     {
7     case X_AXIS_IN_SECONDS: case X_AXIS_IN_SAMPLES: case X_AXIS_AS_PERCENTAGE:
8     case X_AXIS_IN_BEATS: case X_AXIS_IN_MEASURES: case X_AXIS_AS_CLOCK:
9       return(true);
10       break;
11     }
12   return(false);
13 }
14 
15 
shows_axes(int n)16 bool shows_axes(int n)
17 {
18   switch (n)
19     {
20     case SHOW_NO_AXES: case SHOW_ALL_AXES: case SHOW_X_AXIS:
21     case SHOW_ALL_AXES_UNLABELLED: case SHOW_X_AXIS_UNLABELLED:
22     case SHOW_BARE_X_AXIS:
23       return(true);
24       break;
25     }
26   return(false);
27 }
28 
29 
30 typedef struct tick_descriptor {
31   double hi, lo;
32   int max_ticks;
33   double flo, fhi, mlo, mhi, step, tenstep;
34   int tens;
35   int maj_tick_len, min_tick_len, min_label_width, max_label_width;
36   char *min_label, *max_label;
37   mus_float_t grid_scale;
38 } tick_descriptor;
39 
40 
free_tick_descriptor(tick_descriptor * td)41 static tick_descriptor *free_tick_descriptor(tick_descriptor *td)
42 {
43   if (td)
44     {
45       if (td->min_label) {free(td->min_label); td->min_label = NULL;}
46       if (td->max_label) {free(td->max_label); td->max_label = NULL;}
47       free(td);
48     }
49   return(NULL);
50 }
51 
52 
describe_ticks(tick_descriptor * gd_td,double lo,double hi,int max_ticks,mus_float_t grid_scale)53 static tick_descriptor *describe_ticks(tick_descriptor *gd_td, double lo, double hi, int max_ticks, mus_float_t grid_scale)
54 {
55   /* given absolute (unchangeable) axis bounds lo and hi, and maximum number of ticks to use, find a "pretty" tick placement */
56   /* much of the work here involves floating point rounding problems.  We assume the tick labeller will round as well */
57 
58   tick_descriptor *td;
59   int ten, hib, lob, offset = 0;
60   double flog10, plog10;
61   double frac, ften, hilo_diff, eten, flt_ten;
62   double inside, mfdiv, mten, mften;
63   int mticks, mdiv;
64 
65   if (!gd_td)
66     td = (tick_descriptor *)calloc(1, sizeof(tick_descriptor));
67   else
68     {
69       td = gd_td;
70       if ((td->hi == hi) &&
71 	  (td->lo == lo) &&
72 	  (td->max_ticks == max_ticks) &&
73 	  ((fabs(td->grid_scale - grid_scale)) < .01))
74 	return(td);
75     }
76   td->hi = hi;
77   td->lo = lo;
78   td->grid_scale = grid_scale;
79   hilo_diff = hi - lo;
80   if (hilo_diff < .001)
81     {
82       offset = (int)hi;
83       hi -= offset;
84       lo -= offset;
85     }
86   td->max_ticks = max_ticks;
87   flt_ten = log10(hilo_diff);
88   ten = (int)floor(flt_ten);
89   frac = flt_ten - ten;
90   if (frac > .9999) ten++;
91   eten = pow(10, ten);
92   hib = (int)floor(hi / eten);
93   lob = (int)ceil(lo / eten);
94   /* it's possible to wrap-around here and get negative numbers (so we keep the offset separate above) */
95   if (lob != hib)
96     {
97       td->mlo = (double)(lob * eten);
98       td->mhi = (double)(hib * eten);
99     }
100   else
101     {
102       double flt_ften;
103       /* try next lower power of ten */
104       ften = eten * .1;
105       flt_ften = (hi / ften);
106       hib = (int)floor(flt_ften);
107       frac = flt_ften - hib;
108       if (frac > .9999) hib++;
109       lob = (int)ceil(lo / ften);
110       td->mlo = (double)(lob * ften);
111       td->mhi = (double)(hib * ften);
112     }
113   inside = (td->mhi - td->mlo) / hilo_diff;
114   mticks = (int)floor(inside * max_ticks);
115 
116   if (mticks <= 1) mdiv = 1;
117   else if (mticks < 3) mdiv = mticks;
118   else if (mticks == 3) mdiv = 2;
119   else if (mticks < 6) mdiv = mticks;
120   else if (mticks < 10) mdiv = 5;
121   else mdiv = (int)(10 * floor(mticks / 10));
122 
123   mfdiv = (td->mhi - td->mlo) / mdiv;
124   flog10 = floor(log10(mfdiv));
125   plog10 = pow(10, flog10);
126   td->tens = (int)fabs(flog10);
127 
128   mten = grid_scale * (double)(floor(4.0 * (.00001 + (mfdiv / plog10)))) / 4.0;
129   if (mten < 1.0) mten = 1.0;
130   if ((mten == 1.0) || (mten == 2.0) || (mten == 2.5) || (mten == 5.0)) ften = mten;
131   else if (mten < 2.0) ften = 2.0;
132   else if (mten < 2.5) ften = 2.5;
133   else if (mten < 5.0) ften = 5.0;
134   else ften = 10.0;
135 
136   td->tenstep = ften;
137   mften = ften * plog10;
138   td->step = mften;
139   flt_ten = lo / mften;
140   lob = (int)ceil(flt_ten);
141   frac = lob - flt_ten;
142   if (frac > .9999) lob--;
143   td->flo = lob * mften;
144   flt_ten = (hi / mften);
145   hib = (int)floor(flt_ten);
146   frac = flt_ten - hib;
147   if (frac > .9999) hib++;
148   td->fhi = hib * mften;
149   if (hilo_diff < .001)
150     {
151       td->mlo += offset;
152       td->mhi += offset;
153       td->flo += offset;
154       td->fhi += offset;
155     }
156   return(td);
157 }
158 
159 
first_beat(chan_info * cp,double val)160 static bool first_beat(chan_info *cp, double val)
161 {
162   int measure, beat;
163   double beat_frac;
164   beat = (int)val;
165   beat_frac = val - beat;
166   measure = (int)(beat / cp->beats_per_measure);
167   beat = beat - measure * cp->beats_per_measure;
168   return((beat == 0) &&
169 	 (beat_frac < .001));
170 }
171 
172 
measure_number(int bpm,double val)173 static char *measure_number(int bpm, double val)
174 {
175   /* split out the measure number, change to beat count (1-based), add fraction, if any */
176   /* "val" is in terms of beats */
177   char *buf;
178   int measure, beat;
179   double beat_frac;
180   beat = (int)val;
181   beat_frac = val - beat;
182   measure = (int)(beat / bpm);
183   beat = beat - measure * bpm;
184   buf = (char *)calloc(64, sizeof(char));
185   if (beat_frac > .001)
186     {
187       char *frac_buf, *tmp; /* according to the C spec, there's no way to get %f to omit the leading "0" */
188       frac_buf = (char *)calloc(32, sizeof(char));
189       snprintf(frac_buf, 32, "%.3f", beat_frac);
190       if (frac_buf[0] == '0')
191 	tmp = (frac_buf + 1);  /* omit the leading "0" */
192       else tmp = frac_buf;
193       snprintf(buf, 64, "%d(%d)%s", 1 + measure, 1 + beat, tmp);
194       free(frac_buf);
195     }
196   else snprintf(buf, 64, "%d(%d)", 1 + measure, 1 + beat);
197   return(buf);
198 }
199 
200 
clock_number(double loc,int tens)201 static char *clock_number(double loc, int tens)
202 {
203   /* DD:HH:MM:SS.ddd */
204   #define CLOCK_BUFFER_SIZE 64
205 
206   int day, hour, minute, second;
207   double frac_second;
208   char *buf;
209 
210   second = (int)loc;
211   frac_second = loc - second;
212   minute = (int)floor(second / 60);
213   hour = (int)floor(minute / 60);
214   day = (int)floor(hour / 24);
215   second %= 60;
216   minute %= 60;
217   hour %= 24;
218 
219   buf = (char *)calloc(CLOCK_BUFFER_SIZE, sizeof(char));
220 
221   if (day > 0)
222     snprintf(buf, CLOCK_BUFFER_SIZE, "%02d:%02d:%02d:%02d.%0*d", day, hour, minute, second, tens, (int)(frac_second * pow(10.0, tens)));
223   else
224     {
225       if (hour > 0)
226 	snprintf(buf, CLOCK_BUFFER_SIZE, "%02d:%02d:%02d.%0*d", hour, minute, second, tens, (int)(frac_second * pow(10.0, tens)));
227       else
228 	{
229 	  if (minute > 0)
230 	    snprintf(buf, CLOCK_BUFFER_SIZE, "%02d:%02d.%0*d", minute, second, tens, (int)(frac_second * pow(10.0, tens)));
231 	  else
232 	    {
233 	      if (second > 0)
234 		snprintf(buf, CLOCK_BUFFER_SIZE, "%d.%0*d", second, tens, (int)(frac_second * pow(10.0, tens)));
235 	      else snprintf(buf, CLOCK_BUFFER_SIZE, "0.%0*d", tens, (int)(frac_second * pow(10.0, tens)));
236 	    }
237 	}
238     }
239 
240   return(buf);
241 }
242 
243 
location_to_string(double loc,int style,int bpm,int tens)244 static char *location_to_string(double loc, int style, int bpm, int tens)
245 {
246   if (style == X_AXIS_IN_SAMPLES)
247     tens = 0;
248   else
249     {
250       if (tens == 0)
251 	tens = 1; /* in x axis we usually want the ".0" */
252     }
253 
254   switch (style)
255     {
256     case X_AXIS_AS_CLOCK:
257       return(clock_number(loc, tens));
258       break;
259     case X_AXIS_IN_MEASURES:
260       return(measure_number(bpm, loc));
261       break;
262     default:
263       return(prettyf(loc, tens));
264       break;
265     }
266   return(prettyf(loc, tens));
267 }
268 
269 
x_axis_location_to_string(chan_info * cp,double loc)270 char *x_axis_location_to_string(chan_info *cp, double loc)
271 {
272   if (cp)
273     {
274       axis_info *ap;
275       ap = cp->axis; /* time graph */
276       if (ap)
277 	{
278 	  tick_descriptor *tdx;
279 	  tdx = ap->x_ticks;
280 	  if (tdx)
281 	    return(location_to_string(loc, cp->x_axis_style, cp->beats_per_measure, tdx->tens));
282 	}
283     }
284   return(prettyf(loc, 2));
285 }
286 
287 
free_axis_info(axis_info * ap)288 axis_info *free_axis_info(axis_info *ap)
289 {
290   if (!ap) return(NULL);
291   if (ap->x_ticks) ap->x_ticks = free_tick_descriptor(ap->x_ticks);
292   if (ap->y_ticks) ap->y_ticks = free_tick_descriptor(ap->y_ticks);
293   /* leave ap->ax alone -- it actually belongs to cp */
294   if (ap->xlabel)
295     {
296       free(ap->xlabel);
297       ap->xlabel = NULL;
298     }
299   if (ap->default_xlabel)
300     {
301       free(ap->default_xlabel);
302       ap->default_xlabel = NULL;
303     }
304   if (ap->ylabel)
305     {
306       free(ap->ylabel);
307       ap->ylabel = NULL;
308     }
309   free(ap);
310   return(NULL);
311 }
312 
313 
grf_x(double val,axis_info * ap)314 int grf_x(double val, axis_info *ap)
315 {
316   if (val >= ap->x1) return(ap->x_axis_x1);
317   if (val <= ap->x0) return(ap->x_axis_x0);
318   return((int)(ap->x_base + val * ap->x_scale));
319 }
320 
321 
grf_y(mus_float_t val,axis_info * ap)322 int grf_y(mus_float_t val, axis_info *ap)
323 {
324   if (val >= ap->y1) return(ap->y_axis_y1);
325   if (val <= ap->y0) return(ap->y_axis_y0);
326   return((int)(ap->y_base + val * ap->y_scale));
327 }
328 
329 
init_axis_scales(axis_info * ap)330 void init_axis_scales(axis_info *ap)
331 {
332   if ((ap->x_axis_x0 == ap->x_axis_x1) || (ap->x0 == ap->x1))
333     ap->x_scale = 0.0;
334   else ap->x_scale = ((double)(ap->x_axis_x1 - ap->x_axis_x0)) / ((double)(ap->x1 - ap->x0));
335   ap->x_base = (double)(ap->x_axis_x0 - ap->x0 * ap->x_scale);
336   if ((ap->y_axis_y0 == ap->y_axis_y1) || (ap->y0 == ap->y1))
337     ap->y_scale = 0.0;
338   else ap->y_scale = (mus_float_t)(ap->y_axis_y1 - ap->y_axis_y0) / (ap->y1 - ap->y0);
339   ap->y_base = (mus_float_t)(ap->y_axis_y0 - ap->y0 * ap->y_scale);
340 }
341 
342 
tick_grf_x(double val,axis_info * ap,x_axis_style_t style,int srate)343 static int tick_grf_x(double val, axis_info *ap, x_axis_style_t style, int srate)
344 {
345   int res = 0;
346   switch (style)
347     {
348     case X_AXIS_AS_CLOCK:
349     case X_AXIS_IN_SECONDS:
350     default:
351       res = (int)(ap->x_base + val * ap->x_scale);
352       break;
353 
354     case X_AXIS_IN_BEATS:
355     case X_AXIS_IN_MEASURES:
356       if (ap->cp)
357 	res = (int)(ap->x_base + val * ap->x_scale * 60.0 / ap->cp->beats_per_minute);
358       else res = (int)(ap->x_base + val * ap->x_scale);
359       break;
360 
361     case X_AXIS_IN_SAMPLES:
362       res = (int)(ap->x_axis_x0 + (val - ap->x0 * srate) * ap->x_scale / srate);
363       break;
364 
365     case X_AXIS_AS_PERCENTAGE:
366       res = (int)(ap->x_axis_x0 + (val - ap->x0 / ap->xmax) * ap->x_scale * ap->xmax);
367       break;
368     }
369   if (res >= -32768)
370     {
371       if (res < 32768) return(res);
372       return(32767);
373     }
374   return(-32768);
375 }
376 
377 
378 #if HAVE_GL
379   #if WITH_GL2PS
380     void gl2ps_text(const char *msg);
381   #endif
382 
383 static bool gl_fonts_activated = false;
384 static int label_base, number_base;
385 
activate_gl_fonts(void)386 static void activate_gl_fonts(void)
387 {
388 #if USE_MOTIF
389   if (!gl_fonts_activated)
390     {
391       XFontStruct *label, *number;
392       label = (XFontStruct *)(AXIS_LABEL_FONT(ss));
393       number = (XFontStruct *)(AXIS_NUMBERS_FONT(ss));
394       label_base = glGenLists(128);
395       number_base = glGenLists(128);
396       glXUseXFont(label->fid, 32, 96, label_base + 32);
397       glXUseXFont(number->fid, 32, 96, number_base + 32);
398       gl_fonts_activated = true;
399     }
400 #else
401   if (!gl_fonts_activated)
402     {
403       label_base = glGenLists(128);
404       number_base = glGenLists(128);
405       gl_fonts_activated = true;
406     }
407 #endif
408 }
409 
410 
reload_label_font(void)411 void reload_label_font(void)
412 {
413 #if USE_MOTIF
414   if (gl_fonts_activated)
415     {
416       XFontStruct *label;
417       glDeleteLists(label_base, 128);
418       label_base = glGenLists(128);
419       label = (XFontStruct *)(AXIS_LABEL_FONT(ss));
420       glXUseXFont(label->fid, 32, 96, label_base + 32);
421     }
422 #else
423   if (gl_fonts_activated)
424     {
425       glDeleteLists(label_base, 128);
426       label_base = glGenLists(128);
427       /* gdk_gl_font_use_pango_font(AXIS_LABEL_FONT(ss), 32, 96, label_base + 32); */
428     }
429 #endif
430 }
431 
432 
reload_number_font(void)433 void reload_number_font(void)
434 {
435 #if USE_MOTIF
436   if (gl_fonts_activated)
437     {
438       XFontStruct *number;
439       glDeleteLists(number_base, 128);
440       number_base = glGenLists(128);
441       number = (XFontStruct *)(AXIS_NUMBERS_FONT(ss));
442       glXUseXFont(number->fid, 32, 96, number_base + 32);
443     }
444 #else
445   if (gl_fonts_activated)
446     {
447       glDeleteLists(number_base, 128);
448       number_base = glGenLists(128);
449       /* gdk_gl_font_use_pango_font(AXIS_NUMBERS_FONT(ss), 32, 96, number_base + 32); */
450     }
451 #endif
452 }
453 #endif
454 
455 
draw_horizontal_grid_line(int y,axis_info * ap,graphics_context * ax)456 static void draw_horizontal_grid_line(int y, axis_info *ap, graphics_context *ax)
457 {
458   color_t old_color;
459   old_color = get_foreground_color(ax);
460   if (ap->cp->selected)
461     set_foreground_color(ax, ss->selected_grid_color);
462   else set_foreground_color(ax, ss->grid_color);
463   draw_line(ax, ap->y_axis_x0, y, ap->x_axis_x1, y);
464   set_foreground_color(ax, old_color);
465 }
466 
467 
draw_vertical_grid_line(int x,axis_info * ap,graphics_context * ax)468 static void draw_vertical_grid_line(int x, axis_info *ap, graphics_context *ax)
469 {
470   color_t old_color;
471   old_color = get_foreground_color(ax);
472   if (ap->cp->selected)
473     set_foreground_color(ax, ss->selected_grid_color);
474   else set_foreground_color(ax, ss->grid_color);
475   draw_line(ax, x, ap->x_axis_y0, x, ap->y_axis_y1);
476   set_foreground_color(ax, old_color);
477 }
478 
479 
draw_x_number(const char * label,int x,int y,int hgt,axis_info * ap,graphics_context * ax,printing_t printing)480 static void draw_x_number(const char *label, int x, int y, int hgt, axis_info *ap, graphics_context *ax, printing_t printing)
481 {
482   if (x < 0) x = 0; /* if no y axis and no labels, this sometimes is pushed left too far */
483 
484 #if USE_MOTIF
485   y = y + hgt + 1;
486 #else
487   y = y + 4;
488 #endif
489   draw_string(ax, x, y, label, mus_strlen(label));
490   if (printing)
491     ps_draw_string(ap, x, y, label);
492 }
493 
494 
draw_y_number(const char * label,int x,int y,int hgt,axis_info * ap,graphics_context * ax,printing_t printing)495 static void draw_y_number(const char *label, int x, int y, int hgt, axis_info *ap, graphics_context *ax, printing_t printing)
496 {
497 #if USE_MOTIF
498   y = y + (int)(hgt / 2);
499 #else
500   y = y - (int)(hgt / 2);
501 #endif
502   draw_string(ax, x, y, label, mus_strlen(label));
503   if (printing)
504     ps_draw_string(ap, x, y, label);
505 }
506 
507 
draw_label(const char * label,int x,int y,int yoff,axis_info * ap,graphics_context * ax,printing_t printing)508 static void draw_label(const char *label, int x, int y, int yoff, axis_info *ap, graphics_context *ax, printing_t printing)
509 {
510   draw_string(ax, x - 10, y, label, mus_strlen(label));
511   if (printing)
512     ps_draw_string(ap, x - 10, y, label);
513 }
514 
515 
draw_vertical_tick(int x,int y0,int y1,axis_info * ap,graphics_context * ax,printing_t printing,bool include_grid)516 static void draw_vertical_tick(int x, int y0, int y1, axis_info *ap, graphics_context *ax, printing_t printing, bool include_grid)
517 {
518   draw_line(ax, x, y1, x, y0);
519   if (printing) ps_draw_line(ap, x, y1, x, y0);
520   if (include_grid) draw_vertical_grid_line(x, ap, ax);
521 }
522 
523 
draw_horizontal_tick(int x0,int x1,int y,axis_info * ap,graphics_context * ax,printing_t printing,bool include_grid)524 static void draw_horizontal_tick(int x0, int x1, int y, axis_info *ap, graphics_context *ax, printing_t printing, bool include_grid)
525 {
526   draw_line(ax, x0, y, x1, y);
527   if (printing) ps_draw_line(ap, x0, y, x1, y);
528   if (include_grid) draw_horizontal_grid_line(y, ap, ax);
529 }
530 
531 
draw_log_tick_label(const char * label,int logx,int y,int hgt,int x_label_width,int right_border_width,axis_info * ap,graphics_context * ax,printing_t printing,bool use_tiny_font)532 static void draw_log_tick_label(const char *label, int logx, int y, int hgt, int x_label_width, int right_border_width,
533 				axis_info *ap, graphics_context *ax, printing_t printing, bool use_tiny_font)
534 {
535   /* is there room for a label? */
536   /* the main label is at ap->x_label_x to that plus x_label_width */
537   int lx0, lx1, tx0, tx1, label_width;
538   lx0 = ap->x_label_x;
539   lx1 = lx0 + x_label_width;
540   label_width = number_width(label, use_tiny_font);
541   tx0 = (int)(logx - .45 * label_width);
542   if ((tx0 + label_width) > ap->x_axis_x1)
543     tx0 = (int)(logx - label_width + .75 * right_border_width);
544   tx1 = tx0 + label_width;
545   if ((lx0 > tx1) || (lx1 < tx0))
546     draw_x_number(label, tx0, y, hgt, ap, ax, printing);
547 }
548 
549 
use_tiny(graphics_context * ax,printing_t printing)550 static void use_tiny(graphics_context *ax, printing_t printing)
551 {
552 #if USE_MOTIF
553   ax->current_font = ((XFontStruct *)(TINY_FONT(ss)))->fid;
554   XSetFont(ax->dp, ax->gc, ((XFontStruct *)(TINY_FONT(ss)))->fid);
555 #endif
556   if (printing) ps_set_tiny_numbers_font();
557 }
558 
559 
set_numbers_font(graphics_context * ax,printing_t printing,bool use_tiny_font)560 void set_numbers_font(graphics_context *ax, printing_t printing, bool use_tiny_font)
561 {
562   if (use_tiny_font)
563     use_tiny(ax, printing);
564   else
565     {
566 #if USE_MOTIF
567       ax->current_font = ((XFontStruct *)(AXIS_NUMBERS_FONT(ss)))->fid;
568       XSetFont(ax->dp, ax->gc, ((XFontStruct *)(AXIS_NUMBERS_FONT(ss)))->fid);
569 #endif
570       if (printing) ps_set_number_font();
571     }
572 }
573 
574 
set_labels_font(graphics_context * ax,printing_t printing,bool use_tiny_font)575 static void set_labels_font(graphics_context *ax, printing_t printing, bool use_tiny_font)
576 {
577   if (use_tiny_font)
578     use_tiny(ax, printing);
579   else
580     {
581 #if USE_MOTIF
582       ax->current_font = ((XFontStruct *)(AXIS_LABEL_FONT(ss)))->fid;
583       XSetFont(ax->dp, ax->gc, ((XFontStruct *)(AXIS_LABEL_FONT(ss)))->fid);
584 #endif
585       if (printing) ps_set_label_font();
586     }
587 }
588 
589 
make_axes_1(axis_info * ap,x_axis_style_t x_style,int srate,show_axes_t axes,printing_t printing,with_x_axis_t show_x_axis,with_grid_t with_grid,log_axis_t log_axes,mus_float_t grid_scale)590 void make_axes_1(axis_info *ap, x_axis_style_t x_style, int srate, show_axes_t axes, printing_t printing,
591 		 with_x_axis_t show_x_axis, with_grid_t with_grid, log_axis_t log_axes, mus_float_t grid_scale)
592 {
593   int width, height;
594   int axis_thickness, left_border_width, bottom_border_width, top_border_width, right_border_width, inner_border_width;
595   int major_tick_length, minor_tick_length, x_tick_spacing, y_tick_spacing;
596   bool include_x_label, include_x_ticks, include_x_tick_labels, include_y_ticks, include_y_tick_labels, include_grid;
597   bool y_axis_linear = true, x_axis_linear = true, use_tiny_font = false;
598   int x_label_width, x_label_height, x_number_height;
599   int num_ticks;
600   tick_descriptor *tdx = NULL, *tdy = NULL;
601   int curx, cury;
602   graphics_context *ax;
603 #if HAVE_GL
604   mus_float_t xthick, ythick, xmajorlen, xminorlen, ymajorlen, yminorlen;
605 #endif
606 
607   ax = ap->ax;
608   width = ap->width;
609   height = ap->height;
610   ap->graph_active = ((width > 4) || (height > 10));
611   include_grid = ((ap->cp) && (with_grid));
612 
613   if ((axes == SHOW_NO_AXES) || (width < 40) || (height < 40) || (ap->xmax == 0.0))
614     {
615       /* leave it set up for bare graph */
616       if (height > 100)
617 	{
618 	  ap->y_axis_y0 = ap->y_offset + height - 20;
619 	  ap->y_axis_y1 = ap->y_offset + 10;
620 	}
621       else
622 	{
623 	  ap->y_axis_y0 = ap->y_offset + (int)(0.8 * height);
624 	  ap->y_axis_y1 = ap->y_offset + (int)(0.1 * height);
625 	}
626       if (width > 100)
627 	{
628 	  ap->x_axis_x1 = ap->graph_x0 + width - 10;
629 	  ap->x_axis_x0 = ap->graph_x0 + 20;
630 	}
631       else
632 	{
633 	  ap->x_axis_x1 = ap->graph_x0 + (int)(0.9 * width);
634 	  ap->x_axis_x0 = ap->graph_x0 + (int)(0.2 * width);
635 	}
636       init_axis_scales(ap);
637       return;
638     }
639 
640   left_border_width = 10;
641 #if USE_MOTIF
642   bottom_border_width = 10;
643 #else
644   bottom_border_width = 8;
645 #endif
646   top_border_width = 10;
647   right_border_width = 14;
648   inner_border_width = 5;
649   x_tick_spacing = 20;
650   if (width < 250) x_tick_spacing = 10 + (width / 25);
651   y_tick_spacing = 20;
652   if (height < 250) y_tick_spacing = 10 + (height / 25);
653   if ((height < 100) || (width < 100))
654     {
655       major_tick_length = 4;
656       minor_tick_length = 2;
657     }
658   else
659     {
660       major_tick_length = 9;
661       minor_tick_length = 5;
662     }
663   axis_thickness = 2;
664 #if HAVE_GL
665   xthick = (mus_float_t)(2 * axis_thickness) / (mus_float_t)height;
666   ythick = (mus_float_t)(2 * axis_thickness) / (mus_float_t)width;
667   xmajorlen = (mus_float_t)(2 * major_tick_length) / (mus_float_t)height;
668   xminorlen = (mus_float_t)(2 * minor_tick_length) / (mus_float_t)height;
669   ymajorlen = (mus_float_t)(2 * major_tick_length) / (mus_float_t)width;
670   yminorlen = (mus_float_t)(2 * minor_tick_length) / (mus_float_t)width;
671 #endif
672 
673   if (show_x_axis)
674     {
675       if (axes == SHOW_BARE_X_AXIS)
676 	{
677 	  include_x_label = false;
678 	  include_x_tick_labels = false;
679 	  include_x_ticks = false;
680 	}
681       else
682 	{
683 	  if ((axes == SHOW_X_AXIS_UNLABELLED) || (axes == SHOW_ALL_AXES_UNLABELLED))
684 	    include_x_label = false;
685 	  else include_x_label = ((ap->xlabel) && ((height > 100) && (width > 100)));
686 	  include_x_tick_labels = ((height > 60) && (width > 100));
687 	  include_x_ticks = ((height > 40) && (width > 40));
688 	}
689     }
690   else
691     {
692       include_x_label = false;
693       include_x_tick_labels = false;
694       include_x_ticks = false;
695     }
696   if (log_axes == WITH_LOG_X_AXIS) x_axis_linear = false;
697 
698   if ((axes != SHOW_X_AXIS) && (axes != SHOW_X_AXIS_UNLABELLED))
699     {
700       include_y_tick_labels = ((width > 100) && (height > 60));
701       include_y_ticks = ((width > 100) && (height > 40));
702     }
703   else
704     {
705       include_y_tick_labels = false;
706       include_y_ticks = false;
707     }
708   if (log_axes == WITH_LOG_Y_AXIS) y_axis_linear = false;
709 
710   curx = left_border_width;
711   cury = height - bottom_border_width;
712   use_tiny_font = ((width < 250) || (height < 140));
713 
714   x_number_height = number_height((use_tiny_font) ? TINY_FONT(ss) : AXIS_NUMBERS_FONT(ss));
715   x_label_height = 0;
716   x_label_width = 0;
717 
718   if (include_x_label)
719     {
720       x_label_width = label_width(ap->xlabel, use_tiny_font);
721       if ((x_label_width + curx + right_border_width) > width)
722 	{
723 	  include_x_label = false;
724 	  x_label_width = 0;
725 	  x_label_height = 0;
726 	}
727       else x_label_height = label_height(use_tiny_font);
728     }
729   else
730     {
731       if (include_x_ticks)
732 	x_label_height = label_height(use_tiny_font);
733       /* bare x axis case handled later */
734     }
735 
736   if (y_axis_linear)
737     {
738       if (include_y_ticks)
739 	{
740 	  /* figure out how long the longest tick label will be and make room for it */
741 	  /* values go from ap->y0 to ap->y1 */
742 	  /* basic tick spacing is tick_spacing pixels */
743 
744 	  num_ticks = cury / y_tick_spacing;
745 	  /* ticks start and stop at 10-based locations (i.e. sloppy axis bounds) */
746 	  /* so, given the current min..max, find the pretty min..max for ticks */
747 
748 	  if (ap->y1 <= ap->y0)
749 	    {
750 	      if (ap->y0 != 0.0)
751 		ap->y1 = ap->y0 * 1.25;
752 	      else ap->y1 = 1.0;
753 	    }
754 
755 	  tdy = describe_ticks(ap->y_ticks, ap->y0, ap->y1, num_ticks, grid_scale);
756 	  ap->y_ticks = tdy;
757 	  if (include_y_tick_labels)
758 	    {
759 	      int tick_label_width;
760 	      if (tdy->min_label)
761 		{
762 		  free(tdy->min_label);
763 		  tdy->min_label = NULL;
764 		}
765 	      tdy->min_label = prettyf(tdy->mlo, tdy->tens);
766 	      tdy->min_label_width = number_width(tdy->min_label, use_tiny_font);
767 
768 	      if (tdy->max_label)
769 		{
770 		  free(tdy->max_label);
771 		  tdy->max_label = NULL;
772 		}
773 	      tdy->max_label = prettyf(tdy->mhi, tdy->tens);
774 	      tdy->max_label_width = number_width(tdy->max_label, use_tiny_font);
775 	      tick_label_width = tdy->min_label_width;
776 	      if (tick_label_width < tdy->max_label_width)
777 		tick_label_width = tdy->max_label_width;
778 	      if (((curx + tick_label_width) > (int)(.61 * width)) ||
779 		  ((4 * x_number_height) > height))
780 		include_y_tick_labels = false;
781 	      else curx += tick_label_width;
782 	    }
783 
784 	  curx += major_tick_length;
785 	  tdy->maj_tick_len = major_tick_length;
786 	  tdy->min_tick_len = minor_tick_length;
787 	  ap->y_axis_y1 = top_border_width;
788 	}
789       else ap->y_axis_y1 = 0;
790     }
791   else
792     {
793       /* log case */
794       if (include_y_tick_labels)
795 	curx += number_width("10000", use_tiny_font);
796       curx += major_tick_length;
797       ap->y_axis_y1 = include_y_ticks ? top_border_width : 0;
798     }
799 
800   ap->x_axis_x1 = width - right_border_width;
801   ap->x_axis_x0 = curx;
802 
803   if (ap->x1 <= ap->x0)
804     {
805       if (ap->x0 != 0.0)
806 	ap->x1 = ap->x0 * 1.25;
807       else ap->x1 = .1;
808     }
809 
810   if ((x_axis_linear) && (include_x_ticks))
811     {
812       num_ticks = (ap->x_axis_x1 - curx) / x_tick_spacing;
813       switch (x_style)
814 	{
815 	case X_AXIS_AS_CLOCK:
816 	case X_AXIS_IN_SECONDS:
817 	default:
818 	  tdx = describe_ticks(ap->x_ticks, ap->x0, ap->x1, num_ticks, grid_scale);
819 	  break;
820 
821 	case X_AXIS_IN_SAMPLES:
822 	  tdx = describe_ticks(ap->x_ticks, ap->x0 * srate, ap->x1 * srate, num_ticks, grid_scale);
823 	  break;
824 
825 	case X_AXIS_IN_BEATS:
826 	case X_AXIS_IN_MEASURES:
827 	  if (ap->cp) /* cp==null probably can't happen -- ap->cp is null (only?) if we're called from the envelope editor */
828 	    {
829 	      mus_float_t beats_per_second;
830 	      beats_per_second = ap->cp->beats_per_minute / 60.0;
831 	      tdx = describe_ticks(ap->x_ticks,
832 				   ap->x0 * beats_per_second,
833 				   ap->x1 * beats_per_second,
834 				   num_ticks,
835 				   grid_scale);
836 	      /* here we are getting the intra-beat settings, if x-axis-in-measures */
837 	    }
838 	  else tdx = describe_ticks(ap->x_ticks, ap->x0, ap->x1, num_ticks, grid_scale);
839 	  break;
840 
841 	  /* measure-positions or some such list could use marks */
842 
843 	case X_AXIS_AS_PERCENTAGE:
844 	  tdx = describe_ticks(ap->x_ticks, ap->x0 / ap->xmax, ap->x1 / ap->xmax, num_ticks, grid_scale);
845 	  break;
846 	}
847       ap->x_ticks = tdx;
848       if (include_x_tick_labels)
849 	{
850 	  int tick_label_width;
851 	  if (tdx->min_label)
852 	    {
853 	      free(tdx->min_label);
854 	      tdx->min_label = NULL;
855 	    }
856 	  tdx->min_label = location_to_string(tdx->mlo, x_style, (ap->cp) ? (ap->cp->beats_per_measure) : 1, tdx->tens);
857 	  tdx->min_label_width = number_width(tdx->min_label, use_tiny_font);
858 	  if (tdx->max_label)
859 	    {
860 	      free(tdx->max_label);
861 	      tdx->max_label = NULL;
862 	    }
863 	  tdx->max_label = location_to_string(tdx->mhi, x_style, (ap->cp) ? (ap->cp->beats_per_measure) : 1, tdx->tens);
864 	  tdx->max_label_width = number_width(tdx->max_label, use_tiny_font);
865 	  tick_label_width = tdx->min_label_width;
866 	  if (tick_label_width < tdx->max_label_width)
867 	    tick_label_width = tdx->max_label_width;
868 	  if ((curx + 2 * tick_label_width) > (int)(.61 * width))
869 	    include_x_tick_labels = false;
870 	}
871       tdx->maj_tick_len = major_tick_length;
872       tdx->min_tick_len = minor_tick_length;
873     }
874 
875   if ((include_x_label) || (include_x_tick_labels))
876     {
877       ap->x_label_y = cury;
878       ap->x_label_x = (curx + width - x_label_width) / 2;
879       cury -= (x_label_height + inner_border_width);
880     }
881   else
882     {
883       if (axes == SHOW_BARE_X_AXIS)
884 	cury -= (label_height(false) + inner_border_width);
885     }
886 
887   ap->y_axis_y0 = cury;
888   ap->y_axis_x0 = curx;
889   ap->y_axis_x0 += ap->graph_x0;
890   ap->x_axis_x0 += ap->graph_x0;
891   ap->x_axis_x1 += ap->graph_x0;
892   ap->x_label_x += ap->graph_x0;
893   ap->x_axis_y0 = cury;
894   /* now if y_offset is in use, apply global shift in y direction */
895   ap->x_axis_y0 += ap->y_offset;
896   ap->y_axis_y0 += ap->y_offset;
897   ap->y_axis_y1 += ap->y_offset;
898   ap->x_label_y += ap->y_offset;
899 
900   init_axis_scales(ap);
901 
902   if ((printing) && (ap->cp) &&
903       ((ap->cp->chan == 0) || (ap->cp->sound->channel_style != CHANNELS_SUPERIMPOSED)))
904     ps_bg(ap, ax);
905 #if HAVE_GL
906   if (ap->use_gl) activate_gl_fonts();
907   ap->used_gl = ap->use_gl;
908 #endif
909 
910   /* x axis label */
911   if (include_x_label)
912     {
913       set_labels_font(ax, printing, use_tiny_font);
914 #if HAVE_GL
915       if (ap->use_gl)
916 	{
917 	  mus_float_t yl;
918 	  yl = -0.5 - xthick - ((mus_float_t)(4 * major_tick_length + x_label_height) / (mus_float_t)height);
919 	  glColor3f(0.0, 0.0, 0.0);
920 	  glRasterPos3f(-0.1, 0.0, yl);
921 	  glListBase(label_base);
922   #if WITH_GL2PS
923 	  if (ss->gl_printing) gl2ps_text(ap->xlabel);
924   #endif
925 	  glCallLists(mus_strlen(ap->xlabel), GL_UNSIGNED_BYTE, (GLubyte *)(ap->xlabel));
926 	}
927       else
928 #endif
929 	{
930 	  draw_label(ap->xlabel, ap->x_label_x, ap->x_label_y + inner_border_width, x_label_height, ap, ax, printing);
931 	}
932     }
933 
934   /* x axis */
935   if (show_x_axis)
936     {
937 #if HAVE_GL
938       if (ap->use_gl)
939 	{
940 	  glBegin(GL_POLYGON);
941 	  glColor3f(0.0, 0.0, 0.0);
942 	  glVertex3f(-0.501 - ythick, 0.0, -0.501 - xthick);
943 	  glVertex3f(0.50, 0.0, -0.501 - xthick);
944 	  glVertex3f(0.50, 0.0, -0.501);
945 	  glVertex3f(-0.501 - ythick, 0.0, -0.501);
946 	  glEnd();
947 	}
948       else
949 #endif
950 	{
951 	  fill_rectangle(ax, ap->x_axis_x0, ap->x_axis_y0, (uint32_t)(ap->x_axis_x1 - ap->x_axis_x0), axis_thickness);
952 	}
953     }
954 
955   /* y axis */
956   if ((axes != SHOW_X_AXIS) && (axes != SHOW_X_AXIS_UNLABELLED))
957     {
958 #if HAVE_GL
959       if (ap->use_gl)
960 	{
961 	  glBegin(GL_POLYGON);
962 	  glColor3f(0.0, 0.0, 0.0);
963 	  glVertex3f(-0.501 - ythick, 0.0, -0.501 - xthick);
964 	  glVertex3f(-0.501, 0.0, -0.501 - xthick);
965 	  glVertex3f(-0.501, 0.0, 0.50);
966 	  glVertex3f(-0.501 - ythick, 0.0, 0.50);
967 	  glEnd();
968 
969 	  /* draw rotated text here doesn't look very good -- the code in Mesa/progs/xdemos/xrotfontdemo.c uses
970 	   *   Mesa/progs/xdemos/xuserotfont.c which first sets up a bitmap very much like rotate_text in snd-xutils.c
971 	   *   then code much like the x axis label drawer above.
972 	   */
973 	}
974       else
975 #endif
976 	{
977 #if (!USE_NO_GUI)
978 	  if ((ap->cp) && (ap->ylabel) && (include_y_tick_labels))
979 	    {
980 	      int y_label_width = 0;
981 	      y_label_width = label_width(ap->ylabel, use_tiny_font);
982 	      if ((ap->y_axis_y0 - ap->y_axis_y1) > (y_label_width + 20))
983 		draw_rotated_axis_label(ap->cp,	ax, ap->ylabel,
984 					(tdy) ?
985 					    (ap->y_axis_x0 - tdy->maj_tick_len - tdy->min_label_width - inner_border_width) :
986 					    (ap->y_axis_x0 - inner_border_width - 30),
987 					/* tdy might be null if not y_axis_linear (sonogram + log-freq + y axis label) */
988 					(int)((ap->y_axis_y0 + ap->y_axis_y1 - y_label_width) * 0.5) - 8);
989 	    }
990 #endif
991 	  fill_rectangle(ax, ap->y_axis_x0, ap->y_axis_y1, axis_thickness, (uint32_t)(ap->y_axis_y0 - ap->y_axis_y1));
992 	}
993     }
994 
995   if (printing)
996     {
997       if (show_x_axis)
998 	ps_fill_rectangle(ap, ap->x_axis_x0, ap->x_axis_y0, ap->x_axis_x1 - ap->x_axis_x0, axis_thickness);
999       if ((axes != SHOW_X_AXIS) && (axes != SHOW_X_AXIS_UNLABELLED))
1000 	ps_fill_rectangle(ap, ap->y_axis_x0, ap->y_axis_y1, axis_thickness, ap->y_axis_y0 - ap->y_axis_y1);
1001     }
1002 
1003   /* linear axis ticks/labels */
1004   if ((include_y_tick_labels) ||
1005       (include_x_tick_labels))
1006     set_numbers_font(ax, printing, use_tiny_font);
1007 
1008   if ((y_axis_linear) && (include_y_tick_labels))
1009     {
1010 #if HAVE_GL
1011       if (ap->use_gl)
1012 	{
1013 	  mus_float_t xl;
1014 	  xl = -0.5 - ythick - ((mus_float_t)(3 * tdy->maj_tick_len + tdy->min_label_width + inner_border_width) / (mus_float_t)width);
1015 	  glRasterPos3f(xl, 0.0, (tdy->mlo - ap->y0) / (ap->y1 - ap->y0) - 0.51);
1016 	  glListBase(number_base);
1017   #if WITH_GL2PS
1018 	  if (ss->gl_printing) gl2ps_text(tdy->min_label);
1019   #endif
1020 	  glCallLists(mus_strlen(tdy->min_label), GL_UNSIGNED_BYTE, (GLubyte *)(tdy->min_label));
1021 
1022 	  xl = -0.5 - ythick - ((mus_float_t)(3 * tdy->maj_tick_len + tdy->max_label_width + inner_border_width) / (mus_float_t)width);
1023 	  glRasterPos3f(xl, 0.0, (tdy->mhi - ap->y0) / (ap->y1 - ap->y0) - 0.51);
1024 	  glListBase(number_base);
1025   #if WITH_GL2PS
1026 	  if (ss->gl_printing) gl2ps_text(tdy->max_label);
1027   #endif
1028 	  glCallLists(mus_strlen(tdy->max_label), GL_UNSIGNED_BYTE, (GLubyte *)(tdy->max_label));
1029 	}
1030       else
1031 #endif
1032 	{
1033 	  /* y axis numbers */
1034 
1035 	  draw_y_number(tdy->min_label,
1036 			ap->y_axis_x0 - tdy->maj_tick_len - tdy->min_label_width - inner_border_width,
1037 			grf_y(tdy->mlo, ap), x_number_height,
1038 			ap, ax, printing);
1039 	  draw_y_number(tdy->max_label,
1040 			ap->y_axis_x0 - tdy->maj_tick_len - tdy->max_label_width - inner_border_width,
1041 			grf_y(tdy->mhi, ap), x_number_height,
1042 			ap, ax, printing);
1043 	}
1044     }
1045 
1046   if ((x_axis_linear) && (include_x_tick_labels))
1047     {
1048       int lx0, lx1, tx0, tx1;
1049       /* the label is at ap->x_label_x to that plus x_label_width */
1050       /* the number label widths are tdx->max|min_label_width */
1051       lx0 = ap->x_label_x;
1052       lx1 = lx0 + x_label_width;
1053       tx0 = (int)(tick_grf_x(tdx->mlo, ap, x_style, srate) - .45 * tdx->min_label_width);
1054       tx1 = tx0 + tdx->min_label_width;
1055       if ((lx0 > tx1) || (lx1 < tx0))
1056 	{
1057 #if HAVE_GL
1058 	  if (ap->use_gl)
1059 	    {
1060 	      mus_float_t yl;
1061 	      yl = -0.5 - xthick - ((mus_float_t)(3 * major_tick_length + x_number_height + inner_border_width) / (mus_float_t)height);
1062 	      glRasterPos3f((tdx->mlo - ap->x0) / (ap->x1 - ap->x0) - 0.53, 0.0, yl);
1063 	      glListBase(number_base);
1064   #if WITH_GL2PS
1065 	      if (ss->gl_printing) gl2ps_text(tdx->min_label);
1066   #endif
1067 	      glCallLists(mus_strlen(tdx->min_label), GL_UNSIGNED_BYTE, (GLubyte *)(tdx->min_label));
1068 	    }
1069 	  else
1070 #endif
1071 	    {
1072 	      /* x axis min label */
1073 	      draw_x_number(tdx->min_label, tx0, ap->x_axis_y0 + major_tick_length, x_number_height, ap, ax, printing);
1074 	    }
1075 	}
1076       tx0 = (int)(tick_grf_x(tdx->mhi, ap, x_style, srate) - (.45 * tdx->max_label_width)); /* try centered label first */
1077       if ((int)(tx0 + tdx->max_label_width) > ap->x_axis_x1)
1078 	tx0 = (int)(tick_grf_x(tdx->mhi, ap, x_style, srate) - tdx->max_label_width + .75 * right_border_width);
1079       tx1 = tx0 + tdx->max_label_width;
1080       if ((lx0 > tx1) || (lx1 < tx0))
1081 	{
1082 #if HAVE_GL
1083 	  if (ap->use_gl)
1084 	    {
1085 	      mus_float_t yl;
1086 	      yl = -0.5 - xthick - ((mus_float_t)(3 * major_tick_length + x_number_height + inner_border_width) / (mus_float_t)height);
1087 	      glRasterPos3f((tdx->mhi - ap->x0) / (ap->x1 - ap->x0) - 0.53, 0.0, yl);
1088 	      glListBase(number_base);
1089   #if WITH_GL2PS
1090 	      if (ss->gl_printing) gl2ps_text(tdx->max_label);
1091   #endif
1092 	      glCallLists(mus_strlen(tdx->max_label), GL_UNSIGNED_BYTE, (GLubyte *)(tdx->max_label));
1093 	    }
1094 	  else
1095 #endif
1096 	    {
1097 	      /* x axis max label */
1098 	      draw_x_number(tdx->max_label, tx0, ap->x_axis_y0 + major_tick_length, x_number_height, ap, ax, printing);
1099 	    }
1100 	}
1101     }
1102 
1103   if ((y_axis_linear) && (include_y_ticks))
1104     {
1105       double fy, tens;
1106       int ty, x0, majx, minx, x;
1107       /* start ticks at flo, go to fhi by step, major ticks at mlo mhi and intervals of tenstep surrounding */
1108       x0 = ap->y_axis_x0;
1109       majx = x0 - tdy->maj_tick_len;
1110       minx = x0 - tdy->min_tick_len;
1111       fy = tdy->mlo;
1112       ty = grf_y(fy, ap);
1113 #if HAVE_GL
1114       if (ap->use_gl)
1115 	{
1116 	  mus_float_t ypos;
1117 	  ypos = (fy - ap->y0) / (ap->y1 - ap->y0) - 0.5;
1118 	  glBegin(GL_LINES);
1119 	  glVertex3f(-0.50 - ymajorlen, 0.0, ypos);
1120 	  glVertex3f(-0.501, 0.0, ypos);
1121 	  glEnd();
1122 	}
1123       else
1124 #endif
1125 	{
1126 	  draw_horizontal_tick(majx, x0, ty, ap, ax, printing, include_grid);
1127 	}
1128 
1129       tens = 0.0;
1130       fy -= tdy->step;
1131       while (fy >= tdy->flo)
1132 	{
1133 	  tens += tdy->tenstep;
1134 	  if (tens == 10.0)
1135 	    {
1136 	      tens = 0.0;
1137 	      x = majx;
1138 	    }
1139 	  else x = minx;
1140 	  ty = grf_y(fy, ap);
1141 #if HAVE_GL
1142 	  if (ap->use_gl)
1143 	    {
1144 	      mus_float_t ypos;
1145 	      ypos = (fy - ap->y0) / (ap->y1 - ap->y0) - 0.5;
1146 	      glBegin(GL_LINES);
1147 	      glVertex3f(-0.50 - ((x == majx) ? ymajorlen : yminorlen), 0.0, ypos);
1148 	      glVertex3f(-0.501, 0.0, ypos);
1149 	      glEnd();
1150 	    }
1151 	  else
1152 #endif
1153 	    {
1154 	      draw_horizontal_tick(x, x0, ty, ap, ax, printing, include_grid);
1155 	    }
1156 	  fy -= tdy->step;
1157 	}
1158       tens = 0.0;
1159       fy = tdy->mlo;
1160       fy += tdy->step;
1161       while (fy <= tdy->fhi)
1162 	{
1163 	  tens += tdy->tenstep;
1164 	  if (tens == 10.0)
1165 	    {
1166 	      tens = 0.0;
1167 	      x = majx;
1168 	    }
1169 	  else x = minx;
1170 	  ty = grf_y(fy, ap);
1171 #if HAVE_GL
1172 	  if (ap->use_gl)
1173 	    {
1174 	      mus_float_t ypos;
1175 	      ypos = (fy - ap->y0) / (ap->y1 - ap->y0) - 0.5;
1176 	      glBegin(GL_LINES);
1177 	      glVertex3f(-0.50 - ((x == majx) ? ymajorlen : yminorlen), 0.0, ypos);
1178 	      glVertex3f(-0.501, 0.0, ypos);
1179 	      glEnd();
1180 	    }
1181 	  else
1182 #endif
1183 	    {
1184 	      draw_horizontal_tick(x, x0, ty, ap, ax, printing, include_grid);
1185 	    }
1186 	  fy += tdy->step;
1187 	}
1188     }
1189   if ((x_axis_linear) && (include_x_ticks))
1190     {
1191       bool major_tick_is_less_than_measure = false;
1192       double fx, tens;
1193       int tx, y0, majy, miny, y;
1194       y0 = ap->x_axis_y0;
1195       majy = y0 + tdx->maj_tick_len;
1196       miny = y0 + tdx->min_tick_len;
1197       /* start at leftmost major tick and work toward y axis */
1198       fx = tdx->mlo;
1199       tx = tick_grf_x(fx, ap, x_style, srate);
1200 
1201       if ((ap->cp) &&
1202 	  (x_style == X_AXIS_IN_MEASURES) &&
1203 	  ((tdx->tenstep * tdx->step) <= ((60.0 * ap->cp->beats_per_measure) / (mus_float_t)(ap->cp->beats_per_minute))))
1204 	major_tick_is_less_than_measure = true;
1205 
1206 #if HAVE_GL
1207       if (ap->use_gl)
1208 	{
1209 	  mus_float_t xpos;
1210 	  xpos = (fx - ap->x0) / (ap->x1 - ap->x0) - 0.5;
1211 	  glBegin(GL_LINES);
1212 	  glVertex3f(xpos, 0.0, -0.50 - xmajorlen);
1213 	  glVertex3f(xpos, 0.0, -0.501);
1214 	  glEnd();
1215 	}
1216       else
1217 #endif
1218 	{
1219 	  if ((major_tick_is_less_than_measure) &&
1220 	      (first_beat(ap->cp, fx)))
1221 	    draw_vertical_tick(tx, y0 - major_tick_length, majy + minor_tick_length, ap, ax, printing, include_grid);
1222 	  else draw_vertical_tick(tx, y0, majy, ap, ax, printing, include_grid);
1223 	}
1224       tens = 0.0;
1225       fx -= tdx->step;
1226       while (fx >= tdx->flo)
1227 	{
1228 	  tens += tdx->tenstep;
1229 	  if (tens == 10.0)
1230 	    {
1231 	      tens = 0.0;
1232 	      y = majy;
1233 	    }
1234 	  else y = miny;
1235 	  tx = tick_grf_x(fx, ap, x_style, srate);
1236 #if HAVE_GL
1237 	  if (ap->use_gl)
1238 	    {
1239 	      mus_float_t xpos;
1240 	      xpos = (fx - ap->x0) / (ap->x1 - ap->x0) - 0.5;
1241 	      glBegin(GL_LINES);
1242 	      glVertex3f(xpos, 0.0, -0.50 - ((y == majy) ? xmajorlen : xminorlen));
1243 	      glVertex3f(xpos, 0.0, -0.501);
1244 	      glEnd();
1245 	    }
1246 	  else
1247 #endif
1248 	    {
1249 	      if ((major_tick_is_less_than_measure) &&
1250 		  (first_beat(ap->cp, fx)))
1251 		draw_vertical_tick(tx, y0 - major_tick_length, y + minor_tick_length, ap, ax, printing, include_grid);
1252 	      else draw_vertical_tick(tx, y0, y, ap, ax, printing, include_grid);
1253 	    }
1254 	  fx -= tdx->step;
1255 	}
1256       tens = 0.0;
1257       fx = tdx->mlo;
1258       /* now start at leftmost major tick and work towards right end */
1259       fx += tdx->step;
1260       while (fx <= tdx->fhi)
1261 	{
1262 	  tens += tdx->tenstep;
1263 	  if (tens == 10.0)
1264 	    {
1265  	      tens = 0.0;
1266 	      y = majy;
1267 	    }
1268 	  else y = miny;
1269 	  tx = tick_grf_x(fx, ap, x_style, srate);
1270 #if HAVE_GL
1271 	  if (ap->use_gl)
1272 	    {
1273 	      mus_float_t xpos;
1274 	      xpos = (fx - ap->x0) / (ap->x1 - ap->x0) - 0.5;
1275 	      glBegin(GL_LINES);
1276 	      glVertex3f(xpos, 0.0, -0.50 - ((y == majy) ? xmajorlen : xminorlen));
1277 	      glVertex3f(xpos, 0.0, -0.501);
1278 	      glEnd();
1279 	    }
1280 	  else
1281 #endif
1282 	    {
1283 	      if ((major_tick_is_less_than_measure) &&
1284 		  (first_beat(ap->cp, fx)))
1285 		draw_vertical_tick(tx, y0 - major_tick_length, y + minor_tick_length, ap, ax, printing, include_grid);
1286 	      else draw_vertical_tick(tx, y0, y, ap, ax, printing, include_grid);
1287 	    }
1288 	  fx += tdx->step;
1289 	}
1290     }
1291 
1292   /* All linear axis stuff has been taken care of. Check for log axes (assume fft context, not spectrogram so no GL) */
1293   /* x axis overall label has already gone out */
1294 
1295   if ((!x_axis_linear) &&
1296       (show_x_axis) &&
1297       (include_x_ticks))
1298     {
1299       double min_freq, max_freq;
1300       mus_float_t minlx = 0.0, maxlx, fap_range, log_range, lscale = 1.0, curlx;
1301       int logx;
1302       int y0, majy, miny, i;
1303       const char *label = NULL;
1304       mus_float_t freq = 0.0, freq10 = 0.0;
1305       /* get min (log-freq or spectrum-start), max, add major ticks and brief labels, then if room add log-style minor ticks (100's, 1000's) */
1306       y0 = ap->x_axis_y0;
1307       majy = y0 + major_tick_length;
1308       miny = y0 + minor_tick_length;
1309       min_freq = ap->x0;
1310       max_freq = ap->x1;
1311       if (include_x_tick_labels)
1312 	set_numbers_font(ax, printing, use_tiny_font);
1313       fap_range = max_freq - min_freq;
1314       if (min_freq > 1.0) minlx = log(min_freq); else minlx = 0.0;
1315       maxlx = log(max_freq);
1316       log_range = (maxlx - minlx);
1317       lscale = fap_range / log_range;
1318       for (i = 0; i < 3; i++)
1319 	{
1320 	  switch (i)
1321 	    {
1322 	    case 0:
1323 	      label = "100";
1324 	      freq = 100.0;
1325 	      break;
1326 
1327 	    case 1:
1328 	      label = "1000";
1329 	      freq = 1000.0;
1330 	      break;
1331 
1332 	    case 2:
1333 	      label = "10000";
1334 	      freq = 10000.0;
1335 	      break;
1336 	    }
1337 	  if ((min_freq <= freq) && (max_freq >= freq))
1338 	    {
1339 	      /* draw major tick at freq */
1340 	      freq10 = freq / 10.0;
1341 	      logx = grf_x(min_freq + lscale * (log(freq) - minlx), ap);
1342 	      draw_vertical_tick(logx, y0, majy, ap, ax, printing, include_grid);
1343 	      draw_log_tick_label(label, logx, ap->x_axis_y0 + major_tick_length, x_number_height, x_label_width, right_border_width,
1344 				  ap, ax, printing, use_tiny_font);
1345 	      if (width > 200)
1346 		{
1347 		  curlx = snd_round(min_freq / freq10) * freq10;
1348 		  for (; curlx < freq; curlx += freq10)
1349 		    {
1350 		      logx = grf_x(min_freq + lscale * (log(curlx) - minlx), ap);
1351 		      draw_vertical_tick(logx, y0, miny, ap, ax, printing, include_grid);
1352 		    }
1353 		}
1354 	    }
1355 	}
1356     }
1357 
1358   if ((!y_axis_linear) &&
1359       (axes != SHOW_X_AXIS) &&
1360       (axes != SHOW_X_AXIS_UNLABELLED) &&
1361       (include_y_ticks))
1362     {
1363       double min_freq, max_freq;
1364       mus_float_t minlx = 0.0, maxlx, fap_range, log_range, lscale = 1.0, curly;
1365       int logy;
1366       int x0, majx, minx, i;
1367       const char *label = NULL;
1368       mus_float_t freq = 0.0, freq10 = 0.0;
1369       /* get min (log-freq or spectrum-start), max, add major ticks and brief labels, then if room add log-style minor ticks (100's, 1000's) */
1370       x0 = ap->y_axis_x0;
1371       majx = x0 - major_tick_length;
1372       minx = x0 - minor_tick_length;
1373       min_freq = ap->y0;
1374       max_freq = ap->y1;
1375       if (include_y_tick_labels)
1376 	set_numbers_font(ax, printing, use_tiny_font);
1377       fap_range = max_freq - min_freq;
1378       if (min_freq > 1.0) minlx = log(min_freq); else minlx = 0.0;
1379       maxlx = log(max_freq);
1380       log_range = (maxlx - minlx);
1381       lscale = fap_range / log_range;
1382       for (i = 0; i < 3; i++)
1383 	{
1384 	  switch (i)
1385 	    {
1386 	    case 0:
1387 	      label = "100";
1388 	      freq = 100.0;
1389 	      break;
1390 
1391 	    case 1:
1392 	      label = "1000";
1393 	      freq = 1000.0;
1394 	      break;
1395 
1396 	    case 2:
1397 	      label = "10000";
1398 	      freq = 10000.0;
1399 	      break;
1400 	    }
1401 	  if ((min_freq <= freq) && (max_freq >= freq))
1402 	    {
1403 	      /* draw major tick at freq */
1404 	      freq10 = freq / 10.0;
1405 	      logy = grf_y(min_freq + lscale * (log(freq) - minlx), ap);
1406 	      draw_horizontal_tick(majx, x0, logy, ap, ax, printing, include_grid);
1407 	      if (include_y_tick_labels)
1408 		{
1409 		  int label_width;
1410 		  label_width = number_width(label, use_tiny_font);
1411 		  /* y axis number */
1412 		  draw_y_number(label,
1413 				ap->y_axis_x0 - major_tick_length - label_width - inner_border_width,
1414 				logy, x_number_height,
1415 				ap, ax, printing);
1416 		}
1417 	      if (height > 200)
1418 		{
1419 		  curly = snd_round(min_freq / freq10) * freq10;
1420 		  for (; curly < freq; curly += freq10)
1421 		    {
1422 		      logy = grf_y(min_freq + lscale * (log(curly) - minlx), ap);
1423 		      draw_horizontal_tick(minx, x0, logy, ap, ax, printing, include_grid);
1424 		    }
1425 		}
1426 	    }
1427 	}
1428     }
1429 }
1430 
1431 
make_axis_info(chan_info * cp,double xmin,double xmax,mus_float_t ymin,mus_float_t ymax,const char * xlabel,double x0,double x1,mus_float_t y0,mus_float_t y1,axis_info * old_ap)1432 axis_info *make_axis_info (chan_info *cp, double xmin, double xmax, mus_float_t ymin, mus_float_t ymax,
1433 			   const char *xlabel, double x0, double x1, mus_float_t y0, mus_float_t y1, axis_info *old_ap)
1434 {
1435   axis_info *ap;
1436   if (old_ap)
1437     ap = old_ap;
1438   else
1439     {
1440       ap = (axis_info *)calloc(1, sizeof(axis_info));
1441       ap->cp = cp;
1442     }
1443   ap->xmin = xmin;
1444   ap->xmax = xmax;
1445   if (ap->xmin == ap->xmax) ap->xmax += .001;
1446   ap->ymin = ymin;
1447   ap->ymax = ymax;
1448   if ((xlabel) &&
1449       (!(mus_strcmp(xlabel, ap->xlabel))))
1450     {
1451       /* this apparently should leave the default_xlabel and ylabels alone */
1452       if (ap->xlabel) free(ap->xlabel);
1453       ap->xlabel = mus_strdup(xlabel);
1454     }
1455   ap->x0 = x0;
1456   ap->x1 = x1;
1457   if (ap->x0 == ap->x1) ap->x1 += .001;
1458   if (ap->x1 > ap->xmax) ap->x1 = ap->xmax;
1459   ap->y0 = y0;
1460   ap->y1 = y1;
1461   ap->y_offset = 0;
1462   ap->y_ambit = ap->ymax - ap->ymin;
1463   ap->x_ambit = ap->xmax - ap->xmin;
1464   return(ap);
1465 }
1466 
1467 
1468 #if (!USE_NO_GUI)
1469 
get_ap(chan_info * cp,axis_info_t ap_id,const char * caller)1470 static axis_info *get_ap(chan_info *cp, axis_info_t ap_id, const char *caller)
1471 {
1472   #define AXIS_INFO_ID_OK(Id)    (Id <= (int)LISP_AXIS_INFO)
1473 
1474   if (AXIS_INFO_ID_OK(ap_id))
1475     switch (ap_id)
1476       {
1477       case TIME_AXIS_INFO:      return(cp->axis);                              break;
1478       case TRANSFORM_AXIS_INFO: if (cp->fft) return(cp->fft->axis);            break;
1479       case LISP_AXIS_INFO:      if (cp->lisp_info) return(lisp_info_axis(cp)); break;
1480       }
1481 
1482   Xen_error(Xen_make_error_type("no-such-axis"),
1483 	    Xen_list_6(((!(cp->squelch_update)) || (!(AXIS_INFO_ID_OK(ap_id)))) ?
1484 		         C_string_to_Xen_string("~A: no such axis: ~A of sound ~A (~A), chan: ~A (axis should be " S_time_graph ", " S_lisp_graph ", or " S_transform_graph ")") :
1485 		         C_string_to_Xen_string("~A: no such axis: ~A of sound ~A (~A), chan: ~A does not exist, probably because output is squelched"),
1486 		       C_string_to_Xen_string(caller),
1487 		       C_int_to_Xen_integer((int)(ap_id)),
1488 		       C_int_to_Xen_sound(cp->sound->index),
1489 		       C_string_to_Xen_string(cp->sound->short_filename),
1490 		       C_int_to_Xen_integer(cp->chan)));
1491   return(NULL);
1492 }
1493 
1494 #define TO_C_AXIS_INFO(Snd, Chn, Ap, Caller) get_ap(get_cp(Snd, Chn, Caller), (Xen_is_integer(Ap)) ? (axis_info_t)Xen_integer_to_C_int(Ap) : TIME_AXIS_INFO, Caller)
1495 
1496 
g_x_to_position(Xen val,Xen snd,Xen chn,Xen ap)1497 static Xen g_x_to_position(Xen val, Xen snd, Xen chn, Xen ap)
1498 {
1499   #define H_x_to_position "(" S_x_to_position " val :optional snd chn (ax " S_time_graph ")): x pixel loc of val"
1500   Xen_check_type(Xen_is_number(val), val, 1, S_x_to_position, "a number");
1501   Snd_assert_channel(S_x_to_position, snd, chn, 2);
1502   Xen_check_type(Xen_is_integer_or_unbound(ap), ap, 4, S_x_to_position, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1503   return(C_int_to_Xen_integer(grf_x(Xen_real_to_C_double(val),
1504 				    TO_C_AXIS_INFO(snd, chn, ap, S_x_to_position))));
1505 }
1506 
1507 
g_y_to_position(Xen val,Xen snd,Xen chn,Xen ap)1508 static Xen g_y_to_position(Xen val, Xen snd, Xen chn, Xen ap)
1509 {
1510   #define H_y_to_position "(" S_y_to_position " val :optional snd chn (ax " S_time_graph ")): y pixel loc of val"
1511   Xen_check_type(Xen_is_number(val), val, 1, S_y_to_position, "a number");
1512   Snd_assert_channel(S_y_to_position, snd, chn, 2);
1513   Xen_check_type(Xen_is_integer_or_unbound(ap), ap, 4, S_y_to_position, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1514   return(C_int_to_Xen_integer(grf_y(Xen_real_to_C_double(val),
1515 				    TO_C_AXIS_INFO(snd, chn, ap, S_y_to_position))));
1516 }
1517 
1518 
g_position_to_x(Xen val,Xen snd,Xen chn,Xen ap)1519 static Xen g_position_to_x(Xen val, Xen snd, Xen chn, Xen ap)
1520 {
1521   #define H_position_to_x "(" S_position_to_x " val :optional snd chn (ax " S_time_graph ")): x axis value corresponding to pixel val"
1522   Xen_check_type(Xen_is_integer(val), val, 1, S_position_to_x, "an integer");
1523   Snd_assert_channel(S_position_to_x, snd, chn, 2);
1524   Xen_check_type(Xen_is_integer_or_unbound(ap), ap, 4, S_position_to_x, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1525   return(C_double_to_Xen_real(ungrf_x(TO_C_AXIS_INFO(snd, chn, ap, S_position_to_x),
1526 				      Xen_integer_to_C_int(val))));
1527 }
1528 
1529 
g_position_to_y(Xen val,Xen snd,Xen chn,Xen ap)1530 static Xen g_position_to_y(Xen val, Xen snd, Xen chn, Xen ap)
1531 {
1532   #define H_position_to_y "(" S_position_to_y " val :optional snd chn (ax " S_time_graph ")): y axis value corresponding to pixel val"
1533   Xen_check_type(Xen_is_integer(val), val, 1, S_position_to_y, "an integer");
1534   Snd_assert_channel(S_position_to_y, snd, chn, 2);
1535   Xen_check_type(Xen_is_integer_or_unbound(ap), ap, 4, S_position_to_y, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1536   return(C_double_to_Xen_real(ungrf_y(TO_C_AXIS_INFO(snd, chn, ap, S_position_to_y),
1537 				      Xen_integer_to_C_int(val))));
1538 }
1539 
1540 
g_axis_info(Xen snd,Xen chn,Xen ap_id)1541 static Xen g_axis_info(Xen snd, Xen chn, Xen ap_id)
1542 {
1543   #define H_axis_info "(" S_axis_info " :optional snd chn (ax " S_time_graph ")): info about axis: (list losamp hisamp \
1544 x0 y0 x1 y1 xmin ymin xmax ymax pix_x0 pix_y0 pix_x1 pix_y1 y_offset xscale yscale xlabel ylabel new-peaks)"
1545   axis_info *ap;
1546   Snd_assert_channel(S_axis_info, snd, chn, 1);
1547   Xen_check_type(Xen_is_integer_or_unbound(ap_id), ap_id, 3, S_axis_info, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1548   ap = TO_C_AXIS_INFO(snd, chn, ap_id, S_axis_info);
1549   if (!ap) return(Xen_empty_list);
1550   return(Xen_cons(C_llong_to_Xen_llong(ap->losamp),
1551 	  Xen_cons(C_llong_to_Xen_llong(ap->hisamp),
1552 	   Xen_cons(C_double_to_Xen_real(ap->x0),
1553 	    Xen_cons(C_double_to_Xen_real(ap->y0),
1554 	     Xen_cons(C_double_to_Xen_real(ap->x1),
1555 	      Xen_cons(C_double_to_Xen_real(ap->y1),
1556 	       Xen_cons(C_double_to_Xen_real(ap->xmin),
1557 		Xen_cons(C_double_to_Xen_real(ap->ymin),
1558 		 Xen_cons(C_double_to_Xen_real(ap->xmax),
1559 		  Xen_cons(C_double_to_Xen_real(ap->ymax),
1560 		   Xen_cons(C_int_to_Xen_integer(ap->x_axis_x0),
1561 		    Xen_cons(C_int_to_Xen_integer(ap->y_axis_y0),
1562 		     Xen_cons(C_int_to_Xen_integer(ap->x_axis_x1),
1563 		      Xen_cons(C_int_to_Xen_integer(ap->y_axis_y1),
1564 		       Xen_cons(C_int_to_Xen_integer(ap->y_offset),
1565 			Xen_cons(C_double_to_Xen_real(ap->x_scale),
1566 			 Xen_cons(C_double_to_Xen_real(ap->y_scale),
1567 			  Xen_cons((ap->xlabel) ? C_string_to_Xen_string(ap->xlabel) : Xen_false,
1568 			   Xen_cons((ap->ylabel) ? C_string_to_Xen_string(ap->ylabel) : Xen_false,
1569 			    Xen_cons((ap->cp) ? C_bool_to_Xen_boolean(ap->cp->new_peaks) : Xen_false,
1570 			     Xen_empty_list)))))))))))))))))))));
1571 }
1572 
1573 
1574 #if USE_MOTIF
1575   #define Xen_unwrap_snd_gc(Value) Xen_unwrap_C_pointer(Xen_cadr(Value))
1576   #define Xen_is_GC(Value) (Xen_is_list(Value) && (Xen_list_length(Value) >= 2) && \
1577                           (Xen_is_symbol(Xen_car(Value))) && \
1578 			  (strcmp("GC", Xen_symbol_to_C_string(Xen_car(Value))) == 0))
1579 #else
1580   #define Xen_unwrap_snd_gc(Value) 0
1581   #define Xen_is_GC(Value) 0
1582 #endif
1583 
1584 
g_draw_axes(Xen args)1585 static Xen g_draw_axes(Xen args)
1586 {
1587   #define H_draw_axes "(" S_draw_axes " wid gc label (x0 0.0) (x1 1.0) (y0 -1.0) (y1 1.0) (style " S_x_axis_in_seconds ") (axes " S_show_all_axes ")): \
1588 draws axes in the widget 'wid', using the graphics context 'gc', with the x-axis label 'label' \
1589 going from x0 to x1 (floats) along the x axis, y0 to y1 along the y axis, with " S_x_axis_style " \
1590 'style' (" S_x_axis_in_seconds " etc); the axes are actually displayed if 'axes' is " S_show_all_axes ". \
1591 Returns actual (pixel) axis bounds -- a list (x0 y0 x1 y1)."
1592 
1593 #if USE_MOTIF
1594   Widget w;
1595   GC gc;
1596 #endif
1597 
1598   Xen val, xwid, xgc, label_ref;
1599   double x0 = 0.0, x1 = 1.0;
1600   mus_float_t y0 = -1.0, y1 = 1.0;
1601   x_axis_style_t x_style = X_AXIS_IN_SECONDS;
1602   show_axes_t axes = SHOW_ALL_AXES;
1603   graphics_context *ax;
1604   axis_info *ap;
1605   int len;
1606 
1607   len = Xen_list_length(args);
1608   Xen_check_type((len >= 3) && (len < 10), args, 1, S_draw_axes, "3 required and 6 optional args");
1609 
1610 
1611   xwid = Xen_list_ref(args, 0);
1612   Xen_check_type(Xen_is_widget(xwid), xwid, 1, S_draw_axes, "widget");
1613   xgc = Xen_list_ref(args, 1);
1614   Xen_check_type(Xen_is_GC(xgc), xgc, 2, S_draw_axes, "snd-gc");
1615 
1616 #if USE_MOTIF
1617   w = (Widget)(Xen_unwrap_widget(xwid));
1618   gc = (GC)(Xen_unwrap_snd_gc(xgc));
1619 #endif
1620 
1621   label_ref = Xen_list_ref(args, 2);
1622   Xen_check_type(Xen_is_string(label_ref) || Xen_is_false(label_ref), label_ref, 3, S_draw_axes, "a string");
1623   if (len > 3)
1624     {
1625       Xen xx0;
1626       xx0 = Xen_list_ref(args, 3);
1627       Xen_check_type(Xen_is_number(xx0), xx0, 4, S_draw_axes, "a number");
1628       x0 = Xen_real_to_C_double(xx0);
1629       if (len > 4)
1630 	{
1631 	  Xen xx1;
1632 	  xx1 = Xen_list_ref(args, 4);
1633 	  Xen_check_type(Xen_is_number(xx1), xx1, 5, S_draw_axes, "a number");
1634 	  x1 = Xen_real_to_C_double(xx1);
1635 	  if (len > 5)
1636 	    {
1637 	      Xen xy0;
1638 	      xy0 = Xen_list_ref(args, 5);
1639 	      Xen_check_type(Xen_is_number(xy0), xy0, 6, S_draw_axes, "a number");
1640 	      y0 = Xen_real_to_C_double(xy0);
1641 	      if (len > 6)
1642 		{
1643 		  Xen xy1;
1644 		  xy1 = Xen_list_ref(args, 6);
1645 		  Xen_check_type(Xen_is_number(xy1), xy1, 7, S_draw_axes, "a number");
1646 		  y1 = Xen_real_to_C_double(xy1);
1647 		  if (len > 7)
1648 		    {
1649 		      Xen xstyle;
1650 		      int tmp;
1651 		      xstyle = Xen_list_ref(args, 7);
1652 		      Xen_check_type(Xen_is_integer(xstyle), xstyle, 8, S_draw_axes, "axis style");
1653 		      tmp = Xen_integer_to_C_int(xstyle);
1654 		      if (!(is_x_axis_style(tmp)))
1655 			Xen_out_of_range_error(S_draw_axes, 7, xstyle, "axis style");
1656 		      x_style = (x_axis_style_t)tmp;
1657 		      if (len > 8)
1658 			{
1659 			  Xen xaxes;
1660 			  xaxes = Xen_list_ref(args, 8);
1661 			  Xen_check_type(Xen_is_integer(xaxes), xaxes, 9, S_draw_axes, S_show_axes " choice");
1662 			  tmp = Xen_integer_to_C_int(xaxes);
1663 			  if (!(shows_axes(tmp)))
1664 			    Xen_out_of_range_error(S_draw_axes, 8, xaxes, S_show_axes " choice");
1665 			  axes = (show_axes_t)Xen_integer_to_C_int(xaxes);
1666 			}}}}}}
1667 
1668   ap = (axis_info *)calloc(1, sizeof(axis_info));
1669   ax = (graphics_context *)calloc(1, sizeof(graphics_context));
1670   ap->ax = ax;
1671 
1672 #if USE_MOTIF
1673   ax->dp = XtDisplay(w);
1674   ax->wn = XtWindow(w);
1675 #endif
1676 
1677   ap->xmin = x0;
1678   ap->xmax = x1;
1679   ap->ymin = y0;
1680   ap->ymax = y1;
1681   ap->y_ambit = y1 - y0;
1682   ap->x_ambit = x1 - x0;
1683   if (Xen_is_string(label_ref))
1684     ap->xlabel = mus_strdup(Xen_string_to_C_string(label_ref));
1685   ap->x0 = x0;
1686   ap->x1 = x1;
1687   ap->y0 = y0;
1688   ap->y1 = y1;
1689   ap->width = widget_width(w);
1690   ap->window_width = ap->width;
1691   ap->y_offset = 0;
1692   ap->height = widget_height(w);
1693   ap->graph_x0 = 0;
1694   clear_window(ax);
1695   ax->gc = gc;
1696 
1697   make_axes_1(ap, x_style, 1, axes, NOT_PRINTING, WITH_X_AXIS, NO_GRID, WITH_LINEAR_AXES, grid_density(ss));
1698 
1699   val = Xen_cons(C_int_to_Xen_integer(ap->x_axis_x0),
1700 	 Xen_cons(C_int_to_Xen_integer(ap->y_axis_y0),
1701 	  Xen_cons(C_int_to_Xen_integer(ap->x_axis_x1),
1702 	   Xen_cons(C_int_to_Xen_integer(ap->y_axis_y1),
1703 	    Xen_empty_list))));
1704 
1705   free_axis_info(ap);
1706   return(val);
1707 }
1708 
1709 
g_x_axis_label(Xen snd,Xen chn,Xen ax)1710 static Xen g_x_axis_label(Xen snd, Xen chn, Xen ax)
1711 {
1712   #define H_x_axis_label "(" S_x_axis_label " :optional snd chn (ax " S_time_graph ")): current x axis label"
1713   axis_info *ap;
1714 
1715   Snd_assert_channel(S_x_axis_label, snd, chn, 1);
1716   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 3, S_x_axis_label, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1717   ap = TO_C_AXIS_INFO(snd, chn, ax, S_x_axis_label);
1718 
1719   return(C_string_to_Xen_string(ap->xlabel));
1720 }
1721 
1722 
g_set_x_axis_label(Xen label,Xen snd,Xen chn,Xen ax)1723 static Xen g_set_x_axis_label(Xen label, Xen snd, Xen chn, Xen ax)
1724 {
1725   axis_info *ap;
1726 
1727   Snd_assert_channel(S_set S_x_axis_label, snd, chn, 2);
1728   Xen_check_type(Xen_is_string(label) || Xen_is_false(label), label, 1, S_set S_x_axis_label, "a string");
1729   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_set S_x_axis_label, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1730 
1731   ap = TO_C_AXIS_INFO(snd, chn, ax, S_x_axis_label);
1732   if (ap->xlabel) free(ap->xlabel);
1733   if (ap->default_xlabel) free(ap->default_xlabel);
1734 
1735   if (Xen_is_false(label))
1736     {
1737       ap->xlabel = NULL;
1738       ap->default_xlabel = NULL;
1739     }
1740   else
1741     {
1742       ap->xlabel = mus_strdup(Xen_string_to_C_string(label));
1743       if ((Xen_is_integer(ax)) && (Xen_integer_to_C_int(ax) == (int)TRANSFORM_AXIS_INFO))
1744 	set_fft_info_xlabel(ap->cp, ap->xlabel);
1745       ap->default_xlabel = mus_strdup(ap->xlabel);
1746     }
1747 
1748   update_graph(ap->cp);
1749   return(label);
1750 }
1751 
with_four_setter_args(g_set_x_axis_label_reversed,g_set_x_axis_label)1752 with_four_setter_args(g_set_x_axis_label_reversed, g_set_x_axis_label)
1753 
1754 
1755 static Xen g_y_axis_label(Xen snd, Xen chn, Xen ax)
1756 {
1757   #define H_y_axis_label "(" S_y_axis_label " :optional snd chn (ax " S_time_graph ")): current y axis label"
1758   axis_info *ap;
1759 
1760   Snd_assert_channel(S_y_axis_label, snd, chn, 1);
1761   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 3, S_y_axis_label, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1762   ap = TO_C_AXIS_INFO(snd, chn, ax, S_y_axis_label);
1763 
1764   return(C_string_to_Xen_string(ap->ylabel));
1765 }
1766 
g_set_y_axis_label(Xen label,Xen snd,Xen chn,Xen ax)1767 static Xen g_set_y_axis_label(Xen label, Xen snd, Xen chn, Xen ax)
1768 {
1769   axis_info *ap;
1770 
1771   Snd_assert_channel(S_set S_y_axis_label, snd, chn, 2);
1772   Xen_check_type(Xen_is_string(label) || Xen_is_false(label), label, 1, S_set S_y_axis_label, "a string");
1773 
1774   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_set S_y_axis_label, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1775   ap = TO_C_AXIS_INFO(snd, chn, ax, S_y_axis_label);
1776   if (ap->ylabel) free(ap->ylabel);
1777 
1778   if (Xen_is_false(label))
1779     ap->ylabel = NULL;
1780   else ap->ylabel = mus_strdup(Xen_string_to_C_string(label));
1781   update_graph(ap->cp);
1782 
1783   return(label);
1784 }
1785 
with_four_setter_args(g_set_y_axis_label_reversed,g_set_y_axis_label)1786 with_four_setter_args(g_set_y_axis_label_reversed, g_set_y_axis_label)
1787 
1788 
1789 
1790 static Xen g_x_bounds(Xen snd, Xen chn, Xen ax)
1791 {
1792   #define H_x_bounds "(" S_x_bounds " :optional snd chn axis): a list (x0 x1) giving the current x axis bounds of snd channel chn"
1793   axis_info *ap;
1794 
1795   Snd_assert_channel(S_x_bounds, snd, chn, 1);
1796   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_x_bounds, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1797   ap = TO_C_AXIS_INFO(snd, chn, ax, S_x_bounds);
1798 
1799   return(Xen_list_2(C_double_to_Xen_real(ap->x0),
1800 		    C_double_to_Xen_real(ap->x1)));
1801   /* wavogram settings depend on context -- no easy way to map back to user's notion of bounds */
1802 }
1803 
1804 
g_set_x_bounds(Xen bounds,Xen snd,Xen chn,Xen ax)1805 static Xen g_set_x_bounds(Xen bounds, Xen snd, Xen chn, Xen ax)
1806 {
1807   chan_info *cp;
1808   axis_info *ap;
1809   mus_float_t x0 = 0.0, x1 = 0.0;
1810 
1811   Snd_assert_channel(S_set S_x_bounds, snd, chn, 2);
1812   Xen_check_type(Xen_is_number(bounds) || (Xen_is_list(bounds) && (Xen_list_length(bounds) == 2)), bounds, 1, S_set S_x_bounds, "a list: (x0 x1) or a number");
1813   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_set S_x_bounds, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1814   ap = TO_C_AXIS_INFO(snd, chn, ax, S_set S_x_bounds);
1815 
1816   cp = get_cp(snd, chn, S_set S_x_bounds);
1817   if (!cp) return(Xen_false);
1818 
1819   if (Xen_is_number(bounds))
1820     {
1821       x0 = 0.0;
1822       x1 = Xen_real_to_C_double(bounds);
1823     }
1824   else
1825     {
1826       x0 = Xen_real_to_C_double(Xen_car(bounds));
1827       x1 = Xen_real_to_C_double(Xen_cadr(bounds));
1828       if (x1 < x0)
1829 	Xen_out_of_range_error(S_set S_x_bounds, 1, bounds, "x1 < x0?");
1830     }
1831 
1832   if (ap == cp->axis)
1833     {
1834       if (cp->time_graph_type == GRAPH_ONCE)
1835 	{
1836 	  snd_info *sp;
1837 	  set_x_axis_x0x1(cp, x0, x1);
1838 	  sp = cp->sound;
1839 	  if (sp->nchans > 1)
1840 	    {
1841 	      if ((!Xen_is_bound(chn)) && (cp->sound->channel_style == CHANNELS_COMBINED))
1842 		{
1843 		  uint32_t i;
1844 		  for (i = 0; i < sp->nchans; i++)
1845 		    if ((int)i != cp->chan)
1846 		      set_x_axis_x0x1(sp->chans[i], x0, x1);
1847 		  /* y-bounds are already tied together in the channels-combined case */
1848 		}
1849 	    }
1850 	}
1851     }
1852   else
1853     {
1854       ap->x0 = x0;
1855       ap->x1 = x1;
1856     }
1857   return(bounds);
1858 }
1859 
with_four_setter_args(g_set_x_bounds_reversed,g_set_x_bounds)1860 with_four_setter_args(g_set_x_bounds_reversed, g_set_x_bounds)
1861 
1862 
1863 
1864 static Xen g_y_bounds(Xen snd, Xen chn, Xen ax)
1865 {
1866   #define H_y_bounds "(" S_y_bounds " :optional snd chn axis): a list (y0 y1) giving the current y axis bounds of snd channel chn"
1867   axis_info *ap;
1868 
1869   Snd_assert_channel(S_y_bounds, snd, chn, 1);
1870   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_y_bounds, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1871   ap = TO_C_AXIS_INFO(snd, chn, ax, S_y_bounds);
1872 
1873   return(Xen_list_2(C_double_to_Xen_real(ap->y0),
1874 		    C_double_to_Xen_real(ap->y1)));
1875 }
1876 
1877 
g_set_y_bounds(Xen bounds,Xen snd,Xen chn,Xen ax)1878 static Xen g_set_y_bounds(Xen bounds, Xen snd, Xen chn, Xen ax)
1879 {
1880   chan_info *cp;
1881   axis_info *ap;
1882   mus_float_t low = 0.0, hi = 0.0;
1883 
1884   Snd_assert_channel(S_set S_y_bounds, snd, chn, 2);
1885   Xen_check_type((Xen_is_number(bounds)) || (Xen_is_list(bounds)), bounds, 1, S_set S_y_bounds, "a list or a number");
1886   Xen_check_type(Xen_is_integer_or_unbound(ax), ax, 4, S_set S_y_bounds, S_time_graph ", " S_transform_graph ", or " S_lisp_graph);
1887   ap = TO_C_AXIS_INFO(snd, chn, ax, S_set S_y_bounds);
1888 
1889   cp = get_cp(snd, chn, S_set S_y_bounds);
1890   if (!cp) return(Xen_false);
1891 
1892   if (Xen_is_number(bounds))
1893     {
1894       hi = Xen_real_to_C_double(bounds);
1895       low = -hi;
1896     }
1897   else
1898     {
1899       int len;
1900       Xen y0 = Xen_undefined, y1 = Xen_undefined;
1901       len = Xen_list_length(bounds);
1902       if (len > 0)
1903 	{
1904 	  y0 = Xen_car(bounds);
1905 	  if (len > 1)
1906 	    y1 = Xen_cadr(bounds);
1907 	}
1908       if (Xen_is_number(y0))
1909 	{
1910 	  low = Xen_real_to_C_double(y0);
1911 	  if (Xen_is_number(y1))
1912 	    hi = Xen_real_to_C_double(y1);
1913 	  else
1914 	    {
1915 	      if (low < 0.0)
1916 		hi = -low;
1917 	      else
1918 		{
1919 		  hi = low;
1920 		  low = -low;
1921 		}
1922 	    }
1923 	}
1924       else
1925 	{
1926 	  if (ap == cp->axis)
1927 	    {
1928 	      /* if no bounds given, use maxamp */
1929 	      hi = channel_maxamp(cp, AT_CURRENT_EDIT_POSITION);
1930 	      if (hi < 0.0) hi = -hi;
1931 	      if (hi == 0.0) hi = .001;
1932 	      low = -hi;
1933 	    }
1934 	}
1935     }
1936 
1937   if (hi > low)
1938     {
1939       ap->ymin = low;
1940       ap->ymax = hi;
1941       ap->y_ambit = (ap->ymax - ap->ymin);
1942       ap->y0 = low;
1943       ap->y1 = hi;
1944       ap->zy = 1.0;
1945       ap->sy = 0.0;
1946       if (ap == cp->axis)
1947 	{
1948 	  resize_sy_and_zy(cp);
1949 	  apply_y_axis_change(cp);
1950 	}
1951     }
1952 
1953   return(bounds);
1954 }
1955 
with_four_setter_args(g_set_y_bounds_reversed,g_set_y_bounds)1956 with_four_setter_args(g_set_y_bounds_reversed, g_set_y_bounds)
1957 
1958 
1959 Xen_wrap_4_optional_args(g_x_to_position_w, g_x_to_position)
1960 Xen_wrap_4_optional_args(g_y_to_position_w, g_y_to_position)
1961 Xen_wrap_4_optional_args(g_position_to_x_w, g_position_to_x)
1962 Xen_wrap_4_optional_args(g_position_to_y_w, g_position_to_y)
1963 Xen_wrap_3_optional_args(g_axis_info_w, g_axis_info)
1964 #if (!USE_NO_GUI)
1965 Xen_wrap_any_args(g_draw_axes_w, g_draw_axes)
1966 #endif
1967 Xen_wrap_3_optional_args(g_x_axis_label_w, g_x_axis_label)
1968 Xen_wrap_3_optional_args(g_y_axis_label_w, g_y_axis_label)
1969 Xen_wrap_3_optional_args(g_x_bounds_w, g_x_bounds)
1970 Xen_wrap_3_optional_args(g_y_bounds_w, g_y_bounds)
1971 #if HAVE_SCHEME
1972 #define g_set_x_axis_label_w g_set_x_axis_label_reversed
1973 #define g_set_y_axis_label_w g_set_y_axis_label_reversed
1974 #define g_set_x_bounds_w g_set_x_bounds_reversed
1975 #define g_set_y_bounds_w g_set_y_bounds_reversed
1976 #else
1977 Xen_wrap_4_optional_args(g_set_x_axis_label_w, g_set_x_axis_label)
1978 Xen_wrap_4_optional_args(g_set_y_axis_label_w, g_set_y_axis_label)
1979 Xen_wrap_4_optional_args(g_set_x_bounds_w, g_set_x_bounds)
1980 Xen_wrap_4_optional_args(g_set_y_bounds_w, g_set_y_bounds)
1981 #endif
1982 
1983 
1984 void g_init_axis(void)
1985 {
1986 #if HAVE_SCHEME
1987   s7_pointer i, p, t, f, r, s;
1988   i = s7_make_symbol(s7, "integer?");
1989   p = s7_make_symbol(s7, "pair?");
1990   f = s7_make_symbol(s7, "float?");
1991   r = s7_make_symbol(s7, "real?");
1992   s = s7_make_symbol(s7, "string?");
1993   t = s7_t(s7);
1994 #endif
1995 
1996   Xen_define_typed_procedure(S_x_to_position, g_x_to_position_w,   1, 3, 0, H_x_to_position, s7_make_signature(s7, 5, i, r, t, t, i));
1997   Xen_define_typed_procedure(S_y_to_position, g_y_to_position_w,   1, 3, 0, H_y_to_position, s7_make_signature(s7, 5, i, r, t, t, i));
1998   Xen_define_typed_procedure(S_position_to_x, g_position_to_x_w,   1, 3, 0, H_position_to_x, s7_make_signature(s7, 5, f, i, t, t, i));
1999   Xen_define_typed_procedure(S_position_to_y, g_position_to_y_w,   1, 3, 0, H_position_to_y, s7_make_signature(s7, 5, f, i, t, t, i));
2000   Xen_define_typed_procedure(S_axis_info,     g_axis_info_w,       0, 3, 0, H_axis_info,     s7_make_signature(s7, 4, p, t, t, i));
2001   Xen_define_typed_procedure(S_draw_axes,     g_draw_axes_w,       0, 0, 1, H_draw_axes,     s7_make_signature(s7, 11, p, t, t, t, r, r, r, r, i, i, p));
2002 
2003   Xen_define_typed_dilambda(S_x_axis_label, g_x_axis_label_w, H_x_axis_label, S_set S_x_axis_label, g_set_x_axis_label_w, 0, 3, 1, 3,
2004 			    s7_make_signature(s7, 4, s, t, t, i), s7_make_signature(s7, 5, s, t, t, i, s));
2005   Xen_define_typed_dilambda(S_y_axis_label, g_y_axis_label_w, H_y_axis_label, S_set S_y_axis_label, g_set_y_axis_label_w, 0, 3, 1, 3,
2006 			    s7_make_signature(s7, 4, s, t, t, i), s7_make_signature(s7, 5, s, t, t, i, s));
2007   Xen_define_typed_dilambda(S_x_bounds, g_x_bounds_w, H_x_bounds, S_set S_x_bounds, g_set_x_bounds_w, 0, 3, 1, 3,
2008 			    s7_make_signature(s7, 4, p, t, t, t), s7_make_signature(s7, 5, p, t, t, t, t));
2009   Xen_define_typed_dilambda(S_y_bounds, g_y_bounds_w, H_y_bounds, S_set S_y_bounds, g_set_y_bounds_w, 0, 3, 1, 3,
2010 			    s7_make_signature(s7, 4, p, t, t, t), s7_make_signature(s7, 5, p, t, t, t, t));
2011 
2012   Xen_define_constant(S_time_graph,      TIME_AXIS_INFO,      "time domain graph axis info");
2013   Xen_define_constant(S_transform_graph, TRANSFORM_AXIS_INFO, "frequency domain graph axis info");
2014   Xen_define_constant(S_lisp_graph,      LISP_AXIS_INFO,      "lisp graph axis info");
2015 }
2016 
2017 #endif
2018 /* end no gui (covers entire xen section) */
2019 /*   (if something is moved here, remember to add stubs to snd-nogui.c) */
2020