"Fossies" - the Fresh Open Source Software Archive

Member "snd-20.9/snd-print.c" (8 Sep 2020, 23599 Bytes) of package /linux/misc/snd-20.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "snd-print.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.7_vs_20.8.

    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 
   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 
   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 
   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 
   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 
   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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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);
  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);
  670 void gl2ps_text(const char *msg)
  671 {
  672   gl2psText(msg, "Times-Roman", 20);
  673 }
  674 
  675 #else
  676 
  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 
  689 static Xen g_eps_file(void) {return(C_string_to_Xen_string(eps_file(ss)));}
  690 
  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 
  703 static Xen g_eps_left_margin(void) {return(C_double_to_Xen_real(eps_left_margin(ss)));}
  704 
  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 
  714 static Xen g_eps_bottom_margin(void) {return(C_double_to_Xen_real(eps_bottom_margin(ss)));}
  715 
  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 
  725 static Xen g_eps_size(void) {return(C_double_to_Xen_real(eps_size(ss)));}
  726 
  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 
  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)));}
  750 static s7_pointer acc_eps_file(s7_scheme *sc, s7_pointer args) {return(g_set_eps_file(s7_cadr(args)));}
  751 static s7_pointer acc_eps_left_margin(s7_scheme *sc, s7_pointer args) {return(g_set_eps_left_margin(s7_cadr(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 
  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 }