1 #include "snd.h"
2
3 /* create Postscript version of graph */
4
5
6 static char *pbuf = NULL;
7 static int bbx = 0, bby = 0, bx0 = 0, by0 = 0;
8 static int ps_fd;
9
10 static char *nbuf = NULL;
11 static int nbuf_ctr = 0;
12 #define NBUF_SIZE 8192
13
14
ps_flush(int fd)15 static void ps_flush(int fd)
16 {
17 if (nbuf_ctr > 0)
18 {
19 ssize_t bytes;
20 bytes = write(fd, nbuf, nbuf_ctr);
21 if (bytes == 0) fprintf(stderr, "ps_flush write error");
22 nbuf_ctr = 0;
23 memset((void *)nbuf, 0, NBUF_SIZE);
24 }
25 }
26
27
ps_write(const char * buf)28 static void ps_write(const char *buf)
29 {
30 /* sending tiny buffers over the net is a total loss -- grab a bunch at a time */
31 int i, len;
32 if (!nbuf)
33 {
34 nbuf = (char *)calloc(NBUF_SIZE, sizeof(char));
35 nbuf_ctr = 0;
36 }
37 len = mus_strlen(buf);
38 for (i = 0; i < len; i++)
39 {
40 nbuf[nbuf_ctr++] = buf[i];
41 if (nbuf_ctr == NBUF_SIZE) ps_flush(ps_fd);
42 }
43 memset((void *)buf, 0, PRINT_BUFFER_SIZE);
44 }
45
46
start_ps_graph(const char * output,const char * title)47 static int start_ps_graph(const char *output, const char *title)
48 {
49 ps_fd = CREAT(output, 0666);
50 if (ps_fd == -1) return(-1);
51 if (!pbuf) pbuf = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
52 bbx = 0;
53 bby = 0;
54
55 snprintf(pbuf, PRINT_BUFFER_SIZE,
56 "%%!PS-Adobe-2.0 EPSF-2.0\n%%%%Title: %s\n%%%%Creator: Snd: %s\n%%%%CreationDate: %s",
57 title,
58 SND_DATE,
59 snd_local_time());
60 ps_write(pbuf);
61 snprintf(pbuf, PRINT_BUFFER_SIZE,
62 "\n%%%%BoundingBox:(atend)\n%%%%EndComments\n%%%%EndProlog\n%%%%Page: 1 1\n");
63 ps_write(pbuf);
64 snprintf(pbuf, PRINT_BUFFER_SIZE,
65 "/LT {lineto} bind def\n/RF {rectfill} bind def\n/RG {setrgbcolor} bind def\n/NAF {newpath arc fill} bind def\n\n");
66 ps_write(pbuf);
67
68 snprintf(pbuf, PRINT_BUFFER_SIZE,
69 "gsave [%.3f 0.0 0.0 %.3f %.3f %.3f] concat\n\n",
70 eps_size(ss), eps_size(ss), eps_left_margin(ss), eps_bottom_margin(ss));
71 ps_write(pbuf);
72 return(0);
73 }
74
75
ps_graph(chan_info * cp,int x0,int y0)76 static void ps_graph(chan_info *cp, int x0, int y0)
77 {
78 cp->printing = PRINTING;
79 bx0 = x0;
80 by0 = y0;
81 display_channel_data(cp);
82 cp->printing = NOT_PRINTING;
83 }
84
85
end_ps_graph(void)86 static void end_ps_graph(void)
87 {
88 snprintf(pbuf, PRINT_BUFFER_SIZE,
89 "%s\nshowpage\n%%%%Trailer\n%%%%BoundingBox: %d %d %d %d\n",
90 ((eps_left_margin(ss) != 0) || (eps_bottom_margin(ss) != 0)) ? "\ngrestore" : "",
91 0, 0,
92 (int)(bbx + 10 + eps_left_margin(ss)),
93 (int)(bby + 10 + eps_bottom_margin(ss)));
94 ps_write(pbuf);
95 ps_flush(ps_fd);
96 snd_close(ps_fd, "eps file");
97 if (nbuf)
98 {
99 free(nbuf);
100 nbuf = NULL;
101 nbuf_ctr = 0;
102 }
103 }
104
105
106 /* the x and y values in the "points" are relative to grf_x/y:
107 *
108 * x: ap->x_axis_x0 + (val - ap->x0) * ap->x_scale
109 * y: ap->y_axis_y0 + (val * MUS_FIX_TO_FLOAT - ap->y0) * ap->y_scale
110 *
111 * kept here in full precision since normally printers have much higher resolution than screens
112 */
113
reflect_y(axis_info * ap,int y)114 static int reflect_y(axis_info *ap, int y)
115 {
116 return(ap->height - y);
117 }
118
119
120 static mus_float_t *xpts = NULL;
121 static mus_float_t *ypts = NULL;
122 static mus_float_t *ypts1 = NULL;
123
ps_allocate_grf_points(void)124 void ps_allocate_grf_points(void)
125 {
126 if (!xpts) xpts = (mus_float_t *)calloc(POINT_BUFFER_SIZE, sizeof(mus_float_t));
127 if (!ypts) ypts = (mus_float_t *)calloc(POINT_BUFFER_SIZE, sizeof(mus_float_t));
128 if (!ypts1) ypts1 = (mus_float_t *)calloc(POINT_BUFFER_SIZE, sizeof(mus_float_t));
129 }
130
131
ps_set_grf_points(double x,int j,mus_float_t ymin,mus_float_t ymax)132 void ps_set_grf_points(double x, int j, mus_float_t ymin, mus_float_t ymax)
133 {
134 xpts[j] = x;
135 ypts[j] = ymin;
136 ypts1[j] = ymax;
137 }
138
139
ps_set_grf_point(double x,int j,mus_float_t y)140 void ps_set_grf_point(double x, int j, mus_float_t y)
141 {
142 xpts[j] = x;
143 ypts[j] = y;
144 }
145
146
ps_grf_x(axis_info * ap,mus_float_t val)147 static mus_float_t ps_grf_x(axis_info *ap, mus_float_t val)
148 {
149 return(ap->x_axis_x0 + bx0 + (val - ap->x0) * ap->x_scale);
150 }
151
152
ps_grf_y(axis_info * ap,mus_float_t val)153 static mus_float_t ps_grf_y(axis_info *ap, mus_float_t val)
154 {
155 return(by0 + ap->height - (ap->y_axis_y0 + (val - ap->y0) * ap->y_scale));
156 }
157
158
ps_draw_lines(axis_info * ap,int j,mus_float_t * xpts,mus_float_t * ypts)159 static void ps_draw_lines(axis_info *ap, int j, mus_float_t *xpts, mus_float_t *ypts)
160 {
161 int i;
162 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f moveto\n", ps_grf_x(ap, xpts[0]), ps_grf_y(ap, ypts[0]));
163 ps_write(pbuf);
164 for (i = 1; i < j; i++)
165 {
166 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, ypts[i]));
167 ps_write(pbuf);
168 }
169 snprintf(pbuf, PRINT_BUFFER_SIZE, " stroke\n");
170 ps_write(pbuf);
171 }
172
173
ps_draw_dots(axis_info * ap,int j,mus_float_t * xpts,mus_float_t * ypts,int dot_size)174 static void ps_draw_dots(axis_info *ap, int j, mus_float_t *xpts, mus_float_t *ypts, int dot_size)
175 {
176 int i;
177 mus_float_t arc_size;
178 arc_size = .5 * dot_size; /* radius here, diameter in X */
179 for (i = 0; i < j; i++)
180 {
181 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f 0 360 NAF\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, ypts[i]), arc_size);
182 ps_write(pbuf);
183 }
184 }
185
186
ps_fill_polygons(axis_info * ap,int j,mus_float_t * xpts,mus_float_t * ypts,mus_float_t y0)187 static void ps_fill_polygons(axis_info *ap, int j, mus_float_t *xpts, mus_float_t *ypts, mus_float_t y0)
188 {
189 int i;
190 for (i = 1; i < j; i++)
191 {
192 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f moveto\n", ps_grf_x(ap, xpts[i - 1]), ps_grf_y(ap, ypts[i - 1]));
193 ps_write(pbuf);
194 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, ypts[i]));
195 ps_write(pbuf);
196 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, y0));
197 ps_write(pbuf);
198 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i - 1]), ps_grf_y(ap, y0));
199 ps_write(pbuf);
200 snprintf(pbuf, PRINT_BUFFER_SIZE, " closepath fill\n");
201 ps_write(pbuf);
202 }
203 }
204
205
ps_draw_grf_points(axis_info * ap,int j,mus_float_t y0,graph_style_t graph_style,int dot_size)206 void ps_draw_grf_points(axis_info *ap, int j, mus_float_t y0, graph_style_t graph_style, int dot_size)
207 {
208 switch (graph_style)
209 {
210 case GRAPH_LINES:
211 default:
212 ps_draw_lines(ap, j, xpts, ypts);
213 break;
214 case GRAPH_DOTS:
215 ps_draw_dots(ap, j, xpts, ypts, dot_size);
216 break;
217 case GRAPH_FILLED:
218 ps_fill_polygons(ap, j, xpts, ypts, y0);
219 break;
220 case GRAPH_DOTS_AND_LINES:
221 ps_draw_lines(ap, j, xpts, ypts);
222 if (dot_size > 1) ps_draw_dots(ap, j, xpts, ypts, dot_size);
223 break;
224 case GRAPH_LOLLIPOPS:
225 {
226 int i, gy0, size8, size4;
227 if (dot_size > 1) ps_draw_dots(ap, j, xpts, ypts, dot_size);
228 gy0 = (int)ps_grf_y(ap, y0);
229 size8 = dot_size / 8;
230 size4 = dot_size / 4;
231 if (size4 < 1) size4 = 1;
232 for (i = 0; i < j; i++)
233 {
234 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f %.2f RF\n",
235 ps_grf_x(ap, xpts[i]) - size8,
236 (double)gy0,
237 (double)size4,
238 ps_grf_y(ap, ypts[i]) - gy0);
239 ps_write(pbuf);
240 }
241 }
242 break;
243 }
244 }
245
246
ps_draw_both_grf_points(axis_info * ap,int j,graph_style_t graph_style,int dot_size)247 void ps_draw_both_grf_points(axis_info *ap, int j, graph_style_t graph_style, int dot_size)
248 {
249 int i, size8, size4;
250 switch (graph_style)
251 {
252 case GRAPH_LINES:
253 default:
254 ps_draw_lines(ap, j, xpts, ypts);
255 ps_draw_lines(ap, j, xpts, ypts1);
256 break;
257 case GRAPH_DOTS:
258 ps_draw_dots(ap, j, xpts, ypts, dot_size);
259 ps_draw_dots(ap, j, xpts, ypts1, dot_size);
260 break;
261 case GRAPH_FILLED:
262 for (i = 1; i < j; i++)
263 {
264 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f moveto\n", ps_grf_x(ap, xpts[i - 1]), ps_grf_y(ap, ypts[i - 1]));
265 ps_write(pbuf);
266 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, ypts[i]));
267 ps_write(pbuf);
268 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i]), ps_grf_y(ap, ypts1[i]));
269 ps_write(pbuf);
270 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f lineto\n", ps_grf_x(ap, xpts[i - 1]), ps_grf_y(ap, ypts1[i - 1]));
271 ps_write(pbuf);
272 snprintf(pbuf, PRINT_BUFFER_SIZE, " closepath fill\n");
273 ps_write(pbuf);
274 }
275 break;
276 case GRAPH_DOTS_AND_LINES:
277 if (dot_size > 1)
278 {
279 ps_draw_dots(ap, j, xpts, ypts, dot_size);
280 ps_draw_dots(ap, j, xpts, ypts1, dot_size);
281 }
282 ps_draw_lines(ap, j, xpts, ypts);
283 ps_draw_lines(ap, j, xpts, ypts1);
284 break;
285 case GRAPH_LOLLIPOPS:
286 if (dot_size > 1)
287 {
288 ps_draw_dots(ap, j, xpts, ypts, dot_size);
289 ps_draw_dots(ap, j, xpts, ypts1, dot_size);
290 }
291 size8 = dot_size / 8;
292 size4 = dot_size / 4;
293 if (size4 < 1) size4 = 1;
294 for (i = 0; i < j; i++)
295 {
296 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f %.2f RF\n",
297 ps_grf_x(ap, xpts[i]) - size8,
298 ps_grf_y(ap, ypts[i]),
299 (double)size4,
300 ps_grf_y(ap, ypts1[i]) - ps_grf_y(ap, ypts[i]));
301 ps_write(pbuf);
302 }
303
304 break;
305 }
306 }
307
308
309 static int last_color = -1;
310
ps_draw_sono_rectangle(axis_info * ap,int color,mus_float_t x,mus_float_t y,mus_float_t width,mus_float_t height)311 void ps_draw_sono_rectangle(axis_info *ap, int color, mus_float_t x, mus_float_t y, mus_float_t width, mus_float_t height)
312 {
313 rgb_t r, g, b;
314 if (last_color != color)
315 {
316 get_current_color(color_map(ss), color, &r, &g, &b);
317 last_color = color;
318 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f RG\n", rgb_to_float(r), rgb_to_float(g), rgb_to_float(b));
319 ps_write(pbuf);
320 }
321 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.1f %.1f %.2f %.2f RF\n", ps_grf_x(ap, x) + 2, ps_grf_y(ap, y), width, height);
322 ps_write(pbuf);
323 }
324
325
ps_reset_color(void)326 void ps_reset_color(void)
327 {
328 snprintf(pbuf, PRINT_BUFFER_SIZE, " 0 setgray\n");
329 ps_write(pbuf);
330 last_color = -1;
331 }
332
333
334 #if USE_MOTIF
ps_set_color(color_t color)335 static void ps_set_color(color_t color)
336 {
337 Colormap cmap;
338 XColor tmp_color;
339 Display *dpy;
340 dpy = XtDisplay(main_shell(ss));
341 cmap = DefaultColormap(dpy, DefaultScreen(dpy));
342 tmp_color.flags = DoRed | DoGreen | DoBlue;
343 tmp_color.pixel = color;
344 XQueryColor(dpy, cmap, &tmp_color);
345 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f RG\n",
346 rgb_to_float(tmp_color.red),
347 rgb_to_float(tmp_color.green),
348 rgb_to_float(tmp_color.blue));
349 ps_write(pbuf);
350 last_color = -1;
351 }
352 #endif
353
354
ps_bg(axis_info * ap,graphics_context * ax)355 void ps_bg(axis_info *ap, graphics_context *ax)
356 {
357 /* get background color, fill graph, then set foreground for axis */
358 chan_info *cp;
359 cp = ap->cp;
360 #if USE_MOTIF
361 {
362 XGCValues gv;
363 XGetGCValues(main_display(ss), ax->gc, GCBackground, &gv);
364 ps_set_color(gv.background);
365 }
366 #endif
367 snprintf(pbuf, PRINT_BUFFER_SIZE, " %d %d %d %d RF\n",
368 ap->graph_x0 + bx0, ap->y_offset + by0, ap->width, ap->height);
369 ps_write(pbuf);
370 ps_fg(cp, ax);
371 }
372
373
ps_fg(chan_info * cp,graphics_context * ax)374 void ps_fg(chan_info *cp, graphics_context *ax)
375 {
376 /* set foreground color for subsequent line drawing */
377 #if USE_MOTIF
378 ps_set_color(get_foreground_color(ax));
379 #endif
380 }
381
382
383 /* the rest are in real coordinates except upsidedown from PS point of view */
384
ps_draw_line(axis_info * ap,int x0,int y0,int x1,int y1)385 void ps_draw_line(axis_info *ap, int x0, int y0, int x1, int y1)
386 {
387 int py0, py1, px0, px1;
388 px0 = x0 + bx0;
389 px1 = x1 + bx0;
390 py0 = reflect_y(ap, y0) + by0;
391 py1 = reflect_y(ap, y1) + by0;
392 if (px0 > bbx) bbx = px0;
393 if (px1 > bbx) bbx = px1;
394 if (py0 > bby) bby = py0;
395 if (py1 > bby) bby = py1;
396 snprintf(pbuf, PRINT_BUFFER_SIZE, " 0 setlinewidth %d %d moveto %d %d lineto stroke\n", px0, py0, px1, py1);
397 ps_write(pbuf);
398 }
399
400
ps_draw_spectro_line(axis_info * ap,int color,mus_float_t x0,mus_float_t y0,mus_float_t x1,mus_float_t y1)401 void ps_draw_spectro_line(axis_info *ap, int color, mus_float_t x0, mus_float_t y0, mus_float_t x1, mus_float_t y1)
402 {
403 /* these are in local coords */
404 rgb_t r, g, b;
405 if (last_color != color)
406 {
407 get_current_color(color_map(ss), color, &r, &g, &b);
408 last_color = color;
409 snprintf(pbuf, PRINT_BUFFER_SIZE, " %.2f %.2f %.2f RG\n", rgb_to_float(r), rgb_to_float(g), rgb_to_float(b));
410 ps_write(pbuf);
411 }
412 ps_draw_line(ap, (int)x0, (int)y0, (int)x1, (int)y1);
413 }
414
415
ps_fill_rectangle(axis_info * ap,int x0,int y0,int width,int height)416 void ps_fill_rectangle(axis_info *ap, int x0, int y0, int width, int height)
417 {
418 int py0, py1, px0, px1;
419 px0 = x0 + bx0;
420 px1 = x0 + bx0 + width;
421 py0 = reflect_y(ap, y0) + by0;
422 py1 = reflect_y(ap, y0 + height) + by0;
423 if (px0 > bbx) bbx = px0;
424 if (px1 > bbx) bbx = px1;
425 if (py0 > bby) bby = py0;
426 if (py1 > bby) bby = py1;
427 snprintf(pbuf, PRINT_BUFFER_SIZE, " %d %d %d %d RF\n", px0, py0, width, -height);
428 ps_write(pbuf);
429 }
430
431
ps_draw_string(axis_info * ap,int x0,int y0,const char * str)432 void ps_draw_string(axis_info *ap, int x0, int y0, const char *str)
433 {
434 int px0, py0;
435 px0 = x0 + bx0;
436 py0 = reflect_y(ap, y0) + by0;
437 if (px0 > bbx) bbx = px0;
438 if (py0 > bby) bby = py0;
439 snprintf(pbuf, PRINT_BUFFER_SIZE, " %d %d moveto (%s) show\n", px0, py0, str);
440 ps_write(pbuf);
441 }
442
443
ps_set_number_font(void)444 void ps_set_number_font(void)
445 {
446 snprintf(pbuf, PRINT_BUFFER_SIZE, " /Courier findfont 15 scalefont setfont\n");
447 ps_write(pbuf);
448 }
449
450
ps_set_label_font(void)451 void ps_set_label_font(void)
452 {
453 snprintf(pbuf, PRINT_BUFFER_SIZE, " /Times-Roman findfont 20 scalefont setfont\n");
454 ps_write(pbuf);
455 }
456
457
ps_set_bold_peak_numbers_font(void)458 void ps_set_bold_peak_numbers_font(void)
459 {
460 snprintf(pbuf, PRINT_BUFFER_SIZE, " /Times-Bold findfont 14 scalefont setfont\n");
461 ps_write(pbuf);
462 }
463
464
ps_set_peak_numbers_font(void)465 void ps_set_peak_numbers_font(void)
466 {
467 snprintf(pbuf, PRINT_BUFFER_SIZE, " /Times-Roman findfont 14 scalefont setfont\n");
468 ps_write(pbuf);
469 }
470
471
ps_set_tiny_numbers_font(void)472 void ps_set_tiny_numbers_font(void)
473 {
474 snprintf(pbuf, PRINT_BUFFER_SIZE, " /Times-Roman findfont 12 scalefont setfont\n");
475 ps_write(pbuf);
476 }
477
478
479 #define PRINTED_VERTICAL_SPACING 25
480
snd_print_or_error(const char * output)481 static char *snd_print_or_error(const char *output)
482 {
483 if ((output) && (*output))
484 {
485 int j, i, err;
486 int *offsets = NULL;
487 sync_info *si;
488 chan_info *ccp;
489 char *errstr = NULL;
490 ccp = current_channel();
491 if (!ccp)
492 return(mus_strdup("nothing to print?"));
493 si = sync_to_chan(ccp);
494 offsets = (int *)calloc(si->chans, sizeof(int));
495 for (j = 0, i = (si->chans - 1); i >= 0; i--)
496 {
497 offsets[i] = j;
498 j += ((((axis_info *)((si->cps[i])->axis))->height) + PRINTED_VERTICAL_SPACING);
499 }
500 if (si->chans > 1)
501 for (i = 0; i < si->chans; )
502 {
503 snd_info *sp;
504 sp = (si->cps[i])->sound;
505 if (!sp) break;
506 if (sp->channel_style == CHANNELS_COMBINED)
507 for (j = i + 1; (j < i + (int)sp->nchans) && (j < si->chans); j++)
508 offsets[j] = offsets[i];
509 else
510 if (sp->channel_style == CHANNELS_SUPERIMPOSED)
511 for (j = i; (j < i + (int)sp->nchans - 1) && (j < si->chans); j++)
512 offsets[j] = offsets[i + sp->nchans - 1];
513 i += sp->nchans;
514 }
515 err = start_ps_graph(output, ((si->cps[0])->sound)->filename);
516 if (err == 0)
517 {
518 for (i = 0; i < si->chans; i++)
519 ps_graph(si->cps[i], 0, offsets[i]);
520 end_ps_graph();
521 }
522 else errstr = mus_format("print %s failed: %s", output, snd_io_strerror());
523 free_sync_info(si);
524 if (offsets) free(offsets);
525 return(errstr);
526 }
527 else return(mus_strdup("print sound: eps file name needed"));
528 }
529
530
snd_print(const char * output)531 bool snd_print(const char *output)
532 {
533 char *error;
534 error = snd_print_or_error(output);
535 if (error)
536 {
537 snd_error_without_format(error);
538 free(error);
539 return(false);
540 }
541 return(true);
542 }
543
544
print_enved(const char * output,int y0)545 void print_enved(const char *output, int y0)
546 {
547 if ((output) && (*output))
548 {
549 int err;
550 err = start_ps_graph(output, "Envelope Editor");
551 if (err == 0)
552 {
553 bx0 = 0;
554 by0 = y0;
555 env_redisplay_with_print();
556 end_ps_graph();
557 }
558 else snd_error("print env %s failed: %s", output, snd_io_strerror());
559 }
560 else snd_error_without_format("print envelope: eps file name needed");
561 }
562
563
g_graph_to_ps(Xen filename)564 static Xen g_graph_to_ps(Xen filename)
565 {
566 #define H_graph_to_ps "(" S_graph_to_ps " :optional (filename eps-file)): write the current Snd displays to an EPS file"
567
568 char *error;
569 const char *file;
570
571 Xen_check_type(Xen_is_string_or_unbound(filename), filename, 1, S_graph_to_ps, "a string (filename)");
572
573 if (Xen_is_string(filename))
574 file = Xen_string_to_C_string(filename);
575 else file = eps_file(ss);
576
577 error = snd_print_or_error(file);
578 if (error)
579 {
580 Xen result;
581 result = C_string_to_Xen_string(error);
582 free(error);
583 Xen_error(Xen_make_error_type("cannot-print"),
584 Xen_list_3(C_string_to_Xen_string(S_graph_to_ps ": can't print ~S (~A)"),
585 C_string_to_Xen_string(file),
586 result));
587 }
588 return(C_string_to_Xen_string(file));
589 }
590
591
592 /* ---------------- gl -> ps ---------------- */
593
594 #if HAVE_GL && WITH_GL2PS
595
596 #include "gl2ps.h"
597
598 #define NUM_GL2PS_TYPES 6
599 static int gl2ps_types[NUM_GL2PS_TYPES] = {GL2PS_EPS, GL2PS_PS, GL2PS_PDF, GL2PS_TEX, GL2PS_SVG, GL2PS_PGF};
600
601
g_gl_graph_to_ps(Xen filename,Xen output_type,Xen snd,Xen chn)602 static Xen g_gl_graph_to_ps(Xen filename, Xen output_type, Xen snd, Xen chn)
603 {
604 #define H_gl_graph_to_ps "(" S_gl_graph_to_ps " :optional filename (type 0) snd chn) produces a postscript output file from \
605 OpenGL graphics. type can be 0: eps, 1: ps, 2: pdf, 3: tex, 4: svg, 5: pgf."
606
607 const char *file;
608 FILE *fp;
609 chan_info *cp;
610 int state = GL2PS_OVERFLOW, buffsize = 1024 * 1024, type = 0;
611
612 Xen_check_type(Xen_is_string_or_unbound(filename), filename, 1, S_gl_graph_to_ps, "a string (filename)");
613 Xen_check_type(Xen_is_integer_or_unbound(output_type), output_type, 2, S_gl_graph_to_ps, "an integer, 0=eps");
614
615 Snd_assert_channel(S_gl_graph_to_ps, snd, chn, 3);
616 cp = get_cp(snd, chn, S_gl_graph_to_ps);
617 if (!cp) return(Xen_false);
618
619 if (Xen_is_string(filename))
620 file = Xen_string_to_C_string(filename);
621 else file = eps_file(ss);
622
623 if (Xen_is_integer(output_type))
624 type = Xen_integer_to_C_int(output_type);
625 if ((type < 0) || (type >= NUM_GL2PS_TYPES))
626 Xen_out_of_range_error(S_gl_graph_to_ps, 2, output_type, "must be between 0 and 5");
627
628 fp = fopen(file, "wb");
629
630 while (state == GL2PS_OVERFLOW)
631 {
632 GLint err;
633 buffsize += 1024 * 1024;
634 err = gl2psBeginPage(cp->sound->short_filename, "Snd", NULL,
635 gl2ps_types[type],
636 GL2PS_BSP_SORT,
637 GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT | GL2PS_OCCLUSION_CULL, /* perhaps also GL2PS_NO_BLENDING */
638 GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, file);
639 if (err != GL2PS_SUCCESS)
640 {
641 /* if an error occurs, gl2ps itself insists on printing something -- this needs to be fixed! */
642 state = (int)err;
643 }
644 else
645 {
646 ss->gl_printing = true;
647 display_channel_fft_data(cp);
648 ss->gl_printing = false;
649
650 state = gl2psEndPage();
651 }
652 }
653 fclose(fp);
654
655 return(C_string_to_Xen_string(file));
656 }
657
658
659 char *gl2ps_version(void);
gl2ps_version(void)660 char *gl2ps_version(void)
661 {
662 char *buf;
663 buf = (char *)calloc(128, sizeof(char));
664 snprintf(buf, 128, "gl2ps %d.%d.%d", GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION);
665 return(buf);
666 }
667
668
669 void gl2ps_text(const char *msg);
gl2ps_text(const char * msg)670 void gl2ps_text(const char *msg)
671 {
672 gl2psText(msg, "Times-Roman", 20);
673 }
674
675 #else
676
g_gl_graph_to_ps(Xen filename,Xen output_type,Xen snd_ignore,Xen chn_ignore)677 static Xen g_gl_graph_to_ps(Xen filename, Xen output_type, Xen snd_ignore, Xen chn_ignore)
678 {
679 #define H_gl_graph_to_ps "gl-graph->ps is a no-op in this version of Snd"
680 Xen_check_type(Xen_is_string_or_unbound(filename), filename, 1, S_gl_graph_to_ps, "a string (filename)");
681 Xen_check_type(Xen_is_integer_or_unbound(output_type), output_type, 2, S_gl_graph_to_ps, "an integer, 0=eps");
682 return(Xen_false);
683 }
684 #endif
685
686 /* -------------------------------- */
687
688
g_eps_file(void)689 static Xen g_eps_file(void) {return(C_string_to_Xen_string(eps_file(ss)));}
690
g_set_eps_file(Xen val)691 static Xen g_set_eps_file(Xen val)
692 {
693 #define H_eps_file "(" S_eps_file "): File:Print and " S_graph_to_ps " file name (snd.eps)"
694 Xen_check_type(Xen_is_string(val), val, 1, S_set S_eps_file, "a string");
695 if (eps_file(ss)) free(eps_file(ss));
696 set_eps_file(mus_strdup(Xen_string_to_C_string(val)));
697 return(C_string_to_Xen_string(eps_file(ss)));
698 }
699
700
701 #define MAX_EPS_MARGIN 1000.0
702
g_eps_left_margin(void)703 static Xen g_eps_left_margin(void) {return(C_double_to_Xen_real(eps_left_margin(ss)));}
704
g_set_eps_left_margin(Xen val)705 static Xen g_set_eps_left_margin(Xen val)
706 {
707 #define H_eps_left_margin "(" S_eps_left_margin "): File:Print and " S_graph_to_ps " left margin"
708 Xen_check_type(Xen_is_number(val), val, 1, S_set S_eps_left_margin, "a number");
709 set_eps_left_margin(mus_fclamp(0.0, Xen_real_to_C_double(val), MAX_EPS_MARGIN));
710 return(C_double_to_Xen_real(eps_left_margin(ss)));
711 }
712
713
g_eps_bottom_margin(void)714 static Xen g_eps_bottom_margin(void) {return(C_double_to_Xen_real(eps_bottom_margin(ss)));}
715
g_set_eps_bottom_margin(Xen val)716 static Xen g_set_eps_bottom_margin(Xen val)
717 {
718 #define H_eps_bottom_margin "(" S_eps_bottom_margin "): File:Print and " S_graph_to_ps " bottom margin"
719 Xen_check_type(Xen_is_number(val), val, 1, S_set S_eps_bottom_margin, "a number");
720 set_eps_bottom_margin(mus_fclamp(0.0, Xen_real_to_C_double(val), MAX_EPS_MARGIN));
721 return(C_double_to_Xen_real(eps_bottom_margin(ss)));
722 }
723
724
g_eps_size(void)725 static Xen g_eps_size(void) {return(C_double_to_Xen_real(eps_size(ss)));}
726
g_set_eps_size(Xen val)727 static Xen g_set_eps_size(Xen val)
728 {
729 #define MAX_EPS_SIZE 1000.0
730 #define H_eps_size "(" S_eps_size "): File:Print and " S_graph_to_ps " output size scaler (1.0)"
731 Xen_check_type(Xen_is_number(val), val, 1, S_set S_eps_size, "a number");
732 set_eps_size(mus_fclamp(0.0, Xen_real_to_C_double(val), MAX_EPS_SIZE));
733 return(C_double_to_Xen_real(eps_size(ss)));
734 }
735
736
Xen_wrap_1_optional_arg(g_graph_to_ps_w,g_graph_to_ps)737 Xen_wrap_1_optional_arg(g_graph_to_ps_w, g_graph_to_ps)
738 Xen_wrap_4_optional_args(g_gl_graph_to_ps_w, g_gl_graph_to_ps)
739 Xen_wrap_no_args(g_eps_file_w, g_eps_file)
740 Xen_wrap_1_arg(g_set_eps_file_w, g_set_eps_file)
741 Xen_wrap_no_args(g_eps_left_margin_w, g_eps_left_margin)
742 Xen_wrap_1_arg(g_set_eps_left_margin_w, g_set_eps_left_margin)
743 Xen_wrap_no_args(g_eps_size_w, g_eps_size)
744 Xen_wrap_1_arg(g_set_eps_size_w, g_set_eps_size)
745 Xen_wrap_no_args(g_eps_bottom_margin_w, g_eps_bottom_margin)
746 Xen_wrap_1_arg(g_set_eps_bottom_margin_w, g_set_eps_bottom_margin)
747
748 #if HAVE_SCHEME
749 static s7_pointer acc_eps_bottom_margin(s7_scheme *sc, s7_pointer args) {return(g_set_eps_bottom_margin(s7_cadr(args)));}
acc_eps_file(s7_scheme * sc,s7_pointer args)750 static s7_pointer acc_eps_file(s7_scheme *sc, s7_pointer args) {return(g_set_eps_file(s7_cadr(args)));}
acc_eps_left_margin(s7_scheme * sc,s7_pointer args)751 static s7_pointer acc_eps_left_margin(s7_scheme *sc, s7_pointer args) {return(g_set_eps_left_margin(s7_cadr(args)));}
acc_eps_size(s7_scheme * sc,s7_pointer args)752 static s7_pointer acc_eps_size(s7_scheme *sc, s7_pointer args) {return(g_set_eps_size(s7_cadr(args)));}
753 #endif
754
g_init_print(void)755 void g_init_print(void)
756 {
757 #if HAVE_SCHEME
758 s7_pointer i, t, r, s, pcl_s, pcl_r;
759 r = s7_make_symbol(s7, "real?");
760 s = s7_make_symbol(s7, "string?");
761 i = s7_make_symbol(s7, "integer?");
762 t = s7_t(s7);
763 pcl_s = s7_make_circular_signature(s7, 0, 1, s);
764 pcl_r = s7_make_circular_signature(s7, 0, 1, r);
765 #endif
766
767 Xen_define_typed_procedure(S_graph_to_ps, g_graph_to_ps_w, 0, 1, 0, H_graph_to_ps, pcl_s);
768 Xen_define_typed_procedure(S_gl_graph_to_ps, g_gl_graph_to_ps_w, 0, 4, 0, H_gl_graph_to_ps, s7_make_signature(s7, 5, s, s, i, t, t));
769
770 Xen_define_typed_dilambda(S_eps_file, g_eps_file_w, H_eps_file,
771 S_set S_eps_file, g_set_eps_file_w, 0, 0, 1, 0, pcl_s, pcl_s);
772
773 Xen_define_typed_dilambda(S_eps_left_margin, g_eps_left_margin_w, H_eps_left_margin,
774 S_set S_eps_left_margin, g_set_eps_left_margin_w, 0, 0, 1, 0, pcl_r, pcl_r);
775
776 Xen_define_typed_dilambda(S_eps_bottom_margin, g_eps_bottom_margin_w, H_eps_bottom_margin,
777 S_set S_eps_bottom_margin, g_set_eps_bottom_margin_w, 0, 0, 1, 0, pcl_r, pcl_r);
778
779 Xen_define_typed_dilambda(S_eps_size, g_eps_size_w, H_eps_size,
780 S_set S_eps_size, g_set_eps_size_w, 0, 0, 1, 0, pcl_r, pcl_r);
781
782 #if HAVE_GL && WITH_GL2PS
783 Xen_provide_feature("gl2ps");
784 #endif
785
786 #if HAVE_SCHEME
787 s7_set_setter(s7, ss->eps_bottom_margin_symbol, s7_make_function(s7, "[acc-" S_eps_bottom_margin "]", acc_eps_bottom_margin, 2, 0, false, "accessor"));
788 s7_set_setter(s7, ss->eps_file_symbol, s7_make_function(s7, "[acc-" S_eps_file "]", acc_eps_file, 2, 0, false, "accessor"));
789 s7_set_setter(s7, ss->eps_left_margin_symbol, s7_make_function(s7, "[acc-" S_eps_left_margin "]", acc_eps_left_margin, 2, 0, false, "accessor"));
790 s7_set_setter(s7, ss->eps_size_symbol, s7_make_function(s7, "[acc-" S_eps_size "]", acc_eps_size, 2, 0, false, "accessor"));
791
792 s7_set_documentation(s7, ss->eps_bottom_margin_symbol, "*eps-bottom-margin*: File:Print and graph->ps bottom margin");
793 s7_set_documentation(s7, ss->eps_file_symbol, "*eps-file*: File:Print and graph->ps file name (snd.eps)");
794 s7_set_documentation(s7, ss->eps_left_margin_symbol, "*eps-left-margin*: File:Print and graph->ps left margin");
795 s7_set_documentation(s7, ss->eps_size_symbol, "*eps-size*: File:Print and graph->ps output size scaler (1.0)");
796 #endif
797 }
798