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